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