|
@ -111,7 +111,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
|
|
Register receiver, |
|
|
Register receiver, |
|
|
String* name, |
|
|
String* name, |
|
|
Register r0, |
|
|
Register r0, |
|
|
Register extra) { |
|
|
Register r1) { |
|
|
ASSERT(name->IsSymbol()); |
|
|
ASSERT(name->IsSymbol()); |
|
|
__ IncrementCounter(&Counters::negative_lookups, 1); |
|
|
__ IncrementCounter(&Counters::negative_lookups, 1); |
|
|
__ IncrementCounter(&Counters::negative_lookups_miss, 1); |
|
|
__ IncrementCounter(&Counters::negative_lookups_miss, 1); |
|
@ -121,11 +121,13 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
|
|
|
|
|
|
|
|
const int kInterceptorOrAccessCheckNeededMask = |
|
|
const int kInterceptorOrAccessCheckNeededMask = |
|
|
(1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
|
|
(1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
|
|
|
|
|
|
|
|
// Bail out if the receiver has a named interceptor or requires access checks.
|
|
|
// Bail out if the receiver has a named interceptor or requires access checks.
|
|
|
__ test(FieldOperand(r0, Map::kBitFieldOffset), |
|
|
__ test_b(FieldOperand(r0, Map::kBitFieldOffset), |
|
|
Immediate(kInterceptorOrAccessCheckNeededMask)); |
|
|
kInterceptorOrAccessCheckNeededMask); |
|
|
__ j(not_zero, miss_label, not_taken); |
|
|
__ j(not_zero, miss_label, not_taken); |
|
|
|
|
|
|
|
|
|
|
|
// Check that receiver is a JSObject.
|
|
|
__ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); |
|
|
__ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); |
|
|
__ j(below, miss_label, not_taken); |
|
|
__ j(below, miss_label, not_taken); |
|
|
|
|
|
|
|
@ -158,10 +160,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
|
|
for (int i = 0; i < kProbes; i++) { |
|
|
for (int i = 0; i < kProbes; i++) { |
|
|
// r0 points to properties hash.
|
|
|
// r0 points to properties hash.
|
|
|
// Compute the masked index: (hash + i + i * i) & mask.
|
|
|
// Compute the masked index: (hash + i + i * i) & mask.
|
|
|
if (extra.is(no_reg)) { |
|
|
Register index = r1; |
|
|
__ push(receiver); |
|
|
|
|
|
} |
|
|
|
|
|
Register index = extra.is(no_reg) ? receiver : extra; |
|
|
|
|
|
// Capacity is smi 2^n.
|
|
|
// Capacity is smi 2^n.
|
|
|
__ mov(index, FieldOperand(properties, kCapacityOffset)); |
|
|
__ mov(index, FieldOperand(properties, kCapacityOffset)); |
|
|
__ dec(index); |
|
|
__ dec(index); |
|
@ -173,27 +172,18 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
|
|
ASSERT(StringDictionary::kEntrySize == 3); |
|
|
ASSERT(StringDictionary::kEntrySize == 3); |
|
|
__ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
|
|
|
__ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
|
|
|
|
|
|
|
|
|
Register entity_name = extra.is(no_reg) ? properties : extra; |
|
|
Register entity_name = r1; |
|
|
// Having undefined at this place means the name is not contained.
|
|
|
// Having undefined at this place means the name is not contained.
|
|
|
ASSERT_EQ(kSmiTagSize, 1); |
|
|
ASSERT_EQ(kSmiTagSize, 1); |
|
|
__ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
|
|
__ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
|
|
kElementsStartOffset - kHeapObjectTag)); |
|
|
kElementsStartOffset - kHeapObjectTag)); |
|
|
__ cmp(entity_name, Factory::undefined_value()); |
|
|
__ cmp(entity_name, Factory::undefined_value()); |
|
|
if (extra.is(no_reg)) { |
|
|
|
|
|
// 'receiver' shares a register with 'entity_name'.
|
|
|
|
|
|
__ pop(receiver); |
|
|
|
|
|
} |
|
|
|
|
|
if (i != kProbes - 1) { |
|
|
if (i != kProbes - 1) { |
|
|
__ j(equal, &done, taken); |
|
|
__ j(equal, &done, taken); |
|
|
|
|
|
|
|
|
// Stop if found the property.
|
|
|
// Stop if found the property.
|
|
|
__ cmp(entity_name, Handle<String>(name)); |
|
|
__ cmp(entity_name, Handle<String>(name)); |
|
|
__ j(equal, miss_label, not_taken); |
|
|
__ j(equal, miss_label, not_taken); |
|
|
|
|
|
|
|
|
if (extra.is(no_reg)) { |
|
|
|
|
|
// Restore the properties if their register was occupied by the name.
|
|
|
|
|
|
__ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
// Give up probing if still not found the undefined value.
|
|
|
// Give up probing if still not found the undefined value.
|
|
|
__ j(not_equal, miss_label, not_taken); |
|
|
__ j(not_equal, miss_label, not_taken); |
|
@ -525,6 +515,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
Register receiver, |
|
|
Register receiver, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
Label* miss) { |
|
|
Label* miss) { |
|
|
ASSERT(holder->HasNamedInterceptor()); |
|
|
ASSERT(holder->HasNamedInterceptor()); |
|
|
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
|
|
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
|
@ -541,6 +532,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
receiver, |
|
|
receiver, |
|
|
scratch1, |
|
|
scratch1, |
|
|
scratch2, |
|
|
scratch2, |
|
|
|
|
|
scratch3, |
|
|
holder, |
|
|
holder, |
|
|
lookup, |
|
|
lookup, |
|
|
name, |
|
|
name, |
|
@ -552,6 +544,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
receiver, |
|
|
receiver, |
|
|
scratch1, |
|
|
scratch1, |
|
|
scratch2, |
|
|
scratch2, |
|
|
|
|
|
scratch3, |
|
|
name, |
|
|
name, |
|
|
holder, |
|
|
holder, |
|
|
miss); |
|
|
miss); |
|
@ -564,6 +557,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
Register receiver, |
|
|
Register receiver, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
JSObject* interceptor_holder, |
|
|
JSObject* interceptor_holder, |
|
|
LookupResult* lookup, |
|
|
LookupResult* lookup, |
|
|
String* name, |
|
|
String* name, |
|
@ -603,7 +597,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
Register holder = |
|
|
Register holder = |
|
|
stub_compiler_->CheckPrototypes(object, receiver, |
|
|
stub_compiler_->CheckPrototypes(object, receiver, |
|
|
interceptor_holder, scratch1, |
|
|
interceptor_holder, scratch1, |
|
|
scratch2, name, depth1, miss); |
|
|
scratch2, scratch3, name, depth1, miss); |
|
|
|
|
|
|
|
|
// Invoke an interceptor and if it provides a value,
|
|
|
// Invoke an interceptor and if it provides a value,
|
|
|
// branch to |regular_invoke|.
|
|
|
// branch to |regular_invoke|.
|
|
@ -619,7 +613,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
if (interceptor_holder != lookup->holder()) { |
|
|
if (interceptor_holder != lookup->holder()) { |
|
|
stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
|
|
stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
|
|
lookup->holder(), scratch1, |
|
|
lookup->holder(), scratch1, |
|
|
scratch2, name, depth2, miss); |
|
|
scratch2, scratch3, name, depth2, miss); |
|
|
} else { |
|
|
} else { |
|
|
// CheckPrototypes has a side effect of fetching a 'holder'
|
|
|
// CheckPrototypes has a side effect of fetching a 'holder'
|
|
|
// for API (object which is instanceof for the signature). It's
|
|
|
// for API (object which is instanceof for the signature). It's
|
|
@ -655,12 +649,13 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
|
|
Register receiver, |
|
|
Register receiver, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
String* name, |
|
|
String* name, |
|
|
JSObject* interceptor_holder, |
|
|
JSObject* interceptor_holder, |
|
|
Label* miss_label) { |
|
|
Label* miss_label) { |
|
|
Register holder = |
|
|
Register holder = |
|
|
stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
|
|
stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
|
|
scratch1, scratch2, name, |
|
|
scratch1, scratch2, scratch3, name, |
|
|
miss_label); |
|
|
miss_label); |
|
|
|
|
|
|
|
|
__ EnterInternalFrame(); |
|
|
__ EnterInternalFrame(); |
|
@ -862,14 +857,15 @@ Register StubCompiler::CheckPrototypes(JSObject* object, |
|
|
Register object_reg, |
|
|
Register object_reg, |
|
|
JSObject* holder, |
|
|
JSObject* holder, |
|
|
Register holder_reg, |
|
|
Register holder_reg, |
|
|
Register scratch, |
|
|
Register scratch1, |
|
|
|
|
|
Register scratch2, |
|
|
String* name, |
|
|
String* name, |
|
|
int save_at_depth, |
|
|
int save_at_depth, |
|
|
Label* miss, |
|
|
Label* miss) { |
|
|
Register extra) { |
|
|
|
|
|
// Make sure there's no overlap between holder and object registers.
|
|
|
// Make sure there's no overlap between holder and object registers.
|
|
|
ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg)); |
|
|
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
|
|
ASSERT(!extra.is(object_reg) && !extra.is(holder_reg) && !extra.is(scratch)); |
|
|
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
|
|
|
|
|
&& !scratch2.is(scratch1)); |
|
|
// Keep track of the current object in register reg.
|
|
|
// Keep track of the current object in register reg.
|
|
|
Register reg = object_reg; |
|
|
Register reg = object_reg; |
|
|
JSObject* current = object; |
|
|
JSObject* current = object; |
|
@ -909,31 +905,31 @@ Register StubCompiler::CheckPrototypes(JSObject* object, |
|
|
miss, |
|
|
miss, |
|
|
reg, |
|
|
reg, |
|
|
name, |
|
|
name, |
|
|
scratch, |
|
|
scratch1, |
|
|
extra); |
|
|
scratch2); |
|
|
__ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
|
|
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
|
|
reg = holder_reg; // from now the object is in holder_reg
|
|
|
reg = holder_reg; // from now the object is in holder_reg
|
|
|
__ mov(reg, FieldOperand(scratch, Map::kPrototypeOffset)); |
|
|
__ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
|
|
} else if (Heap::InNewSpace(prototype)) { |
|
|
} else if (Heap::InNewSpace(prototype)) { |
|
|
// Get the map of the current object.
|
|
|
// Get the map of the current object.
|
|
|
__ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
|
|
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
|
|
__ cmp(Operand(scratch), Immediate(Handle<Map>(current->map()))); |
|
|
__ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); |
|
|
// Branch on the result of the map check.
|
|
|
// Branch on the result of the map check.
|
|
|
__ j(not_equal, miss, not_taken); |
|
|
__ j(not_equal, miss, not_taken); |
|
|
// Check access rights to the global object. This has to happen
|
|
|
// Check access rights to the global object. This has to happen
|
|
|
// after the map check so that we know that the object is
|
|
|
// after the map check so that we know that the object is
|
|
|
// actually a global object.
|
|
|
// actually a global object.
|
|
|
if (current->IsJSGlobalProxy()) { |
|
|
if (current->IsJSGlobalProxy()) { |
|
|
__ CheckAccessGlobalProxy(reg, scratch, miss); |
|
|
__ CheckAccessGlobalProxy(reg, scratch1, miss); |
|
|
|
|
|
|
|
|
// Restore scratch register to be the map of the object.
|
|
|
// Restore scratch register to be the map of the object.
|
|
|
// We load the prototype from the map in the scratch register.
|
|
|
// We load the prototype from the map in the scratch register.
|
|
|
__ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
|
|
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
|
|
} |
|
|
} |
|
|
// The prototype is in new space; we cannot store a reference
|
|
|
// The prototype is in new space; we cannot store a reference
|
|
|
// to it in the code. Load it from the map.
|
|
|
// to it in the code. Load it from the map.
|
|
|
reg = holder_reg; // from now the object is in holder_reg
|
|
|
reg = holder_reg; // from now the object is in holder_reg
|
|
|
__ mov(reg, FieldOperand(scratch, Map::kPrototypeOffset)); |
|
|
__ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
|
|
} else { |
|
|
} else { |
|
|
// Check the map of the current object.
|
|
|
// Check the map of the current object.
|
|
|
__ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
|
|
__ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
|
@ -944,7 +940,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object, |
|
|
// after the map check so that we know that the object is
|
|
|
// after the map check so that we know that the object is
|
|
|
// actually a global object.
|
|
|
// actually a global object.
|
|
|
if (current->IsJSGlobalProxy()) { |
|
|
if (current->IsJSGlobalProxy()) { |
|
|
__ CheckAccessGlobalProxy(reg, scratch, miss); |
|
|
__ CheckAccessGlobalProxy(reg, scratch1, miss); |
|
|
} |
|
|
} |
|
|
// The prototype is in old space; load it directly.
|
|
|
// The prototype is in old space; load it directly.
|
|
|
reg = holder_reg; // from now the object is in holder_reg
|
|
|
reg = holder_reg; // from now the object is in holder_reg
|
|
@ -971,7 +967,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object, |
|
|
// Perform security check for access to the global object.
|
|
|
// Perform security check for access to the global object.
|
|
|
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
|
|
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
|
|
if (holder->IsJSGlobalProxy()) { |
|
|
if (holder->IsJSGlobalProxy()) { |
|
|
__ CheckAccessGlobalProxy(reg, scratch, miss); |
|
|
__ CheckAccessGlobalProxy(reg, scratch1, miss); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// If we've skipped any global objects, it's not enough to verify
|
|
|
// If we've skipped any global objects, it's not enough to verify
|
|
@ -981,7 +977,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object, |
|
|
object, |
|
|
object, |
|
|
holder, |
|
|
holder, |
|
|
name, |
|
|
name, |
|
|
scratch, |
|
|
scratch1, |
|
|
miss); |
|
|
miss); |
|
|
if (result->IsFailure()) set_failure(Failure::cast(result)); |
|
|
if (result->IsFailure()) set_failure(Failure::cast(result)); |
|
|
|
|
|
|
|
@ -995,6 +991,7 @@ void StubCompiler::GenerateLoadField(JSObject* object, |
|
|
Register receiver, |
|
|
Register receiver, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
int index, |
|
|
int index, |
|
|
String* name, |
|
|
String* name, |
|
|
Label* miss) { |
|
|
Label* miss) { |
|
@ -1005,7 +1002,7 @@ void StubCompiler::GenerateLoadField(JSObject* object, |
|
|
// Check the prototype chain.
|
|
|
// Check the prototype chain.
|
|
|
Register reg = |
|
|
Register reg = |
|
|
CheckPrototypes(object, receiver, holder, |
|
|
CheckPrototypes(object, receiver, holder, |
|
|
scratch1, scratch2, name, miss); |
|
|
scratch1, scratch2, scratch3, name, miss); |
|
|
|
|
|
|
|
|
// Get the value from the properties.
|
|
|
// Get the value from the properties.
|
|
|
GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
|
|
GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
|
@ -1019,6 +1016,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, |
|
|
Register name_reg, |
|
|
Register name_reg, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
AccessorInfo* callback, |
|
|
AccessorInfo* callback, |
|
|
String* name, |
|
|
String* name, |
|
|
Label* miss, |
|
|
Label* miss, |
|
@ -1030,7 +1028,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, |
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
Register reg = |
|
|
Register reg = |
|
|
CheckPrototypes(object, receiver, holder, |
|
|
CheckPrototypes(object, receiver, holder, |
|
|
scratch1, scratch2, name, miss); |
|
|
scratch1, scratch2, scratch3, name, miss); |
|
|
|
|
|
|
|
|
Handle<AccessorInfo> callback_handle(callback); |
|
|
Handle<AccessorInfo> callback_handle(callback); |
|
|
|
|
|
|
|
@ -1094,6 +1092,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object, |
|
|
Register receiver, |
|
|
Register receiver, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
Object* value, |
|
|
Object* value, |
|
|
String* name, |
|
|
String* name, |
|
|
Label* miss) { |
|
|
Label* miss) { |
|
@ -1104,7 +1103,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object, |
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
Register reg = |
|
|
Register reg = |
|
|
CheckPrototypes(object, receiver, holder, |
|
|
CheckPrototypes(object, receiver, holder, |
|
|
scratch1, scratch2, name, miss); |
|
|
scratch1, scratch2, scratch3, name, miss); |
|
|
|
|
|
|
|
|
// Return the constant value.
|
|
|
// Return the constant value.
|
|
|
__ mov(eax, Handle<Object>(value)); |
|
|
__ mov(eax, Handle<Object>(value)); |
|
@ -1119,6 +1118,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
|
|
Register name_reg, |
|
|
Register name_reg, |
|
|
Register scratch1, |
|
|
Register scratch1, |
|
|
Register scratch2, |
|
|
Register scratch2, |
|
|
|
|
|
Register scratch3, |
|
|
String* name, |
|
|
String* name, |
|
|
Label* miss) { |
|
|
Label* miss) { |
|
|
ASSERT(interceptor_holder->HasNamedInterceptor()); |
|
|
ASSERT(interceptor_holder->HasNamedInterceptor()); |
|
@ -1147,7 +1147,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
|
|
// property from further up the prototype chain if the call fails.
|
|
|
// property from further up the prototype chain if the call fails.
|
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
|
|
Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
|
|
scratch1, scratch2, name, miss); |
|
|
scratch1, scratch2, scratch3, |
|
|
|
|
|
name, miss); |
|
|
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); |
|
|
ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); |
|
|
|
|
|
|
|
|
// Save necessary data before invoking an interceptor.
|
|
|
// Save necessary data before invoking an interceptor.
|
|
@ -1195,6 +1196,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
|
|
lookup->holder(), |
|
|
lookup->holder(), |
|
|
scratch1, |
|
|
scratch1, |
|
|
scratch2, |
|
|
scratch2, |
|
|
|
|
|
scratch3, |
|
|
name, |
|
|
name, |
|
|
miss); |
|
|
miss); |
|
|
} |
|
|
} |
|
@ -1235,7 +1237,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
Register holder_reg = |
|
|
Register holder_reg = |
|
|
CheckPrototypes(object, receiver, interceptor_holder, |
|
|
CheckPrototypes(object, receiver, interceptor_holder, |
|
|
scratch1, scratch2, name, miss); |
|
|
scratch1, scratch2, scratch3, name, miss); |
|
|
__ pop(scratch2); // save old return address
|
|
|
__ pop(scratch2); // save old return address
|
|
|
PushInterceptorArguments(masm(), receiver, holder_reg, |
|
|
PushInterceptorArguments(masm(), receiver, holder_reg, |
|
|
name_reg, interceptor_holder); |
|
|
name_reg, interceptor_holder); |
|
@ -1310,8 +1312,8 @@ Object* CallStubCompiler::CompileCallField(JSObject* object, |
|
|
__ j(zero, &miss, not_taken); |
|
|
__ j(zero, &miss, not_taken); |
|
|
|
|
|
|
|
|
// Do the right check and compute the holder register.
|
|
|
// Do the right check and compute the holder register.
|
|
|
Register reg = CheckPrototypes(object, edx, holder, ebx, eax, |
|
|
Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi, |
|
|
name, &miss, edi); |
|
|
name, &miss); |
|
|
|
|
|
|
|
|
GenerateFastPropertyLoad(masm(), edi, reg, holder, index); |
|
|
GenerateFastPropertyLoad(masm(), edi, reg, holder, index); |
|
|
|
|
|
|
|
@ -1373,7 +1375,7 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object, |
|
|
|
|
|
|
|
|
CheckPrototypes(JSObject::cast(object), edx, |
|
|
CheckPrototypes(JSObject::cast(object), edx, |
|
|
holder, ebx, |
|
|
holder, ebx, |
|
|
eax, name, &miss, edi); |
|
|
eax, edi, name, &miss); |
|
|
|
|
|
|
|
|
if (argc == 0) { |
|
|
if (argc == 0) { |
|
|
// Noop, return the length.
|
|
|
// Noop, return the length.
|
|
@ -1519,7 +1521,7 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, |
|
|
__ j(zero, &miss); |
|
|
__ j(zero, &miss); |
|
|
CheckPrototypes(JSObject::cast(object), edx, |
|
|
CheckPrototypes(JSObject::cast(object), edx, |
|
|
holder, ebx, |
|
|
holder, ebx, |
|
|
eax, name, &miss, edi); |
|
|
eax, edi, name, &miss); |
|
|
|
|
|
|
|
|
// Get the elements array of the object.
|
|
|
// Get the elements array of the object.
|
|
|
__ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
|
|
__ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
|
@ -1594,7 +1596,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, |
|
|
Context::STRING_FUNCTION_INDEX, |
|
|
Context::STRING_FUNCTION_INDEX, |
|
|
eax); |
|
|
eax); |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
ebx, edx, name, &miss, edi); |
|
|
ebx, edx, edi, name, &miss); |
|
|
|
|
|
|
|
|
Register receiver = ebx; |
|
|
Register receiver = ebx; |
|
|
Register index = edi; |
|
|
Register index = edi; |
|
@ -1659,7 +1661,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, |
|
|
Context::STRING_FUNCTION_INDEX, |
|
|
Context::STRING_FUNCTION_INDEX, |
|
|
eax); |
|
|
eax); |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
ebx, edx, name, &miss, edi); |
|
|
ebx, edx, edi, name, &miss); |
|
|
|
|
|
|
|
|
Register receiver = eax; |
|
|
Register receiver = eax; |
|
|
Register index = edi; |
|
|
Register index = edi; |
|
@ -1764,7 +1766,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, |
|
|
|
|
|
|
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
CheckPrototypes(JSObject::cast(object), edx, holder, |
|
|
CheckPrototypes(JSObject::cast(object), edx, holder, |
|
|
ebx, eax, name, depth, &miss, edi); |
|
|
ebx, eax, edi, name, depth, &miss); |
|
|
|
|
|
|
|
|
// Patch the receiver on the stack with the global proxy if
|
|
|
// Patch the receiver on the stack with the global proxy if
|
|
|
// necessary.
|
|
|
// necessary.
|
|
@ -1787,7 +1789,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, |
|
|
GenerateDirectLoadGlobalFunctionPrototype( |
|
|
GenerateDirectLoadGlobalFunctionPrototype( |
|
|
masm(), Context::STRING_FUNCTION_INDEX, eax); |
|
|
masm(), Context::STRING_FUNCTION_INDEX, eax); |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
ebx, edx, name, &miss, edi); |
|
|
ebx, edx, edi, name, &miss); |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
@ -1807,7 +1809,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, |
|
|
GenerateDirectLoadGlobalFunctionPrototype( |
|
|
GenerateDirectLoadGlobalFunctionPrototype( |
|
|
masm(), Context::NUMBER_FUNCTION_INDEX, eax); |
|
|
masm(), Context::NUMBER_FUNCTION_INDEX, eax); |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
ebx, edx, name, &miss, edi); |
|
|
ebx, edx, edi, name, &miss); |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -1828,7 +1830,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, |
|
|
GenerateDirectLoadGlobalFunctionPrototype( |
|
|
GenerateDirectLoadGlobalFunctionPrototype( |
|
|
masm(), Context::BOOLEAN_FUNCTION_INDEX, eax); |
|
|
masm(), Context::BOOLEAN_FUNCTION_INDEX, eax); |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
|
|
ebx, edx, name, &miss, edi); |
|
|
ebx, edx, edi, name, &miss); |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -1888,6 +1890,7 @@ Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, |
|
|
edx, |
|
|
edx, |
|
|
ebx, |
|
|
ebx, |
|
|
edi, |
|
|
edi, |
|
|
|
|
|
eax, |
|
|
&miss); |
|
|
&miss); |
|
|
|
|
|
|
|
|
// Restore receiver.
|
|
|
// Restore receiver.
|
|
@ -1950,7 +1953,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
CheckPrototypes(object, edx, holder, ebx, eax, name, &miss, edi); |
|
|
CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss); |
|
|
|
|
|
|
|
|
// Get the value from the cell.
|
|
|
// Get the value from the cell.
|
|
|
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
|
|
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
|
@ -2226,7 +2229,7 @@ Object* LoadStubCompiler::CompileLoadNonexistent(String* name, |
|
|
// Check the maps of the full prototype chain. Also check that
|
|
|
// Check the maps of the full prototype chain. Also check that
|
|
|
// global property cells up to (but not including) the last object
|
|
|
// global property cells up to (but not including) the last object
|
|
|
// in the prototype chain are empty.
|
|
|
// in the prototype chain are empty.
|
|
|
CheckPrototypes(object, eax, last, ebx, edx, name, &miss); |
|
|
CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss); |
|
|
|
|
|
|
|
|
// If the last object in the prototype chain is a global object,
|
|
|
// If the last object in the prototype chain is a global object,
|
|
|
// check that the global property cell is empty.
|
|
|
// check that the global property cell is empty.
|
|
@ -2263,7 +2266,7 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object, |
|
|
// -----------------------------------
|
|
|
// -----------------------------------
|
|
|
Label miss; |
|
|
Label miss; |
|
|
|
|
|
|
|
|
GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss); |
|
|
GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss); |
|
|
__ bind(&miss); |
|
|
__ bind(&miss); |
|
|
GenerateLoadMiss(masm(), Code::LOAD_IC); |
|
|
GenerateLoadMiss(masm(), Code::LOAD_IC); |
|
|
|
|
|
|
|
@ -2284,7 +2287,7 @@ Object* LoadStubCompiler::CompileLoadCallback(String* name, |
|
|
Label miss; |
|
|
Label miss; |
|
|
|
|
|
|
|
|
Failure* failure = Failure::InternalError(); |
|
|
Failure* failure = Failure::InternalError(); |
|
|
bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, |
|
|
bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, |
|
|
callback, name, &miss, &failure); |
|
|
callback, name, &miss, &failure); |
|
|
if (!success) return failure; |
|
|
if (!success) return failure; |
|
|
|
|
|
|
|
@ -2307,7 +2310,7 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object, |
|
|
// -----------------------------------
|
|
|
// -----------------------------------
|
|
|
Label miss; |
|
|
Label miss; |
|
|
|
|
|
|
|
|
GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss); |
|
|
GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss); |
|
|
__ bind(&miss); |
|
|
__ bind(&miss); |
|
|
GenerateLoadMiss(masm(), Code::LOAD_IC); |
|
|
GenerateLoadMiss(masm(), Code::LOAD_IC); |
|
|
|
|
|
|
|
@ -2338,6 +2341,7 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, |
|
|
ecx, |
|
|
ecx, |
|
|
edx, |
|
|
edx, |
|
|
ebx, |
|
|
ebx, |
|
|
|
|
|
edi, |
|
|
name, |
|
|
name, |
|
|
&miss); |
|
|
&miss); |
|
|
|
|
|
|
|
@ -2370,7 +2374,7 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check that the maps haven't changed.
|
|
|
// Check that the maps haven't changed.
|
|
|
CheckPrototypes(object, eax, holder, ebx, edx, name, &miss, edi); |
|
|
CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss); |
|
|
|
|
|
|
|
|
// Get the value from the cell.
|
|
|
// Get the value from the cell.
|
|
|
__ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
|
|
__ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
|
@ -2415,7 +2419,7 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name, |
|
|
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
|
|
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
|
|
__ j(not_equal, &miss, not_taken); |
|
|
__ j(not_equal, &miss, not_taken); |
|
|
|
|
|
|
|
|
GenerateLoadField(receiver, holder, edx, ebx, ecx, index, name, &miss); |
|
|
GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); |
|
|
|
|
|
|
|
|
__ bind(&miss); |
|
|
__ bind(&miss); |
|
|
__ DecrementCounter(&Counters::keyed_load_field, 1); |
|
|
__ DecrementCounter(&Counters::keyed_load_field, 1); |
|
@ -2444,7 +2448,7 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name, |
|
|
__ j(not_equal, &miss, not_taken); |
|
|
__ j(not_equal, &miss, not_taken); |
|
|
|
|
|
|
|
|
Failure* failure = Failure::InternalError(); |
|
|
Failure* failure = Failure::InternalError(); |
|
|
bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, |
|
|
bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, |
|
|
callback, name, &miss, &failure); |
|
|
callback, name, &miss, &failure); |
|
|
if (!success) return failure; |
|
|
if (!success) return failure; |
|
|
|
|
|
|
|
@ -2474,7 +2478,7 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name, |
|
|
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
|
|
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
|
|
__ j(not_equal, &miss, not_taken); |
|
|
__ j(not_equal, &miss, not_taken); |
|
|
|
|
|
|
|
|
GenerateLoadConstant(receiver, holder, edx, ebx, ecx, |
|
|
GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, |
|
|
value, name, &miss); |
|
|
value, name, &miss); |
|
|
__ bind(&miss); |
|
|
__ bind(&miss); |
|
|
__ DecrementCounter(&Counters::keyed_load_constant_function, 1); |
|
|
__ DecrementCounter(&Counters::keyed_load_constant_function, 1); |
|
@ -2510,6 +2514,7 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, |
|
|
eax, |
|
|
eax, |
|
|
ecx, |
|
|
ecx, |
|
|
ebx, |
|
|
ebx, |
|
|
|
|
|
edi, |
|
|
name, |
|
|
name, |
|
|
&miss); |
|
|
&miss); |
|
|
__ bind(&miss); |
|
|
__ bind(&miss); |
|
|