| 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);
|
|
|