Revision: 14342
Author:   [email protected]
Date:     Thu Apr 18 13:37:27 2013
Log:      Add infrastructure to automatucally generate IC miss stubs

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

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/code-stubs-hydrogen.cc
 /branches/bleeding_edge/src/code-stubs.cc
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/ic.h
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Apr 18 03:32:18 2013 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Apr 18 13:37:27 2013
@@ -159,6 +159,30 @@
   __ cmp(scratch1, scratch2);
   __ b(ne, not_a_heap_number);
 }
+
+
+void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
+  // Update the static counter each time a new code stub is generated.
+  Isolate* isolate = masm->isolate();
+  isolate->counters()->code_stubs()->Increment();
+
+ CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
+  int param_count = descriptor->register_param_count_;
+  {
+    // Call the runtime system in a fresh internal frame.
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    ASSERT(descriptor->register_param_count_ == 0 ||
+           r0.is(descriptor->register_params_[param_count - 1]));
+    // Push arguments
+    for (int i = 0; i < param_count; ++i) {
+      __ push(descriptor->register_params_[i]);
+    }
+    ExternalReference miss = descriptor->miss_handler_;
+    __ CallExternalReference(miss, descriptor->register_param_count_);
+  }
+
+  __ Ret();
+}


 void ToNumberStub::Generate(MacroAssembler* masm) {
=======================================
--- /branches/bleeding_edge/src/code-stubs-hydrogen.cc Thu Apr 18 03:51:24 2013 +++ /branches/bleeding_edge/src/code-stubs-hydrogen.cc Thu Apr 18 13:37:27 2013
@@ -61,11 +61,7 @@
         arguments_length_(NULL),
         info_(stub, isolate),
         context_(NULL) {
-    int major_key = stub->MajorKey();
-    descriptor_ = isolate->code_stub_interface_descriptor(major_key);
-    if (descriptor_->register_param_count_ < 0) {
-      stub->InitializeInterfaceDescriptor(isolate, descriptor_);
-    }
+    descriptor_ = stub->GetInterfaceDescriptor(isolate);
     parameters_.Reset(new HParameter*[descriptor_->register_param_count_]);
   }
   virtual bool BuildGraph();
@@ -96,6 +92,9 @@


 bool CodeStubGraphBuilderBase::BuildGraph() {
+  // Update the static counter each time a new code stub is generated.
+  isolate()->counters()->code_stubs()->Increment();
+
   if (FLAG_trace_hydrogen) {
     const char* name = CodeStub::MajorName(stub()->MajorKey(), false);
PrintF("-----------------------------------------------------------\n");
@@ -176,16 +175,87 @@
       : CodeStubGraphBuilderBase(Isolate::Current(), stub) {}

  protected:
-  virtual HValue* BuildCodeStub();
+  virtual HValue* BuildCodeStub() {
+    if (casted_stub()->IsMiss()) {
+      return BuildCodeInitializedStub();
+    } else {
+      return BuildCodeUninitializedStub();
+    }
+  }
+
+  virtual HValue* BuildCodeInitializedStub() {
+    UNIMPLEMENTED();
+    return NULL;
+  }
+
+  virtual HValue* BuildCodeUninitializedStub() {
+    // Force a deopt that falls back to the runtime.
+    HValue* undefined = graph()->GetConstantUndefined();
+    CheckBuilder builder(this);
+    builder.CheckNotUndefined(undefined);
+    builder.End();
+    return undefined;
+  }
+
   Stub* casted_stub() { return static_cast<Stub*>(stub()); }
 };


+Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) {
+  Factory* factory = isolate->factory();
+
+  // Generate the new code.
+  MacroAssembler masm(isolate, NULL, 256);
+
+  {
+    // Update the static counter each time a new code stub is generated.
+    isolate->counters()->code_stubs()->Increment();
+
+    // Nested stubs are not allowed for leaves.
+    AllowStubCallsScope allow_scope(&masm, false);
+
+    // Generate the code for the stub.
+    masm.set_generating_stub(true);
+    NoCurrentFrameScope scope(&masm);
+    GenerateLightweightMiss(&masm);
+  }
+
+  // Create the code object.
+  CodeDesc desc;
+  masm.GetCode(&desc);
+
+  // Copy the generated code into a heap object.
+  Code::Flags flags = Code::ComputeFlags(
+      GetCodeKind(),
+      GetICState(),
+      GetExtraICState(),
+      GetStubType(), -1);
+  Handle<Code> new_object = factory->NewCode(
+      desc, flags, masm.CodeObject(), NeedsImmovableCode());
+  return new_object;
+}
+
+
 template <class Stub>
 static Handle<Code> DoGenerateCode(Stub* stub) {
-  CodeStubGraphBuilder<Stub> builder(stub);
-  LChunk* chunk = OptimizeGraph(builder.CreateGraph());
-  return chunk->Codegen();
+  Isolate* isolate = Isolate::Current();
+  CodeStub::Major  major_key =
+      static_cast<HydrogenCodeStub*>(stub)->MajorKey();
+  CodeStubInterfaceDescriptor* descriptor =
+      isolate->code_stub_interface_descriptor(major_key);
+  if (descriptor->register_param_count_ < 0) {
+    stub->InitializeInterfaceDescriptor(isolate, descriptor);
+  }
+ // The miss case without stack parameters can use a light-weight stub to enter
+  // the runtime that is significantly faster than using the standard
+  // stub-failure deopt mechanism.
+  if (stub->IsMiss() && descriptor->stack_parameter_count_ == NULL) {
+    return stub->GenerateLightweightMissCode(isolate);
+  } else {
+    CodeStubGraphBuilder<Stub> builder(stub);
+    LChunk* chunk = OptimizeGraph(builder.CreateGraph());
+    return chunk->Codegen();
+  }
 }


@@ -248,9 +318,7 @@


 Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
-  CodeStubGraphBuilder<FastCloneShallowArrayStub> builder(this);
-  LChunk* chunk = OptimizeGraph(builder.CreateGraph());
-  return chunk->Codegen();
+  return DoGenerateCode(this);
 }


