Revision: 22526
Author:   [email protected]
Date:     Tue Jul 22 14:27:53 2014 UTC
Log: Move function prototype handling into a special handler rather than IC Adjust hydrogen handling of function.prototype to be based on map feedback. Handle non-instance prototype loading using an IC rather than in the hydrogen instruction. In the future, remove the special instruction and replace by multiple hydrogen instructions.

BUG=
[email protected]

Review URL: https://codereview.chromium.org/408193002
http://code.google.com/p/v8/source/detail?r=22526

Modified:
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/stub-cache.cc
 /branches/bleeding_edge/src/type-info.cc
 /branches/bleeding_edge/src/type-info.h
 /branches/bleeding_edge/src/typing.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Jul 21 11:19:56 2014 UTC +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Jul 22 14:27:53 2014 UTC
@@ -3143,17 +3143,6 @@
   Register function = ToRegister(instr->function());
   Register result = ToRegister(instr->result());

-  // Check that the function really is a function. Load map into the
-  // result register.
-  __ CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
-  DeoptimizeIf(ne, instr->environment());
-
-  // Make sure that the function has an instance prototype.
-  Label non_instance;
-  __ ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
-  __ tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
-  __ b(ne, &non_instance);
-
   // Get the prototype or initial map from the function.
   __ ldr(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -3170,12 +3159,6 @@

   // Get the prototype from the initial map.
   __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
-  __ jmp(&done);
-
-  // Non-instance prototype: Fetch prototype from constructor field
-  // in initial map.
-  __ bind(&non_instance);
-  __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset));

   // All done.
   __ bind(&done);
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Mon Jul 21 11:19:56 2014 UTC +++ /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Tue Jul 22 14:27:53 2014 UTC
@@ -3332,16 +3332,6 @@
   Register result = ToRegister(instr->result());
   Register temp = ToRegister(instr->temp());

-  // Check that the function really is a function. Leaves map in the result
-  // register.
-  __ CompareObjectType(function, result, temp, JS_FUNCTION_TYPE);
-  DeoptimizeIf(ne, instr->environment());
-
-  // Make sure that the function has an instance prototype.
-  Label non_instance;
-  __ Ldrb(temp, FieldMemOperand(result, Map::kBitFieldOffset));
-  __ Tbnz(temp, Map::kHasNonInstancePrototype, &non_instance);
-
   // Get the prototype or initial map from the function.
   __ Ldr(result, FieldMemOperand(function,
JSFunction::kPrototypeOrInitialMapOffset));
@@ -3357,12 +3347,6 @@

   // Get the prototype from the initial map.
   __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
-  __ B(&done);
-
- // Non-instance prototype: fetch prototype from constructor field in initial
-  // map.
-  __ Bind(&non_instance);
-  __ Ldr(result, FieldMemOperand(result, Map::kConstructorOffset));

   // All done.
   __ Bind(&done);
=======================================
--- /branches/bleeding_edge/src/ast.h   Mon Jul 21 15:59:05 2014 UTC
+++ /branches/bleeding_edge/src/ast.h   Tue Jul 22 14:27:53 2014 UTC
@@ -1684,7 +1684,6 @@
   BailoutId LoadId() const { return load_id_; }

   bool IsStringAccess() const { return is_string_access_; }
-  bool IsFunctionPrototype() const { return is_function_prototype_; }

   // Type feedback information.
   virtual bool IsMonomorphic() V8_OVERRIDE {
@@ -1702,7 +1701,6 @@
   }
   void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
   void set_is_string_access(bool b) { is_string_access_ = b; }
-  void set_is_function_prototype(bool b) { is_function_prototype_ = b; }
   void mark_for_call() { is_for_call_ = true; }
   bool IsForCall() { return is_for_call_; }

@@ -1716,10 +1714,7 @@
   int PropertyFeedbackSlot() const { return property_feedback_slot_; }

  protected:
-  Property(Zone* zone,
-           Expression* obj,
-           Expression* key,
-           int pos)
+  Property(Zone* zone, Expression* obj, Expression* key, int pos)
       : Expression(zone, pos),
         obj_(obj),
         key_(key),
