Index: src/ia32/stub-cache-ia32.cc |
=================================================================== |
--- src/ia32/stub-cache-ia32.cc (revision 2423) |
+++ src/ia32/stub-cache-ia32.cc (working copy) |
@@ -273,116 +273,8 @@ |
} |
-void StubCompiler::GenerateLoadField(MacroAssembler* masm, |
- JSObject* object, |
- JSObject* holder, |
- Register receiver, |
- Register scratch1, |
- Register scratch2, |
- int index, |
- Label* miss_label) { |
- // Check that the receiver isn't a smi. |
- __ test(receiver, Immediate(kSmiTagMask)); |
- __ j(zero, miss_label, not_taken); |
- // Check that the maps haven't changed. |
- Register reg = |
- masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); |
- // Get the value from the properties. |
- GenerateFastPropertyLoad(masm, eax, reg, holder, index); |
- __ ret(0); |
-} |
- |
- |
-void StubCompiler::GenerateLoadCallback(MacroAssembler* masm, |
- JSObject* object, |
- JSObject* holder, |
- Register receiver, |
- Register name, |
- Register scratch1, |
- Register scratch2, |
- AccessorInfo* callback, |
- Label* miss_label) { |
- // Check that the receiver isn't a smi. |
- __ test(receiver, Immediate(kSmiTagMask)); |
- __ j(zero, miss_label, not_taken); |
- |
- // Check that the maps haven't changed. |
- Register reg = |
- masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); |
- |
- // Push the arguments on the JS stack of the caller. |
- __ pop(scratch2); // remove return address |
- __ push(receiver); // receiver |
- __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data |
- __ push(name); // name |
- __ push(reg); // holder |
- __ push(scratch2); // restore return address |
- |
- // Do tail-call to the runtime system. |
- ExternalReference load_callback_property = |
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
- __ TailCallRuntime(load_callback_property, 4); |
-} |
- |
- |
-void StubCompiler::GenerateLoadConstant(MacroAssembler* masm, |
- JSObject* object, |
- JSObject* holder, |
- Register receiver, |
- Register scratch1, |
- Register scratch2, |
- Object* value, |
- Label* miss_label) { |
- // Check that the receiver isn't a smi. |
- __ test(receiver, Immediate(kSmiTagMask)); |
- __ j(zero, miss_label, not_taken); |
- |
- // Check that the maps haven't changed. |
- Register reg = |
- masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); |
- |
- // Return the constant value. |
- __ mov(eax, Handle<Object>(value)); |
- __ ret(0); |
-} |
- |
- |
-void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm, |
- JSObject* object, |
- JSObject* holder, |
- Smi* lookup_hint, |
- Register receiver, |
- Register name, |
- Register scratch1, |
- Register scratch2, |
- Label* miss_label) { |
- // Check that the receiver isn't a smi. |
- __ test(receiver, Immediate(kSmiTagMask)); |
- __ j(zero, miss_label, not_taken); |
- |
- // Check that the maps haven't changed. |
- Register reg = |
- masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); |
- |
- // Push the arguments on the JS stack of the caller. |
- __ pop(scratch2); // remove return address |
- __ push(receiver); // receiver |
- __ push(reg); // holder |
- __ push(name); // name |
- // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or |
- // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method? |
- __ push(Immediate(lookup_hint)); |
- __ push(scratch2); // restore return address |
- |
- // Do tail-call to the runtime system. |
- ExternalReference load_ic_property = |
- ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); |
- __ TailCallRuntime(load_ic_property, 4); |
-} |
- |
- |
void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
Code* code = NULL; |
@@ -474,10 +366,159 @@ |
#undef __ |
- |
#define __ ACCESS_MASM(masm()) |
+Register StubCompiler::CheckPrototypes(JSObject* object, |
+ Register object_reg, |
+ JSObject* holder, |
+ Register holder_reg, |
+ Register scratch, |
+ String* name, |
+ Label* miss) { |
+ // Check that the maps haven't changed. |
+ Register result = |
+ masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); |
+ |
+ // If we've skipped any global objects, it's not enough to verify |
+ // that their maps haven't changed. |
+ while (object != holder) { |
+ if (object->IsGlobalObject()) { |
+ GlobalObject* global = GlobalObject::cast(object); |
+ Object* probe = global->EnsurePropertyCell(name); |
+ if (probe->IsFailure()) { |
+ set_failure(Failure::cast(probe)); |
+ return result; |
+ } |
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
+ ASSERT(cell->value()->IsTheHole()); |
+ __ mov(scratch, Immediate(Handle<Object>(cell))); |
+ __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
+ Immediate(Factory::the_hole_value())); |
+ __ j(not_equal, miss, not_taken); |
+ } |
+ object = JSObject::cast(object->GetPrototype()); |
+ } |
+ |
+ // Return the register containin the holder. |
+ return result; |
+} |
+ |
+ |
+void StubCompiler::GenerateLoadField(JSObject* object, |
+ JSObject* holder, |
+ Register receiver, |
+ Register scratch1, |
+ Register scratch2, |
+ int index, |
+ String* name, |
+ Label* miss) { |
+ // Check that the receiver isn't a smi. |
+ __ test(receiver, Immediate(kSmiTagMask)); |
+ __ j(zero, miss, not_taken); |
+ |
+ // Check the prototype chain. |
+ Register reg = |
+ CheckPrototypes(object, receiver, holder, |
+ scratch1, scratch2, name, miss); |
+ |
+ // Get the value from the properties. |
+ GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
+ __ ret(0); |
+} |
+ |
+ |
+void StubCompiler::GenerateLoadCallback(JSObject* object, |
+ JSObject* holder, |
+ Register receiver, |
+ Register name_reg, |
+ Register scratch1, |
+ Register scratch2, |
+ AccessorInfo* callback, |
+ String* name, |
+ Label* miss) { |
+ // Check that the receiver isn't a smi. |
+ __ test(receiver, Immediate(kSmiTagMask)); |
+ __ j(zero, miss, not_taken); |
+ |
+ // Check that the maps haven't changed. |
+ Register reg = |
+ CheckPrototypes(object, receiver, holder, |
+ scratch1, scratch2, name, miss); |
+ |
+ // Push the arguments on the JS stack of the caller. |
+ __ pop(scratch2); // remove return address |
+ __ push(receiver); // receiver |
+ __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data |
+ __ push(name_reg); // name |
+ __ push(reg); // holder |
+ __ push(scratch2); // restore return address |
+ |
+ // Do tail-call to the runtime system. |
+ ExternalReference load_callback_property = |
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
+ __ TailCallRuntime(load_callback_property, 4); |
+} |
+ |
+ |
+void StubCompiler::GenerateLoadConstant(JSObject* object, |
+ JSObject* holder, |
+ Register receiver, |
+ Register scratch1, |
+ Register scratch2, |
+ Object* value, |
+ String* name, |
+ Label* miss) { |
+ // Check that the receiver isn't a smi. |
+ __ test(receiver, Immediate(kSmiTagMask)); |
+ __ j(zero, miss, not_taken); |
+ |
+ // Check that the maps haven't changed. |
+ Register reg = |
+ CheckPrototypes(object, receiver, holder, |
+ scratch1, scratch2, name, miss); |
+ |
+ // Return the constant value. |
+ __ mov(eax, Handle<Object>(value)); |
+ __ ret(0); |
+} |
+ |
+ |
+void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
+ JSObject* holder, |
+ Smi* lookup_hint, |
+ Register receiver, |
+ Register name_reg, |
+ Register scratch1, |
+ Register scratch2, |
+ String* name, |
+ Label* miss) { |
+ // Check that the receiver isn't a smi. |
+ __ test(receiver, Immediate(kSmiTagMask)); |
+ __ j(zero, miss, not_taken); |
+ |
+ // Check that the maps haven't changed. |
+ Register reg = |
+ CheckPrototypes(object, receiver, holder, |
+ scratch1, scratch2, name, miss); |
+ |
+ // Push the arguments on the JS stack of the caller. |
+ __ pop(scratch2); // remove return address |
+ __ push(receiver); // receiver |
+ __ push(reg); // holder |
+ __ push(name_reg); // name |
+ // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or |
+ // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method? |
+ __ push(Immediate(lookup_hint)); |
+ __ push(scratch2); // restore return address |
+ |
+ // Do tail-call to the runtime system. |
+ ExternalReference load_ic_property = |
+ ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); |
+ __ TailCallRuntime(load_ic_property, 4); |
+} |
+ |
+ |
// TODO(1241006): Avoid having lazy compile stubs specialized by the |
// number of arguments. It is not needed anymore. |
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { |
@@ -520,7 +561,8 @@ |
// Do the right check and compute the holder register. |
Register reg = |
- masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); |
+ CheckPrototypes(JSObject::cast(object), edx, holder, |
+ ebx, ecx, name, &miss); |
GenerateFastPropertyLoad(masm(), edi, reg, holder, index); |
@@ -553,6 +595,7 @@ |
Object* CallStubCompiler::CompileCallConstant(Object* object, |
JSObject* holder, |
JSFunction* function, |
+ String* name, |
CheckType check) { |
// ----------- S t a t e ------------- |
// ----------------------------------- |
@@ -575,7 +618,8 @@ |
switch (check) { |
case RECEIVER_MAP_CHECK: |
// Check that the maps haven't changed. |
- __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); |
+ CheckPrototypes(JSObject::cast(object), edx, holder, |
+ ebx, ecx, name, &miss); |
// Patch the receiver on the stack with the global proxy if |
// necessary. |
@@ -595,8 +639,8 @@ |
GenerateLoadGlobalFunctionPrototype(masm(), |
Context::STRING_FUNCTION_INDEX, |
ecx); |
- __ CheckMaps(JSObject::cast(object->GetPrototype()), |
- ecx, holder, ebx, edx, &miss); |
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder, |
+ ebx, edx, name, &miss); |
break; |
case NUMBER_CHECK: { |
@@ -611,8 +655,8 @@ |
GenerateLoadGlobalFunctionPrototype(masm(), |
Context::NUMBER_FUNCTION_INDEX, |
ecx); |
- __ CheckMaps(JSObject::cast(object->GetPrototype()), |
- ecx, holder, ebx, edx, &miss); |
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder, |
+ ebx, edx, name, &miss); |
break; |
} |
@@ -628,13 +672,14 @@ |
GenerateLoadGlobalFunctionPrototype(masm(), |
Context::BOOLEAN_FUNCTION_INDEX, |
ecx); |
- __ CheckMaps(JSObject::cast(object->GetPrototype()), |
- ecx, holder, ebx, edx, &miss); |
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder, |
+ ebx, edx, name, &miss); |
break; |
} |
case JSARRAY_HAS_FAST_ELEMENTS_CHECK: |
- __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); |
+ CheckPrototypes(JSObject::cast(object), edx, holder, |
+ ebx, ecx, name, &miss); |
// Make sure object->elements()->map() != Heap::dictionary_array_map() |
// Get the elements array of the object. |
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); |
@@ -692,7 +737,8 @@ |
// Check that maps have not changed and compute the holder register. |
Register reg = |
- masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); |
+ CheckPrototypes(JSObject::cast(object), edx, holder, |
+ ebx, ecx, name, &miss); |
// Enter an internal frame. |
__ EnterInternalFrame(); |
@@ -771,7 +817,7 @@ |
} |
// Check that the maps haven't changed. |
- masm()->CheckMaps(object, edx, holder, ebx, ecx, &miss); |
+ CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss); |
// Get the value from the cell. |
__ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
@@ -1033,6 +1079,7 @@ |
} |
+ |
Object* LoadStubCompiler::CompileLoadField(JSObject* object, |
JSObject* holder, |
int index, |
@@ -1045,7 +1092,7 @@ |
Label miss; |
__ mov(eax, (Operand(esp, kPointerSize))); |
- GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss); |
+ GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss); |
__ bind(&miss); |
GenerateLoadMiss(masm(), Code::LOAD_IC); |
@@ -1066,8 +1113,8 @@ |
Label miss; |
__ mov(eax, (Operand(esp, kPointerSize))); |
- GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx, |
- edx, callback, &miss); |
+ GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, |
+ callback, name, &miss); |
__ bind(&miss); |
GenerateLoadMiss(masm(), Code::LOAD_IC); |
@@ -1088,7 +1135,7 @@ |
Label miss; |
__ mov(eax, (Operand(esp, kPointerSize))); |
- GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss); |
+ GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss); |
__ bind(&miss); |
GenerateLoadMiss(masm(), Code::LOAD_IC); |
@@ -1110,14 +1157,14 @@ |
__ mov(eax, (Operand(esp, kPointerSize))); |
// TODO(368): Compile in the whole chain: all the interceptors in |
// prototypes and ultimate answer. |
- GenerateLoadInterceptor(masm(), |
- receiver, |
+ GenerateLoadInterceptor(receiver, |
holder, |
holder->InterceptorPropertyLookupHint(name), |
eax, |
ecx, |
edx, |
ebx, |
+ name, |
&miss); |
__ bind(&miss); |
@@ -1154,7 +1201,7 @@ |
} |
// Check that the maps haven't changed. |
- masm()->CheckMaps(object, eax, holder, ebx, edx, &miss); |
+ CheckPrototypes(object, eax, holder, ebx, edx, name, &miss); |
// Get the value from the cell. |
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
@@ -1200,7 +1247,8 @@ |
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
__ j(not_equal, &miss, not_taken); |
- GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss); |
+ GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss); |
+ |
__ bind(&miss); |
__ DecrementCounter(&Counters::keyed_load_field, 1); |
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
@@ -1229,8 +1277,8 @@ |
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
__ j(not_equal, &miss, not_taken); |
- GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx, |
- callback, &miss); |
+ GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx, |
+ callback, name, &miss); |
__ bind(&miss); |
__ DecrementCounter(&Counters::keyed_load_callback, 1); |
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
@@ -1259,7 +1307,8 @@ |
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
__ j(not_equal, &miss, not_taken); |
- GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss); |
+ GenerateLoadConstant(receiver, holder, ecx, ebx, edx, |
+ value, name, &miss); |
__ bind(&miss); |
__ DecrementCounter(&Counters::keyed_load_constant_function, 1); |
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
@@ -1287,14 +1336,14 @@ |
__ cmp(Operand(eax), Immediate(Handle<String>(name))); |
__ j(not_equal, &miss, not_taken); |
- GenerateLoadInterceptor(masm(), |
- receiver, |
+ GenerateLoadInterceptor(receiver, |
holder, |
Smi::FromInt(JSObject::kLookupInHolder), |
ecx, |
eax, |
edx, |
ebx, |
+ name, |
&miss); |
__ bind(&miss); |
__ DecrementCounter(&Counters::keyed_load_interceptor, 1); |