Turn the NumberToStringStub into a hydrogen stub.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 24 Sep 2013 09:31:07 +0000 (09:31 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 24 Sep 2013 09:31:07 +0000 (09:31 +0000)
This adds a BuildLookupNumberStringCache() in Hydrogen, which will
be used by the hydrogen version of StringAddStub, in addition to the
hydrogen version of NumberToStringStub.

R=mvstanton@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=16874

Review URL: https://codereview.chromium.org/23726041

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

17 files changed:
src/arm/code-stubs-arm.cc
src/arm/code-stubs-arm.h
src/arm/full-codegen-arm.cc
src/arm/lithium-codegen-arm.cc
src/code-stubs-hydrogen.cc
src/code-stubs.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/code-stubs-ia32.cc
src/ia32/code-stubs-ia32.h
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/x64/code-stubs-x64.cc
src/x64/code-stubs-x64.h
src/x64/full-codegen-x64.cc
src/x64/lithium-codegen-x64.cc

index faad278..2c7fb78 100644 (file)
@@ -59,6 +59,16 @@ void ToNumberStub::InitializeInterfaceDescriptor(
 }
 
 
+void NumberToStringStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { r0 };
+  descriptor->register_param_count_ = 1;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ = NULL;
+}
+
+
 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -968,22 +978,6 @@ static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
 }
 
 
-void NumberToStringStub::Generate(MacroAssembler* masm) {
-  Label runtime;
-
-  __ ldr(r1, MemOperand(sp, 0));
-
-  // Generate code to lookup number in the number string cache.
-  __ LookupNumberStringCache(r1, r0, r2, r3, r4, &runtime);
-  __ add(sp, sp, Operand(1 * kPointerSize));
-  __ Ret();
-
-  __ bind(&runtime);
-  // Handle number to string in the runtime system if not found in the cache.
-  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
-}
-
-
 static void ICCompareStub_CheckInputType(MacroAssembler* masm,
                                          Register input,
                                          Register scratch,
index 380a83b..c03d8f2 100644 (file)
@@ -256,18 +256,6 @@ class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
 };
 
 
