From 9c48fbda7584acbae31c9413b04f5487cf19fc26 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Mon, 23 Sep 2013 10:58:45 +0000 Subject: [PATCH] Turn the NumberToStringStub into a hydrogen stub. 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 Review URL: https://codereview.chromium.org/23726041 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16874 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/code-stubs-arm.cc | 26 +++--- src/arm/code-stubs-arm.h | 12 --- src/arm/full-codegen-arm.cc | 4 +- src/arm/lithium-codegen-arm.cc | 5 -- src/code-stubs-hydrogen.cc | 13 +++ src/code-stubs.h | 19 ++++ src/hydrogen-instructions.h | 12 +++ src/hydrogen.cc | 146 +++++++++++++++++++++++++++++-- src/hydrogen.h | 9 ++ src/ia32/code-stubs-ia32.cc | 25 +++--- src/ia32/code-stubs-ia32.h | 12 --- src/ia32/full-codegen-ia32.cc | 4 +- src/ia32/lithium-codegen-ia32.cc | 5 -- src/x64/code-stubs-x64.cc | 26 +++--- src/x64/code-stubs-x64.h | 12 --- src/x64/full-codegen-x64.cc | 4 +- src/x64/lithium-codegen-x64.cc | 5 -- 17 files changed, 229 insertions(+), 110 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 0335607754..2f3cbdd4d5 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -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) { @@ -972,22 +982,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, diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h index a404f01739..07e6f12be3 100644 --- a/src/arm/code-stubs-arm.h +++ b/src/arm/code-stubs-arm.h @@ -257,18 +257,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, diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 195fc8c5be..df42a75851 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -3590,8 +3590,8 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) { void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { ZoneList* 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); diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 2680c348d6..f84aa427e3 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -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); diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 0d06209b61..af37c29cca 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -338,6 +338,19 @@ Handle ToNumberStub::GenerateCode(Isolate* isolate) { } +template <> +HValue* CodeStubGraphBuilder::BuildCodeStub() { + info()->MarkAsSavesCallerDoubles(); + HValue* number = GetParameter(NumberToStringStub::kNumber); + return BuildNumberToString(number); +} + + +Handle NumberToStringStub::GenerateCode(Isolate* isolate) { + return DoGenerateCode(isolate, this); +} + + template <> HValue* CodeStubGraphBuilder::BuildCodeStub() { Factory* factory = isolate()->factory(); diff --git a/src/code-stubs.h b/src/code-stubs.h index 30ec1c76ca..a5c2f88b22 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -464,6 +464,25 @@ class ToNumberStub: public HydrogenCodeStub { }; +class NumberToStringStub V8_FINAL : public HydrogenCodeStub { + public: + NumberToStringStub() {} + + virtual Handle 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) diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 8cb2f59174..a5cfe3b84d 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -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); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 50882a8a7f..3ce9a948f3 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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(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(mask, graph()->GetConstant1()); + mask = Add(mask, graph()->GetConstant1()); + + // Check whether object is a smi. + IfBuilder if_objectissmi(this); + if_objectissmi.If(object); + if_objectissmi.Then(); + { + // Compute hash for smi similar to smi_get_hash(). + HValue* hash = Add(Token::BIT_AND, object, mask); + + // Load the key. + HValue* key_index = Add(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(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( + object, isolate()->factory()->heap_number_map()); + if_objectisnumber.Then(); + { + // Compute hash for heap number similar to double_get_hash(). + HValue* low = Add( + object, HObjectAccess::ForHeapNumberValueLowestBits()); + HValue* high = Add( + object, HObjectAccess::ForHeapNumberValueHighestBits()); + HValue* hash = Add(Token::BIT_XOR, low, high); + hash = Add(Token::BIT_AND, hash, mask); + + // Load the key. + HValue* key_index = Add(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(key); + if_keyisnumber.AndIf( + key, isolate()->factory()->heap_number_map()); + if_keyisnumber.Then(); + { + // Check if values of key and object match. + IfBuilder if_keyeqobject(this); + if_keyeqobject.If( + Add(key, HObjectAccess::ForHeapNumberValue()), + Add(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(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(number); + Push(Add( + 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); } diff --git a/src/hydrogen.h b/src/hydrogen.h index a371fa571b..35433bd385 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -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, diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 6128633729..83613ccc86 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -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) diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h index f36cd610ca..dc536e7eae 100644 --- a/src/ia32/code-stubs-ia32.h +++ b/src/ia32/code-stubs-ia32.h @@ -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 }; diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 9a2c3ce72c..5250f4b44f 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -3549,8 +3549,8 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { ZoneList* 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); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 98a049b64a..7b3dd07746 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -1365,11 +1365,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); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 8f27374af5..1896c00f92 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -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) diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h index c3eac81671..c76abcf001 100644 --- a/src/x64/code-stubs-x64.h +++ b/src/x64/code-stubs-x64.h @@ -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 }; diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index f9d1ffab0f..55feb4cdae 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -3507,8 +3507,8 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { ZoneList* 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); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 83a8cb2498..27d064d3b4 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -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);