Handle all object types (minus smi) in load/store ICs
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 14 Nov 2013 16:25:31 +0000 (16:25 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 14 Nov 2013 16:25:31 +0000 (16:25 +0000)
R=ulan@chromium.org

Review URL: https://chromiumcodereview.appspot.com/62953007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17755 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/arm/stub-cache-arm.cc
src/ia32/stub-cache-ia32.cc
src/ic-inl.h
src/ic.cc
src/ic.h
src/objects-inl.h
src/objects.h
src/stub-cache.cc
src/stub-cache.h
src/type-info.cc
src/x64/stub-cache-x64.cc
test/mjsunit/load-callback-from-value-classic.js [new file with mode: 0644]

index 0362c1a..a163c53 100644 (file)
@@ -1298,34 +1298,33 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 }
 
 
-void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
-                                             Label* success,
-                                             Label* miss) {
+void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
   if (!miss->is_unused()) {
-    __ b(success);
+    Label success;
+    __ b(&success);
     __ bind(miss);
     TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
   }
 }
 
 
-void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
-                                              Label* success,
-                                              Label* miss) {
+void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
   if (!miss->is_unused()) {
-    __ b(success);
+    Label success;
+    __ b(&success);
     GenerateRestoreName(masm(), miss, name);
     TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
   }
 }
 
 
 Register LoadStubCompiler::CallbackHandlerFrontend(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Register object_reg,
     Handle<JSObject> holder,
     Handle<Name> name,
-    Label* success,
     Handle<Object> callback) {
   Label miss;
 
@@ -1362,7 +1361,7 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
     __ b(ne, &miss);
   }
 
-  HandlerFrontendFooter(name, success, &miss);
+  HandlerFrontendFooter(name, &miss);
   return reg;
 }
 
@@ -1468,7 +1467,7 @@ void LoadStubCompiler::GenerateLoadCallback(
 
 void LoadStubCompiler::GenerateLoadInterceptor(
     Register holder_reg,
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> interceptor_holder,
     LookupResult* lookup,
     Handle<Name> name) {
@@ -2539,11 +2538,23 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
 }
 
 
+void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
+  Label success;
+  // Check that the object is a boolean.
+  __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+  __ cmp(object, ip);
+  __ b(eq, &success);
+  __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+  __ cmp(object, ip);
+  __ b(ne, miss);
+  __ bind(&success);
+}
+
+
 void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
                                               Handle<JSObject> holder,
                                               Handle<Name> name,
-                                              CheckType check,
-                                              Label* success) {
+                                              CheckType check) {
   // ----------- S t a t e -------------
   //  -- r2    : name
   //  -- lr    : return address
@@ -2619,15 +2630,8 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       break;
     }
     case BOOLEAN_CHECK: {
-      Label fast;
-      // Check that the object is a boolean.
-      __ LoadRoot(ip, Heap::kTrueValueRootIndex);
-      __ cmp(r1, ip);
-      __ b(eq, &fast);
-      __ LoadRoot(ip, Heap::kFalseValueRootIndex);
-      __ cmp(r1, ip);
-      __ b(ne, &miss);
-      __ bind(&fast);
+      GenerateBooleanCheck(r1, &miss);
+
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
@@ -2638,11 +2642,14 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
     }
   }
 
-  __ b(success);
+  Label success;
+  __ b(&success);
 
   // Handle call cache miss.
   __ bind(&miss);
   GenerateMissBranch();
+
+  __ bind(&success);
 }
 
 
@@ -2671,10 +2678,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
     if (!code.is_null()) return code;
   }
 
-  Label success;
-
-  CompileHandlerFrontend(object, holder, name, check, &success);
-  __ bind(&success);
+  CompileHandlerFrontend(object, holder, name, check);
   CompileHandlerBackend(function);
 
   // Return the generated code.
@@ -2785,9 +2789,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
 
   // Stub never generated for non-global objects that require access checks.
   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -2813,9 +2815,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
     Handle<JSObject> holder,
     Handle<Name> name,
     const CallOptimization& call_optimization) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
 
   Register values[] = { value() };
   GenerateFastApiCall(
@@ -2910,15 +2910,12 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> last,
     Handle<Name> name,
     Handle<JSGlobalObject> global) {
-  Label success;
+  NonexistentHandlerFrontend(object, last, name, global);
 
-  NonexistentHandlerFrontend(object, last, name, &success, global);
-
-  __ bind(&success);
   // Return undefined if maps of the full prototype chain are still the
   // same and no global property with this name contains a value.
   __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
@@ -3013,12 +3010,12 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
 
 
 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<GlobalObject> global,
     Handle<PropertyCell> cell,
     Handle<Name> name,
     bool is_dont_delete) {
-  Label success, miss;
+  Label miss;
 
   HandlerFrontendHeader(object, receiver(), global, name, &miss);
 
@@ -3033,8 +3030,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
     __ b(eq, &miss);
   }
 
-  HandlerFrontendFooter(name, &success, &miss);
-  __ bind(&success);
+  HandlerFrontendFooter(name, &miss);
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
index 43576d6..66edf2e 100644 (file)
@@ -1267,34 +1267,33 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 }
 
 
-void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
-                                             Label* success,
-                                             Label* miss) {
+void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
   if (!miss->is_unused()) {
-    __ jmp(success);
+    Label success;
+    __ jmp(&success);
     __ bind(miss);
     TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
   }
 }
 
 
-void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
-                                              Label* success,
-                                              Label* miss) {
+void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
   if (!miss->is_unused()) {
-    __ jmp(success);
+    Label success;
+    __ jmp(&success);
     GenerateRestoreName(masm(), miss, name);
     TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
   }
 }
 
 
 Register LoadStubCompiler::CallbackHandlerFrontend(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Register object_reg,
     Handle<JSObject> holder,
     Handle<Name> name,
-    Label* success,
     Handle<Object> callback) {
   Label miss;
 
@@ -1344,7 +1343,7 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
     __ j(not_equal, &miss);
   }
 
-  HandlerFrontendFooter(name, success, &miss);
+  HandlerFrontendFooter(name, &miss);
   return reg;
 }
 
@@ -1450,7 +1449,7 @@ void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
 
 void LoadStubCompiler::GenerateLoadInterceptor(
     Register holder_reg,
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> interceptor_holder,
     LookupResult* lookup,
     Handle<Name> name) {
@@ -2613,11 +2612,21 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
 }
 
 
+void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
+  Label success;
+  // Check that the object is a boolean.
+  __ cmp(object, factory()->true_value());
+  __ j(equal, &success);
+  __ cmp(object, factory()->false_value());
+  __ j(not_equal, miss);
+  __ bind(&success);
+}
+
+
 void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
                                               Handle<JSObject> holder,
                                               Handle<Name> name,
