OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
843 const char* op_name = Token::Name(op_); | 843 const char* op_name = Token::Name(op_); |
844 const char* overwrite_name; | 844 const char* overwrite_name; |
845 switch (mode_) { | 845 switch (mode_) { |
846 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 846 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
847 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 847 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
848 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 848 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
849 default: overwrite_name = "UnknownOverwrite"; break; | 849 default: overwrite_name = "UnknownOverwrite"; break; |
850 } | 850 } |
851 | 851 |
852 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 852 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
853 "GenericBinaryOpStub_%s_%s%s_%s%s_%s", | 853 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", |
854 op_name, | 854 op_name, |
855 overwrite_name, | 855 overwrite_name, |
856 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 856 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
857 args_in_registers_ ? "RegArgs" : "StackArgs", | 857 args_in_registers_ ? "RegArgs" : "StackArgs", |
858 args_reversed_ ? "_R" : "", | 858 args_reversed_ ? "_R" : "", |
859 NumberInfo::ToString(operands_type_)); | 859 NumberInfo::ToString(static_operands_type_), |
| 860 BinaryOpIC::GetName(runtime_operands_type_)); |
860 return name_; | 861 return name_; |
861 } | 862 } |
862 | 863 |
863 | 864 |
864 // Call the specialized stub for a binary operation. | 865 // Call the specialized stub for a binary operation. |
865 class DeferredInlineBinaryOperation: public DeferredCode { | 866 class DeferredInlineBinaryOperation: public DeferredCode { |
866 public: | 867 public: |
867 DeferredInlineBinaryOperation(Token::Value op, | 868 DeferredInlineBinaryOperation(Token::Value op, |
868 Register dst, | 869 Register dst, |
869 Register left, | 870 Register left, |
(...skipping 7206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8076 | 8077 |
8077 | 8078 |
8078 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 8079 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
8079 Label call_runtime; | 8080 Label call_runtime; |
8080 | 8081 |
8081 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | 8082 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); |
8082 | 8083 |
8083 // Generate fast case smi code if requested. This flag is set when the fast | 8084 // Generate fast case smi code if requested. This flag is set when the fast |
8084 // case smi code is not generated by the caller. Generating it here will speed | 8085 // case smi code is not generated by the caller. Generating it here will speed |
8085 // up common operations. | 8086 // up common operations. |
8086 if (HasSmiCodeInStub()) { | 8087 if (ShouldGenerateSmiCode()) { |
8087 GenerateSmiCode(masm, &call_runtime); | 8088 GenerateSmiCode(masm, &call_runtime); |
8088 } else if (op_ != Token::MOD) { // MOD goes straight to runtime. | 8089 } else if (op_ != Token::MOD) { // MOD goes straight to runtime. |
8089 GenerateLoadArguments(masm); | 8090 if (!HasArgsInRegisters()) { |
| 8091 GenerateLoadArguments(masm); |
| 8092 } |
8090 } | 8093 } |
8091 | 8094 |
8092 // Floating point case. | 8095 // Floating point case. |
8093 switch (op_) { | 8096 if (ShouldGenerateFPCode()) { |
8094 case Token::ADD: | 8097 switch (op_) { |
8095 case Token::SUB: | 8098 case Token::ADD: |
8096 case Token::MUL: | 8099 case Token::SUB: |
8097 case Token::DIV: { | 8100 case Token::MUL: |
8098 if (CpuFeatures::IsSupported(SSE2)) { | 8101 case Token::DIV: { |
8099 CpuFeatures::Scope use_sse2(SSE2); | 8102 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
8100 if (NumberInfo::IsNumber(operands_type_)) { | 8103 HasSmiCodeInStub()) { |
8101 if (FLAG_debug_code) { | 8104 // Execution reaches this point when the first non-smi argument occurs |
8102 // Assert at runtime that inputs are only numbers. | 8105 // (and only if smi code is generated). This is the right moment to |
8103 __ AbortIfNotNumber(edx, | 8106 // patch to HEAP_NUMBERS state. The transition is attempted only for |
8104 "GenericBinaryOpStub operand not a number."); | 8107 // the four basic operations. The stub stays in the DEFAULT state |
8105 __ AbortIfNotNumber(eax, | 8108 // forever for all other operations (also if smi code is skipped). |
8106 "GenericBinaryOpStub operand not a number."); | 8109 GenerateTypeTransition(masm); |
8107 } | |
8108 FloatingPointHelper::LoadSSE2Operands(masm); | |
8109 } else { | |
8110 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); | |
8111 } | 8110 } |
8112 | 8111 |
| 8112 Label not_floats; |
| 8113 if (CpuFeatures::IsSupported(SSE2)) { |
| 8114 CpuFeatures::Scope use_sse2(SSE2); |
| 8115 if (NumberInfo::IsNumber(static_operands_type_)) { |
| 8116 if (FLAG_debug_code) { |
| 8117 // Assert at runtime that inputs are only numbers. |
| 8118 __ AbortIfNotNumber(edx, |
| 8119 "GenericBinaryOpStub operand not a number."); |
| 8120 __ AbortIfNotNumber(eax, |
| 8121 "GenericBinaryOpStub operand not a number."); |
| 8122 } |
| 8123 FloatingPointHelper::LoadSSE2Operands(masm); |
| 8124 } else { |
| 8125 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); |
| 8126 } |
| 8127 |
| 8128 switch (op_) { |
| 8129 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 8130 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 8131 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 8132 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 8133 default: UNREACHABLE(); |
| 8134 } |
| 8135 GenerateHeapResultAllocation(masm, &call_runtime); |
| 8136 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 8137 GenerateReturn(masm); |
| 8138 } else { // SSE2 not available, use FPU. |
| 8139 if (NumberInfo::IsNumber(static_operands_type_)) { |
| 8140 if (FLAG_debug_code) { |
| 8141 // Assert at runtime that inputs are only numbers. |
| 8142 __ AbortIfNotNumber(edx, |
| 8143 "GenericBinaryOpStub operand not a number."); |
| 8144 __ AbortIfNotNumber(eax, |
| 8145 "GenericBinaryOpStub operand not a number."); |
| 8146 } |
| 8147 } else { |
| 8148 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
| 8149 } |
| 8150 FloatingPointHelper::LoadFloatOperands( |
| 8151 masm, |
| 8152 ecx, |
| 8153 FloatingPointHelper::ARGS_IN_REGISTERS); |
| 8154 switch (op_) { |
| 8155 case Token::ADD: __ faddp(1); break; |
| 8156 case Token::SUB: __ fsubp(1); break; |
| 8157 case Token::MUL: __ fmulp(1); break; |
| 8158 case Token::DIV: __ fdivp(1); break; |
| 8159 default: UNREACHABLE(); |
| 8160 } |
| 8161 Label after_alloc_failure; |
| 8162 GenerateHeapResultAllocation(masm, &after_alloc_failure); |
| 8163 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 8164 GenerateReturn(masm); |
| 8165 __ bind(&after_alloc_failure); |
| 8166 __ ffree(); |
| 8167 __ jmp(&call_runtime); |
| 8168 } |
| 8169 __ bind(¬_floats); |
| 8170 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
| 8171 !HasSmiCodeInStub()) { |
| 8172 // Execution reaches this point when the first non-number argument |
| 8173 // occurs (and only if smi code is skipped from the stub, otherwise |
| 8174 // the patching has already been done earlier in this case branch). |
| 8175 // Try patching to STRINGS for ADD operation. |
| 8176 if (op_ == Token::ADD) { |
| 8177 GenerateTypeTransition(masm); |
| 8178 } |
| 8179 } |
| 8180 break; |
| 8181 } |
| 8182 case Token::MOD: { |
| 8183 // For MOD we go directly to runtime in the non-smi case. |
| 8184 break; |
| 8185 } |
| 8186 case Token::BIT_OR: |
| 8187 case Token::BIT_AND: |
| 8188 case Token::BIT_XOR: |
| 8189 case Token::SAR: |
| 8190 case Token::SHL: |
| 8191 case Token::SHR: { |
| 8192 Label non_smi_result; |
| 8193 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); |
8113 switch (op_) { | 8194 switch (op_) { |
8114 case Token::ADD: __ addsd(xmm0, xmm1); break; | 8195 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; |
8115 case Token::SUB: __ subsd(xmm0, xmm1); break; | 8196 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |
8116 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 8197 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |
8117 case Token::DIV: __ divsd(xmm0, xmm1); break; | 8198 case Token::SAR: __ sar_cl(eax); break; |
| 8199 case Token::SHL: __ shl_cl(eax); break; |
| 8200 case Token::SHR: __ shr_cl(eax); break; |
8118 default: UNREACHABLE(); | 8201 default: UNREACHABLE(); |
8119 } | 8202 } |
8120 GenerateHeapResultAllocation(masm, &call_runtime); | 8203 if (op_ == Token::SHR) { |
8121 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 8204 // Check if result is non-negative and fits in a smi. |
| 8205 __ test(eax, Immediate(0xc0000000)); |
| 8206 __ j(not_zero, &call_runtime); |
| 8207 } else { |
| 8208 // Check if result fits in a smi. |
| 8209 __ cmp(eax, 0xc0000000); |
| 8210 __ j(negative, &non_smi_result); |
| 8211 } |
| 8212 // Tag smi result and return. |
| 8213 __ SmiTag(eax); |
8122 GenerateReturn(masm); | 8214 GenerateReturn(masm); |
8123 } else { // SSE2 not available, use FPU. | 8215 |
8124 if (NumberInfo::IsNumber(operands_type_)) { | 8216 // All ops except SHR return a signed int32 that we load in |
8125 if (FLAG_debug_code) { | 8217 // a HeapNumber. |
8126 // Assert at runtime that inputs are only numbers. | 8218 if (op_ != Token::SHR) { |
8127 __ AbortIfNotNumber(edx, | 8219 __ bind(&non_smi_result); |
8128 "GenericBinaryOpStub operand not a number."); | 8220 // Allocate a heap number if needed. |
8129 __ AbortIfNotNumber(eax, | 8221 __ mov(ebx, Operand(eax)); // ebx: result |
8130 "GenericBinaryOpStub operand not a number."); | 8222 Label skip_allocation; |
| 8223 switch (mode_) { |
| 8224 case OVERWRITE_LEFT: |
| 8225 case OVERWRITE_RIGHT: |
| 8226 // If the operand was an object, we skip the |
| 8227 // allocation of a heap number. |
| 8228 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
| 8229 1 * kPointerSize : 2 * kPointerSize)); |
| 8230 __ test(eax, Immediate(kSmiTagMask)); |
| 8231 __ j(not_zero, &skip_allocation, not_taken); |
| 8232 // Fall through! |
| 8233 case NO_OVERWRITE: |
| 8234 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 8235 __ bind(&skip_allocation); |
| 8236 break; |
| 8237 default: UNREACHABLE(); |
8131 } | 8238 } |
8132 } else { | 8239 // Store the result in the HeapNumber and return. |
8133 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 8240 if (CpuFeatures::IsSupported(SSE2)) { |
| 8241 CpuFeatures::Scope use_sse2(SSE2); |
| 8242 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 8243 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 8244 } else { |
| 8245 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 8246 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 8247 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 8248 } |
| 8249 GenerateReturn(masm); |
8134 } | 8250 } |
8135 FloatingPointHelper::LoadFloatOperands( | 8251 break; |
8136 masm, | |
8137 ecx, | |
8138 FloatingPointHelper::ARGS_IN_REGISTERS); | |
8139 switch (op_) { | |
8140 case Token::ADD: __ faddp(1); break; | |
8141 case Token::SUB: __ fsubp(1); break; | |
8142 case Token::MUL: __ fmulp(1); break; | |
8143 case Token::DIV: __ fdivp(1); break; | |
8144 default: UNREACHABLE(); | |
8145 } | |
8146 Label after_alloc_failure; | |
8147 GenerateHeapResultAllocation(masm, &after_alloc_failure); | |
8148 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
8149 GenerateReturn(masm); | |
8150 __ bind(&after_alloc_failure); | |
8151 __ ffree(); | |
8152 __ jmp(&call_runtime); | |
8153 } | 8252 } |
| 8253 default: UNREACHABLE(); break; |
8154 } | 8254 } |
8155 case Token::MOD: { | |
8156 // For MOD we go directly to runtime in the non-smi case. | |
8157 break; | |
8158 } | |
8159 case Token::BIT_OR: | |
8160 case Token::BIT_AND: | |
8161 case Token::BIT_XOR: | |
8162 case Token::SAR: | |
8163 case Token::SHL: | |
8164 case Token::SHR: { | |
8165 Label non_smi_result; | |
8166 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | |
8167 switch (op_) { | |
8168 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | |
8169 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | |
8170 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; | |
8171 case Token::SAR: __ sar_cl(eax); break; | |
8172 case Token::SHL: __ shl_cl(eax); break; | |
8173 case Token::SHR: __ shr_cl(eax); break; | |
8174 default: UNREACHABLE(); | |
8175 } | |
8176 if (op_ == Token::SHR) { | |
8177 // Check if result is non-negative and fits in a smi. | |
8178 __ test(eax, Immediate(0xc0000000)); | |
8179 __ j(not_zero, &call_runtime); | |
8180 } else { | |
8181 // Check if result fits in a smi. | |
8182 __ cmp(eax, 0xc0000000); | |
8183 __ j(negative, &non_smi_result); | |
8184 } | |
8185 // Tag smi result and return. | |
8186 __ SmiTag(eax); | |
8187 GenerateReturn(masm); | |
8188 | |
8189 // All ops except SHR return a signed int32 that we load in a HeapNumber. | |
8190 if (op_ != Token::SHR) { | |
8191 __ bind(&non_smi_result); | |
8192 // Allocate a heap number if needed. | |
8193 __ mov(ebx, Operand(eax)); // ebx: result | |
8194 Label skip_allocation; | |
8195 switch (mode_) { | |
8196 case OVERWRITE_LEFT: | |
8197 case OVERWRITE_RIGHT: | |
8198 // If the operand was an object, we skip the | |
8199 // allocation of a heap number. | |
8200 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | |
8201 1 * kPointerSize : 2 * kPointerSize)); | |
8202 __ test(eax, Immediate(kSmiTagMask)); | |
8203 __ j(not_zero, &skip_allocation, not_taken); | |
8204 // Fall through! | |
8205 case NO_OVERWRITE: | |
8206 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | |
8207 __ bind(&skip_allocation); | |
8208 break; | |
8209 default: UNREACHABLE(); | |
8210 } | |
8211 // Store the result in the HeapNumber and return. | |
8212 if (CpuFeatures::IsSupported(SSE2)) { | |
8213 CpuFeatures::Scope use_sse2(SSE2); | |
8214 __ cvtsi2sd(xmm0, Operand(ebx)); | |
8215 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | |
8216 } else { | |
8217 __ mov(Operand(esp, 1 * kPointerSize), ebx); | |
8218 __ fild_s(Operand(esp, 1 * kPointerSize)); | |
8219 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
8220 } | |
8221 GenerateReturn(masm); | |
8222 } | |
8223 break; | |
8224 } | |
8225 default: UNREACHABLE(); break; | |
8226 } | 8255 } |
8227 | 8256 |
8228 // If all else fails, use the runtime system to get the correct | 8257 // If all else fails, use the runtime system to get the correct |
8229 // result. If arguments was passed in registers now place them on the | 8258 // result. If arguments was passed in registers now place them on the |
8230 // stack in the correct order below the return address. | 8259 // stack in the correct order below the return address. |
8231 __ bind(&call_runtime); | 8260 __ bind(&call_runtime); |
8232 if (HasArgsInRegisters()) { | 8261 if (HasArgsInRegisters()) { |
8233 __ pop(ecx); | 8262 GenerateRegisterArgsPush(masm); |
8234 if (HasArgsReversed()) { | |
8235 __ push(eax); | |
8236 __ push(edx); | |
8237 } else { | |
8238 __ push(edx); | |
8239 __ push(eax); | |
8240 } | |
8241 __ push(ecx); | |
8242 } | 8263 } |
| 8264 |
8243 switch (op_) { | 8265 switch (op_) { |
8244 case Token::ADD: { | 8266 case Token::ADD: { |
8245 // Test for string arguments before calling runtime. | 8267 // Test for string arguments before calling runtime. |
8246 Label not_strings, not_string1, string1, string1_smi2; | 8268 Label not_strings, not_string1, string1, string1_smi2; |
8247 Result answer; | 8269 |
| 8270 // If this stub has already generated FP-specific code then the arguments |
| 8271 // are already in edx, eax |
| 8272 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
| 8273 GenerateLoadArguments(masm); |
| 8274 } |
| 8275 |
8248 __ test(edx, Immediate(kSmiTagMask)); | 8276 __ test(edx, Immediate(kSmiTagMask)); |
8249 __ j(zero, ¬_string1); | 8277 __ j(zero, ¬_string1); |
8250 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx); | 8278 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx); |
8251 __ j(above_equal, ¬_string1); | 8279 __ j(above_equal, ¬_string1); |
8252 | 8280 |
8253 // First argument is a string, test second. | 8281 // First argument is a string, test second. |
8254 __ test(eax, Immediate(kSmiTagMask)); | 8282 __ test(eax, Immediate(kSmiTagMask)); |
8255 __ j(zero, &string1_smi2); | 8283 __ j(zero, &string1_smi2); |
8256 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | 8284 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); |
8257 __ j(above_equal, &string1); | 8285 __ j(above_equal, &string1); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8326 break; | 8354 break; |
8327 case Token::SHL: | 8355 case Token::SHL: |
8328 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | 8356 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); |
8329 break; | 8357 break; |
8330 case Token::SHR: | 8358 case Token::SHR: |
8331 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 8359 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
8332 break; | 8360 break; |
8333 default: | 8361 default: |
8334 UNREACHABLE(); | 8362 UNREACHABLE(); |
8335 } | 8363 } |
| 8364 |
| 8365 // Generate an unreachable reference to the DEFAULT stub so that it can be |
| 8366 // found at the end of this stub when clearing ICs at GC. |
| 8367 if (runtime_operands_type_ != BinaryOpIC::DEFAULT) { |
| 8368 GenericBinaryOpStub uninit(MinorKey(), BinaryOpIC::DEFAULT); |
| 8369 __ TailCallStub(&uninit); |
| 8370 } |
8336 } | 8371 } |
8337 | 8372 |
8338 | 8373 |
8339 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, | 8374 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, |
8340 Label* alloc_failure) { | 8375 Label* alloc_failure) { |
8341 Label skip_allocation; | 8376 Label skip_allocation; |
8342 OverwriteMode mode = mode_; | 8377 OverwriteMode mode = mode_; |
8343 if (HasArgsReversed()) { | 8378 if (HasArgsReversed()) { |
8344 if (mode == OVERWRITE_RIGHT) { | 8379 if (mode == OVERWRITE_RIGHT) { |
8345 mode = OVERWRITE_LEFT; | 8380 mode = OVERWRITE_LEFT; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8379 __ mov(eax, ebx); | 8414 __ mov(eax, ebx); |
8380 __ bind(&skip_allocation); | 8415 __ bind(&skip_allocation); |
8381 break; | 8416 break; |
8382 default: UNREACHABLE(); | 8417 default: UNREACHABLE(); |
8383 } | 8418 } |
8384 } | 8419 } |
8385 | 8420 |
8386 | 8421 |
8387 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { | 8422 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
8388 // If arguments are not passed in registers read them from the stack. | 8423 // If arguments are not passed in registers read them from the stack. |
8389 if (!HasArgsInRegisters()) { | 8424 ASSERT(!HasArgsInRegisters()); |
8390 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 8425 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
8391 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 8426 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
8392 } | |
8393 } | 8427 } |
8394 | 8428 |
8395 | 8429 |
8396 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { | 8430 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { |
8397 // If arguments are not passed in registers remove them from the stack before | 8431 // If arguments are not passed in registers remove them from the stack before |
8398 // returning. | 8432 // returning. |
8399 if (!HasArgsInRegisters()) { | 8433 if (!HasArgsInRegisters()) { |
8400 __ ret(2 * kPointerSize); // Remove both operands | 8434 __ ret(2 * kPointerSize); // Remove both operands |
8401 } else { | 8435 } else { |
8402 __ ret(0); | 8436 __ ret(0); |
8403 } | 8437 } |
8404 } | 8438 } |
8405 | 8439 |
8406 | 8440 |
| 8441 void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| 8442 ASSERT(HasArgsInRegisters()); |
| 8443 __ pop(ecx); |
| 8444 if (HasArgsReversed()) { |
| 8445 __ push(eax); |
| 8446 __ push(edx); |
| 8447 } else { |
| 8448 __ push(edx); |
| 8449 __ push(eax); |
| 8450 } |
| 8451 __ push(ecx); |
| 8452 } |
| 8453 |
| 8454 |
| 8455 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 8456 Label get_result; |
| 8457 |
| 8458 // Keep a copy of operands on the stack and make sure they are also in |
| 8459 // edx, eax. |
| 8460 if (HasArgsInRegisters()) { |
| 8461 GenerateRegisterArgsPush(masm); |
| 8462 } else { |
| 8463 GenerateLoadArguments(masm); |
| 8464 } |
| 8465 |
| 8466 // Internal frame is necessary to handle exceptions properly. |
| 8467 __ EnterInternalFrame(); |
| 8468 |
| 8469 // Push arguments on stack if the stub expects them there. |
| 8470 if (!HasArgsInRegisters()) { |
| 8471 __ push(edx); |
| 8472 __ push(eax); |
| 8473 } |
| 8474 // Call the stub proper to get the result in eax. |
| 8475 __ call(&get_result); |
| 8476 __ LeaveInternalFrame(); |
| 8477 |
| 8478 __ pop(ecx); // Return address. |
| 8479 // Left and right arguments are now on top. |
| 8480 // Push the operation result. The tail call to BinaryOp_Patch will |
| 8481 // return it to the original caller. |
| 8482 __ push(eax); |
| 8483 // Push this stub's key. Although the operation and the type info are |
| 8484 // encoded into the key, the encoding is opaque, so push them too. |
| 8485 __ push(Immediate(Smi::FromInt(MinorKey()))); |
| 8486 __ push(Immediate(Smi::FromInt(op_))); |
| 8487 __ push(Immediate(Smi::FromInt(runtime_operands_type_))); |
| 8488 |
| 8489 __ push(ecx); // Return address. |
| 8490 |
| 8491 // Patch the caller to an appropriate specialized stub |
| 8492 // and return the operation result. |
| 8493 __ TailCallExternalReference( |
| 8494 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), |
| 8495 6, |
| 8496 1); |
| 8497 |
| 8498 // The entry point for the result calculation is assumed to be immediately |
| 8499 // after this sequence. |
| 8500 __ bind(&get_result); |
| 8501 } |
| 8502 |
| 8503 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
| 8504 GenericBinaryOpStub stub(key, type_info); |
| 8505 HandleScope scope; |
| 8506 return stub.GetCode(); |
| 8507 } |
| 8508 |
| 8509 |
8407 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 8510 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
8408 // Input on stack: | 8511 // Input on stack: |
8409 // esp[4]: argument (should be number). | 8512 // esp[4]: argument (should be number). |
8410 // esp[0]: return address. | 8513 // esp[0]: return address. |
8411 // Test that eax is a number. | 8514 // Test that eax is a number. |
8412 Label runtime_call; | 8515 Label runtime_call; |
8413 Label runtime_call_clear_stack; | 8516 Label runtime_call_clear_stack; |
8414 Label input_not_smi; | 8517 Label input_not_smi; |
8415 Label loaded; | 8518 Label loaded; |
8416 __ mov(eax, Operand(esp, kPointerSize)); | 8519 __ mov(eax, Operand(esp, kPointerSize)); |
(...skipping 2863 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11280 | 11383 |
11281 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 11384 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
11282 // tagged as a small integer. | 11385 // tagged as a small integer. |
11283 __ bind(&runtime); | 11386 __ bind(&runtime); |
11284 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 11387 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
11285 } | 11388 } |
11286 | 11389 |
11287 #undef __ | 11390 #undef __ |
11288 | 11391 |
11289 } } // namespace v8::internal | 11392 } } // namespace v8::internal |
OLD | NEW |