@@ -1727,8 +1722,7 @@
         property_feedback_slot_(kInvalidFeedbackSlot),
         is_for_call_(false),
         is_uninitialized_(false),
-        is_string_access_(false),
-        is_function_prototype_(false) { }
+        is_string_access_(false) {}

  private:
   Expression* obj_;
@@ -1740,7 +1734,6 @@
   bool is_for_call_ : 1;
   bool is_uninitialized_ : 1;
   bool is_string_access_ : 1;
-  bool is_function_prototype_ : 1;
 };


=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Mon Jul 21 13:10:14 2014 UTC
+++ /branches/bleeding_edge/src/code-stubs.h    Tue Jul 22 14:27:53 2014 UTC
@@ -899,14 +899,26 @@
 };


-class FunctionPrototypeStub: public ICStub {
+// TODO(verwaest): Translate to hydrogen code stub.
+class FunctionPrototypeStub : public PlatformCodeStub {
  public:
   FunctionPrototypeStub(Isolate* isolate, Code::Kind kind)
-      : ICStub(isolate, kind) { }
+      : PlatformCodeStub(isolate) {
+    bit_field_ = KindBits::encode(kind);
+  }
   virtual void Generate(MacroAssembler* masm);
+  virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
+  virtual InlineCacheState GetICState() { return MONOMORPHIC; }
+  virtual ExtraICState GetExtraICState() const { return kind(); }
+
+ protected:
+  class KindBits : public BitField<Code::Kind, 0, 4> {};
+  virtual Code::Kind kind() const { return KindBits::decode(bit_field_); }

  private:
   virtual CodeStub::Major MajorKey() const { return FunctionPrototype; }
+  virtual int MinorKey() const { return bit_field_; }
+  int bit_field_;
 };


=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Mon Jul 21 11:19:56 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Jul 22 14:27:53 2014 UTC
@@ -6070,6 +6070,11 @@
 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
   if (!CanInlinePropertyAccess(type_)) return false;
   if (IsJSObjectFieldAccessor()) return IsLoad();
+  if (this->map()->function_with_prototype() &&
+      !this->map()->has_non_instance_prototype() &&
+      name_.is_identical_to(isolate()->factory()->prototype_string())) {
+    return IsLoad();
+  }
   if (!LookupDescriptor()) return false;
   if (lookup_.IsFound()) {
     if (IsLoad()) return true;
@@ -6160,6 +6165,12 @@
     ASSERT(info->IsLoad());
     return New<HLoadNamedField>(object, checked_object, access);
   }
+
+ if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
+      info->map()->function_with_prototype()) {
+    ASSERT(!info->map()->has_non_instance_prototype());
+    return New<HLoadFunctionPrototype>(checked_object);
+  }

   HValue* checked_holder = checked_object;
   if (info->has_holder()) {
@@ -6575,8 +6586,7 @@
     CHECK_ALIVE(VisitForValue(prop->obj()));
     HValue* object = Top();
     HValue* key = NULL;
-    if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
-        prop->IsStringAccess()) {
+    if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
       CHECK_ALIVE(VisitForValue(prop->key()));
       key = Top();
     }
@@ -7286,11 +7296,6 @@
     AddInstruction(char_code);
     instr = NewUncasted<HStringCharFromCode>(char_code);

-  } else if (expr->IsFunctionPrototype()) {
-    HValue* function = Pop();
-    BuildCheckHeapObject(function);
-    instr = New<HLoadFunctionPrototype>(function);
-
   } else if (expr->key()->IsPropertyName()) {
     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
     HValue* object = Pop();
@@ -7330,8 +7335,7 @@
   if (TryArgumentsAccess(expr)) return;

   CHECK_ALIVE(VisitForValue(expr->obj()));
-  if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) ||
-      expr->IsStringAccess()) {
+  if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) {
     CHECK_ALIVE(VisitForValue(expr->key()));
   }

@@ -10025,8 +10029,7 @@
   HValue* object = Top();

   HValue* key = NULL;