-                                              CheckType check,
-                                              Label* success) {
+                                              CheckType check) {
   // ----------- S t a t e -------------
   //  -- ecx                 : name
   //  -- esp[0]              : return address
@@ -2696,13 +2705,7 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       break;
     }
     case BOOLEAN_CHECK: {
-      Label fast;
-      // Check that the object is a boolean.
-      __ cmp(edx, factory()->true_value());
-      __ j(equal, &fast);
-      __ cmp(edx, factory()->false_value());
-      __ j(not_equal, &miss);
-      __ bind(&fast);
+      GenerateBooleanCheck(edx, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
@@ -2713,11 +2716,14 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
     }
   }
 
-  __ jmp(success);
+  Label success;
+  __ jmp(&success);
 
   // Handle call cache miss.
   __ bind(&miss);
   GenerateMissBranch();
+
+  __ bind(&success);
 }
 
 
@@ -2747,10 +2753,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
     if (!code.is_null()) return code;
   }
 
-  Label success;
-
-  CompileHandlerFrontend(object, holder, name, check, &success);
-  __ bind(&success);
+  CompileHandlerFrontend(object, holder, name, check);
   CompileHandlerBackend(function);
 
   // Return the generated code.
@@ -2885,9 +2888,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
 
   __ pop(scratch1());  // remove the return address
   __ push(receiver());
@@ -2911,9 +2912,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
     Handle<JSObject> holder,
     Handle<Name> name,
     const CallOptimization& call_optimization) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
 
   Register values[] = { value() };
   GenerateFastApiCall(
@@ -3020,15 +3019,12 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> last,
     Handle<Name> name,
     Handle<JSGlobalObject> global) {
-  Label success;
+  NonexistentHandlerFrontend(object, last, name, global);
 
-  NonexistentHandlerFrontend(object, last, name, &success, global);
-
-  __ bind(&success);
   // Return undefined if maps of the full prototype chain are still the
   // same and no global property with this name contains a value.
   __ mov(eax, isolate()->factory()->undefined_value());
@@ -3118,12 +3114,12 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
 
 
 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<GlobalObject> global,
     Handle<PropertyCell> cell,
     Handle<Name> name,
     bool is_dont_delete) {
-  Label success, miss;
+  Label miss;
 
   HandlerFrontendHeader(object, receiver(), global, name, &miss);
   // Get the value from the cell.
@@ -3143,8 +3139,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
   }
 
-  HandlerFrontendFooter(name, &success, &miss);
-  __ bind(&success);
+  HandlerFrontendFooter(name, &miss);
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1);
index 06cbf2e..c1c5c5e 100644 (file)
@@ -100,8 +100,7 @@ void IC::SetTargetAtAddress(Address address, Code* target) {
 }
 
 
-InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object,
-                                                JSObject* holder) {
+InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object) {
   if (object->IsJSObject()) return OWN_MAP;
 
   // If the object is a value, we use the prototype map for the cache.
@@ -111,13 +110,12 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object,
 }
 
 
-JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
+HeapObject* IC::GetCodeCacheHolder(Isolate* isolate,
                                  Object* object,
                                  InlineCacheHolderFlag holder) {
   Object* map_owner =
       holder == OWN_MAP ? object : object->GetPrototype(isolate);
-  ASSERT(map_owner->IsJSObject());
-  return JSObject::cast(map_owner);
+  return HeapObject::cast(map_owner);
 }
 
 
index 640b188..187023e 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1005,7 +1005,7 @@ void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
                              Handle<String> name) {
   if (!handler->is_handler()) return set_target(*handler);
   Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
-      receiver, handler, name, strict_mode());
+      name, receiver, handler, strict_mode());
   set_target(*ic);
 }
 
@@ -1035,9 +1035,13 @@ bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
 }
 
 
