From: sgjesse@chromium.org Date: Tue, 22 Feb 2011 12:26:31 +0000 (+0000) Subject: X64: Refactor the string add in the type recording binary operation stub X-Git-Tag: upstream/4.7.83~20126 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0a15b9116a10a78e269bd2afad53f2d8ded4df13;p=platform%2Fupstream%2Fv8.git X64: Refactor the string add in the type recording binary operation stub This makes the code have the same structore as on IA32 and ARM, and will also support possible fast adding a smi and string where the string is to the right and fast adding of String objects. Review URL: http://codereview.chromium.org/6542060 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6892 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 40f4fe2..87fa87d 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -2958,10 +2958,10 @@ void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { ASSERT(op_ == Token::ADD); + Label left_not_string, call_runtime; Register left = r1; Register right = r0; - Label left_not_string, call_runtime; // Check if left argument is a string. __ JumpIfSmi(left, &left_not_string); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 6331a6e..cb05c38 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2385,14 +2385,14 @@ void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { - NearLabel call_runtime; + ASSERT(op_ == Token::ADD); + NearLabel left_not_string, call_runtime; // Registers containing left and right operands respectively. Register left = edx; Register right = eax; // Test if left operand is a string. - NearLabel left_not_string; __ test(left, Immediate(kSmiTagMask)); __ j(zero, &left_not_string); __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index d160aaf..240087e 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -1336,54 +1336,33 @@ void TypeRecordingBinaryOpStub::GenerateFloatingPointCode( void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { - GenerateRegisterArgsPush(masm); - // Registers containing left and right operands respectively. - Register lhs = rdx; - Register rhs = rax; - - // Test for string arguments before calling runtime. - Label not_strings, both_strings, not_string1, string1, string1_smi2; - - __ JumpIfNotString(lhs, r8, ¬_string1); - - // First argument is a a string, test second. - __ JumpIfSmi(rhs, &string1_smi2); - __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9); - __ j(above_equal, &string1); - - // First and second argument are strings. - 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); + ASSERT(op_ == Token::ADD); + NearLabel left_not_string, call_runtime; - // Replace second argument on stack and tailcall string add stub to make - // the result. - __ movq(Operand(rsp, 1 * kPointerSize), rbx); - __ TailCallStub(&string_add_stub); + // Registers containing left and right operands respectively. + Register left = rdx; + Register right = rax; - // Only first argument is a string. - __ bind(&string1); - __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); + // Test if left operand is a string. + __ JumpIfSmi(left, &left_not_string); + __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); + __ j(above_equal, &left_not_string); + StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); + GenerateRegisterArgsPush(masm); + __ TailCallStub(&string_add_left_stub); - // First argument was not a string, test second. - __ bind(¬_string1); - __ JumpIfNotString(rhs, rhs, ¬_strings); + // Left operand is not a string, test right. + __ bind(&left_not_string); + __ JumpIfSmi(right, &call_runtime); + __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); + __ j(above_equal, &call_runtime); - // Only second argument is a string. - __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); + StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); + GenerateRegisterArgsPush(masm); + __ TailCallStub(&string_add_right_stub); - __ bind(¬_strings); // Neither argument is a string. - // Pop arguments, because CallRuntimeCode wants to push them again. - __ pop(rcx); - __ pop(rax); - __ pop(rdx); - __ push(rcx); + __ bind(&call_runtime); } @@ -1440,9 +1419,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { + ASSERT(operands_type_ == TRBinaryOpIC::STRING); ASSERT(op_ == Token::ADD); GenerateStringAddCode(masm); - + // Try to add arguments as strings, otherwise, transition to the generic + // TRBinaryOpIC type. GenerateTypeTransition(masm); } @@ -3802,14 +3783,15 @@ void StringCharAtGenerator::GenerateSlow( void StringAddStub::Generate(MacroAssembler* masm) { - Label string_add_runtime; + Label string_add_runtime, call_builtin; + Builtins::JavaScript builtin_id = Builtins::ADD; // Load the two arguments. - __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. - __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. + __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). + __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). // Make sure that both arguments are strings if not known in advance. - if (string_check_) { + if (flags_ == NO_STRING_ADD_FLAGS) { Condition is_smi; is_smi = masm->CheckSmi(rax); __ j(is_smi, &string_add_runtime); @@ -3821,6 +3803,20 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ j(is_smi, &string_add_runtime); __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); __ j(above_equal, &string_add_runtime); + } else { + // Here at least one of the arguments is definitely a string. + // We convert the one that is not known to be a string. + if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { + ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); + GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, + &call_builtin); + builtin_id = Builtins::STRING_ADD_RIGHT; + } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { + ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); + GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, + &call_builtin); + builtin_id = Builtins::STRING_ADD_LEFT; + } } // Both arguments are strings. @@ -3848,14 +3844,14 @@ void StringAddStub::Generate(MacroAssembler* masm) { // rbx: length of first string // rcx: length of second string // rdx: second string - // r8: map of first string if string check was performed above - // r9: map of second string if string check was performed above + // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) + // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) Label string_add_flat_result, longer_than_two; __ bind(&both_not_zero_length); // If arguments where known to be strings, maps are not loaded to r8 and r9 // by the code above. - if (!string_check_) { + if (flags_ != NO_STRING_ADD_FLAGS) { __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); } @@ -4041,6 +4037,54 @@ void StringAddStub::Generate(MacroAssembler* masm) { // Just jump to runtime to add the two strings. __ bind(&string_add_runtime); __ TailCallRuntime(Runtime::kStringAdd, 2, 1); + + if (call_builtin.is_linked()) { + __ bind(&call_builtin); + __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); + } +} + + +void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, + int stack_offset, + Register arg, + Register scratch1, + Register scratch2, + Register scratch3, + Label* slow) { + // First check if the argument is already a string. + Label not_string, done; + __ JumpIfSmi(arg, ¬_string); + __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); + __ j(below, &done); + + // Check the number to string cache. + Label not_cached; + __ bind(¬_string); + // Puts the cached result into scratch1. + NumberToStringStub::GenerateLookupNumberStringCache(masm, + arg, + scratch1, + scratch2, + scratch3, + false, + ¬_cached); + __ movq(arg, scratch1); + __ movq(Operand(rsp, stack_offset), arg); + __ jmp(&done); + + // Check if the argument is a safe string wrapper. + __ bind(¬_cached); + __ JumpIfSmi(arg, slow); + __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. + __ j(not_equal, slow); + __ testb(FieldOperand(scratch1, Map::kBitField2Offset), + Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); + __ j(zero, slow); + __ movq(arg, FieldOperand(arg, JSValue::kValueOffset)); + __ movq(Operand(rsp, stack_offset), arg); + + __ bind(&done); } diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h index 119b699..1e6fc65 100644 --- a/src/x64/code-stubs-x64.h +++ b/src/x64/code-stubs-x64.h @@ -360,24 +360,35 @@ class StringHelper : public AllStatic { // Flag that indicates how to generate code for the stub StringAddStub. enum StringAddFlags { NO_STRING_ADD_FLAGS = 0, - NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. + // Omit left string check in stub (left is definitely a string). + NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0, + // Omit right string check in stub (right is definitely a string). + NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1, + // Omit both string checks in stub. + NO_STRING_CHECK_IN_STUB = + NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB }; class StringAddStub: public CodeStub { public: - explicit StringAddStub(StringAddFlags flags) { - string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); - } + explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} private: Major MajorKey() { return StringAdd; } - int MinorKey() { return string_check_ ? 0 : 1; } + int MinorKey() { return flags_; } void Generate(MacroAssembler* masm); - // Should the stub check whether arguments are strings? - bool string_check_; + void GenerateConvertArgument(MacroAssembler* masm, + int stack_offset, + Register arg, + Register scratch1, + Register scratch2, + Register scratch3, + Label* slow); + + const StringAddFlags flags_; };