Version 1.2.14.
Added separate paged heap space for global property cells and avoid updating the write barrier when storing into them.
Improved peep-hole optimization on ARM platforms by not emitting unnecessary debug information.
Re-enabled ICs for loads and calls that skip a global object during lookup through the prototype chain.
Allowed access through global proxies to use ICs.
Fixed issue 401.
git-svn-id: http://v8.googlecode.com/svn/trunk@2438 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index e3e5502..6d9ace8 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -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,
@@ -351,6 +247,17 @@
}
+void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
+ __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
+ __ mov(r0, scratch1);
+ __ Ret();
+}
+
+
// Generate StoreField code, value is passed in r0 register.
// After executing generated code, the receiver_reg and name_reg
// may be clobbered.
@@ -462,6 +369,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 +561,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 +594,7 @@
Object* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
+ String* name,
CheckType check) {
// ----------- S t a t e -------------
// -- lr: return address
@@ -569,7 +618,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 +636,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 +652,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 +669,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));
@@ -685,7 +734,8 @@
}
-Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
+Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
+ GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
@@ -699,11 +749,19 @@
// Get the number of arguments.
const int argc = arguments().immediate();
- // Check that the map of the global has not changed.
- __ ldr(r2, MemOperand(sp, argc * kPointerSize));
- __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
- __ cmp(r3, Operand(Handle<Map>(object->map())));
- __ b(ne, &miss);
+ // Get the receiver from the stack.
+ __ ldr(r0, MemOperand(sp, argc * kPointerSize));
+
+ // If the object is the holder then we know that it's a global
+ // object which can only happen for contextual calls. In this case,
+ // the receiver cannot be a smi.
+ if (object != holder) {
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, &miss);
+ }
+
+ // Check that the maps haven't changed.
+ CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -715,8 +773,10 @@
// Patch the receiver on the stack with the global proxy if
// necessary.
- __ ldr(r3, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
- __ str(r3, MemOperand(sp, argc * kPointerSize));
+ if (object->IsGlobalObject()) {
+ __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+ __ str(r3, MemOperand(sp, argc * kPointerSize));
+ }
// Setup the context (function already in r1).
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
@@ -902,8 +962,6 @@
// Store the value in the cell.
__ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
- __ mov(r1, Operand(JSGlobalPropertyCell::kValueOffset));
- __ RecordWrite(r2, r1, r3);
__ Ret();
@@ -932,7 +990,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);
@@ -953,7 +1011,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);
@@ -975,7 +1033,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);
@@ -996,14 +1054,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);
@@ -1013,7 +1071,8 @@
}
-Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
+Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
+ GlobalObject* holder,
JSGlobalPropertyCell* cell,
String* name,
bool is_dont_delete) {
@@ -1026,11 +1085,19 @@
__ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
- // Check that the map of the global has not changed.
+ // Get the receiver from the stack.
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
- __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ cmp(r3, Operand(Handle<Map>(object->map())));
- __ b(ne, &miss);
+
+ // If the object is the holder then we know that it's a global
+ // object which can only happen for contextual calls. In this case,
+ // the receiver cannot be a smi.
+ if (object != holder) {
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &miss);
+ }
+
+ // Check that the map of the global has not changed.
+ CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -1073,7 +1140,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);
@@ -1098,8 +1165,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);
@@ -1125,7 +1191,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);
@@ -1151,14 +1217,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);