-void IC::PatchCache(Handle<HeapObject> receiver,
+void IC::PatchCache(Handle<Object> object,
                     Handle<String> name,
                     Handle<Code> code) {
+  // TODO(verwaest): Handle smi here as well.
+  if (!object->IsHeapObject()) return;
+
+  Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
   switch (state()) {
     case UNINITIALIZED:
     case PREMONOMORPHIC:
@@ -1097,13 +1101,6 @@ Handle<Code> LoadIC::SimpleFieldLoad(int offset,
 void LoadIC::UpdateCaches(LookupResult* lookup,
                           Handle<Object> object,
                           Handle<String> name) {
-  // TODO(verwaest): It would be nice to support loading fields from smis as
-  // well. For now just fail to update the cache.
-  if (!object->IsHeapObject()) return;
-
-  Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
-
-  Handle<Code> code;
   if (state() == UNINITIALIZED) {
     // This is the first time we execute this inline cache.
     // Set the target to the pre monomorphic stub to delay
@@ -1111,27 +1108,23 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
     set_target(*pre_monomorphic_stub());
     TRACE_IC("LoadIC", name);
     return;
-  } else if (!lookup->IsCacheable()) {
+  }
+
+  Handle<Code> code;
+  if (!lookup->IsCacheable()) {
     // Bail out if the result is not cacheable.
     code = slow_stub();
-  } else if (object->IsString() &&
-             name->Equals(isolate()->heap()->length_string())) {
-    int length_index = String::kLengthOffset / kPointerSize;
-    code = SimpleFieldLoad(length_index);
-  } else if (!object->IsJSObject()) {
-    // TODO(jkummerow): It would be nice to support non-JSObjects in
-    // ComputeLoadHandler, then we wouldn't need to go generic here.
-    code = slow_stub();
   } else if (!lookup->IsProperty()) {
-    code = kind() == Code::LOAD_IC
-        ? isolate()->stub_cache()->ComputeLoadNonexistent(
-              name, Handle<JSObject>::cast(receiver))
-        : slow_stub();
+    if (kind() == Code::LOAD_IC) {
+      code = isolate()->stub_cache()->ComputeLoadNonexistent(name, object);
+    } else {
+      code = slow_stub();
+    }
   } else {
-    code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
+    code = ComputeHandler(lookup, object, name);
   }
 
-  PatchCache(receiver, name, code);
+  PatchCache(object, name, code);
   TRACE_IC("LoadIC", name);
 }
 
@@ -1144,18 +1137,22 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
 
 
 Handle<Code> IC::ComputeHandler(LookupResult* lookup,
-                                Handle<JSObject> receiver,
+                                Handle<Object> object,
                                 Handle<String> name,
                                 Handle<Object> value) {
+  InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object);
+  Handle<HeapObject> stub_holder(GetCodeCacheHolder(
+      isolate(), *object, cache_holder));
+
   Handle<Code> code = isolate()->stub_cache()->FindHandler(
-      name, receiver, kind());
+      name, stub_holder, kind(), cache_holder, strict_mode());
   if (!code.is_null()) return code;
 
-  code = CompileHandler(lookup, receiver, name, value);
+  code = CompileHandler(lookup, object, name, value, cache_holder);
   ASSERT(code->is_handler());
 
   if (code->type() != Code::NORMAL) {
-    HeapObject::UpdateMapCodeCache(receiver, name, code);
+    HeapObject::UpdateMapCodeCache(stub_holder, name, code);
   }
 
   return code;
@@ -1163,29 +1160,35 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup,
 
 
 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
-                                    Handle<JSObject> receiver,
+                                    Handle<Object> object,
                                     Handle<String> name,
-                                    Handle<Object> unused) {
+                                    Handle<Object> unused,
+                                    InlineCacheHolderFlag cache_holder) {
+  if (object->IsString() && name->Equals(isolate()->heap()->length_string())) {
+    int length_index = String::kLengthOffset / kPointerSize;
+    return SimpleFieldLoad(length_index);
+  }
+
   Handle<JSObject> holder(lookup->holder());
-  LoadStubCompiler compiler(isolate(), kind());
+  LoadStubCompiler compiler(isolate(), cache_holder, kind());
 
   switch (lookup->type()) {
     case FIELD: {
       PropertyIndex field = lookup->GetFieldIndex();
-      if (receiver.is_identical_to(holder)) {
+      if (object.is_identical_to(holder)) {
         return SimpleFieldLoad(field.translate(holder),
                                field.is_inobject(holder),
                                lookup->representation());
       }
       return compiler.CompileLoadField(
-          receiver, holder, name, field, lookup->representation());
+          object, holder, name, field, lookup->representation());
     }
     case CONSTANT: {
       Handle<Object> constant(lookup->GetConstant(), isolate());
       // TODO(2803): Don't compute a stub for cons strings because they cannot
       // be embedded into code.
       if (constant->IsConsString()) break;
-      return compiler.CompileLoadConstant(receiver, holder, name, constant);
+      return compiler.CompileLoadConstant(object, holder, name, constant);
     }
     case NORMAL:
       if (kind() != Code::LOAD_IC) break;
@@ -1194,26 +1197,31 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
         Handle<PropertyCell> cell(
             global->GetPropertyCell(lookup), isolate());
         Handle<Code> code = compiler.CompileLoadGlobal(
-            receiver, global, cell, name, lookup->IsDontDelete());
+            object, global, cell, name, lookup->IsDontDelete());
         // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
-        HeapObject::UpdateMapCodeCache(receiver, name, code);
+        Handle<HeapObject> stub_holder(GetCodeCacheHolder(
+            isolate(), *object, cache_holder));
+        HeapObject::UpdateMapCodeCache(stub_holder, name, code);
         return code;
       }
       // There is only one shared stub for loading normalized
       // properties. It does not traverse the prototype chain, so the
-      // property must be found in the receiver for the stub to be
+      // property must be found in the object for the stub to be
       // applicable.
-      if (!holder.is_identical_to(receiver)) break;
+      if (!object.is_identical_to(holder)) break;
       return isolate()->builtins()->LoadIC_Normal();
     case CALLBACKS: {
       // Use simple field loads for some well-known callback properties.
       int object_offset;
-      Handle<Map> map(receiver->map());
-      if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
-        PropertyIndex index =
-            PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
-        return compiler.CompileLoadField(
-            receiver, receiver, name, index, Representation::Tagged());
+      if (object->IsJSObject()) {
+        Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+        Handle<Map> map(receiver->map());
+        if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
+          PropertyIndex index =
+              PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
+          return compiler.CompileLoadField(
+              receiver, receiver, name, index, Representation::Tagged());
+        }
       }
 
       Handle<Object> callback(lookup->GetCallbackObject(), isolate());
@@ -1221,8 +1229,8 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
         Handle<ExecutableAccessorInfo> info =
             Handle<ExecutableAccessorInfo>::cast(callback);
         if (v8::ToCData<Address>(info->getter()) == 0) break;
-        if (!info->IsCompatibleReceiver(*receiver)) break;
-        return compiler.CompileLoadCallback(receiver, holder, name, info);
+        if (!info->IsCompatibleReceiver(*object)) break;
+        return compiler.CompileLoadCallback(object, holder, name, info);
       } else if (callback->IsAccessorPair()) {
         Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
                               isolate());
@@ -1230,13 +1238,20 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
         if (holder->IsGlobalObject()) break;
         if (!holder->HasFastProperties()) break;
         Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
+        if (!object->IsJSObject() &&
+            !function->IsBuiltin() &&
+            function->shared()->is_classic_mode()) {
+          // Calling non-strict non-builtins with a value as the receiver
+          // requires boxing.
+          break;
+        }
         CallOptimization call_optimization(function);
         if (call_optimization.is_simple_api_call() &&
-            call_optimization.IsCompatibleReceiver(*receiver)) {
+            call_optimization.IsCompatibleReceiver(*object)) {
           return compiler.CompileLoadCallback(
-              receiver, holder, name, call_optimization);
+              object, holder, name, call_optimization);
         }
-        return compiler.CompileLoadViaGetter(receiver, holder, name, function);
+        return compiler.CompileLoadViaGetter(object, holder, name, function);
       }
       // TODO(dcarney): Handle correctly.
       if (callback->IsDeclaredAccessorInfo()) break;
@@ -1246,7 +1261,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
     }
     case INTERCEPTOR:
       ASSERT(HasInterceptorGetter(*holder));
-      return compiler.CompileLoadInterceptor(receiver, holder, name);
+      return compiler.CompileLoadInterceptor(object, holder, name);
     default:
       break;
   }
@@ -1582,9 +1597,14 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
 
 
 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
-                                     Handle<JSObject> receiver,
+                                     Handle<Object> object,
                                      Handle<String> name,