=======================================
--- /branches/bleeding_edge/src/code-stubs.cc   Thu Apr 18 02:50:46 2013
+++ /branches/bleeding_edge/src/code-stubs.cc   Thu Apr 18 13:37:27 2013
@@ -37,6 +37,16 @@
 namespace v8 {
 namespace internal {

+
+CodeStubInterfaceDescriptor::CodeStubInterfaceDescriptor()
+    : register_param_count_(-1),
+      stack_parameter_count_(NULL),
+      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
+      register_params_(NULL),
+      deoptimization_handler_(NULL),
+      miss_handler_(IC_Utility(IC::kUnreachable), Isolate::Current()) { }
+
+
 bool CodeStub::FindCodeInCache(Code** code_out, Isolate* isolate) {
   UnseededNumberDictionary* stubs = isolate->heap()->code_stubs();
   int index = stubs->FindEntry(GetKey());
=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Thu Apr 18 02:50:46 2013
+++ /branches/bleeding_edge/src/code-stubs.h    Thu Apr 18 13:37:27 2013
@@ -29,6 +29,7 @@
 #define V8_CODE_STUBS_H_

 #include "allocation.h"
+#include "assembler.h"
 #include "globals.h"
 #include "codegen.h"

@@ -260,17 +261,15 @@

 enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE };

+
 struct CodeStubInterfaceDescriptor {
-  CodeStubInterfaceDescriptor()
-      : register_param_count_(-1),
-        stack_parameter_count_(NULL),
-        function_mode_(NOT_JS_FUNCTION_STUB_MODE),
-        register_params_(NULL) { }
+  CodeStubInterfaceDescriptor();
   int register_param_count_;
   const Register* stack_parameter_count_;
   StubFunctionMode function_mode_;
   Register* register_params_;
   Address deoptimization_handler_;
+  ExternalReference miss_handler_;

   int environment_length() const {
     if (stack_parameter_count_ != NULL) {
@@ -283,18 +282,51 @@

 class HydrogenCodeStub : public CodeStub {
  public:
-  // Retrieve the code for the stub. Generate the code if needed.
-  virtual Handle<Code> GenerateCode() = 0;
+  enum InitializationState {
+    CODE_STUB_IS_NOT_MISS,
+    CODE_STUB_IS_MISS
+  };
+
+  explicit HydrogenCodeStub(InitializationState state) {
+    is_miss_ = (state == CODE_STUB_IS_MISS);
+  }

   virtual Code::Kind GetCodeKind() const { return Code::STUB; }

   CodeStubInterfaceDescriptor* GetInterfaceDescriptor(Isolate* isolate) {
     return isolate->code_stub_interface_descriptor(MajorKey());
   }
+
+  bool IsMiss() { return is_miss_; }
+
+  template<class SubClass>
+  static Handle<Code> GetUninitialized(Isolate* isolate) {
+    SubClass::GenerateAheadOfTime(isolate);
+    return SubClass().GetCode(isolate);
+  }

   virtual void InitializeInterfaceDescriptor(
       Isolate* isolate,
       CodeStubInterfaceDescriptor* descriptor) = 0;
+
+  // Retrieve the code for the stub. Generate the code if needed.
+  virtual Handle<Code> GenerateCode() = 0;
+
+  virtual int NotMissMinorKey() = 0;
+
+  Handle<Code> GenerateLightweightMissCode(Isolate* isolate);
+
+ private:
+  class MinorKeyBits: public BitField<int, 0, kStubMinorKeyBits - 1> {};
+  class IsMissBits: public BitField<bool, kStubMinorKeyBits - 1, 1> {};
+
+  void GenerateLightweightMiss(MacroAssembler* masm);
+  virtual int MinorKey() {
+    return IsMissBits::encode(is_miss_) |
+        MinorKeyBits::encode(NotMissMinorKey());
+  }
+
+  bool is_miss_;
 };


@@ -467,7 +499,8 @@
   FastCloneShallowArrayStub(Mode mode,
                             AllocationSiteMode allocation_site_mode,
                             int length)
-      : mode_(mode),
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS),
+        mode_(mode),
         allocation_site_mode_(allocation_site_mode),
         length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) {
     ASSERT_GE(length_, 0);
@@ -513,7 +546,7 @@
   STATIC_ASSERT(kFastCloneModeCount < 16);
   STATIC_ASSERT(kMaximumClonedLength < 16);
   Major MajorKey() { return FastCloneShallowArray; }
-  int MinorKey() {
+  int NotMissMinorKey() {
     return AllocationSiteModeBits::encode(allocation_site_mode_)
         | ModeBits::encode(mode_)
         | LengthBits::encode(length_);
@@ -526,7 +559,9 @@
   // Maximum number of properties in copied object.
   static const int kMaximumClonedProperties = 6;

-  explicit FastCloneShallowObjectStub(int length) : length_(length) {
+  explicit FastCloneShallowObjectStub(int length)
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS),
+        length_(length) {
     ASSERT_GE(length_, 0);
     ASSERT_LE(length_, kMaximumClonedProperties);
   }
@@ -543,7 +578,7 @@
   int length_;

   Major MajorKey() { return FastCloneShallowObject; }
-  int MinorKey() { return length_; }
+  int NotMissMinorKey() { return length_; }

   DISALLOW_COPY_AND_ASSIGN(FastCloneShallowObjectStub);
 };
@@ -1291,19 +1326,20 @@
  public:
   KeyedLoadDictionaryElementStub() {}

+  void Generate(MacroAssembler* masm);
+
+ private:
   Major MajorKey() { return KeyedLoadElement; }
   int MinorKey() { return DICTIONARY_ELEMENTS; }

-  void Generate(MacroAssembler* masm);
-
- private:
   DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub);
 };


 class KeyedLoadFastElementStub : public HydrogenCodeStub {
  public:
-  KeyedLoadFastElementStub(bool is_js_array, ElementsKind elements_kind) {
+  KeyedLoadFastElementStub(bool is_js_array, ElementsKind elements_kind)
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {
     bit_field_ = ElementsKindBits::encode(elements_kind) |
         IsJSArrayBits::encode(is_js_array);
   }
@@ -1323,12 +1359,12 @@
       CodeStubInterfaceDescriptor* descriptor);

  private:
+  class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
   class IsJSArrayBits: public BitField<bool, 8, 1> {};
-  class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
   uint32_t bit_field_;

   Major MajorKey() { return KeyedLoadElement; }
-  int MinorKey() { return bit_field_; }
+  int NotMissMinorKey() { return bit_field_; }

   DISALLOW_COPY_AND_ASSIGN(KeyedLoadFastElementStub);
 };
@@ -1338,14 +1374,12 @@
  public:
   KeyedStoreFastElementStub(bool is_js_array,
                             ElementsKind elements_kind,
-                            KeyedAccessStoreMode mode) {
+                            KeyedAccessStoreMode mode)
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {
     bit_field_ = ElementsKindBits::encode(elements_kind) |
         IsJSArrayBits::encode(is_js_array) |
         StoreModeBits::encode(mode);
   }
-
-  Major MajorKey() { return KeyedStoreElement; }
-  int MinorKey() { return bit_field_; }

   bool is_js_array() const {
     return IsJSArrayBits::decode(bit_field_);
@@ -1370,6 +1404,9 @@
   class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {};
   class IsJSArrayBits: public BitField<bool,                12, 1> {};
   uint32_t bit_field_;
+
+  Major MajorKey() { return KeyedStoreElement; }
+  int NotMissMinorKey() { return bit_field_; }

   DISALLOW_COPY_AND_ASSIGN(KeyedStoreFastElementStub);
 };
@@ -1378,7 +1415,8 @@
 class TransitionElementsKindStub : public HydrogenCodeStub {
  public:
   TransitionElementsKindStub(ElementsKind from_kind,
-                             ElementsKind to_kind) {
+                             ElementsKind to_kind)
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {
     bit_field_ = FromKindBits::encode(from_kind) |
         ToKindBits::encode(to_kind);
   }
@@ -1403,7 +1441,7 @@
   uint32_t bit_field_;

   Major MajorKey() { return TransitionElementsKind; }
-  int MinorKey() { return bit_field_; }
+  int NotMissMinorKey() { return bit_field_; }

   DISALLOW_COPY_AND_ASSIGN(TransitionElementsKindStub);
 };
@@ -1411,11 +1449,9 @@

 class ArrayNoArgumentConstructorStub : public HydrogenCodeStub {
  public:
-  ArrayNoArgumentConstructorStub() {
+  ArrayNoArgumentConstructorStub()
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {
   }
-
-  Major MajorKey() { return ArrayNoArgumentConstructor; }
-  int MinorKey() { return 0; }

   virtual Handle<Code> GenerateCode();

@@ -1424,17 +1460,17 @@
       CodeStubInterfaceDescriptor* descriptor);

  private:
+  Major MajorKey() { return ArrayNoArgumentConstructor; }
+  int NotMissMinorKey() { return 0; }
+
   DISALLOW_COPY_AND_ASSIGN(ArrayNoArgumentConstructorStub);
 };


 class ArraySingleArgumentConstructorStub : public HydrogenCodeStub {
  public:
-  ArraySingleArgumentConstructorStub() {
-  }
-
-  Major MajorKey() { return ArraySingleArgumentConstructor; }
-  int MinorKey() { return 0; }
+  ArraySingleArgumentConstructorStub()
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {}

   virtual Handle<Code> GenerateCode();

@@ -1443,17 +1479,17 @@
       CodeStubInterfaceDescriptor* descriptor);

  private:
+  Major MajorKey() { return ArraySingleArgumentConstructor; }
+  int NotMissMinorKey() { return 0; }
+
   DISALLOW_COPY_AND_ASSIGN(ArraySingleArgumentConstructorStub);
 };


 class ArrayNArgumentsConstructorStub : public HydrogenCodeStub {
  public:
-  ArrayNArgumentsConstructorStub() {
-  }
-
-  Major MajorKey() { return ArrayNArgumentsConstructor; }
-  int MinorKey() { return 0; }
+  ArrayNArgumentsConstructorStub()
+      : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {}

   virtual Handle<Code> GenerateCode();

@@ -1462,6 +1498,9 @@
       CodeStubInterfaceDescriptor* descriptor);

  private:
+  Major MajorKey() { return ArrayNArgumentsConstructor; }
+  int NotMissMinorKey() { return 0; }
+
   DISALLOW_COPY_AND_ASSIGN(ArrayNArgumentsConstructorStub);
 };

=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Wed Apr 17 06:51:08 2013 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Apr 18 13:37:27 2013
@@ -141,6 +141,31 @@

 #define __ ACCESS_MASM(masm)

+
+void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
+  // Update the static counter each time a new code stub is generated.
+  Isolate* isolate = masm->isolate();
+  isolate->counters()->code_stubs()->Increment();
+
+ CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
+  int param_count = descriptor->register_param_count_;
+  {
+    // Call the runtime system in a fresh internal frame.
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    ASSERT(descriptor->register_param_count_ == 0 ||
+           eax.is(descriptor->register_params_[param_count - 1]));
+    // Push arguments
+    for (int i = 0; i < param_count; ++i) {
+      __ push(descriptor->register_params_[i]);
+    }
+    ExternalReference miss = descriptor->miss_handler_;
+    __ CallExternalReference(miss, descriptor->register_param_count_);
+  }
+
+  __ ret(0);
+}
+
+
 void ToNumberStub::Generate(MacroAssembler* masm) {
   // The ToNumber stub takes one argument in eax.
   Label check_heap_number, call_builtin;
=======================================
--- /branches/bleeding_edge/src/ic.cc   Thu Apr 18 01:14:59 2013
+++ /branches/bleeding_edge/src/ic.cc   Thu Apr 18 13:37:27 2013
@@ -2764,6 +2764,13 @@
   ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
   return ic.target();
 }
