#define __ ACCESS_MASM(masm)
+
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
+ Register type,
+ Label* global_object) {
+ // Register usage:
+ // type: holds the receiver instance type on entry.
+ __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
+ __ b(eq, global_object);
+ __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
+ __ b(eq, global_object);
+ __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
+ __ b(eq, global_object);
+}
+
+
+// Generated code falls through if the receiver is a regular non-global
+// JS object with slow properties and no interceptors.
+static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm,
+ Register receiver,
+ Register elements,
+ Register t0,
+ Register t1,
+ Label* miss) {
+ // Register usage:
+ // receiver: holds the receiver on entry and is unchanged.
+ // elements: holds the property dictionary on fall through.
+ // Scratch registers:
+ // t0: used to holds the receiver map.
+ // t1: used to holds the receiver instance type, receiver bit mask and
+ // elements map.
+
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss);
+
+ // Check that the receiver is a valid JS object.
+ __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
+ __ b(lt, miss);
+
+ // If this assert fails, we have to check upper bound too.
+ ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+ GenerateGlobalInstanceTypeCheck(masm, t1, miss);
+
+ // Check that the global object does not require access checks.
+ __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
+ __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
+ (1 << Map::kHasNamedInterceptor)));
+ __ b(nz, miss);
+
+ __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+ __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
+ __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+ __ cmp(t1, ip);
+ __ b(nz, miss);
+}
+
+
// Helper function used from LoadIC/CallIC GenerateNormal.
-// receiver: Receiver. It is not clobbered if a jump to the miss label is
-// done
+//
+// elements: Property dictionary. It is not clobbered if a jump to the miss
+// label is done.
// name: Property name. It is not clobbered if a jump to the miss label is
// done
// result: Register for the result. It is only updated if a jump to the miss
-// label is not done. Can be the same as receiver or name clobbering
+// label is not done. Can be the same as elements or name clobbering
// one of these in the case of not jumping to the miss label.
-// The three scratch registers need to be different from the receiver, name and
+// The two scratch registers need to be different from elements, name and
// result.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm,
Label* miss,
- Register receiver,
+ Register elements,
Register name,
Register result,
Register scratch1,
- Register scratch2,
- Register scratch3,
- DictionaryCheck check_dictionary) {
+ Register scratch2) {
// Main use of the scratch registers.
- // scratch1: Used to hold the property dictionary.
- // scratch2: Used as temporary and to hold the capacity of the property
+ // scratch1: Used as temporary and to hold the capacity of the property
// dictionary.
- // scratch3: Used as temporary.
+ // scratch2: Used as temporary.
Label done;
- // Check for the absence of an interceptor.
- // Load the map into scratch1.
- __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kMapOffset));
-
- // Bail out if the receiver has a named interceptor.
- __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
- __ tst(scratch2, Operand(1 << Map::kHasNamedInterceptor));
- __ b(nz, miss);
-
- // Bail out if we have a JS global proxy object.
- __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
- __ cmp(scratch2, Operand(JS_GLOBAL_PROXY_TYPE));
- __ b(eq, miss);
-
- // Possible work-around for http://crbug.com/16276.
- // See also: http://codereview.chromium.org/155418.
- __ cmp(scratch2, Operand(JS_GLOBAL_OBJECT_TYPE));
- __ b(eq, miss);
- __ cmp(scratch2, Operand(JS_BUILTINS_OBJECT_TYPE));
- __ b(eq, miss);
-
- // Load the properties array.
- __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- // Check that the properties array is a dictionary.
- if (check_dictionary == CHECK_DICTIONARY) {
- __ ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
- __ cmp(scratch2, ip);
- __ b(ne, miss);
- }
-
// Compute the capacity mask.
const int kCapacityOffset = StringDictionary::kHeaderSize +
StringDictionary::kCapacityIndex * kPointerSize;
- __ ldr(scratch2, FieldMemOperand(scratch1, kCapacityOffset));
- __ mov(scratch2, Operand(scratch2, ASR, kSmiTagSize)); // convert smi to int
- __ sub(scratch2, scratch2, Operand(1));
+ __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
+ __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int
+ __ sub(scratch1, scratch1, Operand(1));
const int kElementsStartOffset = StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
static const int kProbes = 4;
for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
- __ ldr(scratch3, FieldMemOperand(name, String::kHashFieldOffset));
+ __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
if (i > 0) {
// Add the probe offset (i + i * i) left shifted to avoid right shifting
// the hash in a separate instruction. The value hash + i + i * i is right
// shifted in the following and instruction.
ASSERT(StringDictionary::GetProbeOffset(i) <
1 << (32 - String::kHashFieldOffset));
- __ add(scratch3, scratch3, Operand(
+ __ add(scratch2, scratch2, Operand(
StringDictionary::GetProbeOffset(i) << String::kHashShift));
}
- __ and_(scratch3, scratch2, Operand(scratch3, LSR, String::kHashShift));
+ __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
// Scale the index by multiplying by the element size.
ASSERT(StringDictionary::kEntrySize == 3);
- // scratch3 = scratch3 * 3.
- __ add(scratch3, scratch3, Operand(scratch3, LSL, 1));
+ // scratch2 = scratch2 * 3.
+ __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
// Check if the key is identical to the name.
- __ add(scratch3, scratch1, Operand(scratch3, LSL, 2));
- __ ldr(ip, FieldMemOperand(scratch3, kElementsStartOffset));
+ __ add(scratch2, elements, Operand(scratch2, LSL, 2));
+ __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
__ cmp(name, Operand(ip));
if (i != kProbes - 1) {
__ b(eq, &done);
}
// Check that the value is a normal property.
- __ bind(&done); // scratch3 == scratch1 + 4 * index
- __ ldr(scratch2,
- FieldMemOperand(scratch3, kElementsStartOffset + 2 * kPointerSize));
- __ tst(scratch2, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ __ bind(&done); // scratch2 == elements + 4 * index
+ __ ldr(scratch1,
+ FieldMemOperand(scratch2, kElementsStartOffset + 2 * kPointerSize));
+ __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
__ b(ne, miss);
// Get the value at the masked, scaled index and return.
__ ldr(result,
- FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize));
+ FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
}
Register receiver,
Register scratch1,
Register scratch2,
+ int interceptor_bit,
Label* slow) {
// Check that the object isn't a smi.
__ BranchOnSmi(receiver, slow);
__ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
// Check bit field.
__ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
- __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
- __ b(ne, slow);
+ __ tst(scratch2,
+ Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
+ __ b(nz, slow);
// Check that the object is some kind of JS object EXCEPT JS Value type.
// In the case that the object is a value-wrapper object,
// we enter the runtime system to make sure that indexing into string
}
-static void GenerateNormalHelper(MacroAssembler* masm,
- int argc,
- bool is_global_object,
- Label* miss,
- Register scratch) {
- // Search dictionary - put result in register r1.
- GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY);
+static void GenerateFunctionTailCall(MacroAssembler* masm,
+ int argc,
+ Label* miss,
+ Register scratch) {
+ // r1: function
// Check that the value isn't a smi.
__ tst(r1, Operand(kSmiTagMask));
__ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
__ b(ne, miss);
- // Patch the receiver with the global proxy if necessary.
- if (is_global_object) {
- __ ldr(r0, MemOperand(sp, argc * kPointerSize));
- __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
- __ str(r0, MemOperand(sp, argc * kPointerSize));
- }
-
// Invoke the function.
ParameterCount actual(argc);
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
// -- r2 : name
// -- lr : return address
// -----------------------------------
- Label miss, global_object, non_global_object;
+ Label miss;
// Get the receiver of the function from the stack into r1.
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
- // Check that the receiver isn't a smi.
- __ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the receiver is a valid JS object. Put the map in r3.
- __ CompareObjectType(r1, r3, r0, FIRST_JS_OBJECT_TYPE);
- __ b(lt, &miss);
-
- // If this assert fails, we have to check upper bound too.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
- // Check for access to global object.
- __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
- __ b(eq, &global_object);
- __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
- __ b(ne, &non_global_object);
+ GenerateDictionaryLoadReceiverCheck(masm, r1, r0, r3, r4, &miss);
- // Accessing global object: Load and invoke.
- __ bind(&global_object);
- // Check that the global object does not require access checks.
- __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
- __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
- __ b(ne, &miss);
- GenerateNormalHelper(masm, argc, true, &miss, r4);
-
- // Accessing non-global object: Check for access to global proxy.
- Label global_proxy, invoke;
- __ bind(&non_global_object);
- __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
- __ b(eq, &global_proxy);
- // Check that the non-global, non-global-proxy object does not
- // require access checks.
- __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
- __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
- __ b(ne, &miss);
- __ bind(&invoke);
- GenerateNormalHelper(masm, argc, false, &miss, r4);
+ // r0: elements
+ // Search the dictionary - put result in register r1.
+ GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
- // Global object access: Check access rights.
- __ bind(&global_proxy);
- __ CheckAccessGlobalProxy(r1, r0, &miss);
- __ b(&invoke);
+ GenerateFunctionTailCall(masm, argc, &miss, r4);
__ bind(&miss);
}
// -- lr : return address
// -----------------------------------
+ if (id == IC::kCallIC_Miss) {
+ __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
+ } else {
+ __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
+ }
+
// Get the receiver of the function from the stack.
__ ldr(r3, MemOperand(sp, argc * kPointerSize));
__ LeaveInternalFrame();
// Check if the receiver is a global object of some sort.
- Label invoke, global;
- __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
- __ tst(r2, Operand(kSmiTagMask));
- __ b(eq, &invoke);
- __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
- __ b(eq, &global);
- __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
- __ b(ne, &invoke);
-
- // Patch the receiver on the stack.
- __ bind(&global);
- __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
- __ str(r2, MemOperand(sp, argc * kPointerSize));
+ // This can happen only for regular CallIC but not KeyedCallIC.
+ if (id == IC::kCallIC_Miss) {
+ Label invoke, global;
+ __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
+ __ tst(r2, Operand(kSmiTagMask));
+ __ b(eq, &invoke);
+ __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
+ __ b(eq, &global);
+ __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
+ __ b(ne, &invoke);
+
+ // Patch the receiver on the stack.
+ __ bind(&global);
+ __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+ __ str(r2, MemOperand(sp, argc * kPointerSize));
+ __ bind(&invoke);
+ }
// Invoke the function.
ParameterCount actual(argc);
- __ bind(&invoke);
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
}
// Now the key is known to be a smi. This place is also jumped to from below
// where a numeric string is converted to a smi.
- GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &slow_call);
+ GenerateKeyedLoadReceiverCheck(
+ masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
GenerateFastArrayLoad(
masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
// receiver in r1 is not used after this point.
// r2: key
// r1: function
-
- // Check that the value in r1 is a JSFunction.
- __ BranchOnSmi(r1, &slow_call);
- __ CompareObjectType(r1, r0, r0, JS_FUNCTION_TYPE);
- __ b(ne, &slow_call);
- // Invoke the function.
- ParameterCount actual(argc);
- __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+ GenerateFunctionTailCall(masm, argc, &slow_call, r0);
__ bind(&check_number_dictionary);
// r2: key
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
- GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &lookup_monomorphic_cache);
+ GenerateKeyedLoadReceiverCheck(
+ masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
- __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
- __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+ __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
+ __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
__ cmp(r3, ip);
__ b(ne, &lookup_monomorphic_cache);
- GenerateDictionaryLoad(
- masm, &slow_load, r1, r2, r1, r0, r3, r4, DICTIONARY_CHECK_DONE);
+ GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
__ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
__ jmp(&do_call);
// -- r0 : receiver
// -- sp[0] : receiver
// -----------------------------------
- Label miss, probe, global;
-
- // Check that the receiver isn't a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the receiver is a valid JS object. Put the map in r3.
- __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE);
- __ b(lt, &miss);
- // If this assert fails, we have to check upper bound too.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+ Label miss;
- // Check for access to global object (unlikely).
- __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
- __ b(eq, &global);
+ GenerateDictionaryLoadReceiverCheck(masm, r0, r1, r3, r4, &miss);
- // Check for non-global object that requires access check.
- __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
- __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
- __ b(ne, &miss);
-
- __ bind(&probe);
- GenerateDictionaryLoad(masm, &miss, r0, r2, r0, r1, r3, r4, CHECK_DICTIONARY);
+ // r1: elements
+ GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
__ Ret();
- // Global object access: Check access rights.
- __ bind(&global);
- __ CheckAccessGlobalProxy(r0, r1, &miss);
- __ b(&probe);
-
// Cache miss: Jump to runtime.
__ bind(&miss);
GenerateMiss(masm);
// -- sp[0] : receiver
// -----------------------------------
+ __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
+
__ mov(r3, r0);
__ Push(r3, r2);
// -- r1 : receiver
// -----------------------------------
+ __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
+
__ Push(r1, r0);
ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
Register key = r0;
Register receiver = r1;
- GenerateKeyedLoadReceiverCheck(masm, receiver, r2, r3, &slow);
-
// Check that the key is a smi.
__ BranchOnNotSmi(key, &check_string);
__ bind(&index_smi);
// Now the key is known to be a smi. This place is also jumped to from below
// where a numeric string is converted to a smi.
+ GenerateKeyedLoadReceiverCheck(
+ masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
+
GenerateFastArrayLoad(
masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow);
__ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
__ bind(&check_string);
GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
+ GenerateKeyedLoadReceiverCheck(
+ masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
+
// If the receiver is a fast-case object, check the keyed lookup
// cache. Otherwise probe the dictionary.
__ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
- __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+ __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
- __ cmp(r3, ip);
+ __ cmp(r4, ip);
__ b(eq, &probe_dictionary);
// Load the map of the receiver, compute the keyed lookup cache hash
// Do a quick inline probe of the receiver's dictionary, if it
// exists.
__ bind(&probe_dictionary);
+ // r1: receiver
+ // r0: key
+ // r3: elements
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
// Load the property to r0.
- GenerateDictionaryLoad(
- masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE);
+ GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
__ Ret();
#define __ ACCESS_MASM(masm)
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
+ Register type,
+ Label* global_object) {
+ // Register usage:
+ // type: holds the receiver instance type on entry.
+ __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
+ __ j(equal, global_object, not_taken);
+ __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
+ __ j(equal, global_object, not_taken);
+ __ cmp(type, JS_GLOBAL_PROXY_TYPE);
+ __ j(equal, global_object, not_taken);
+}
+
+
+// Generated code falls through if the receiver is a regular non-global
+// JS object with slow properties and no interceptors.
+static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm,
+ Register receiver,
+ Register r0,
+ Register r1,
+ Label* miss) {
+ // Register usage:
+ // receiver: holds the receiver on entry and is unchanged.
+ // r0: used to hold receiver instance type.
+ // Holds the property dictionary on fall through.
+ // r1: used to hold receivers map.
+
+ // Check that the receiver isn't a smi.
+ __ test(receiver, Immediate(kSmiTagMask));
+ __ j(zero, miss, not_taken);
+
+ // Check that the receiver is a valid JS object.
+ __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
+ __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
+ __ cmp(r0, FIRST_JS_OBJECT_TYPE);
+ __ j(below, miss, not_taken);
+
+ // If this assert fails, we have to check upper bound too.
+ ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+ GenerateGlobalInstanceTypeCheck(masm, r0, miss);
+
+ // Check for non-global object that requires access check.
+ __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
+ (1 << Map::kIsAccessCheckNeeded) |
+ (1 << Map::kHasNamedInterceptor));
+ __ j(not_zero, miss, not_taken);
+
+ __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
+ __ CheckMap(r0, Factory::hash_table_map(), miss, true);
+}
+
+
// Helper function used to load a property from a dictionary backing storage.
// This function may return false negatives, so miss_label
// must always call a backup property load that is complete.
-// This function is safe to call if the receiver has fast properties,
-// or if name is not a symbol, and will jump to the miss_label in that case.
+// This function is safe to call if name is not a symbol, and will jump to
+// the miss_label in that case.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm,
Label* miss_label,
- Register receiver,
+ Register elements,
Register name,
Register r0,
Register r1,
- Register r2,
- Register result,
- DictionaryCheck check_dictionary) {
+ Register result) {
// Register use:
//
- // name - holds the name of the property and is unchanged.
- // receiver - holds the receiver and is unchanged.
+ // elements - holds the property dictionary on entry and is unchanged.
+ //
+ // name - holds the name of the property on entry and is unchanged.
+ //
// Scratch registers:
- // r0 - used to hold the property dictionary.
//
- // r1 - used for the index into the property dictionary
+ // r0 - used for the index into the property dictionary
//
- // r2 - used to hold the capacity of the property dictionary.
+ // r1 - used to hold the capacity of the property dictionary.
//
// result - holds the result on exit.
Label done;
- // Check for the absence of an interceptor.
- // Load the map into r0.
- __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
-
- // Bail out if the receiver has a named interceptor.
- __ test(FieldOperand(r0, Map::kBitFieldOffset),
- Immediate(1 << Map::kHasNamedInterceptor));
- __ j(not_zero, miss_label, not_taken);
-
- // Bail out if we have a JS global proxy object.
- __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
- __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
- __ j(equal, miss_label, not_taken);
-
- // Possible work-around for http://crbug.com/16276.
- __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
- __ j(equal, miss_label, not_taken);
- __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
- __ j(equal, miss_label, not_taken);
-
- // Load properties array.
- __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
-
- // Check that the properties array is a dictionary.
- if (check_dictionary == CHECK_DICTIONARY) {
- __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
- __ j(not_equal, miss_label);
- }
-
// Compute the capacity mask.
const int kCapacityOffset =
StringDictionary::kHeaderSize +
StringDictionary::kCapacityIndex * kPointerSize;
- __ mov(r2, FieldOperand(r0, kCapacityOffset));
- __ shr(r2, kSmiTagSize); // convert smi to int
- __ dec(r2);
+ __ mov(r1, FieldOperand(elements, kCapacityOffset));
+ __ shr(r1, kSmiTagSize); // convert smi to int
+ __ dec(r1);
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
- __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
- __ shr(r1, String::kHashShift);
+ __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
+ __ shr(r0, String::kHashShift);
if (i > 0) {
- __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
+ __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
}
- __ and_(r1, Operand(r2));
+ __ and_(r0, Operand(r1));
// Scale the index by multiplying by the entry size.
ASSERT(StringDictionary::kEntrySize == 3);
- __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
+ __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
// Check if the key is identical to the name.
- __ cmp(name,
- Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
+ __ cmp(name, Operand(elements, r0, times_4,
+ kElementsStartOffset - kHeapObjectTag));
if (i != kProbes - 1) {
__ j(equal, &done, taken);
} else {
// Check that the value is a normal property.
__ bind(&done);
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
+ __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
__ j(not_zero, miss_label, not_taken);
// Get the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ mov(result, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
+ __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
}
static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
Register receiver,
Register map,
+ int interceptor_bit,
Label* slow) {
// Register use:
// receiver - holds the receiver and is unchanged.
// Check bit field.
__ test_b(FieldOperand(map, Map::kBitFieldOffset),
- KeyedLoadIC::kSlowCaseBitFieldMask);
+ (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
__ j(not_zero, slow, not_taken);
// Check that the object is some kind of JS object EXCEPT JS Value type.
// In the case that the object is a value-wrapper object,
Label slow, check_string, index_smi, index_string;
Label check_pixel_array, probe_dictionary, check_number_dictionary;
- GenerateKeyedLoadReceiverCheck(masm, edx, ecx, &slow);
-
// Check that the key is a smi.
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &check_string, not_taken);
// Now the key is known to be a smi. This place is also jumped to from
// where a numeric string is converted to a smi.
+ GenerateKeyedLoadReceiverCheck(
+ masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
+
GenerateFastArrayLoad(masm,
edx,
eax,
__ bind(&check_string);
GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
+ GenerateKeyedLoadReceiverCheck(
+ masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
+
// If the receiver is a fast-case object, check the keyed lookup
// cache. Otherwise probe the dictionary.
__ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
// Do a quick inline probe of the receiver's dictionary, if it
// exists.
__ bind(&probe_dictionary);
- GenerateDictionaryLoad(masm,
- &slow,
- edx,
- eax,
- ebx,
- ecx,
- edi,
- eax,
- DICTIONARY_CHECK_DONE);
+
+ __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+ GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
+
+ GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
}
-static void GenerateNormalHelper(MacroAssembler* masm,
- int argc,
- bool is_global_object,
- Label* miss) {
+static void GenerateFunctionTailCall(MacroAssembler* masm,
+ int argc,
+ Label* miss) {
// ----------- S t a t e -------------
// -- ecx : name
- // -- edx : receiver
+ // -- edi : function
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- ...
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
- // Search dictionary - put result in register edi.
- __ mov(edi, edx);
- GenerateDictionaryLoad(
- masm, miss, edx, ecx, eax, edi, ebx, edi, CHECK_DICTIONARY);
-
// Check that the result is not a smi.
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, miss, not_taken);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
__ j(not_equal, miss, not_taken);
- // Patch the receiver on stack with the global proxy if necessary.
- if (is_global_object) {
- __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
- __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
- }
-
// Invoke the function.
ParameterCount actual(argc);
__ InvokeFunction(edi, actual, JUMP_FUNCTION);
// -- ...
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
- Label miss, global_object, non_global_object;
+ Label miss;
// Get the receiver of the function from the stack; 1 ~ return address.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
- // Check that the receiver isn't a smi.
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &miss, not_taken);
+ GenerateDictionaryLoadReceiverCheck(masm, edx, eax, ebx, &miss);
- // Check that the receiver is a valid JS object.
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
- __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
- __ cmp(eax, FIRST_JS_OBJECT_TYPE);
- __ j(below, &miss, not_taken);
-
- // If this assert fails, we have to check upper bound too.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
- // Check for access to global object.
- __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
- __ j(equal, &global_object);
- __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
- __ j(not_equal, &non_global_object);
-
- // Accessing global object: Load and invoke.
- __ bind(&global_object);
- // Check that the global object does not require access checks.
- __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
- 1 << Map::kIsAccessCheckNeeded);
- __ j(not_equal, &miss, not_taken);
- GenerateNormalHelper(masm, argc, true, &miss);
-
- // Accessing non-global object: Check for access to global proxy.
- Label global_proxy, invoke;
- __ bind(&non_global_object);
- __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
- __ j(equal, &global_proxy, not_taken);
- // Check that the non-global, non-global-proxy object does not
- // require access checks.
- __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
- 1 << Map::kIsAccessCheckNeeded);
- __ j(not_equal, &miss, not_taken);
- __ bind(&invoke);
- GenerateNormalHelper(masm, argc, false, &miss);
-
- // Global object proxy access: Check access rights.
- __ bind(&global_proxy);
- __ CheckAccessGlobalProxy(edx, eax, &miss);
- __ jmp(&invoke);
+ // eax: elements
+ // Search the dictionary placing the result in edi.
+ GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
+ GenerateFunctionTailCall(masm, argc, &miss);
__ bind(&miss);
}
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
+ if (id == IC::kCallIC_Miss) {
+ __ IncrementCounter(&Counters::call_miss, 1);
+ } else {
+ __ IncrementCounter(&Counters::keyed_call_miss, 1);
+ }
+
// Get the receiver of the function from the stack; 1 ~ return address.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
__ LeaveInternalFrame();
// Check if the receiver is a global object of some sort.
- Label invoke, global;
- __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &invoke, not_taken);
- __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
- __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
- __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
- __ j(equal, &global);
- __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
- __ j(not_equal, &invoke);
-
- // Patch the receiver on the stack.
- __ bind(&global);
- __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
- __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+ // This can happen only for regular CallIC but not KeyedCallIC.
+ if (id == IC::kCallIC_Miss) {
+ Label invoke, global;
+ __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, &invoke, not_taken);
+ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+ __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
+ __ j(equal, &global);
+ __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
+ __ j(not_equal, &invoke);
+
+ // Patch the receiver on the stack.
+ __ bind(&global);
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+ __ bind(&invoke);
+ }
// Invoke the function.
ParameterCount actual(argc);
- __ bind(&invoke);
__ InvokeFunction(edi, actual, JUMP_FUNCTION);
}
// Now the key is known to be a smi. This place is also jumped to from
// where a numeric string is converted to a smi.
- GenerateKeyedLoadReceiverCheck(masm, edx, eax, &slow_call);
+ GenerateKeyedLoadReceiverCheck(
+ masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
GenerateFastArrayLoad(
masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
// receiver in edx is not used after this point.
// ecx: key
// edi: function
-
- // Check that the value in edi is a JavaScript function.
- __ test(edi, Immediate(kSmiTagMask));
- __ j(zero, &slow_call, not_taken);
- __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
- __ j(not_equal, &slow_call, not_taken);
- // Invoke the function.
- ParameterCount actual(argc);
- __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+ GenerateFunctionTailCall(masm, argc, &slow_call);
__ bind(&check_number_dictionary);
// eax: elements
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
- GenerateKeyedLoadReceiverCheck(masm, edx, eax, &lookup_monomorphic_cache);
+ GenerateKeyedLoadReceiverCheck(
+ masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
__ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
- __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::hash_table_map()));
- __ j(not_equal, &lookup_monomorphic_cache, not_taken);
+ __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
- GenerateDictionaryLoad(
- masm, &slow_load, edx, ecx, ebx, eax, edi, edi, DICTIONARY_CHECK_DONE);
+ GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
__ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
__ jmp(&do_call);
// -- ecx : name
// -- esp[0] : return address
// -----------------------------------
- Label miss, probe, global;
-
- // Check that the receiver isn't a smi.
- __ test(eax, Immediate(kSmiTagMask));
- __ j(zero, &miss, not_taken);
-
- // Check that the receiver is a valid JS object.
- __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
- __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
- __ cmp(edx, FIRST_JS_OBJECT_TYPE);
- __ j(less, &miss, not_taken);
-
- // If this assert fails, we have to check upper bound too.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
- // Check for access to global object (unlikely).
- __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
- __ j(equal, &global, not_taken);
+ Label miss;
- // Check for non-global object that requires access check.
- __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
- 1 << Map::kIsAccessCheckNeeded);
- __ j(not_zero, &miss, not_taken);
+ GenerateDictionaryLoadReceiverCheck(masm, eax, edx, ebx, &miss);
+ // edx: elements
// Search the dictionary placing the result in eax.
- __ bind(&probe);
- GenerateDictionaryLoad(masm,
- &miss,
- eax,
- ecx,
- edx,
- edi,
- ebx,
- edi,
- CHECK_DICTIONARY);
- __ mov(eax, edi);
+ GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
__ ret(0);
- // Global object access: Check access rights.
- __ bind(&global);
- __ CheckAccessGlobalProxy(eax, edx, &miss);
- __ jmp(&probe);
-
// Cache miss: Jump to runtime.
__ bind(&miss);
GenerateMiss(masm);
// -- esp[0] : return address
// -----------------------------------
+ __ IncrementCounter(&Counters::load_miss, 1);
+
__ pop(ebx);
__ push(eax); // receiver
__ push(ecx); // name
// -- esp[0] : return address
// -----------------------------------
+ __ IncrementCounter(&Counters::keyed_load_miss, 1);
+
__ pop(ebx);
__ push(edx); // receiver
__ push(eax); // name
namespace v8 {
namespace internal {
-// Flag indicating whether an IC stub needs to check that a backing
-// store is in dictionary case.
-enum DictionaryCheck { CHECK_DICTIONARY, DICTIONARY_CHECK_DONE };
-
// IC_UTIL_LIST defines all utility functions called from generated
// inline caching code. The argument for the macro, ICU, is the function name.
SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss) \
SC(named_store_global_inline, V8.NamedStoreGlobalInline) \
SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss) \
+ SC(call_miss, V8.CallMiss) \
+ SC(keyed_call_miss, V8.KeyedCallMiss) \
+ SC(load_miss, V8.LoadMiss) \
+ SC(keyed_load_miss, V8.KeyedLoadMiss) \
SC(call_const, V8.CallConst) \
SC(call_const_fast_api, V8.CallConstFastApi) \
SC(call_const_interceptor, V8.CallConstInterceptor) \
#define __ ACCESS_MASM(masm)
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
+ Register type,
+ Label* global_object) {
+ // Register usage:
+ // type: holds the receiver instance type on entry.
+ __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE));
+ __ j(equal, global_object);
+ __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE));
+ __ j(equal, global_object);
+ __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE));
+ __ j(equal, global_object);
+}
+
+
+// Generated code falls through if the receiver is a regular non-global
+// JS object with slow properties and no interceptors.
+static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm,
+ Register receiver,
+ Register r0,
+ Register r1,
+ Label* miss) {
+ // Register usage:
+ // receiver: holds the receiver on entry and is unchanged.
+ // r0: used to hold receiver instance type.
+ // Holds the property dictionary on fall through.
+ // r1: used to hold receivers map.
+
+ __ JumpIfSmi(receiver, miss);
+
+ // Check that the receiver is a valid JS object.
+ __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset));
+ __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
+ __ cmpb(r0, Immediate(FIRST_JS_OBJECT_TYPE));
+ __ j(below, miss);
+
+ // If this assert fails, we have to check upper bound too.
+ ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+
+ GenerateGlobalInstanceTypeCheck(masm, r0, miss);
+
+ // Check for non-global object that requires access check.
+ __ testb(FieldOperand(r1, Map::kBitFieldOffset),
+ Immediate((1 << Map::kIsAccessCheckNeeded) |
+ (1 << Map::kHasNamedInterceptor)));
+ __ j(not_zero, miss);
+
+ __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
+ __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset),
+ Heap::kHashTableMapRootIndex);
+ __ j(not_equal, miss);
+}
+
+
// Helper function used to load a property from a dictionary backing storage.
// This function may return false negatives, so miss_label
// must always call a backup property load that is complete.
-// This function is safe to call if the receiver has fast properties,
-// or if name is not a symbol, and will jump to the miss_label in that case.
+// This function is safe to call if name is not a symbol, and will jump to
+// the miss_label in that case.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm,
Label* miss_label,
+ Register elements,
+ Register name,
Register r0,
Register r1,
- Register r2,
- Register name,
- Register r4,
- Register result,
- DictionaryCheck check_dictionary) {
+ Register result) {
// Register use:
//
- // r0 - used to hold the property dictionary and is unchanged.
- //
- // r1 - used to hold the receiver and is unchanged.
+ // elements - holds the property dictionary on entry and is unchanged.
//
- // r2 - used to hold the capacity of the property dictionary.
+ // name - holds the name of the property on entry and is unchanged.
//
- // name - holds the name of the property and is unchanged.
+ // r0 - used to hold the capacity of the property dictionary.
//
- // r4 - used to hold the index into the property dictionary.
+ // r1 - used to hold the index into the property dictionary.
//
// result - holds the result on exit if the load succeeded.
Label done;
- // Check for the absence of an interceptor.
- // Load the map into r0.
- __ movq(r0, FieldOperand(r1, JSObject::kMapOffset));
-
- // Bail out if the receiver has a named interceptor.
- __ testl(FieldOperand(r0, Map::kBitFieldOffset),
- Immediate(1 << Map::kHasNamedInterceptor));
- __ j(not_zero, miss_label);
-
- // Bail out if we have a JS global proxy object.
- __ movzxbq(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
- __ cmpb(r0, Immediate(JS_GLOBAL_PROXY_TYPE));
- __ j(equal, miss_label);
-
- // Possible work-around for http://crbug.com/16276.
- __ cmpb(r0, Immediate(JS_GLOBAL_OBJECT_TYPE));
- __ j(equal, miss_label);
- __ cmpb(r0, Immediate(JS_BUILTINS_OBJECT_TYPE));
- __ j(equal, miss_label);
-
- // Load properties array.
- __ movq(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
-
- if (check_dictionary == CHECK_DICTIONARY) {
- // Check that the properties array is a dictionary.
- __ Cmp(FieldOperand(r0, HeapObject::kMapOffset), Factory::hash_table_map());
- __ j(not_equal, miss_label);
- }
-
// Compute the capacity mask.
const int kCapacityOffset =
StringDictionary::kHeaderSize +
StringDictionary::kCapacityIndex * kPointerSize;
- __ SmiToInteger32(r2, FieldOperand(r0, kCapacityOffset));
- __ decl(r2);
+ __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
+ __ decl(r0);
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
- __ movl(r4, FieldOperand(name, String::kHashFieldOffset));
- __ shrl(r4, Immediate(String::kHashShift));
+ __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
+ __ shrl(r1, Immediate(String::kHashShift));
if (i > 0) {
- __ addl(r4, Immediate(StringDictionary::GetProbeOffset(i)));
+ __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
}
- __ and_(r4, r2);
+ __ and_(r1, r0);
// Scale the index by multiplying by the entry size.
ASSERT(StringDictionary::kEntrySize == 3);
- __ lea(r4, Operand(r4, r4, times_2, 0)); // r4 = r4 * 3
+ __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
// Check if the key is identical to the name.
- __ cmpq(name, Operand(r0, r4, times_pointer_size,
+ __ cmpq(name, Operand(elements, r1, times_pointer_size,
kElementsStartOffset - kHeapObjectTag));
if (i != kProbes - 1) {
__ j(equal, &done);
// Check that the value is a normal property.
__ bind(&done);
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag),
+ __ Test(Operand(elements, r1, times_pointer_size,
+ kDetailsOffset - kHeapObjectTag),
Smi::FromInt(PropertyDetails::TypeField::mask()));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
const int kValueOffset = kElementsStartOffset + kPointerSize;
__ movq(result,
- Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag));
+ Operand(elements, r1, times_pointer_size,
+ kValueOffset - kHeapObjectTag));
}
// -- rsp[0] : return address
// -----------------------------------
+ __ IncrementCounter(&Counters::keyed_load_miss, 1);
+
__ pop(rbx);
__ push(rdx); // receiver
__ push(rax); // name
static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
Register receiver,
Register map,
+ int interceptor_bit,
Label* slow) {
// Register use:
// receiver - holds the receiver and is unchanged.
// Check bit field.
__ testb(FieldOperand(map, Map::kBitFieldOffset),
- Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
+ Immediate((1 << Map::kIsAccessCheckNeeded) |
+ (1 << interceptor_bit)));
__ j(not_zero, slow);
}
Label slow, check_string, index_smi, index_string;
Label check_pixel_array, probe_dictionary, check_number_dictionary;
- GenerateKeyedLoadReceiverCheck(masm, rdx, rcx, &slow);
-
// Check that the key is a smi.
__ JumpIfNotSmi(rax, &check_string);
__ bind(&index_smi);
// Now the key is known to be a smi. This place is also jumped to from below
// where a numeric string is converted to a smi.
+ GenerateKeyedLoadReceiverCheck(
+ masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
+
GenerateFastArrayLoad(masm,
rdx,
rax,
__ bind(&check_string);
GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow);
+ GenerateKeyedLoadReceiverCheck(
+ masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
+
// If the receiver is a fast-case object, check the keyed lookup
// cache. Otherwise probe the dictionary leaving result in rcx.
__ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
__ bind(&probe_dictionary);
// rdx: receiver
// rax: key
- GenerateDictionaryLoad(masm,
- &slow,
- rbx,
- rdx,
- rcx,
- rax,
- rdi,
- rax,
- DICTIONARY_CHECK_DONE);
+ // rbx: elements
+
+ __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
+ __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
+ GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
+
+ GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
// rsp[argc * 8] : argument 1
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
+
+ if (id == IC::kCallIC_Miss) {
+ __ IncrementCounter(&Counters::call_miss, 1);
+ } else {
+ __ IncrementCounter(&Counters::keyed_call_miss, 1);
+ }
+
// Get the receiver of the function from the stack; 1 ~ return address.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
__ LeaveInternalFrame();
// Check if the receiver is a global object of some sort.
- Label invoke, global;
- __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
- __ JumpIfSmi(rdx, &invoke);
- __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
- __ j(equal, &global);
- __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
- __ j(not_equal, &invoke);
-
- // Patch the receiver on the stack.
- __ bind(&global);
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
- __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ // This can happen only for regular CallIC but not KeyedCallIC.
+ if (id == IC::kCallIC_Miss) {
+ Label invoke, global;
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
+ __ JumpIfSmi(rdx, &invoke);
+ __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
+ __ j(equal, &global);
+ __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
+ __ j(not_equal, &invoke);
+
+ // Patch the receiver on the stack.
+ __ bind(&global);
+ __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ __ bind(&invoke);
+ }
// Invoke the function.
ParameterCount actual(argc);
- __ bind(&invoke);
__ InvokeFunction(rdi, actual, JUMP_FUNCTION);
}
}
-static void GenerateNormalHelper(MacroAssembler* masm,
- int argc,
- bool is_global_object,
- Label* miss) {
+static void GenerateFunctionTailCall(MacroAssembler* masm,
+ int argc,
+ Label* miss) {
// ----------- S t a t e -------------
// rcx : function name
- // rdx : receiver
+ // rdi : function
// rsp[0] : return address
// rsp[8] : argument argc
// rsp[16] : argument argc - 1
// rsp[argc * 8] : argument 1
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- // Search dictionary - put result in register rdx.
- GenerateDictionaryLoad(
- masm, miss, rax, rdx, rbx, rcx, rdi, rdi, CHECK_DICTIONARY);
-
__ JumpIfSmi(rdi, miss);
// Check that the value is a JavaScript function.
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
__ j(not_equal, miss);
- // Patch the receiver with the global proxy if necessary.
- if (is_global_object) {
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
- __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
- }
-
// Invoke the function.
ParameterCount actual(argc);
__ InvokeFunction(rdi, actual, JUMP_FUNCTION);
// rsp[argc * 8] : argument 1
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
- Label miss, global_object, non_global_object;
+ Label miss;
// Get the receiver of the function from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(rdx, &miss);
+ GenerateDictionaryLoadReceiverCheck(masm, rdx, rax, rbx, &miss);
- // Check that the receiver is a valid JS object.
- // Because there are so many map checks and type checks, do not
- // use CmpObjectType, but load map and type into registers.
- __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
- __ movb(rax, FieldOperand(rbx, Map::kInstanceTypeOffset));
- __ cmpb(rax, Immediate(FIRST_JS_OBJECT_TYPE));
- __ j(below, &miss);
-
- // If this assert fails, we have to check upper bound too.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
- // Check for access to global object.
- __ cmpb(rax, Immediate(JS_GLOBAL_OBJECT_TYPE));
- __ j(equal, &global_object);
- __ cmpb(rax, Immediate(JS_BUILTINS_OBJECT_TYPE));
- __ j(not_equal, &non_global_object);
-
- // Accessing global object: Load and invoke.
- __ bind(&global_object);
- // Check that the global object does not require access checks.
- __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset));
- __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_equal, &miss);
- GenerateNormalHelper(masm, argc, true, &miss);
-
- // Accessing non-global object: Check for access to global proxy.
- Label global_proxy, invoke;
- __ bind(&non_global_object);
- __ cmpb(rax, Immediate(JS_GLOBAL_PROXY_TYPE));
- __ j(equal, &global_proxy);
- // Check that the non-global, non-global-proxy object does not
- // require access checks.
- __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset));
- __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_equal, &miss);
- __ bind(&invoke);
- GenerateNormalHelper(masm, argc, false, &miss);
+ // rax: elements
+ // Search the dictionary placing the result in rdi.
+ GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
- // Global object proxy access: Check access rights.
- __ bind(&global_proxy);
- __ CheckAccessGlobalProxy(rdx, rax, &miss);
- __ jmp(&invoke);
+ GenerateFunctionTailCall(masm, argc, &miss);
__ bind(&miss);
}
// Now the key is known to be a smi. This place is also jumped to from below
// where a numeric string is converted to a smi.
- GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &slow_call);
+ GenerateKeyedLoadReceiverCheck(
+ masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
GenerateFastArrayLoad(
masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
// receiver in rdx is not used after this point.
// rcx: key
// rdi: function
-
- // Check that the value in edi is a JavaScript function.
- __ JumpIfSmi(rdi, &slow_call);
- __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
- __ j(not_equal, &slow_call);
- // Invoke the function.
- ParameterCount actual(argc);
- __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
+ GenerateFunctionTailCall(masm, argc, &slow_call);
__ bind(&check_number_dictionary);
// eax: elements
// Check whether the elements is a number dictionary.
__ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
Heap::kHashTableMapRootIndex);
+ __ j(not_equal, &slow_load);
__ SmiToInteger32(rbx, rcx);
// ebx: untagged index
GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi);
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
- GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &lookup_monomorphic_cache);
+ GenerateKeyedLoadReceiverCheck(
+ masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
__ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
__ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
Heap::kHashTableMapRootIndex);
__ j(not_equal, &lookup_monomorphic_cache);
- GenerateDictionaryLoad(
- masm, &slow_load, rbx, rdx, rax, rcx, rdi, rdi, DICTIONARY_CHECK_DONE);
+ GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
__ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
__ jmp(&do_call);
// -- rsp[0] : return address
// -----------------------------------
+ __ IncrementCounter(&Counters::load_miss, 1);
+
__ pop(rbx);
__ push(rax); // receiver
__ push(rcx); // name
// -- rcx : name
// -- rsp[0] : return address
// -----------------------------------
- Label miss, probe, global;
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(rax, &miss);
-
- // Check that the receiver is a valid JS object.
- __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
- __ j(below, &miss);
-
- // If this assert fails, we have to check upper bound too.
- ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+ Label miss;
- // Check for access to global object (unlikely).
- __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE);
- __ j(equal, &global);
-
- // Check for non-global object that requires access check.
- __ testl(FieldOperand(rbx, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsAccessCheckNeeded));
- __ j(not_zero, &miss);
+ GenerateDictionaryLoadReceiverCheck(masm, rax, rdx, rbx, &miss);
+ // rdx: elements
// Search the dictionary placing the result in rax.
- __ bind(&probe);
- GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx,
- rcx, rdi, rax, CHECK_DICTIONARY);
+ GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
__ ret(0);
- // Global object access: Check access rights.
- __ bind(&global);
- __ CheckAccessGlobalProxy(rax, rdx, &miss);
- __ jmp(&probe);
-
// Cache miss: Jump to runtime.
__ bind(&miss);
GenerateMiss(masm);