-                                     Handle<Object> value) {
+                                     Handle<Object> value,
+                                     InlineCacheHolderFlag cache_holder) {
+  ASSERT(cache_holder == OWN_MAP);
+  // This is currently guaranteed by checks in StoreIC::Store.
+  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
   Handle<JSObject> holder(lookup->holder());
   StoreStubCompiler compiler(isolate(), strict_mode(), kind());
   switch (lookup->type()) {
index fde4bc7..819cb4b 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -132,11 +132,13 @@ class IC {
 
   // Determines which map must be used for keeping the code stub.
   // These methods should not be called with undefined or null.
-  static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object,
-                                                            JSObject* holder);
-  static inline JSObject* GetCodeCacheHolder(Isolate* isolate,
-                                             Object* object,
-                                             InlineCacheHolderFlag holder);
+  static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
+  // TODO(verwaest): This currently returns a HeapObject rather than JSObject*
+  // since loading the IC for loading the length from strings are stored on
+  // the string map directly, rather than on the JSObject-typed prototype.
+  static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
+                                               Object* object,
+                                               InlineCacheHolderFlag holder);
 
   static bool IsCleared(Code* code) {
     InlineCacheState state = code->ic_state();
@@ -180,13 +182,14 @@ class IC {
 
   // Compute the handler either by compiling or by retrieving a cached version.
   Handle<Code> ComputeHandler(LookupResult* lookup,
-                              Handle<JSObject> receiver,
+                              Handle<Object> object,
                               Handle<String> name,
                               Handle<Object> value = Handle<Code>::null());
   virtual Handle<Code> CompileHandler(LookupResult* lookup,
-                                      Handle<JSObject> receiver,
+                                      Handle<Object> object,
                                       Handle<String> name,
-                                      Handle<Object> value) {
+                                      Handle<Object> value,
+                                      InlineCacheHolderFlag cache_holder) {
     UNREACHABLE();
     return Handle<Code>::null();
   }
@@ -200,7 +203,7 @@ class IC {
 
   void CopyICToMegamorphicCache(Handle<String> name);
   bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
-  void PatchCache(Handle<HeapObject> receiver,
+  void PatchCache(Handle<Object> object,
                   Handle<String> name,
                   Handle<Code> code);
   virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
@@ -422,9 +425,10 @@ class LoadIC: public IC {
                     Handle<String> name);
 
   virtual Handle<Code> CompileHandler(LookupResult* lookup,
-                                      Handle<JSObject> receiver,
+                                      Handle<Object> object,
                                       Handle<String> name,
-                                      Handle<Object> unused);
+                                      Handle<Object> unused,
+                                      InlineCacheHolderFlag cache_holder);
 
  private:
   // Stub accessors.
@@ -617,9 +621,10 @@ class StoreIC: public IC {
                     Handle<String> name,
                     Handle<Object> value);
   virtual Handle<Code> CompileHandler(LookupResult* lookup,
-                                      Handle<JSObject> receiver,
+                                      Handle<Object> object,
                                       Handle<String> name,
-                                      Handle<Object> value);
+                                      Handle<Object> value,
+                                      InlineCacheHolderFlag cache_holder);
 
  private:
   void set_target(Code* code) {
index 5014c91..fced7a9 100644 (file)
@@ -4185,9 +4185,9 @@ Code::Flags Code::ComputeFlags(Kind kind,
 
 Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
                                           ExtraICState extra_ic_state,
+                                          InlineCacheHolderFlag holder,
                                           StubType type,
-                                          int argc,
-                                          InlineCacheHolderFlag holder) {
+                                          int argc) {
   return ComputeFlags(kind, MONOMORPHIC, extra_ic_state, type, argc, holder);
 }
 
index c912f7c..85627b7 100644 (file)
@@ -5253,9 +5253,9 @@ class Code: public HeapObject {
   static inline Flags ComputeMonomorphicFlags(
       Kind kind,
       ExtraICState extra_ic_state = kNoExtraICState,
+      InlineCacheHolderFlag holder = OWN_MAP,
       StubType type = NORMAL,
-      int argc = -1,
-      InlineCacheHolderFlag holder = OWN_MAP);
+      int argc = -1);
 
   static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
   static inline StubType ExtractTypeFromFlags(Flags flags);
index 1bc4b13..9dc89c2 100644 (file)
@@ -102,8 +102,10 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
 Handle<Code> StubCache::FindIC(Handle<Name> name,
                                Handle<Map> stub_holder_map,
                                Code::Kind kind,
-                               Code::ExtraICState extra_state) {
-  Code::Flags flags = Code::ComputeMonomorphicFlags(kind, extra_state);
+                               Code::ExtraICState extra_state,
+                               InlineCacheHolderFlag cache_holder) {
+  Code::Flags flags = Code::ComputeMonomorphicFlags(
+      kind, extra_state, cache_holder);
   Handle<Object> probe(stub_holder_map->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -111,17 +113,10 @@ Handle<Code> StubCache::FindIC(Handle<Name> name,
 }
 
 
-Handle<Code> StubCache::FindIC(Handle<Name> name,
-                               Handle<JSObject> stub_holder,
-                               Code::Kind kind,
-                               Code::ExtraICState extra_ic_state) {
-  return FindIC(name, Handle<Map>(stub_holder->map()), kind, extra_ic_state);
-}
-
-
 Handle<Code> StubCache::FindHandler(Handle<Name> name,
-                                    Handle<JSObject> receiver,
+                                    Handle<HeapObject> stub_holder,
                                     Code::Kind kind,
+                                    InlineCacheHolderFlag cache_holder,
                                     StrictModeFlag strict_mode) {
   Code::ExtraICState extra_ic_state = Code::kNoExtraICState;
   if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
@@ -129,28 +124,36 @@ Handle<Code> StubCache::FindHandler(Handle<Name> name,
         STANDARD_STORE, strict_mode);
   }
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::HANDLER, extra_ic_state, Code::NORMAL, kind);
-  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
+      Code::HANDLER, extra_ic_state, cache_holder, Code::NORMAL, kind);
+
+  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
   return Handle<Code>::null();
 }
 
 
-Handle<Code> StubCache::ComputeMonomorphicIC(Handle<HeapObject> receiver,
+Handle<Code> StubCache::ComputeMonomorphicIC(Handle<Name> name,
+                                             Handle<HeapObject> object,
                                              Handle<Code> handler,
-                                             Handle<Name> name,
                                              StrictModeFlag strict_mode) {
   Code::Kind kind = handler->handler_kind();
-  Handle<Map> map(receiver->map());
-  Handle<Code> ic = FindIC(name, map, kind, strict_mode);
+  // Use the same cache holder for the IC as for the handler.
+  InlineCacheHolderFlag cache_holder =
+      Code::ExtractCacheHolderFromFlags(handler->flags());
+  Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
+      isolate(), *object, cache_holder));
+  Handle<Map> stub_holder_map(stub_holder->map());
+  Handle<Code> ic = FindIC(
+      name, stub_holder_map, kind, strict_mode, cache_holder);
   if (!ic.is_null()) return ic;
 
+  Handle<Map> map(object->map());
   if (kind == Code::LOAD_IC) {
-    LoadStubCompiler ic_compiler(isolate());
+    LoadStubCompiler ic_compiler(isolate(), cache_holder);
     ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
   } else if (kind == Code::KEYED_LOAD_IC) {
-    KeyedLoadStubCompiler ic_compiler(isolate());
+    KeyedLoadStubCompiler ic_compiler(isolate(), cache_holder);
     ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
   } else if (kind == Code::STORE_IC) {
     StoreStubCompiler ic_compiler(isolate(), strict_mode);
@@ -161,13 +164,16 @@ Handle<Code> StubCache::ComputeMonomorphicIC(Handle<HeapObject> receiver,
     ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
   }
 
-  HeapObject::UpdateMapCodeCache(receiver, name, ic);
+  HeapObject::UpdateMapCodeCache(stub_holder, name, ic);
   return ic;
 }
 
 
 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
-                                               Handle<JSObject> receiver) {
+                                               Handle<Object> object) {
+  InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
+  Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
+      isolate(), *object, cache_holder));
   // If no global objects are present in the prototype chain, the load
   // nonexistent IC stub can be shared for all names for a given map
   // and we use the empty string for the map cache in that case.  If
@@ -176,7 +182,7 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
   // specific to the name.
   Handle<Name> cache_name = factory()->empty_string();
   Handle<JSObject> current;
-  Handle<Object> next = receiver;
+  Handle<Object> next = stub_holder;
   Handle<JSGlobalObject> global;
   do {
     current = Handle<JSObject>::cast(next);
@@ -191,13 +197,14 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
 
   // Compile the stub that is either shared for all names or
   // name specific if there are global objects involved.
-  Handle<Code> handler = FindHandler(cache_name, receiver, Code::LOAD_IC);
+  Handle<Code> handler = FindHandler(
+      cache_name, stub_holder, Code::LOAD_IC, cache_holder);
   if (!handler.is_null()) return handler;
 
-  LoadStubCompiler compiler(isolate_);
+  LoadStubCompiler compiler(isolate_, cache_holder);
   handler =
-      compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
-  HeapObject::UpdateMapCodeCache(receiver, cache_name, handler);
+      compiler.CompileLoadNonexistent(object, current, cache_name, global);
+  HeapObject::UpdateMapCodeCache(stub_holder, cache_name, handler);
   return handler;
 }
 
@@ -257,9 +264,8 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
                                             Handle<JSObject> holder,
                                             Handle<JSFunction> function) {
   // Compute the check type and the map.
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*object, *holder);
-  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+  InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
+  Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
       isolate_, *object, cache_holder));
 
   // Compute check type based on receiver/holder.
