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:
parent
755fcfec49
commit
70b8e2d013
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
146
src/hydrogen.cc
146
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<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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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 };
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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 };
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user