Revision: 17804
Author:   [email protected]
Date:     Fri Nov 15 17:53:35 2013 UTC
Log:      Generate KeyedLoadDictionaryElementStub with Hydrogen

[email protected]

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

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-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/codegen.h
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/stub-cache.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Nov 15 10:52:05 2013 UTC +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Nov 15 17:53:35 2013 UTC
@@ -111,6 +111,17 @@
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
 }
+
+
+void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { r1, r0 };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
+}


 void LoadFieldStub::InitializeInterfaceDescriptor(
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Nov 14 14:15:52 2013 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Nov 15 17:53:35 2013 UTC
@@ -1566,8 +1566,7 @@
   sub(t1, t1, Operand(1));

   // Generate an unrolled loop that performs a few probes before giving up.
-  static const int kProbes = 4;
-  for (int i = 0; i < kProbes; i++) {
+  for (int i = 0; i < kNumberDictionaryProbes; i++) {
     // Use t2 for index calculations and keep the hash intact in t0.
     mov(t2, t0);
     // Compute the masked index: (hash + i + i * i) & mask.
@@ -1584,7 +1583,7 @@
     add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
ldr(ip, FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
     cmp(key, Operand(ip));
-    if (i != kProbes - 1) {
+    if (i != kNumberDictionaryProbes - 1) {
       b(eq, &done);
     } else {
       b(ne, miss);
=======================================
--- /branches/bleeding_edge/src/code-stubs-hydrogen.cc Fri Nov 15 10:52:05 2013 UTC +++ /branches/bleeding_edge/src/code-stubs-hydrogen.cc Fri Nov 15 17:53:35 2013 UTC
@@ -1301,6 +1301,141 @@
 Handle<Code> FastNewClosureStub::GenerateCode(Isolate* isolate) {
   return DoGenerateCode(isolate, this);
 }
+
+
+template <>
+class CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>
+    : public CodeStubGraphBuilderBase {
+ public:
+  explicit CodeStubGraphBuilder(Isolate* isolate,
+                                KeyedLoadDictionaryElementStub* stub)
+      : CodeStubGraphBuilderBase(isolate, stub) {}
+
+ protected:
+  HValue* BuildCodeStubHelper(HValue* dictionary,
+                              HValue* key,
+                              HValue* hash,
+                              HValue* mask,
+                              int current_probe);
+
+  virtual HValue* BuildCodeStub();
+
+  KeyedLoadDictionaryElementStub* casted_stub() {
+    return static_cast<KeyedLoadDictionaryElementStub*>(stub());
+  }
+};
+
+
+HValue* CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>::
+    BuildCodeStubHelper(
+    HValue* elements,
+    HValue* key,
+    HValue* hash,
+    HValue* mask,
+    int current_probe) {
+  if (current_probe == kNumberDictionaryProbes) {
+    return NULL;
+  }
+
+  int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe);
+  HValue* raw_index = (current_probe == 0)
+    ? hash
+    : Add<HAdd>(hash, Add<HConstant>(offset));
+  raw_index = Add<HBitwise>(Token::BIT_AND, raw_index, mask);
+  int32_t entry_size = SeededNumberDictionary::kEntrySize;
+  raw_index = Add<HMul>(raw_index, Add<HConstant>(entry_size));
+  raw_index->ClearFlag(HValue::kCanOverflow);
+
+  int32_t base_offset = SeededNumberDictionary::kElementsStartIndex;
+  HValue* key_index = Add<HAdd>(raw_index, Add<HConstant>(base_offset));
+  key_index->ClearFlag(HValue::kCanOverflow);
+
+  HValue* candidate_key = Add<HLoadKeyed>(elements, key_index,
+                                          static_cast<HValue*>(NULL),
+                                          FAST_SMI_ELEMENTS);
+
+  IfBuilder key_compare(this);
+  key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key);
+  key_compare.Then();
+  {
+    // Key at the current probe doesn't match, try at the next probe.
+    HValue* result = BuildCodeStubHelper(elements, key, hash, mask,
+                                         current_probe + 1);
+    if (result == NULL) {
+ key_compare.Deopt("probes exhausted in keyed load dictionary lookup");
+      result = graph()->GetConstantUndefined();
+    } else {
+      Push(result);
+    }
+  }
+  key_compare.Else();
+  {
+    // Key at current probe matches. Details must be zero, otherwise the
+    // dictionary element requires special handling.
+    HValue* details_index = Add<HAdd>(raw_index,
+                                      Add<HConstant>(base_offset + 2));
+    details_index->ClearFlag(HValue::kCanOverflow);
+
+    HValue* details = Add<HLoadKeyed>(elements, details_index,
+                                      static_cast<HValue*>(NULL),
+                                      FAST_SMI_ELEMENTS);
+    IfBuilder details_compare(this);
+    details_compare.If<HCompareNumericAndBranch>(details,
+                                                 graph()->GetConstant0(),
+                                                 Token::NE);
+ details_compare.ThenDeopt("keyed load dictionary element not fast case");
+
+    details_compare.Else();
+    {
+ // Key matches and details are zero --> fast case. Load and return the
+      // value.
+      HValue* result_index = Add<HAdd>(raw_index,
+                                       Add<HConstant>(base_offset + 1));
+      result_index->ClearFlag(HValue::kCanOverflow);
+
+      Push(Add<HLoadKeyed>(elements, result_index,
+                           static_cast<HValue*>(NULL),
+                           FAST_ELEMENTS));
+    }
+    details_compare.End();
+  }
+  key_compare.End();
+
+  return Pop();
+}
+
+
+HValue* CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>::BuildCodeStub() {
+  KeyedLoadDictionaryElementStub* stub = casted_stub();
+
+  HValue* dictionary = GetParameter(0);
+  HValue* key = GetParameter(1);
+  USE(stub);
+  USE(dictionary);
+
+  HValue* elements = AddLoadElements(dictionary);
+
+  Add<HCheckSmi>(key);
+
+  HValue* hash = BuildElementIndexHash(key);
+
+  HValue* capacity = Add<HLoadKeyed>(
+      elements,
+      Add<HConstant>(NameDictionary::kCapacityIndex),
+      static_cast<HValue*>(NULL),
+      FAST_SMI_ELEMENTS);
+
+  HValue* mask = Add<HSub>(capacity, graph()->GetConstant1());
+  mask->ChangeRepresentation(Representation::Integer32());
+  mask->ClearFlag(HValue::kCanOverflow);
+
+  return BuildCodeStubHelper(elements, key, hash, mask, 0);
+}
+
+
+Handle<Code> KeyedLoadDictionaryElementStub::GenerateCode(Isolate* isolate) {
+  return DoGenerateCode(isolate, this);
+}


 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc   Fri Nov 15 10:52:05 2013 UTC
+++ /branches/bleeding_edge/src/code-stubs.cc   Fri Nov 15 17:53:35 2013 UTC
@@ -964,7 +964,8 @@
 }


-void KeyedLoadDictionaryElementStub::Generate(MacroAssembler* masm) {
+void KeyedLoadDictionaryElementPlatformStub::Generate(
+    MacroAssembler* masm) {
   KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
 }

=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Fri Nov 15 10:52:05 2013 UTC
+++ /branches/bleeding_edge/src/code-stubs.h    Fri Nov 15 17:53:35 2013 UTC
@@ -1839,9 +1839,27 @@
 };


-class KeyedLoadDictionaryElementStub : public PlatformCodeStub {
+class KeyedLoadDictionaryElementStub : public HydrogenCodeStub {
  public:
   KeyedLoadDictionaryElementStub() {}
+
+  virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
+
+  virtual void InitializeInterfaceDescriptor(
+      Isolate* isolate,
+      CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+
+ private:
+  Major MajorKey() { return KeyedLoadElement; }
+  int NotMissMinorKey() { return DICTIONARY_ELEMENTS; }
+
+  DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub);
+};
+
+
+class KeyedLoadDictionaryElementPlatformStub : public PlatformCodeStub {
+ public:
+  KeyedLoadDictionaryElementPlatformStub() {}

   void Generate(MacroAssembler* masm);

@@ -1849,7 +1867,7 @@
   Major MajorKey() { return KeyedLoadElement; }
   int MinorKey() { return DICTIONARY_ELEMENTS; }

-  DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub);
+  DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementPlatformStub);
 };


=======================================
--- /branches/bleeding_edge/src/codegen.h       Fri Jul 19 13:30:49 2013 UTC
+++ /branches/bleeding_edge/src/codegen.h       Fri Nov 15 17:53:35 2013 UTC
@@ -112,6 +112,8 @@
   DISALLOW_COPY_AND_ASSIGN(ElementsTransitionGenerator);
 };

+static const int kNumberDictionaryProbes = 4;
+

 } }  // namespace v8::internal