-class NumberToStringStub: public PlatformCodeStub {
- public:
-  NumberToStringStub() { }
-
- private:
-  Major MajorKey() { return NumberToString; }
-  int MinorKey() { return 0; }
-
-  void Generate(MacroAssembler* masm);
-};
-
-
 class RecordWriteStub: public PlatformCodeStub {
  public:
   RecordWriteStub(Register object,
index bab8a00..d49f842 100644 (file)
@@ -3590,8 +3590,8 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(args->length(), 1);
-  // Load the argument on the stack and call the stub.
-  VisitForStackValue(args->at(0));
+  // Load the argument into r0 and call the stub.
+  VisitForAccumulatorValue(args->at(0));
 
   NumberToStringStub stub;
   __ CallStub(&stub);
index 0c5b973..ca38743 100644 (file)
@@ -1090,11 +1090,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
       CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
       break;
     }
-    case CodeStub::NumberToString: {
-      NumberToStringStub stub;
-      CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
-      break;
-    }
     case CodeStub::StringCompare: {
       StringCompareStub stub;
       CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
index 0d06209..af37c29 100644 (file)
@@ -339,6 +339,19 @@ Handle<Code> ToNumberStub::GenerateCode(Isolate* isolate) {
 
 
 template <>
+HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() {
+  info()->MarkAsSavesCallerDoubles();
+  HValue* number = GetParameter(NumberToStringStub::kNumber);
+  return BuildNumberToString(number);
+}
+
+
+Handle<Code> NumberToStringStub::GenerateCode(Isolate* isolate) {
+  return DoGenerateCode(isolate, this);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
   Factory* factory = isolate()->factory();
   HValue* undefined = graph()->GetConstantUndefined();
index 30ec1c7..a5c2f88 100644 (file)
@@ -464,6 +464,25 @@ class ToNumberStub: public HydrogenCodeStub {
 };
 
 
+class NumberToStringStub V8_FINAL : public HydrogenCodeStub {
+ public:
+  NumberToStringStub() {}
+
+  virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
+
+  virtual void InitializeInterfaceDescriptor(
+      Isolate* isolate,
+      CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+
+  // Parameters accessed via CodeStubGraphBuilder::GetParameter()
+  static const int kNumber = 0;
+
+ private:
+  virtual Major MajorKey() V8_OVERRIDE { return NumberToString; }
+  virtual int NotMissMinorKey() V8_OVERRIDE { return 0; }
+};
+
+
 class FastNewClosureStub : public HydrogenCodeStub {
  public:
   explicit FastNewClosureStub(LanguageMode language_mode, bool is_generator)
index 8cb2f59..a5cfe3b 100644 (file)
@@ -5667,6 +5667,18 @@ class HObjectAccess V8_FINAL {
         kDouble, HeapNumber::kValueOffset, Representation::Double());
   }
 
+  static HObjectAccess ForHeapNumberValueLowestBits() {
+    return HObjectAccess(kDouble,
+                         HeapNumber::kValueOffset,
+                         Representation::Integer32());
+  }
+
+  static HObjectAccess ForHeapNumberValueHighestBits() {
+    return HObjectAccess(kDouble,
+                         HeapNumber::kValueOffset + kIntSize,
+                         Representation::Integer32());
+  }
+
   static HObjectAccess ForElementsPointer() {
     return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
   }
index 9e7c237..f3f875e 100644 (file)
@@ -1273,6 +1273,142 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object,
 }
 
 
+HValue* HGraphBuilder::BuildLookupNumberStringCache(
+    HValue* object,
+    HIfContinuation* continuation) {
+  // Create a joinable continuation.
+  HIfContinuation found(graph()->CreateBasicBlock(),
+                        graph()->CreateBasicBlock());
+
+  // Load the number string cache.
+  HValue* number_string_cache =
+      Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
+
+  // Make the hash maks from the length of the number string cache. It
+  // contains two elements (number and string) for each cache entry.
+  HValue* mask = AddLoadFixedArrayLength(number_string_cache);
+  mask->set_type(HType::Smi());
+  mask = Add<HSar>(mask, graph()->GetConstant1());
+  mask = Add<HSub>(mask, graph()->GetConstant1());
+
+  // Check whether object is a smi.
+  IfBuilder if_objectissmi(this);
+  if_objectissmi.If<HIsSmiAndBranch>(object);
+  if_objectissmi.Then();
+  {
+    // Compute hash for smi similar to smi_get_hash().
+    HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask);
+
+    // Load the key.
+    HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
+    HValue* key = AddFastElementAccess(number_string_cache, key_index,
+                                       NULL, NULL, FAST_ELEMENTS, false,
+                                       ALLOW_RETURN_HOLE, STANDARD_STORE);
+
+    // Check if object == key.
+    IfBuilder if_objectiskey(this);
+    if_objectiskey.If<HCompareObjectEqAndBranch>(key, object);
+    if_objectiskey.Then();
+    {
+      // Make the key_index available.
+      Push(key_index);
+    }
+    if_objectiskey.JoinContinuation(&found);
+  }
+  if_objectissmi.Else();
+  {
+    // Check if object is a heap number.
+    IfBuilder if_objectisnumber(this);
+    if_objectisnumber.If<HCompareMap>(
+        object, isolate()->factory()->heap_number_map());
+    if_objectisnumber.Then();
+    {
+      // Compute hash for heap number similar to double_get_hash().
+      HValue* low = Add<HLoadNamedField>(
+          object, HObjectAccess::ForHeapNumberValueLowestBits());
+      HValue* high = Add<HLoadNamedField>(
+          object, HObjectAccess::ForHeapNumberValueHighestBits());
+      HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high);
+      hash = Add<HBitwise>(Token::BIT_AND, hash, mask);
+
+      // Load the key.
+      HValue* key_index = Add<HShl>(hash, graph()->GetConstant1());
+      HValue* key = AddFastElementAccess(number_string_cache, key_index,
+                                        NULL, NULL, FAST_ELEMENTS, false,
+                                        ALLOW_RETURN_HOLE, STANDARD_STORE);
+
+      // Check if key is a heap number.
+      IfBuilder if_keyisnumber(this);
+      if_keyisnumber.IfNot<HIsSmiAndBranch>(key);
+      if_keyisnumber.AndIf<HCompareMap>(
+          key, isolate()->factory()->heap_number_map());
+      if_keyisnumber.Then();
+      {
+        // Check if values of key and object match.
+        IfBuilder if_keyeqobject(this);
+        if_keyeqobject.If<HCompareNumericAndBranch>(
+            Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
+            Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
+            Token::EQ);
+        if_keyeqobject.Then();
+        {
+          // Make the key_index available.
+          Push(key_index);
+        }
+        if_keyeqobject.JoinContinuation(&found);
+      }
+      if_keyisnumber.JoinContinuation(&found);
+    }
+    if_objectisnumber.JoinContinuation(&found);
+  }
+  if_objectissmi.End();
+
+  // Check for cache hit.
+  IfBuilder if_found(this, &found);
+  if_found.Then();
+
+  // Load the value in case of cache hit.
+  HValue* key_index = Pop();
+  HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1());
+  HValue* value = AddFastElementAccess(number_string_cache, value_index,
+                                      NULL, NULL, FAST_ELEMENTS, false,
+                                      ALLOW_RETURN_HOLE, STANDARD_STORE);
+  AddIncrementCounter(isolate()->counters()->number_to_string_native());
+
+  if_found.CaptureContinuation(continuation);
+
+  // The value is only available in true branch of continuation.
+  return value;
+}
+
+
+HValue* HGraphBuilder::BuildNumberToString(HValue* number) {
+  NoObservableSideEffectsScope scope(this);
+
+  // Lookup the number in the number string cache.
+  HIfContinuation continuation;
+  HValue* value = BuildLookupNumberStringCache(number, &continuation);
+  IfBuilder if_found(this, &continuation);
+  if_found.Then();
+
+  // Cache hit.
+  Push(value);
+
+  if_found.Else();
+
+  // Cache miss, fallback to runtime.
+  Add<HPushArgument>(number);
+  Push(Add<HCallRuntime>(
+          isolate()->factory()->empty_string(),
+          Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
+          1));
+
+  if_found.End();
+
+  return Pop();
+}
+
+
 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
     HValue* checked_object,
     HValue* key,
@@ -9009,12 +9145,10 @@ void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
 // Fast support for number to string.
 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
   ASSERT_EQ(1, call->arguments()->length());
-  CHECK_ALIVE(VisitArgumentList(call->arguments()));
-  HValue* context = environment()->context();
-  HCallStub* result =
-      new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
-  Drop(1);
-  return ast_context()->ReturnInstruction(result, call->id());
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* number = Pop();
+  HValue* result = BuildNumberToString(number);
+  return ast_context()->ReturnValue(result);
 }
 
 