@@ -283,7 +289,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
   }
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, Code::CONSTANT, argc, cache_holder);
+      kind, extra_state, cache_holder, Code::CONSTANT, argc);
   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -312,9 +318,8 @@ Handle<Code> StubCache::ComputeCallField(int argc,
                                          Handle<JSObject> holder,
                                          PropertyIndex index) {
   // Compute the check type and the map.
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*object, *holder);
-  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+  InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
+  Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
       isolate_, *object, cache_holder));
 
   // TODO(1233596): We cannot do receiver map check for non-JS objects
@@ -326,7 +331,7 @@ Handle<Code> StubCache::ComputeCallField(int argc,
   }
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, Code::FIELD, argc, cache_holder);
+      kind, extra_state, cache_holder, Code::FIELD, argc);
   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -351,9 +356,8 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
                                                Handle<Object> object,
                                                Handle<JSObject> holder) {
   // Compute the check type and the map.
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*object, *holder);
-  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+  InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
+  Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
       isolate_, *object, cache_holder));
 
   // TODO(1233596): We cannot do receiver map check for non-JS objects
@@ -365,7 +369,7 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
   }
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, Code::INTERCEPTOR, argc, cache_holder);
+      kind, extra_state, cache_holder, Code::INTERCEPTOR, argc);
   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -392,7 +396,7 @@ Handle<Code> StubCache::ComputeCallGlobal(int argc,
                                           Handle<PropertyCell> cell,
                                           Handle<JSFunction> function) {
   Code::Flags flags = Code::ComputeMonomorphicFlags(
-      kind, extra_state, Code::NORMAL, argc);
+      kind, extra_state, OWN_MAP, Code::NORMAL, argc);
   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -1096,10 +1100,7 @@ Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
   masm_.GetCode(&desc);
   Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
 #ifdef ENABLE_DISASSEMBLER
-  if (FLAG_print_code_stubs) {
-    CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
-    code->Disassemble(name, trace_scope.file());
-  }
+  if (FLAG_print_code_stubs) code->Disassemble(name);
 #endif
   return code;
 }