=======================================
--- /branches/bleeding_edge/src/flag-definitions.h Tue Nov 12 10:21:08 2013 UTC +++ /branches/bleeding_edge/src/flag-definitions.h Fri Nov 15 17:53:35 2013 UTC
@@ -202,6 +202,8 @@
 // Flags for experimental implementation features.
 DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
 DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
+DEFINE_bool(compiled_keyed_dictionary_loads, false,
+ "use optimizing compiler to generate keyed dictionary load stubs")
 DEFINE_bool(clever_optimizations, true,
             "Optimize object size, Array shift, DOM strings and string +")
 DEFINE_bool(pretenuring, true, "allocate objects in old space")
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Fri Nov 15 12:10:59 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Fri Nov 15 17:53:35 2013 UTC
@@ -1403,6 +1403,138 @@

   Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
 }
+
+
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper(
+    HValue* elements,
+    HValue* key,
+    HValue* hash,
+    HValue* mask,
+    int current_probe) {
+  if (current_probe == kNumberDictionaryProbes) {
+    return NULL;
+  }
+
+  int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe);
+  HValue* raw_index = (current_probe == 0)
+      ? hash
+      : Add<HAdd>(hash, Add<HConstant>(offset));
+  raw_index = Add<HBitwise>(Token::BIT_AND, raw_index, mask);
+  int32_t entry_size = SeededNumberDictionary::kEntrySize;
+  raw_index = Add<HMul>(raw_index, Add<HConstant>(entry_size));
+  raw_index->ClearFlag(HValue::kCanOverflow);
+
+  int32_t base_offset = SeededNumberDictionary::kElementsStartIndex;
+  HValue* key_index = Add<HAdd>(raw_index, Add<HConstant>(base_offset));
+  key_index->ClearFlag(HValue::kCanOverflow);
+
+  HValue* candidate_key = Add<HLoadKeyed>(elements, key_index,
+                                          static_cast<HValue*>(NULL),
+                                          FAST_SMI_ELEMENTS);
+
+  IfBuilder key_compare(this);
+  key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key);
+  key_compare.Then();
+  {
+    // Key at the current probe doesn't match, try at the next probe.
+    HValue* result = BuildUncheckedDictionaryElementLoadHelper(
+        elements, key, hash, mask, current_probe + 1);
+    if (result == NULL) {
+ key_compare.Deopt("probes exhausted in keyed load dictionary lookup");
+      result = graph()->GetConstantUndefined();
+    } else {
+      Push(result);
+    }
+  }
+  key_compare.Else();
+  {
+    // Key at current probe matches. Details must be zero, otherwise the
+    // dictionary element requires special handling.
+    HValue* details_index = Add<HAdd>(raw_index,
+                                    Add<HConstant>(base_offset + 2));
+    details_index->ClearFlag(HValue::kCanOverflow);
+
+    HValue* details = Add<HLoadKeyed>(elements, details_index,
+                                      static_cast<HValue*>(NULL),
+                                      FAST_SMI_ELEMENTS);
+    IfBuilder details_compare(this);
+    details_compare.If<HCompareNumericAndBranch>(details,
+                                                 graph()->GetConstant0(),
+                                                 Token::NE);
+ details_compare.ThenDeopt("keyed load dictionary element not fast case");
+
+    details_compare.Else();
+    {
+ // Key matches and details are zero --> fast case. Load and return the
+      // value.
+      HValue* result_index = Add<HAdd>(raw_index,
+                                       Add<HConstant>(base_offset + 1));
+      result_index->ClearFlag(HValue::kCanOverflow);
+
+      Push(Add<HLoadKeyed>(elements, result_index,
+                           static_cast<HValue*>(NULL),
+                           FAST_ELEMENTS));
+    }
+    details_compare.End();
+  }
+  key_compare.End();
+
+  return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
+ int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
+  HValue* seed = Add<HConstant>(seed_value);
+  HValue* hash = Add<HBitwise>(Token::BIT_XOR, index, seed);
+
+  // hash = ~hash + (hash << 15);
+  HValue* shifted_hash = Add<HShl>(hash, Add<HConstant>(15));
+  HValue* not_hash = Add<HBitwise>(Token::BIT_XOR, hash,
+                                   graph()->GetConstantMinus1());
+  hash = Add<HAdd>(shifted_hash, not_hash);
+
+  // hash = hash ^ (hash >> 12);
+  shifted_hash = Add<HShr>(hash, Add<HConstant>(12));
+  hash = Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+
+  // hash = hash + (hash << 2);
+  shifted_hash = Add<HShl>(hash, Add<HConstant>(2));
+  hash = Add<HAdd>(hash, shifted_hash);
+
+  // hash = hash ^ (hash >> 4);
+  shifted_hash = Add<HShr>(hash, Add<HConstant>(4));
+  hash = Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+
+  // hash = hash * 2057;
+  hash = Add<HMul>(hash, Add<HConstant>(2057));
+  hash->ClearFlag(HValue::kCanOverflow);
+
+  // hash = hash ^ (hash >> 16);
+  shifted_hash = Add<HShr>(hash, Add<HConstant>(16));
+  return Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+}
+
+
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
+                                                           HValue* key) {
+  HValue* elements = AddLoadElements(receiver);
+
+  HValue* hash = BuildElementIndexHash(key);
+
+  HValue* capacity = Add<HLoadKeyed>(
+      elements,
+      Add<HConstant>(NameDictionary::kCapacityIndex),
+      static_cast<HValue*>(NULL),
+      FAST_SMI_ELEMENTS);
+
+  HValue* mask = Add<HSub>(capacity, graph()->GetConstant1());
+  mask->ChangeRepresentation(Representation::Integer32());
+  mask->ClearFlag(HValue::kCanOverflow);
+
+  return BuildUncheckedDictionaryElementLoadHelper(elements, key,
+                                                   hash, mask, 0);
+}


 HValue* HGraphBuilder::BuildNumberToString(HValue* object,
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Fri Nov 15 10:52:05 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.h      Fri Nov 15 17:53:35 2013 UTC
@@ -1279,6 +1279,9 @@

   HValue* BuildNumberToString(HValue* object, Handle<Type> type);

+  HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
+                                              HValue* key);
+
// Computes the size for a sequential string of the given length and encoding.
   HValue* BuildSeqStringSizeFor(HValue* length,
                                 String::Encoding encoding);
