Port of string plus smi optimization from ia32 to x64 and ARM.
Review URL: http://codereview.chromium.org/668254 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4138 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a46b65c4b9
commit
ed53268006
@ -3681,7 +3681,8 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
|
||||
// Load the argument on the stack and jump to the runtime.
|
||||
Load(args->at(0));
|
||||
|
||||
frame_->CallRuntime(Runtime::kNumberToString, 1);
|
||||
NumberToStringStub stub;
|
||||
frame_->CallStub(&stub, 1);
|
||||
frame_->EmitPush(r0);
|
||||
}
|
||||
|
||||
@ -5280,6 +5281,79 @@ static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) {
|
||||
}
|
||||
|
||||
|
||||
void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
|
||||
Register object,
|
||||
Register result,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
bool object_is_smi,
|
||||
Label* not_found) {
|
||||
// Currently only lookup for smis. Check for smi if object is not known to be
|
||||
// a smi.
|
||||
if (!object_is_smi) {
|
||||
ASSERT(kSmiTag == 0);
|
||||
__ tst(object, Operand(kSmiTagMask));
|
||||
__ b(ne, not_found);
|
||||
}
|
||||
|
||||
// Use of registers. Register result is used as a temporary.
|
||||
Register number_string_cache = result;
|
||||
Register mask = scratch1;
|
||||
Register scratch = scratch2;
|
||||
|
||||
// Load the number string cache.
|
||||
__ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
|
||||
|
||||
// Make the hash mask from the length of the number string cache. It
|
||||
// contains two elements (number and string) for each cache entry.
|
||||
__ ldr(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
|
||||
// Divide length by two (length is not a smi).
|
||||
__ mov(mask, Operand(mask, ASR, 1));
|
||||
__ sub(mask, mask, Operand(1)); // Make mask.
|
||||
|
||||
// Calculate the entry in the number string cache. The hash value in the
|
||||
// number string cache for smis is just the smi value.
|
||||
__ and_(scratch, mask, Operand(object, ASR, 1));
|
||||
|
||||
// Calculate address of entry in string cache: each entry consists
|
||||
// of two pointer sized fields.
|
||||
__ add(scratch,
|
||||
number_string_cache,
|
||||
Operand(scratch, LSL, kPointerSizeLog2 + 1));
|
||||
|
||||
// Check if the entry is the smi we are looking for.
|
||||
Register object1 = scratch1;
|
||||
__ ldr(object1, FieldMemOperand(scratch, FixedArray::kHeaderSize));
|
||||
__ cmp(object, object1);
|
||||
__ b(ne, not_found);
|
||||
|
||||
// Get the result from the cache.
|
||||
__ ldr(result,
|
||||
FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
|
||||
|
||||
__ IncrementCounter(&Counters::number_to_string_native,
|
||||
1,
|
||||
scratch1,
|
||||
scratch2);
|
||||
}
|
||||
|
||||
|
||||
void NumberToStringStub::Generate(MacroAssembler* masm) {
|
||||
Label runtime;
|
||||
|
||||
__ ldr(r1, MemOperand(sp, 0));
|
||||
|
||||
// Generate code to lookup number in the number string cache.
|
||||
GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, false, &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::kNumberToString, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
// On entry r0 (rhs) and r1 (lhs) are the values to be compared.
|
||||
// On exit r0 is 0, positive or negative to indicate the result of
|
||||
// the comparison.
|
||||
@ -5503,7 +5577,7 @@ static void HandleBinaryOpSlowCases(MacroAssembler* masm,
|
||||
// sp[0] : second argument
|
||||
// sp[4] : first argument
|
||||
|
||||
Label not_strings, not_string1, string1;
|
||||
Label not_strings, not_string1, string1, string1_smi2;
|
||||
__ tst(r1, Operand(kSmiTagMask));
|
||||
__ b(eq, ¬_string1);
|
||||
__ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
|
||||
@ -5511,13 +5585,24 @@ static void HandleBinaryOpSlowCases(MacroAssembler* masm,
|
||||
|
||||
// First argument is a a string, test second.
|
||||
__ tst(r0, Operand(kSmiTagMask));
|
||||
__ b(eq, &string1);
|
||||
__ b(eq, &string1_smi2);
|
||||
__ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
|
||||
__ b(ge, &string1);
|
||||
|
||||
// First and second argument are strings.
|
||||
StringAddStub stub(NO_STRING_CHECK_IN_STUB);
|
||||
__ TailCallStub(&stub);
|
||||
StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
|
||||
__ TailCallStub(&string_add_stub);
|
||||
|
||||
__ bind(&string1_smi2);
|
||||
// First argument is a string, second is a smi. Try to lookup the number
|
||||
// string for the smi in the number string cache.
|
||||
NumberToStringStub::GenerateLookupNumberStringCache(
|
||||
masm, r0, r2, r4, r5, true, &string1);
|
||||
|
||||
// Replace second argument on stack and tailcall string add stub to make
|
||||
// the result.
|
||||
__ str(r2, MemOperand(sp, 0));
|
||||
__ TailCallStub(&string_add_stub);
|
||||
|
||||
// Only first argument is a string.
|
||||
__ bind(&string1);
|
||||
|
@ -660,6 +660,39 @@ class StringCompareStub: public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
class NumberToStringStub: public CodeStub {
|
||||
public:
|
||||
NumberToStringStub() { }
|
||||
|
||||
// Generate code to do a lookup in the number string cache. If the number in
|
||||
// the register object is found in the cache the generated code falls through
|
||||
// with the result in the result register. The object and the result register
|
||||
// can be the same. If the number is not found in the cache the code jumps to
|
||||
// the label not_found with only the content of register object unchanged.
|
||||
static void GenerateLookupNumberStringCache(MacroAssembler* masm,
|
||||
Register object,
|
||||
Register result,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
bool object_is_smi,
|
||||
Label* not_found);
|
||||
|
||||
private:
|
||||
Major MajorKey() { return NumberToString; }
|
||||
int MinorKey() { return 0; }
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
|
||||
const char* GetName() { return "NumberToStringStub"; }
|
||||
|
||||
#ifdef DEBUG
|
||||
void Print() {
|
||||
PrintF("NumberToStringStub\n");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ARM_CODEGEN_ARM_H_
|
||||
|
@ -4053,8 +4053,9 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
|
||||
// Load the argument on the stack and jump to the runtime.
|
||||
Load(args->at(0));
|
||||
|
||||
Result answer = frame_->CallRuntime(Runtime::kNumberToString, 1);
|
||||
frame_->Push(&answer);
|
||||
NumberToStringStub stub;
|
||||
Result result = frame_->CallStub(&stub, 1);
|
||||
frame_->Push(&result);
|
||||
}
|
||||
|
||||
|
||||
@ -7207,6 +7208,77 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
|
||||
Register object,
|
||||
Register result,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
bool object_is_smi,
|
||||
Label* not_found) {
|
||||
// Currently only lookup for smis. Check for smi if object is not known to be
|
||||
// a smi.
|
||||
if (!object_is_smi) {
|
||||
__ JumpIfNotSmi(object, not_found);
|
||||
}
|
||||
|
||||
// Use of registers. Register result is used as a temporary.
|
||||
Register number_string_cache = result;
|
||||
Register mask = scratch1;
|
||||
Register scratch = scratch2;
|
||||
|
||||
// Load the number string cache.
|
||||
__ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
|
||||
|
||||
// Make the hash mask from the length of the number string cache. It
|
||||
// contains two elements (number and string) for each cache entry.
|
||||
__ movl(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
|
||||
__ shrl(mask, Immediate(1)); // Divide length by two (length is not a smi).
|
||||
__ subl(mask, Immediate(1)); // Make mask.
|
||||
|
||||
// Calculate the entry in the number string cache. The hash value in the
|
||||
// number string cache for smis is just the smi value.
|
||||
__ movq(scratch, object);
|
||||
__ SmiToInteger32(scratch, scratch);
|
||||
__ andl(scratch, mask);
|
||||
|
||||
// Each entry in string cache consists of two pointer sized fields,
|
||||
// but times_twice_pointer_size (multiplication by 16) scale factor
|
||||
// is not supported by addrmode on x64 platform.
|
||||
// So we have to premultiply entry index before lookup
|
||||
__ shl(scratch, Immediate(kPointerSizeLog2 + 1));
|
||||
// Check if the entry is the smi we are looking for.
|
||||
__ cmpq(object,
|
||||
FieldOperand(number_string_cache,
|
||||
scratch,
|
||||
times_1,
|
||||
FixedArray::kHeaderSize));
|
||||
__ j(not_equal, not_found);
|
||||
|
||||
// Get the result from the cache.
|
||||
__ movq(result,
|
||||
FieldOperand(number_string_cache,
|
||||
scratch,
|
||||
times_1,
|
||||
FixedArray::kHeaderSize + kPointerSize));
|
||||
__ IncrementCounter(&Counters::number_to_string_native, 1);
|
||||
}
|
||||
|
||||
|
||||
void NumberToStringStub::Generate(MacroAssembler* masm) {
|
||||
Label runtime;
|
||||
|
||||
__ movq(rbx, Operand(rsp, kPointerSize));
|
||||
|
||||
// Generate code to lookup number in the number string cache.
|
||||
GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime);
|
||||
__ ret(1 * kPointerSize);
|
||||
|
||||
__ bind(&runtime);
|
||||
// Handle number to string in the runtime system if not found in the cache.
|
||||
__ TailCallRuntime(Runtime::kNumberToString, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
void CompareStub::Generate(MacroAssembler* masm) {
|
||||
Label call_builtin, done;
|
||||
|
||||
@ -8794,6 +8866,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
|
||||
// result. If arguments was passed in registers now place them on the
|
||||
// stack in the correct order below the return address.
|
||||
__ bind(&call_runtime);
|
||||
|
||||
if (HasArgsInRegisters()) {
|
||||
__ pop(rcx);
|
||||
if (HasArgsReversed()) {
|
||||
@ -8805,48 +8878,63 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
__ push(rcx);
|
||||
}
|
||||
|
||||
switch (op_) {
|
||||
case Token::ADD: {
|
||||
// Registers containing left and right operands respectively.
|
||||
Register lhs, rhs;
|
||||
|
||||
if (HasArgsReversed()) {
|
||||
lhs = rax;
|
||||
rhs = rdx;
|
||||
} else {
|
||||
lhs = rdx;
|
||||
rhs = rax;
|
||||
}
|
||||
|
||||
// Test for string arguments before calling runtime.
|
||||
Label not_strings, both_strings, not_string1, string1;
|
||||
Label not_strings, both_strings, not_string1, string1, string1_smi2;
|
||||
Condition is_smi;
|
||||
Result answer;
|
||||
is_smi = masm->CheckSmi(rdx);
|
||||
is_smi = masm->CheckSmi(lhs);
|
||||
__ j(is_smi, ¬_string1);
|
||||
__ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx);
|
||||
__ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8);
|
||||
__ j(above_equal, ¬_string1);
|
||||
|
||||
// First argument is a a string, test second.
|
||||
is_smi = masm->CheckSmi(rax);
|
||||
__ j(is_smi, &string1);
|
||||
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
|
||||
is_smi = masm->CheckSmi(rhs);
|
||||
__ j(is_smi, &string1_smi2);
|
||||
__ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9);
|
||||
__ j(above_equal, &string1);
|
||||
|
||||
// First and second argument are strings.
|
||||
StringAddStub stub(NO_STRING_CHECK_IN_STUB);
|
||||
__ TailCallStub(&stub);
|
||||
StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
|
||||
__ TailCallStub(&string_add_stub);
|
||||
|
||||
__ bind(&string1_smi2);
|
||||
// First argument is a string, second is a smi. Try to lookup the number
|
||||
// string for the smi in the number string cache.
|
||||
NumberToStringStub::GenerateLookupNumberStringCache(
|
||||
masm, rhs, rbx, rcx, r8, true, &string1);
|
||||
|
||||
// Replace second argument on stack and tailcall string add stub to make
|
||||
// the result.
|
||||
__ movq(Operand(rsp, 1 * kPointerSize), rbx);
|
||||
__ TailCallStub(&string_add_stub);
|
||||
|
||||
// Only first argument is a string.
|
||||
__ bind(&string1);
|
||||
__ InvokeBuiltin(
|
||||
HasArgsReversed() ?
|
||||
Builtins::STRING_ADD_RIGHT :
|
||||
Builtins::STRING_ADD_LEFT,
|
||||
JUMP_FUNCTION);
|
||||
__ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
|
||||
|
||||
// First argument was not a string, test second.
|
||||
__ bind(¬_string1);
|
||||
is_smi = masm->CheckSmi(rax);
|
||||
is_smi = masm->CheckSmi(rhs);
|
||||
__ j(is_smi, ¬_strings);
|
||||
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax);
|
||||
__ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, rhs);
|
||||
__ j(above_equal, ¬_strings);
|
||||
|
||||
// Only second argument is a string.
|
||||
__ InvokeBuiltin(
|
||||
HasArgsReversed() ?
|
||||
Builtins::STRING_ADD_LEFT :
|
||||
Builtins::STRING_ADD_RIGHT,
|
||||
JUMP_FUNCTION);
|
||||
__ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
|
||||
|
||||
__ bind(¬_strings);
|
||||
// Neither argument is a string.
|
||||
|
@ -865,6 +865,39 @@ class StringCompareStub: public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
class NumberToStringStub: public CodeStub {
|
||||
public:
|
||||
NumberToStringStub() { }
|
||||
|
||||
// Generate code to do a lookup in the number string cache. If the number in
|
||||
// the register object is found in the cache the generated code falls through
|
||||
// with the result in the result register. The object and the result register
|
||||
// can be the same. If the number is not found in the cache the code jumps to
|
||||
// the label not_found with only the content of register object unchanged.
|
||||
static void GenerateLookupNumberStringCache(MacroAssembler* masm,
|
||||
Register object,
|
||||
Register result,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
bool object_is_smi,
|
||||
Label* not_found);
|
||||
|
||||
private:
|
||||
Major MajorKey() { return NumberToString; }
|
||||
int MinorKey() { return 0; }
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
|
||||
const char* GetName() { return "NumberToStringStub"; }
|
||||
|
||||
#ifdef DEBUG
|
||||
void Print() {
|
||||
PrintF("NumberToStringStub\n");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_X64_CODEGEN_X64_H_
|
||||
|
Loading…
Reference in New Issue
Block a user