-  if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
-      prop->IsStringAccess()) {
+  if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
     CHECK_ALIVE(VisitForValue(prop->key()));
     key = Top();
   }
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Jul 21 11:19:56 2014 UTC +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Jul 22 14:27:53 2014 UTC
@@ -2998,16 +2998,6 @@
   Register temp = ToRegister(instr->temp());
   Register result = ToRegister(instr->result());

-  // Check that the function really is a function.
-  __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
-  DeoptimizeIf(not_equal, instr->environment());
-
-  // Check whether the function has an instance prototype.
-  Label non_instance;
-  __ test_b(FieldOperand(result, Map::kBitFieldOffset),
-            1 << Map::kHasNonInstancePrototype);
-  __ j(not_zero, &non_instance, Label::kNear);
-
   // Get the prototype or initial map from the function.
   __ mov(result,
          FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -3023,12 +3013,6 @@

   // Get the prototype from the initial map.
   __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
-  __ jmp(&done, Label::kNear);
-
-  // Non-instance prototype: Fetch prototype from constructor field
-  // in the function's map.
-  __ bind(&non_instance);
-  __ mov(result, FieldOperand(result, Map::kConstructorOffset));

   // All done.
   __ bind(&done);
=======================================
--- /branches/bleeding_edge/src/ic.cc   Tue Jul 22 08:28:49 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc   Tue Jul 22 14:27:53 2014 UTC
@@ -557,31 +557,6 @@
   if (object->IsUndefined() || object->IsNull()) {
     return TypeError("non_object_property_load", object, name);
   }
-
-  if (FLAG_use_ic) {
-    // Use specialized code for getting prototype of functions.
-    if (object->IsJSFunction() &&
-        String::Equals(isolate()->factory()->prototype_string(), name) &&
-        Handle<JSFunction>::cast(object)->should_have_prototype()) {
-      Handle<Code> stub;
-      if (state() == UNINITIALIZED) {
-        stub = pre_monomorphic_stub();
-      } else if (state() == PREMONOMORPHIC) {
-        FunctionPrototypeStub function_prototype_stub(isolate(), kind());
-        stub = function_prototype_stub.GetCode();
- } else if (!FLAG_compiled_keyed_generic_loads && state() != MEGAMORPHIC) {
-        ASSERT(state() != GENERIC);
-        stub = megamorphic_stub();
-      } else if (FLAG_compiled_keyed_generic_loads && state() != GENERIC) {
-        stub = generic_stub();
-      }
-      if (!stub.is_null()) {
-        set_target(*stub);
-        if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
-      }
- return Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object));
-    }
-  }

   // Check if the name is trivially convertible to an index and get
   // the element or char if so.
@@ -958,6 +933,15 @@
       return string_length_stub.GetCode();
     }
   }
+
+  // Use specialized code for getting prototype of functions.
+  if (object->IsJSFunction() &&
+      String::Equals(isolate()->factory()->prototype_string(), name) &&
+      Handle<JSFunction>::cast(object)->should_have_prototype()) {
+    Handle<Code> stub;
+    FunctionPrototypeStub function_prototype_stub(isolate(), kind());
+    return function_prototype_stub.GetCode();
+  }

   Handle<HeapType> type = receiver_type();
   Handle<JSObject> holder(lookup->holder());
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Mon Jul 21 13:10:14 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc   Tue Jul 22 14:27:53 2014 UTC
@@ -42,11 +42,10 @@
   ASSERT(!heap->InNewSpace(name));
   ASSERT(name->IsUniqueName());

-  // The state bits are not important to the hash function because
-  // the stub cache only contains monomorphic stubs. Make sure that
-  // the bits are the least significant so they will be the ones
-  // masked out.
-  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
+  // The state bits are not important to the hash function because the stub
+  // cache only contains handlers. Make sure that the bits are the least
+  // significant so they will be the ones masked out.
+  ASSERT_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags));
   STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);

// Make sure that the code type and cache holder are not included in the hash.
=======================================
--- /branches/bleeding_edge/src/type-info.cc    Mon Jul 21 15:59:05 2014 UTC
+++ /branches/bleeding_edge/src/type-info.cc    Tue Jul 22 14:27:53 2014 UTC
@@ -173,16 +173,6 @@
     TypeFeedbackId id, Builtins::Name builtin) {
   return *GetInfo(id) == isolate()->builtins()->builtin(builtin);
 }