@@ -1701,6 +1704,8 @@
                                  ElementsKind kind,
                                  int length);

+  HValue* BuildElementIndexHash(HValue* index);
+
   void BuildCompareNil(
       HValue* value,
       Handle<Type> type,
@@ -1727,6 +1732,13 @@
  private:
   HGraphBuilder();

+  HValue* BuildUncheckedDictionaryElementLoadHelper(
+      HValue* elements,
+      HValue* key,
+      HValue* hash,
+      HValue* mask,
+      int current_probe);
+
   void PadEnvironmentForContinuation(HBasicBlock* from,
                                      HBasicBlock* continuation);

=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Nov 15 10:52:05 2013 UTC +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Nov 15 17:53:35 2013 UTC
@@ -116,6 +116,17 @@
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
 }
+
+
+void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { edx, ecx };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+      FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
+}


 void LoadFieldStub::InitializeInterfaceDescriptor(
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Nov 12 09:08:51 2013 UTC +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Nov 15 17:53:35 2013 UTC
@@ -1489,8 +1489,7 @@
   dec(r1);

   // Generate an unrolled loop that performs a few probes before giving up.
-  const int kProbes = 4;
-  for (int i = 0; i < kProbes; i++) {
+  for (int i = 0; i < kNumberDictionaryProbes; i++) {
     // Use r2 for index calculations and keep the hash intact in r0.
     mov(r2, r0);
     // Compute the masked index: (hash + i + i * i) & mask.
@@ -1508,7 +1507,7 @@
                           r2,
                           times_pointer_size,
                           SeededNumberDictionary::kElementsStartOffset));
-    if (i != (kProbes - 1)) {
+    if (i != (kNumberDictionaryProbes - 1)) {
       j(equal, &done);
     } else {
       j(not_equal, miss);
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Fri Nov 15 09:34:44 2013 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc   Fri Nov 15 17:53:35 2013 UTC
@@ -1480,8 +1480,9 @@
         elements_kind).GetCode(isolate());
__ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
   } else {
-    Handle<Code> stub =
-        KeyedLoadDictionaryElementStub().GetCode(isolate());
+    Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
+        ? KeyedLoadDictionaryElementStub().GetCode(isolate())
+        : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate());
__ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
   }

=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Nov 15 10:52:05 2013 UTC +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Nov 15 17:53:35 2013 UTC
@@ -112,6 +112,17 @@
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
 }
+
+
+void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { rdx, rcx };
+  descriptor->register_param_count_ = 2;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ =
+    FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
+}


 void LoadFieldStub::InitializeInterfaceDescriptor(
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Nov 14 15:14:37 2013 UTC +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Fri Nov 15 17:53:35 2013 UTC
@@ -3980,8 +3980,7 @@
   decl(r1);

   // Generate an unrolled loop that performs a few probes before giving up.
-  const int kProbes = 4;
-  for (int i = 0; i < kProbes; i++) {
+  for (int i = 0; i < kNumberDictionaryProbes; i++) {
     // Use r2 for index calculations and keep the hash intact in r0.
     movq(r2, r0);
     // Compute the masked index: (hash + i + i * i) & mask.
@@ -3999,7 +3998,7 @@
                            r2,
                            times_pointer_size,
                            SeededNumberDictionary::kElementsStartOffset));
-    if (i != (kProbes - 1)) {
+    if (i != (kNumberDictionaryProbes - 1)) {
       j(equal, &done);
     } else {
       j(not_equal, miss);

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