@@ -1127,55 +1128,82 @@ void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
 
 
 Register LoadStubCompiler::HandlerFrontendHeader(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Register object_reg,
     Handle<JSObject> holder,
     Handle<Name> name,
     Label* miss) {
-  return CheckPrototypes(object, object_reg, holder,
+  Handle<JSObject> receiver;
+  PrototypeCheckType check_type = CHECK_ALL_MAPS;
+  int function_index = -1;
+  if (object->IsJSObject()) {
+    receiver = Handle<JSObject>::cast(object);
+    check_type = SKIP_RECEIVER;
+  } else {
+    if (object->IsString()) {
+      function_index = Context::STRING_FUNCTION_INDEX;
+    } else if (object->IsSymbol()) {
+      function_index = Context::SYMBOL_FUNCTION_INDEX;
+    } else if (object->IsNumber()) {
+      function_index = Context::NUMBER_FUNCTION_INDEX;
+    } else {
+      ASSERT(object->IsBoolean());
+      // Booleans use the generic oddball map, so an additional check is
+      // needed to ensure the receiver is really a boolean.
+      GenerateBooleanCheck(object_reg, miss);
+      function_index = Context::BOOLEAN_FUNCTION_INDEX;
+    }
+
+    GenerateDirectLoadGlobalFunctionPrototype(
+        masm(), function_index, scratch1(), miss);
+    receiver = handle(JSObject::cast(object->GetPrototype(isolate())));
+    object_reg = scratch1();
+  }
+
+  // Check that the maps starting from the prototype haven't changed.
+  return CheckPrototypes(receiver, object_reg, holder,
                          scratch1(), scratch2(), scratch3(),
-                         name, miss, SKIP_RECEIVER);
+                         name, miss, check_type);
 }
 
 
 // HandlerFrontend for store uses the name register. It has to be restored
 // before a miss.
 Register StoreStubCompiler::HandlerFrontendHeader(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Register object_reg,
     Handle<JSObject> holder,
     Handle<Name> name,
     Label* miss) {
-  return CheckPrototypes(object, object_reg, holder,
+  return CheckPrototypes(Handle<JSObject>::cast(object), object_reg, holder,
                          this->name(), scratch1(), scratch2(),
                          name, miss, SKIP_RECEIVER);
 }
 
 
-Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object,
+Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<Object> object,
                                                     Register object_reg,
                                                     Handle<JSObject> holder,
-                                                    Handle<Name> name,
-                                                    Label* success) {
+                                                    Handle<Name> name) {
   Label miss;
 
   Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
 
-  HandlerFrontendFooter(name, success, &miss);
+  HandlerFrontendFooter(name, &miss);
+
   return reg;
 }
 
 
 void LoadStubCompiler::NonexistentHandlerFrontend(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> last,
     Handle<Name> name,
-    Label* success,
     Handle<JSGlobalObject> global) {
   Label miss;
 
-  Register holder =
-      HandlerFrontendHeader(object, receiver(), last, name, &miss);
+  Register holder = HandlerFrontendHeader(
+      object, receiver(), last, name, &miss);
 
   if (!last->HasFastProperties() &&
       !last->IsJSGlobalObject() &&
@@ -1196,12 +1224,12 @@ void LoadStubCompiler::NonexistentHandlerFrontend(
     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
   }
 
-  HandlerFrontendFooter(name, success, &miss);
+  HandlerFrontendFooter(name, &miss);
 }
 
 
 Handle<Code> LoadStubCompiler::CompileLoadField(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> holder,
     Handle<Name> name,
     PropertyIndex field,
@@ -1221,13 +1249,11 @@ Handle<Code> LoadStubCompiler::CompileLoadField(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadConstant(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<Object> value) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
   GenerateLoadConstant(value);
 
   // Return the generated code.
@@ -1236,15 +1262,12 @@ Handle<Code> LoadStubCompiler::CompileLoadConstant(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadCallback(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Label success;
-
   Register reg = CallbackHandlerFrontend(
-      object, receiver(), holder, name, &success, callback);
-  __ bind(&success);
+      object, receiver(), holder, name, callback);
   GenerateLoadCallback(reg, callback);
 
   // Return the generated code.
@@ -1253,17 +1276,13 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadCallback(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> holder,
     Handle<Name> name,
     const CallOptimization& call_optimization) {
   ASSERT(call_optimization.is_simple_api_call());
-  Label success;
-
   Handle<JSFunction> callback = call_optimization.constant_function();
-  CallbackHandlerFrontend(
-      object, receiver(), holder, name, &success, callback);
-  __ bind(&success);
+  CallbackHandlerFrontend(object, receiver(), holder, name, callback);
   GenerateLoadCallback(call_optimization);
 
   // Return the generated code.
@@ -1272,16 +1291,13 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> holder,
     Handle<Name> name) {
-  Label success;
-
   LookupResult lookup(isolate());
   LookupPostInterceptor(holder, name, &lookup);
 
-  Register reg = HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  Register reg = HandlerFrontend(object, receiver(), holder, name);
   // TODO(368): Compile in the whole chain: all the interceptors in
   // prototypes and ultimate answer.
   GenerateLoadInterceptor(reg, object, holder, &lookup, name);
@@ -1296,7 +1312,6 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
     Handle<JSObject> interceptor_holder,
     Handle<Name> name,
     LookupResult* lookup) {
-  Label success;
   Handle<JSObject> holder(lookup->holder());
   if (lookup->IsField()) {
     PropertyIndex field = lookup->GetFieldIndex();
@@ -1307,8 +1322,7 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
       // We found FIELD property in prototype chain of interceptor's holder.
       // Retrieve a field from field's holder.
       Register reg = HandlerFrontend(
-          interceptor_holder, interceptor_reg, holder, name, &success);
-      __ bind(&success);
+          interceptor_holder, interceptor_reg, holder, name);
       GenerateLoadField(
           reg, holder, field, lookup->representation());
     }
@@ -1321,8 +1335,7 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
     ASSERT(callback->getter() != NULL);
 
     Register reg = CallbackHandlerFrontend(
-        interceptor_holder, interceptor_reg, holder, name, &success, callback);
-    __ bind(&success);
+        interceptor_holder, interceptor_reg, holder, name, callback);
     GenerateLoadCallback(reg, callback);
   }
 }
@@ -1342,14 +1355,11 @@ Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<JSFunction> getter) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
   GenerateLoadViaGetter(masm(), receiver(), getter);
 
   // Return the generated code.
@@ -1442,10 +1452,7 @@ Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<JSFunction> setter) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
   GenerateStoreViaSetter(masm(), setter);
 
   return GetCode(kind(), Code::CALLBACKS, name);
@@ -1555,7 +1562,7 @@ Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
                                                 Code::StubType type,
                                                 Handle<Name> name) {
   Code::Flags flags = Code::ComputeFlags(
-      Code::HANDLER, MONOMORPHIC, extra_state(), type, kind);
+      Code::HANDLER, MONOMORPHIC, extra_state(), type, kind, cache_holder_);
   Handle<Code> code = GetCodeWithFlags(flags, name);
   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
   JitEvent(name, code);
@@ -1723,11 +1730,8 @@ Handle<Code> CallStubCompiler::CompileCustomCall(
 Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
                                        Handle<Name> name) {
   int argc = arguments_.immediate();
-  Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
-                                                    extra_state_,
-                                                    type,
-                                                    argc,
-                                                    cache_holder_);
+  Code::Flags flags = Code::ComputeMonomorphicFlags(
+      kind_, extra_state_, cache_holder_, type, argc);
   return GetCodeWithFlags(flags, name);
 }
 
index 9a82785..2f78fde 100644 (file)
@@ -83,29 +83,21 @@ class StubCache {
   Handle<Code> FindIC(Handle<Name> name,
                       Handle<Map> stub_holder_map,
                       Code::Kind kind,
-                      Code::ExtraICState extra_state = Code::kNoExtraICState);
-
-  Handle<Code> FindIC(Handle<Name> name,
-                      Handle<JSObject> stub_holder,
-                      Code::Kind kind,
-                      Code::ExtraICState extra_state = Code::kNoExtraICState);
+                      Code::ExtraICState extra_state = Code::kNoExtraICState,
+                      InlineCacheHolderFlag cache_holder = OWN_MAP);
 
   Handle<Code> FindHandler(Handle<Name> name,
-                           Handle<JSObject> receiver,
+                           Handle<HeapObject> stub_holder,
                            Code::Kind kind,
+                           InlineCacheHolderFlag cache_holder = OWN_MAP,
                            StrictModeFlag strict_mode = kNonStrictMode);
 