-
-
-bool TypeFeedbackOracle::LoadIsStub(TypeFeedbackId id, ICStub* stub) {
-  Handle<Object> object = GetInfo(id);
-  if (!object->IsCode()) return false;
-  Handle<Code> code = Handle<Code>::cast(object);
-  if (!code->is_load_stub()) return false;
-  if (code->ic_state() != MONOMORPHIC) return false;
-  return stub->Describes(*code);
-}


 void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
@@ -264,16 +254,12 @@
 }


-void TypeFeedbackOracle::PropertyReceiverTypes(
-    TypeFeedbackId id, Handle<String> name,
-    SmallMapList* receiver_types, bool* is_prototype) {
+void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id,
+                                               Handle<String> name,
+ SmallMapList* receiver_types) {
   receiver_types->Clear();
-  FunctionPrototypeStub proto_stub(isolate(), Code::LOAD_IC);
-  *is_prototype = LoadIsStub(id, &proto_stub);
-  if (!*is_prototype) {
-    Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
-    CollectReceiverTypes(id, name, flags, receiver_types);
-  }
+  Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+  CollectReceiverTypes(id, name, flags, receiver_types);
 }


=======================================
--- /branches/bleeding_edge/src/type-info.h     Tue Jun  3 08:12:43 2014 UTC
+++ /branches/bleeding_edge/src/type-info.h     Tue Jul 22 14:27:53 2014 UTC
@@ -41,10 +41,8 @@

   KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id);

-  void PropertyReceiverTypes(TypeFeedbackId id,
-                             Handle<String> name,
-                             SmallMapList* receiver_types,
-                             bool* is_prototype);
+  void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name,
+                             SmallMapList* receiver_types);
   void KeyedPropertyReceiverTypes(TypeFeedbackId id,
                                   SmallMapList* receiver_types,
                                   bool* is_string);
@@ -70,7 +68,6 @@
   Handle<AllocationSite> GetCallNewAllocationSite(int slot);

   bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id);
-  bool LoadIsStub(TypeFeedbackId id, ICStub* stub);

// TODO(1571) We can't use ToBooleanStub::Types as the return value because
   // of various cycles in our headers. Death to tons of implementations in
=======================================
--- /branches/bleeding_edge/src/typing.cc       Mon Jul  7 09:57:29 2014 UTC
+++ /branches/bleeding_edge/src/typing.cc       Tue Jul 22 14:27:53 2014 UTC
@@ -485,10 +485,7 @@
       Literal* lit_key = expr->key()->AsLiteral();
       ASSERT(lit_key != NULL && lit_key->value()->IsString());
       Handle<String> name = Handle<String>::cast(lit_key->value());
-      bool is_prototype;
-      oracle()->PropertyReceiverTypes(
-          id, name, expr->GetReceiverTypes(), &is_prototype);
-      expr->set_is_function_prototype(is_prototype);
+      oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
     } else {
       bool is_string;
       oracle()->KeyedPropertyReceiverTypes(
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Jul 21 11:19:56 2014 UTC +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jul 22 14:27:53 2014 UTC
@@ -3018,16 +3018,6 @@
   Register function = ToRegister(instr->function());
   Register result = ToRegister(instr->result());

-  // Check that the function really is a function.
-  __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
-  DeoptimizeIf(not_equal, instr->environment());
-
-  // Check whether the function has an instance prototype.
-  Label non_instance;
-  __ testb(FieldOperand(result, Map::kBitFieldOffset),
-           Immediate(1 << Map::kHasNonInstancePrototype));
-  __ j(not_zero, &non_instance, Label::kNear);
-
   // Get the prototype or initial map from the function.
   __ movp(result,
          FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -3043,12 +3033,6 @@

   // Get the prototype from the initial map.
   __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
-  __ jmp(&done, Label::kNear);
-
-  // Non-instance prototype: Fetch prototype from constructor field
-  // in the function's map.
-  __ bind(&non_instance);
-  __ movp(result, FieldOperand(result, Map::kConstructorOffset));

   // All done.
   __ bind(&done);

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to