Author: [email protected]
Date: Fri Jul 10 02:40:47 2009
New Revision: 2425
Modified:
branches/bleeding_edge/src/arm/stub-cache-arm.cc
branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
branches/bleeding_edge/src/objects-inl.h
branches/bleeding_edge/src/objects.cc
branches/bleeding_edge/src/objects.h
branches/bleeding_edge/src/stub-cache.cc
branches/bleeding_edge/src/stub-cache.h
branches/bleeding_edge/src/x64/stub-cache-x64.cc
Log:
Re-enable ICs for loads and calls that skips a global object during
lookup through the prototype chain.
Review URL: http://codereview.chromium.org/155344
Modified: branches/bleeding_edge/src/arm/stub-cache-arm.cc
==============================================================================
--- branches/bleeding_edge/src/arm/stub-cache-arm.cc (original)
+++ branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Jul 10 02:40:47
2009
@@ -171,110 +171,6 @@
}
-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.
- __ tst(receiver, Operand(kSmiTagMask));
- __ b(eq, miss_label);
-
- // Check that the maps haven't changed.
- Register reg =
- masm->CheckMaps(object, receiver, holder, scratch1, scratch2,
miss_label);
- GenerateFastPropertyLoad(masm, r0, reg, holder, index);
- __ Ret();
-}
-
-
-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.
- __ tst(receiver, Operand(kSmiTagMask));
- __ b(eq, miss_label);
-
- // Check that the maps haven't changed.
- Register reg =
- masm->CheckMaps(object, receiver, holder, scratch1, scratch2,
miss_label);
-
- // Return the constant value.
- __ mov(r0, Operand(Handle<Object>(value)));
- __ Ret();
-}
-
-
-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.
- __ tst(receiver, Operand(kSmiTagMask));
- __ b(eq, miss_label);
-
- // 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.
- __ push(receiver); // receiver
- __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
- __ push(ip);
- __ push(name); // name
- __ push(reg); // holder
-
- // Do tail-call to the runtime system.
- ExternalReference load_callback_property =
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
- __ TailCallRuntime(load_callback_property, 4);
-}
-
-
-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.
- __ tst(receiver, Operand(kSmiTagMask));
- __ b(eq, miss_label);
-
- // 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.
- __ push(receiver); // receiver
- __ push(reg); // holder
- __ push(name); // name
- __ mov(scratch1, Operand(lookup_hint));
- __ push(scratch1);
-
- // Do tail-call to the runtime system.
- ExternalReference load_ic_property =
- ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
- __ TailCallRuntime(load_ic_property, 4);
-}
-
-
void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
Register scratch,
@@ -462,6 +358,147 @@
#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, Operand(Handle<Object>(cell)));
+ __ ldr(scratch,
+ FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ __ cmp(scratch, Operand(Factory::the_hole_value()));
+ __ b(ne, miss);
+ }
+ 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.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ CheckPrototypes(object, receiver, holder, scratch1, scratch2, name,
miss);
+ GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
+ __ Ret();
+}
+
+
+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.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ CheckPrototypes(object, receiver, holder, scratch1, scratch2, name,
miss);
+
+ // Return the constant value.
+ __ mov(r0, Operand(Handle<Object>(value)));
+ __ Ret();
+}
+
+
+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.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss);
+
+ // 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.
+ __ push(receiver); // receiver
+ __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
+ __ push(ip);
+ __ push(name_reg); // name
+ __ push(reg); // holder
+
+ // Do tail-call to the runtime system.
+ ExternalReference load_callback_property =
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
+ __ TailCallRuntime(load_callback_property, 4);
+}
+
+
+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.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, miss);
+
+ // 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.
+ __ push(receiver); // receiver
+ __ push(reg); // holder
+ __ push(name_reg); // name
+ __ mov(scratch1, Operand(lookup_hint));
+ __ push(scratch1);
+
+ // Do tail-call to the runtime system.
+ ExternalReference load_ic_property =
+ ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
+ __ TailCallRuntime(load_ic_property, 4);
+}
+
+
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
// ----------- S t a t e -------------
// -- r1: function
@@ -513,7 +550,7 @@
// Do the right check and compute the holder register.
Register reg =
- masm()->CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
+ CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name,
&miss);
GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
// Check that the function really is a function.
@@ -546,6 +583,7 @@
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
+ String* name,
CheckType check) {
// ----------- S t a t e -------------
// -- lr: return address
@@ -569,7 +607,7 @@
switch (check) {
case RECEIVER_MAP_CHECK:
// Check that the maps haven't changed.
- __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+ CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name,
&miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
@@ -587,8 +625,8 @@
GenerateLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX,
r2);
- __ CheckMaps(JSObject::cast(object->GetPrototype()),
- r2, holder, r3, r1, &miss);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder,
r3,
+ r1, name, &miss);
break;
case NUMBER_CHECK: {
@@ -603,8 +641,8 @@
GenerateLoadGlobalFunctionPrototype(masm(),
Context::NUMBER_FUNCTION_INDEX,
r2);
- __ CheckMaps(JSObject::cast(object->GetPrototype()),
- r2, holder, r3, r1, &miss);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder,
r3,
+ r1, name, &miss);
break;
}
@@ -620,13 +658,13 @@
GenerateLoadGlobalFunctionPrototype(masm(),
Context::BOOLEAN_FUNCTION_INDEX,
r2);
- __ CheckMaps(JSObject::cast(object->GetPrototype()),
- r2, holder, r3, r1, &miss);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder,
r3,
+ r1, name, &miss);
break;
}
case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
- __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+ CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name,
&miss);
// Make sure object->elements()->map() != Heap::hash_table_map()
// Get the elements array of the object.
__ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
@@ -712,7 +750,7 @@
}
// Check that the maps haven't changed.
- masm()->CheckMaps(object, r0, holder, r3, r2, &miss);
+ CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -941,7 +979,7 @@
__ ldr(r0, MemOperand(sp, 0));
- GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
+ GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -962,7 +1000,7 @@
Label miss;
__ ldr(r0, MemOperand(sp, 0));
- GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback,
&miss);
+ GenerateLoadCallback(object, holder, r0, r2, r3, r1, callback, name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -984,7 +1022,7 @@
__ ldr(r0, MemOperand(sp, 0));
- GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
+ GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -1005,14 +1043,14 @@
__ ldr(r0, MemOperand(sp, 0));
- GenerateLoadInterceptor(masm(),
- object,
+ GenerateLoadInterceptor(object,
holder,
holder->InterceptorPropertyLookupHint(name),
r0,
r2,
r3,
r1,
+ name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -1048,7 +1086,7 @@
}
// Check that the map of the global has not changed.
- masm()->CheckMaps(object, r1, holder, r3, r0, &miss);
+ CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -1091,7 +1129,7 @@
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
- GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
+ GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1116,8 +1154,7 @@
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
- GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
- r1, callback, &miss);
+ GenerateLoadCallback(receiver, holder, r0, r2, r3, r1, callback, name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1143,7 +1180,7 @@
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
- GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
+ GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1169,14 +1206,14 @@
__ cmp(r2, Operand(Handle<String>(name)));
__ b(ne, &miss);
- GenerateLoadInterceptor(masm(),
- receiver,
+ GenerateLoadInterceptor(receiver,
holder,
Smi::FromInt(JSObject::kLookupInHolder),
r0,
r2,
r3,
r1,
+ name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
Modified: branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/stub-cache-ia32.cc (original)
+++ branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Jul 10 02:40:47
2009
@@ -273,114 +273,6 @@
}
-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)
{
@@ -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);
Modified: branches/bleeding_edge/src/objects-inl.h
==============================================================================
--- branches/bleeding_edge/src/objects-inl.h (original)
+++ branches/bleeding_edge/src/objects-inl.h Fri Jul 10 02:40:47 2009
@@ -2653,7 +2653,7 @@
Object* key,
Object* value,
PropertyDetails details) {
- ASSERT(!key->IsString() || details.index() > 0);
+ ASSERT(!key->IsString() || details.IsDeleted() || details.index() > 0);
int index = HashTable<Shape, Key>::EntryToIndex(entry);
WriteBarrierMode mode = FixedArray::GetWriteBarrierMode();
FixedArray::set(index, key, mode);
Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc (original)
+++ branches/bleeding_edge/src/objects.cc Fri Jul 10 02:40:47 2009
@@ -436,8 +436,7 @@
store_value = Heap::AllocateJSGlobalPropertyCell(value);
if (store_value->IsFailure()) return store_value;
}
- Object* dict =
- property_dictionary()->Add(name, store_value, details);
+ Object* dict = property_dictionary()->Add(name, store_value, details);
if (dict->IsFailure()) return dict;
set_properties(StringDictionary::cast(dict));
return value;
@@ -1712,30 +1711,24 @@
} else {
int entry = property_dictionary()->FindEntry(name);
if (entry != StringDictionary::kNotFound) {
- // Make sure to disallow caching for uninitialized constants
- // found in the dictionary-mode objects.
Object* value = property_dictionary()->ValueAt(entry);
if (IsGlobalObject()) {
PropertyDetails d = property_dictionary()->DetailsAt(entry);
if (d.IsDeleted()) {
- // We've skipped a global object during lookup, so we cannot
- // use inline caching because the map of the global object
- // doesn't change if the property should be re-added.
- result->DisallowCaching();
result->NotFound();
return;
}
value = JSGlobalPropertyCell::cast(value)->value();
ASSERT(result->IsLoaded());
}
- if (value->IsTheHole()) {
- result->DisallowCaching();
- }
+ // Make sure to disallow caching for uninitialized constants
+ // found in the dictionary-mode objects.
+ if (value->IsTheHole()) result->DisallowCaching();
result->DictionaryResult(this, entry);
return;
}
// Slow case object skipped during lookup. Do not use inline caching.
- result->DisallowCaching();
+ if (!IsGlobalObject()) result->DisallowCaching();
}
result->NotFound();
}
@@ -6841,6 +6834,26 @@
}
+Object* GlobalObject::EnsurePropertyCell(String* name) {
+ ASSERT(!HasFastProperties());
+ int entry = property_dictionary()->FindEntry(name);
+ if (entry == StringDictionary::kNotFound) {
+ Object* cell =
Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value());
+ if (cell->IsFailure()) return cell;
+ PropertyDetails details(NONE, NORMAL);
+ details = details.AsDeleted();
+ Object* dictionary = property_dictionary()->Add(name, cell, details);
+ if (dictionary->IsFailure()) return dictionary;
+ set_properties(StringDictionary::cast(dictionary));
+ return cell;
+ } else {
+ Object* value = property_dictionary()->ValueAt(entry);
+ ASSERT(value->IsJSGlobalPropertyCell());
+ return value;
+ }
+}
+
+
Object* SymbolTable::LookupString(String* string, Object** s) {
SymbolKey key(string);
return LookupKey(&key, s);
@@ -7200,7 +7213,7 @@
uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
// Insert element at empty or deleted entry
- if (details.index() == 0 && Shape::kIsEnumerable) {
+ if (!details.IsDeleted() && details.index() == 0 &&
Shape::kIsEnumerable) {
// Assign an enumeration index to the property and update
// SetNextEnumerationIndex.
int index = NextEnumerationIndex();
@@ -7273,7 +7286,9 @@
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
- PropertyAttributes attr = DetailsAt(i).attributes();
+ PropertyDetails details = DetailsAt(i);
+ if (details.IsDeleted()) continue;
+ PropertyAttributes attr = details.attributes();
if ((attr & filter) == 0) result++;
}
}
@@ -7297,7 +7312,9 @@
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
- PropertyAttributes attr = DetailsAt(i).attributes();
+ PropertyDetails details = DetailsAt(i);
+ if (details.IsDeleted()) continue;
+ PropertyAttributes attr = details.attributes();
if ((attr & filter) == 0) storage->set(index++, k);
}
}
@@ -7315,13 +7332,12 @@
Object* k = KeyAt(i);
if (IsKey(k)) {
PropertyDetails details = DetailsAt(i);
- if (!details.IsDontEnum()) {
- storage->set(index, k);
- sort_array->set(index,
- Smi::FromInt(details.index()),
- SKIP_WRITE_BARRIER);
- index++;
- }
+ if (details.IsDeleted() || details.IsDontEnum()) continue;
+ storage->set(index, k);
+ sort_array->set(index,
+ Smi::FromInt(details.index()),
+ SKIP_WRITE_BARRIER);
+ index++;
}
}
storage->SortPairs(sort_array, sort_array->length());
@@ -7338,6 +7354,8 @@
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
+ PropertyDetails details = DetailsAt(i);
+ if (details.IsDeleted()) continue;
storage->set(index++, k);
}
}
Modified: branches/bleeding_edge/src/objects.h
==============================================================================
--- branches/bleeding_edge/src/objects.h (original)
+++ branches/bleeding_edge/src/objects.h Fri Jul 10 02:40:47 2009
@@ -3240,6 +3240,9 @@
// Retrieve the property cell used to store a property.
Object* GetPropertyCell(LookupResult* result);
+ // Ensure that the global object has a cell for the given property name.
+ Object* EnsurePropertyCell(String* name);
+
// Casting.
static inline GlobalObject* cast(Object* obj);
Modified: branches/bleeding_edge/src/stub-cache.cc
==============================================================================
--- branches/bleeding_edge/src/stub-cache.cc (original)
+++ branches/bleeding_edge/src/stub-cache.cc Fri Jul 10 02:40:47 2009
@@ -450,7 +450,7 @@
if (!function->is_compiled()) return Failure::InternalError();
// Compile the stub - only create stubs for fully compiled functions.
CallStubCompiler compiler(argc, in_loop);
- code = compiler.CompileCallConstant(object, holder, function, check);
+ code = compiler.CompileCallConstant(object, holder, function, name,
check);
if (code->IsFailure()) return code;
ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
@@ -957,6 +957,10 @@
Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char*
name) {
+ // Check for allocation failures during stub compilation.
+ if (failure_->IsFailure()) return failure_;
+
+ // Create code object in the heap.
CodeDesc desc;
masm_.GetCode(&desc);
Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
Modified: branches/bleeding_edge/src/stub-cache.h
==============================================================================
--- branches/bleeding_edge/src/stub-cache.h (original)
+++ branches/bleeding_edge/src/stub-cache.h Fri Jul 10 02:40:47 2009
@@ -324,7 +324,7 @@
JSARRAY_HAS_FAST_ELEMENTS_CHECK
};
- StubCompiler() : scope_(), masm_(NULL, 256) { }
+ StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
Object* CompileCallInitialize(Code::Flags flags);
Object* CompileCallPreMonomorphic(Code::Flags flags);
@@ -344,40 +344,7 @@
static void GenerateFastPropertyLoad(MacroAssembler* masm,
Register dst, Register src,
JSObject* holder, int index);
- static void GenerateLoadField(MacroAssembler* masm,
- JSObject* object,
- JSObject* holder,
- Register receiver,
- Register scratch1,
- Register scratch2,
- int index,
- Label* miss_label);
- static void GenerateLoadCallback(MacroAssembler* masm,
- JSObject* object,
- JSObject* holder,
- Register receiver,
- Register name,
- Register scratch1,
- Register scratch2,
- AccessorInfo* callback,
- Label* miss_label);
- static void GenerateLoadConstant(MacroAssembler* masm,
- JSObject* object,
- JSObject* holder,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Object* value,
- Label* miss_label);
- static void GenerateLoadInterceptor(MacroAssembler* masm,
- JSObject* object,
- JSObject* holder,
- Smi* lookup_hint,
- Register receiver,
- Register name,
- Register scratch1,
- Register scratch2,
- Label* miss_label);
+
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
Register scratch,
@@ -412,10 +379,60 @@
Object* GetCodeWithFlags(Code::Flags flags, String* name);
MacroAssembler* masm() { return &masm_; }
+ void set_failure(Failure* failure) { failure_ = failure; }
+
+ // Check the integrity of the prototype chain to make sure that the
+ // current IC is still valid.
+ Register CheckPrototypes(JSObject* object,
+ Register object_reg,
+ JSObject* holder,
+ Register holder_reg,
+ Register scratch,
+ String* name,
+ Label* miss);
+
+ void GenerateLoadField(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ int index,
+ String* name,
+ Label* miss);
+
+ void GenerateLoadCallback(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ AccessorInfo* callback,
+ String* name,
+ Label* miss);
+
+ void GenerateLoadConstant(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Object* value,
+ String* name,
+ Label* miss);
+
+ void GenerateLoadInterceptor(JSObject* object,
+ JSObject* holder,
+ Smi* lookup_hint,
+ Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ String* name,
+ Label* miss);
private:
HandleScope scope_;
MacroAssembler masm_;
+ Failure* failure_;
};
@@ -518,6 +535,7 @@
Object* CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
+ String* name,
CheckType check);
Object* CompileCallInterceptor(Object* object,
JSObject* holder,
Modified: branches/bleeding_edge/src/x64/stub-cache-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/stub-cache-x64.cc (original)
+++ branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Jul 10 02:40:47
2009
@@ -42,7 +42,8 @@
Object* CallStubCompiler::CompileCallConstant(Object* a,
JSObject* b,
JSFunction* c,
- StubCompiler::CheckType d) {
+ String* d,
+ StubCompiler::CheckType e) {
UNIMPLEMENTED();
return NULL;
}
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---