Revision: 4401
Author: [email protected]
Date: Tue Apr 13 23:25:11 2010
Log: Add inline caches for loading non-existing properties.
Review URL: http://codereview.chromium.org/1539034
http://code.google.com/p/v8/source/detail?r=4401

Modified:
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/globals.h
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/stub-cache.cc
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Mar 25 10:08:22 2010 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Apr 13 23:25:11 2010
@@ -1387,6 +1387,36 @@
   // Return the generated code.
   return GetCode(NORMAL, name);
 }
+
+
+Object* LoadStubCompiler::CompileLoadNonexistent(JSObject* object) {
+  // ----------- S t a t e -------------
+  //  -- r2    : name
+  //  -- lr    : return address
+  //  -- [sp]  : receiver
+  // -----------------------------------
+  Label miss;
+
+  // Load receiver.
+  __ ldr(r0, MemOperand(sp, 0));
+
+  // Check the maps of the full prototype chain.
+  JSObject* last = object;
+  while (last->GetPrototype() != Heap::null_value()) {
+    last = JSObject::cast(last->GetPrototype());
+  }
+  CheckPrototypes(object, r0, last, r3, r1, Heap::empty_string(), &miss);
+
+ // Return undefined if maps of the full prototype chain is still the same.
+  __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
+  __ Ret();
+
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(NONEXISTENT, Heap::empty_string());
+}


 Object* LoadStubCompiler::CompileLoadField(JSObject* object,
=======================================
--- /branches/bleeding_edge/src/globals.h       Mon Apr 12 00:23:43 2010
+++ /branches/bleeding_edge/src/globals.h       Tue Apr 13 23:25:11 2010
@@ -428,7 +428,11 @@
   CONSTANT_TRANSITION = 6,  // only in fast mode
   NULL_DESCRIPTOR     = 7,  // only in fast mode
   // All properties before MAP_TRANSITION are real.
-  FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION
+  FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
+  // There are no IC stubs for NULL_DESCRIPTORS. Therefore,
+  // NULL_DESCRIPTOR can be used as the type flag for IC stubs for
+  // nonexistent properties.
+  NONEXISTENT = NULL_DESCRIPTOR
 };


=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Mar 25 10:08:22 2010 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Apr 13 23:25:11 2010
@@ -1948,6 +1948,32 @@
 }