+
+
+RUNTIME_FUNCTION(MaybeObject*, Unreachable) {
+  UNREACHABLE();
+  CHECK(false);
+  return isolate->heap()->undefined_value();
+}


 RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) {
=======================================
--- /branches/bleeding_edge/src/ic.h    Thu Mar 28 05:43:19 2013
+++ /branches/bleeding_edge/src/ic.h    Thu Apr 18 13:37:27 2013
@@ -59,6 +59,7 @@
   ICU(UnaryOp_Patch)                                  \
   ICU(BinaryOp_Patch)                                 \
   ICU(CompareIC_Miss)                                 \
+  ICU(Unreachable)                                    \
   ICU(ToBoolean_Patch)
 //
 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Wed Apr 17 09:41:02 2013 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Apr 18 13:37:27 2013
@@ -136,6 +136,31 @@

 #define __ ACCESS_MASM(masm)

+
+void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
+  // Update the static counter each time a new code stub is generated.
+  Isolate* isolate = masm->isolate();
+  isolate->counters()->code_stubs()->Increment();
+
+ CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate);
+  int param_count = descriptor->register_param_count_;
+  {
+    // Call the runtime system in a fresh internal frame.
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    ASSERT(descriptor->register_param_count_ == 0 ||
+           rax.is(descriptor->register_params_[param_count - 1]));
+    // Push arguments
+    for (int i = 0; i < param_count; ++i) {
+      __ push(descriptor->register_params_[i]);
+    }
+    ExternalReference miss = descriptor->miss_handler_;
+    __ CallExternalReference(miss, descriptor->register_param_count_);
+  }
+
+  __ Ret();
+}
+
+
 void ToNumberStub::Generate(MacroAssembler* masm) {
   // The ToNumber stub takes one argument in eax.
   Label check_heap_number, call_builtin;

--
--
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/groups/opt_out.


Reply via email to