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

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
This commit is contained in:
bmeurer@chromium.org 2013-09-24 09:31:07 +00:00
parent 755fcfec49
commit 70b8e2d013
17 changed files with 229 additions and 110 deletions

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

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

View 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);

View 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);

View File

@ -338,6 +338,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();

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

View 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);
}

View 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);
}

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

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

View 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 };

View 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);

View 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);

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

View 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 };

View 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);

View 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);