+Object* LoadStubCompiler::CompileLoadNonexistent(JSObject* object) {
+  // ----------- S t a t e -------------
+  //  -- eax    : receiver
+  //  -- ecx    : name
+  //  -- esp[0] : return address
+  // -----------------------------------
+  Label miss;
+
+  // Check the maps of the full prototype chain.
+  JSObject* last = object;
+  while (last->GetPrototype() != Heap::null_value()) {
+    last = JSObject::cast(last->GetPrototype());
+  }
+ CheckPrototypes(object, eax, last, ebx, edx, Heap::empty_string(), &miss);
+
+ // Return undefined if maps of the full prototype chain is still the same.
+  __ mov(eax, Factory::undefined_value());
+  __ ret(0);
+
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(NONEXISTENT, Heap::empty_string());
+}
+

 Object* LoadStubCompiler::CompileLoadField(JSObject* object,
                                            JSObject* holder,
=======================================
--- /branches/bleeding_edge/src/ic.cc   Thu Apr  8 08:19:06 2010
+++ /branches/bleeding_edge/src/ic.cc   Tue Apr 13 23:25:11 2010
@@ -694,8 +694,8 @@
                           State state,
                           Handle<Object> object,
                           Handle<String> name) {
-  // Bail out if we didn't find a result.
-  if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
+  // Bail out if the result is not cachable.
+  if (!lookup->IsCacheable()) return;

   // Loading properties from values is not common, so don't try to
   // deal with non-JS objects here.
@@ -709,6 +709,9 @@
     // Set the target to the pre monomorphic stub to delay
     // setting the monomorphic state.
     code = pre_monomorphic_stub();
+  } else if (!lookup->IsProperty()) {
+    // Nonexistent property. The result is undefined.
+    code = StubCache::ComputeLoadNonexistent(*name, *receiver);
   } else {
     // Compute monomorphic stub.
     switch (lookup->type()) {
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Tue Apr  6 03:36:38 2010
+++ /branches/bleeding_edge/src/stub-cache.cc   Tue Apr 13 23:25:11 2010
@@ -91,6 +91,28 @@
   primary->value = code;
   return code;
 }
+
+
+Object* StubCache::ComputeLoadNonexistent(String* name, JSObject* receiver) {
+  // The code stub for loading nonexistent properties can be reused
+  // for all names, so we use the empty_string as the name in the map
+  // code cache.
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
+ Object* code = receiver->map()->FindInCodeCache(Heap::empty_string(), flags);
+  if (code->IsUndefined()) {
+    LoadStubCompiler compiler;
+    code = compiler.CompileLoadNonexistent(receiver);
+    if (code->IsFailure()) return code;
+    PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
+                            Code::cast(code),
+                            Heap::empty_string()));
+    Object* result = receiver->map()->UpdateCodeCache(Heap::empty_string(),
+                                                      Code::cast(code));
+    if (result->IsFailure()) return result;
+  }
+  return Set(name, receiver->map(), Code::cast(code));
+}


 Object* StubCache::ComputeLoadField(String* name,
=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Tue Mar 23 07:33:42 2010
+++ /branches/bleeding_edge/src/stub-cache.h    Tue Apr 13 23:25:11 2010
@@ -56,6 +56,8 @@

   // Computes the right stub matching. Inserts the result in the
   // cache before returning.  This might compile a stub if needed.
+  static Object* ComputeLoadNonexistent(String* name, JSObject* receiver);
+
   static Object* ComputeLoadField(String* name,
                                   JSObject* receiver,
                                   JSObject* holder,
@@ -461,18 +463,23 @@

 class LoadStubCompiler: public StubCompiler {
  public:
+  Object* CompileLoadNonexistent(JSObject* object);
+
   Object* CompileLoadField(JSObject* object,
                            JSObject* holder,
                            int index,
                            String* name);
+
   Object* CompileLoadCallback(String* name,
                               JSObject* object,
                               JSObject* holder,
                               AccessorInfo* callback);
+
   Object* CompileLoadConstant(JSObject* object,
                               JSObject* holder,
                               Object* value,
                               String* name);
+
   Object* CompileLoadInterceptor(JSObject* object,
                                  JSObject* holder,
                                  String* name);
@@ -494,17 +501,21 @@
                            JSObject* object,
                            JSObject* holder,
                            int index);
+
   Object* CompileLoadCallback(String* name,
                               JSObject* object,
                               JSObject* holder,
                               AccessorInfo* callback);
+
   Object* CompileLoadConstant(String* name,
                               JSObject* object,
                               JSObject* holder,
                               Object* value);
+
   Object* CompileLoadInterceptor(JSObject* object,
                                  JSObject* holder,
                                  String* name);
+
   Object* CompileLoadArrayLength(String* name);
   Object* CompileLoadStringLength(String* name);
   Object* CompileLoadFunctionPrototype(String* name);
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Mar 25 10:08:22 2010 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Apr 13 23:25:11 2010
@@ -1142,6 +1142,36 @@
   // Return the generated code.
   return GetCode(CONSTANT_FUNCTION, name);
 }
+
+
+Object* LoadStubCompiler::CompileLoadNonexistent(JSObject* object) {
+  // ----------- S t a t e -------------
+  //  -- rcx    : name
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : receiver
+  // -----------------------------------
+  Label miss;
+
+  // Load receiver.
+  __ movq(rax, Operand(rsp, kPointerSize));
+
+  // Check the maps of the full prototype chain.
+  JSObject* last = object;
+  while (last->GetPrototype() != Heap::null_value()) {
+    last = JSObject::cast(last->GetPrototype());
+  }
+ CheckPrototypes(object, rax, last, rbx, rdx, Heap::empty_string(), &miss);
+
+ // Return undefined if maps of the full prototype chain is still the same.
+  __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+  __ ret(0);
+
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+  // Return the generated code.
+  return GetCode(NONEXISTENT, Heap::empty_string());
+}


 Object* LoadStubCompiler::CompileLoadField(JSObject* object,

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

To unsubscribe, reply using "remove me" as the subject.

Reply via email to