index a371fa5..35433bd 100644 (file)
@@ -1237,6 +1237,15 @@ class HGraphBuilder {
                                    ElementsKind to_kind,
                                    bool is_jsarray);
 
+  // Do lookup in the number string cache. If the object is not found
+  // in the cache, the false branch of the continuation is taken;
+  // otherwise the true branch is taken and the returned value contains
+  // the cache value for the object. The returned value must NOT be used
+  // on the false branch.
+  HValue* BuildLookupNumberStringCache(HValue* object,
+                                       HIfContinuation* continuation);
+  HValue* BuildNumberToString(HValue* number);
+
   HInstruction* BuildUncheckedMonomorphicElementAccess(
       HValue* checked_object,
       HValue* key,
index 6128633..83613cc 100644 (file)
@@ -64,6 +64,16 @@ void ToNumberStub::InitializeInterfaceDescriptor(
 }
 
 
+void NumberToStringStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { eax };
+  descriptor->register_param_count_ = 1;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ = NULL;
+}
+
+
 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -3767,21 +3777,6 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
 }
 
 
-void NumberToStringStub::Generate(MacroAssembler* masm) {
-  Label runtime;
-
-  __ mov(ebx, Operand(esp, kPointerSize));
-
-  // Generate code to lookup number in the number string cache.
-  __ LookupNumberStringCache(ebx, eax, ecx, edx, &runtime);
-  __ ret(1 * kPointerSize);
-
-  __ bind(&runtime);
-  // Handle number to string in the runtime system if not found in the cache.
-  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
-}
-
-
 static int NegativeComparisonResult(Condition cc) {
   ASSERT(cc != equal);
   ASSERT((cc == less) || (cc == less_equal)
index f36cd61..dc536e7 100644 (file)
@@ -217,18 +217,6 @@ class StringCompareStub: public PlatformCodeStub {
 };
 
 
-class NumberToStringStub: public PlatformCodeStub {
- public:
-  NumberToStringStub() { }
-
- private:
-  Major MajorKey() { return NumberToString; }
-  int MinorKey() { return 0; }
-
-  void Generate(MacroAssembler* masm);
-};
-
-
 class NameDictionaryLookupStub: public PlatformCodeStub {
  public:
   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
index 9a2c3ce..5250f4b 100644 (file)
@@ -3549,8 +3549,8 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(args->length(), 1);
 
-  // Load the argument on the stack and call the stub.
-  VisitForStackValue(args->at(0));
+  // Load the argument into eax and call the stub.
+  VisitForAccumulatorValue(args->at(0));
 
   NumberToStringStub stub;
   __ CallStub(&stub);
index 4818b3e..86ac466 100644 (file)
@@ -1382,11 +1382,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
       CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
       break;
     }
-    case CodeStub::NumberToString: {
-      NumberToStringStub stub;
-      CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
-      break;
-    }
     case CodeStub::StringCompare: {
       StringCompareStub stub;
       CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
index 8f27374..1896c00 100644 (file)
@@ -60,6 +60,16 @@ void ToNumberStub::InitializeInterfaceDescriptor(
 }
 
 
+void NumberToStringStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { rax };
+  descriptor->register_param_count_ = 1;
+  descriptor->register_params_ = registers;
+  descriptor->deoptimization_handler_ = NULL;
+}
+
+
 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -2909,22 +2919,6 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
 }
 
 
-void NumberToStringStub::Generate(MacroAssembler* masm) {
-  Label runtime;
-
-  StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
-  __ movq(rbx, args.GetArgumentOperand(0));
-
-  // Generate code to lookup number in the number string cache.
-  __ LookupNumberStringCache(rbx, rax, r8, r9, &runtime);
-  __ ret(1 * kPointerSize);
-
-  __ bind(&runtime);
-  // Handle number to string in the runtime system if not found in the cache.
-  __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
-}
-
-
 static int NegativeComparisonResult(Condition cc) {
   ASSERT(cc != equal);
   ASSERT((cc == less) || (cc == less_equal)
index c3eac81..c76abcf 100644 (file)
@@ -208,18 +208,6 @@ class StringCompareStub: public PlatformCodeStub {
 };
 
 
-class NumberToStringStub: public PlatformCodeStub {
- public:
-  NumberToStringStub() { }
-
- private:
-  Major MajorKey() { return NumberToString; }
-  int MinorKey() { return 0; }
-
-  void Generate(MacroAssembler* masm);
-};
-
-
 class NameDictionaryLookupStub: public PlatformCodeStub {
  public:
   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
index f9d1ffa..55feb4c 100644 (file)
@@ -3507,8 +3507,8 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT_EQ(args->length(), 1);
 
-  // Load the argument on the stack and call the stub.
-  VisitForStackValue(args->at(0));
+  // Load the argument into rax and call the stub.
+  VisitForAccumulatorValue(args->at(0));
 
   NumberToStringStub stub;
   __ CallStub(&stub);
index 83a8cb2..27d064d 100644 (file)
@@ -973,11 +973,6 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
       CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
       break;
     }
-    case CodeStub::NumberToString: {
-      NumberToStringStub stub;
-      CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
-      break;
-    }
     case CodeStub::StringCompare: {
       StringCompareStub stub;
       CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);