-  Handle<Code> ComputeMonomorphicIC(Handle<HeapObject> receiver,
+  Handle<Code> ComputeMonomorphicIC(Handle<Name> name,
+                                    Handle<HeapObject> receiver,
                                     Handle<Code> handler,
-                                    Handle<Name> name,
                                     StrictModeFlag strict_mode);
 
-  // Computes the right stub matching. Inserts the result in the
-  // cache before returning.  This might compile a stub if needed.
-  Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
-                                      Handle<JSObject> object);
-
-  // ---
+  Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<Object> object);
 
   Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
 
@@ -501,6 +493,7 @@ class StubCompiler BASE_EMBEDDED {
                            Label* miss,
                            PrototypeCheckType check = CHECK_ALL_MAPS);
 
+  void GenerateBooleanCheck(Register object, Label* miss);
 
  protected:
   Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
@@ -531,8 +524,10 @@ enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
 
 class BaseLoadStoreStubCompiler: public StubCompiler {
  public:
-  BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind)
-      : StubCompiler(isolate), kind_(kind) {
+  BaseLoadStoreStubCompiler(Isolate* isolate,
+                            Code::Kind kind,
+                            InlineCacheHolderFlag cache_holder = OWN_MAP)
+      : StubCompiler(isolate), kind_(kind), cache_holder_(cache_holder) {
     InitializeRegisters();
   }
   virtual ~BaseLoadStoreStubCompiler() { }
@@ -563,21 +558,18 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
   }
 
  protected:
-  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
+  virtual Register HandlerFrontendHeader(Handle<Object> object,
                                          Register object_reg,
                                          Handle<JSObject> holder,
                                          Handle<Name> name,
                                          Label* miss) = 0;
 
-  virtual void HandlerFrontendFooter(Handle<Name> name,
-                                     Label* success,
-                                     Label* miss) = 0;
+  virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0;
 
-  Register HandlerFrontend(Handle<JSObject> object,
+  Register HandlerFrontend(Handle<Object> object,
                            Register object_reg,
                            Handle<JSObject> holder,
-                           Handle<Name> name,
-                           Label* success);
+                           Handle<Name> name);
 
   Handle<Code> GetCode(Code::Kind kind,
                        Code::StubType type,
@@ -617,42 +609,45 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
   void InitializeRegisters();
 
   Code::Kind kind_;
+  InlineCacheHolderFlag cache_holder_;
   Register* registers_;
 };
 
 
 class LoadStubCompiler: public BaseLoadStoreStubCompiler {
  public:
-  LoadStubCompiler(Isolate* isolate, Code::Kind kind = Code::LOAD_IC)
-      : BaseLoadStoreStubCompiler(isolate, kind) { }
+  LoadStubCompiler(Isolate* isolate,
+                   InlineCacheHolderFlag cache_holder = OWN_MAP,
+                   Code::Kind kind = Code::LOAD_IC)
+      : BaseLoadStoreStubCompiler(isolate, kind, cache_holder) { }
   virtual ~LoadStubCompiler() { }
 
-  Handle<Code> CompileLoadField(Handle<JSObject> object,
+  Handle<Code> CompileLoadField(Handle<Object> object,
                                 Handle<JSObject> holder,
                                 Handle<Name> name,
                                 PropertyIndex index,
                                 Representation representation);
 
-  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
+  Handle<Code> CompileLoadCallback(Handle<Object> object,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
                                    Handle<ExecutableAccessorInfo> callback);
 
-  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
+  Handle<Code> CompileLoadCallback(Handle<Object> object,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
                                    const CallOptimization& call_optimization);
 
-  Handle<Code> CompileLoadConstant(Handle<JSObject> object,
+  Handle<Code> CompileLoadConstant(Handle<Object> object,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
                                    Handle<Object> value);
 
-  Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
+  Handle<Code> CompileLoadInterceptor(Handle<Object> object,
                                       Handle<JSObject> holder,
                                       Handle<Name> name);
 
-  Handle<Code> CompileLoadViaGetter(Handle<JSObject> object,
+  Handle<Code> CompileLoadViaGetter(Handle<Object> object,
                                     Handle<JSObject> holder,
                                     Handle<Name> name,
                                     Handle<JSFunction> getter);
@@ -661,12 +656,12 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
                                     Register receiver,
                                     Handle<JSFunction> getter);
 
-  Handle<Code> CompileLoadNonexistent(Handle<JSObject> object,
+  Handle<Code> CompileLoadNonexistent(Handle<Object> object,
                                       Handle<JSObject> last,
                                       Handle<Name> name,
                                       Handle<JSGlobalObject> global);
 
-  Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
+  Handle<Code> CompileLoadGlobal(Handle<Object> object,
                                  Handle<GlobalObject> holder,
                                  Handle<PropertyCell> cell,
                                  Handle<Name> name,
@@ -675,26 +670,22 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
   static Register* registers();
 
  protected:
-  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
+  virtual Register HandlerFrontendHeader(Handle<Object> object,
                                          Register object_reg,
                                          Handle<JSObject> holder,
                                          Handle<Name> name,
                                          Label* miss);
 
-  virtual void HandlerFrontendFooter(Handle<Name> name,
-                                     Label* success,
-                                     Label* miss);
+  virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
 
-  Register CallbackHandlerFrontend(Handle<JSObject> object,
+  Register CallbackHandlerFrontend(Handle<Object> object,
                                    Register object_reg,
                                    Handle<JSObject> holder,
                                    Handle<Name> name,
-                                   Label* success,
                                    Handle<Object> callback);
-  void NonexistentHandlerFrontend(Handle<JSObject> object,
+  void NonexistentHandlerFrontend(Handle<Object> object,
                                   Handle<JSObject> last,
                                   Handle<Name> name,
-                                  Label* success,
                                   Handle<JSGlobalObject> global);
 
   void GenerateLoadField(Register reg,
@@ -706,7 +697,7 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
                             Handle<ExecutableAccessorInfo> callback);
   void GenerateLoadCallback(const CallOptimization& call_optimization);
   void GenerateLoadInterceptor(Register holder_reg,
-                               Handle<JSObject> object,
+                               Handle<Object> object,
                                Handle<JSObject> holder,
                                LookupResult* lookup,
                                Handle<Name> name);
@@ -726,8 +717,9 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
 
 class KeyedLoadStubCompiler: public LoadStubCompiler {
  public:
-  explicit KeyedLoadStubCompiler(Isolate* isolate)
-      : LoadStubCompiler(isolate, Code::KEYED_LOAD_IC) { }
+  KeyedLoadStubCompiler(Isolate* isolate,
+                        InlineCacheHolderFlag cache_holder = OWN_MAP)
+      : LoadStubCompiler(isolate, cache_holder, Code::KEYED_LOAD_IC) { }
 
   Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
 
@@ -827,15 +819,13 @@ class StoreStubCompiler: public BaseLoadStoreStubCompiler {
   }
 
  protected:
-  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
+  virtual Register HandlerFrontendHeader(Handle<Object> object,
                                          Register object_reg,
                                          Handle<JSObject> holder,
                                          Handle<Name> name,
                                          Label* miss);
 
-  virtual void HandlerFrontendFooter(Handle<Name> name,
-                                     Label* success,
-                                     Label* miss);
+  virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
   void GenerateRestoreName(MacroAssembler* masm,
                            Label* label,
                            Handle<Name> name);
@@ -928,8 +918,7 @@ class CallStubCompiler: public StubCompiler {
   void CompileHandlerFrontend(Handle<Object> object,
                               Handle<JSObject> holder,
                               Handle<Name> name,
-                              CheckType check,
-                              Label* success);
+                              CheckType check);
 
   void CompileHandlerBackend(Handle<JSFunction> function);
 
index 65d1364..c548ad3 100644 (file)
@@ -298,11 +298,8 @@ void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
   Code::ExtraICState extra_ic_state =
       CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION);
 
-  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
-                                                    extra_ic_state,
-                                                    Code::NORMAL,
-                                                    arity,
-                                                    OWN_MAP);
+  Code::Flags flags = Code::ComputeMonomorphicFlags(
+      Code::CALL_IC, extra_ic_state, OWN_MAP, Code::NORMAL, arity);
   CollectReceiverTypes(expr->CallFeedbackId(), name, flags, types);
 }
 
index cd5291c..b4222bc 100644 (file)
@@ -1200,34 +1200,33 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 }
 
 
-void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
-                                             Label* success,
-                                             Label* miss) {
+void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
   if (!miss->is_unused()) {
-    __ jmp(success);
+    Label success;
+    __ jmp(&success);
     __ bind(miss);
     TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
   }
 }
 
 
-void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
-                                              Label* success,
-                                              Label* miss) {
+void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
   if (!miss->is_unused()) {
-    __ jmp(success);
+    Label success;
+    __ jmp(&success);
     GenerateRestoreName(masm(), miss, name);
     TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
   }
 }
 
 
 Register LoadStubCompiler::CallbackHandlerFrontend(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Register object_reg,
     Handle<JSObject> holder,
     Handle<Name> name,
-    Label* success,
     Handle<Object> callback) {
   Label miss;
 
@@ -1268,7 +1267,7 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
     __ j(not_equal, &miss);
   }
 
-  HandlerFrontendFooter(name, success, &miss);
+  HandlerFrontendFooter(name, &miss);
   return reg;
 }
 
@@ -1389,7 +1388,7 @@ void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
 
 void LoadStubCompiler::GenerateLoadInterceptor(
     Register holder_reg,
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> interceptor_holder,
     LookupResult* lookup,
     Handle<Name> name) {
@@ -2507,11 +2506,21 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
 }
 
 
+void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
+  Label success;
+  // Check that the object is a boolean.
+  __ CompareRoot(object, Heap::kTrueValueRootIndex);
+  __ j(equal, &success);
+  __ CompareRoot(object, Heap::kFalseValueRootIndex);
+  __ j(not_equal, miss);
+  __ bind(&success);
+}
+
+
 void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
                                               Handle<JSObject> holder,
                                               Handle<Name> name,
-                                              CheckType check,
-                                              Label* success) {
+                                              CheckType check) {
   // ----------- S t a t e -------------
   // rcx                 : function name
   // rsp[0]              : return address
@@ -2593,13 +2602,7 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       break;
     }
     case BOOLEAN_CHECK: {
-      Label fast;
-      // Check that the object is a boolean.
-      __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
-      __ j(equal, &fast);
-      __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
-      __ j(not_equal, &miss);
-      __ bind(&fast);
+      GenerateBooleanCheck(rdx, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
@@ -2610,11 +2613,14 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
     }
   }
 
-  __ jmp(success);
+  Label success;
+  __ jmp(&success);
 
   // Handle call cache miss.
   __ bind(&miss);
   GenerateMissBranch();
+
+  __ bind(&success);
 }
 
 
@@ -2643,10 +2649,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
     if (!code.is_null()) return code;
   }
 
-  Label success;
-
-  CompileHandlerFrontend(object, holder, name, check, &success);
-  __ bind(&success);
+  CompileHandlerFrontend(object, holder, name, check);
   CompileHandlerBackend(function);
 
   // Return the generated code.
@@ -2782,9 +2785,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
     Handle<JSObject> holder,
     Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
 
   __ PopReturnAddressTo(scratch1());
   __ push(receiver());
@@ -2808,9 +2809,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
     Handle<JSObject> holder,
     Handle<Name> name,
     const CallOptimization& call_optimization) {
-  Label success;
-  HandlerFrontend(object, receiver(), holder, name, &success);
-  __ bind(&success);
+  HandlerFrontend(object, receiver(), holder, name);
 
   Register values[] = { value() };
   GenerateFastApiCall(
@@ -2924,15 +2923,12 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
 
 
 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<JSObject> last,
     Handle<Name> name,
     Handle<JSGlobalObject> global) {
-  Label success;
+  NonexistentHandlerFrontend(object, last, name, global);
 
-  NonexistentHandlerFrontend(object, last, name, &success, global);
-
-  __ bind(&success);
   // Return undefined if maps of the full prototype chain are still the
   // same and no global property with this name contains a value.
   __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
@@ -3027,12 +3023,12 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
 
 
 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
-    Handle<JSObject> object,
+    Handle<Object> object,
     Handle<GlobalObject> global,
     Handle<PropertyCell> cell,
     Handle<Name> name,
     bool is_dont_delete) {
-  Label success, miss;
+  Label miss;
   // TODO(verwaest): Directly store to rax. Currently we cannot do this, since
   // rax is used as receiver(), which we would otherwise clobber before a
   // potential miss.
@@ -3051,8 +3047,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
   }
 
-  HandlerFrontendFooter(name, &success, &miss);
-  __ bind(&success);
+  HandlerFrontendFooter(name, &miss);
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1);
diff --git a/test/mjsunit/load-callback-from-value-classic.js b/test/mjsunit/load-callback-from-value-classic.js
new file mode 100644 (file)
index 0000000..0030c61
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Object.defineProperty(Boolean.prototype, "v",
+                      {get:function() { return this; }});
+
+function f(b) {
+  return b.v;
+}
+
+assertEquals("object", typeof f(true));
+assertEquals("object", typeof f(true));
+assertEquals("object", typeof f(true));
+assertEquals("object", typeof f(true));