| 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 2406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2417 | 2417 |
| 2418 // Load the literals array of the function. | 2418 // Load the literals array of the function. |
| 2419 __ movq(literals.reg(), | 2419 __ movq(literals.reg(), |
| 2420 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 2420 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
| 2421 // Literal array. | 2421 // Literal array. |
| 2422 frame_->Push(&literals); | 2422 frame_->Push(&literals); |
| 2423 // Literal index. | 2423 // Literal index. |
| 2424 frame_->Push(Smi::FromInt(node->literal_index())); | 2424 frame_->Push(Smi::FromInt(node->literal_index())); |
| 2425 // Constant properties. | 2425 // Constant properties. |
| 2426 frame_->Push(node->constant_properties()); | 2426 frame_->Push(node->constant_properties()); |
| 2427 // Should the object literal have fast elements? |
| 2428 frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0)); |
| 2427 Result clone; | 2429 Result clone; |
| 2428 if (node->depth() > 1) { | 2430 if (node->depth() > 1) { |
| 2429 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); | 2431 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); |
| 2430 } else { | 2432 } else { |
| 2431 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 2433 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); |
| 2432 } | 2434 } |
| 2433 frame_->Push(&clone); | 2435 frame_->Push(&clone); |
| 2434 | 2436 |
| 2435 for (int i = 0; i < node->properties()->length(); i++) { | 2437 for (int i = 0; i < node->properties()->length(); i++) { |
| 2436 ObjectLiteral::Property* property = node->properties()->at(i); | 2438 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2437 switch (property->kind()) { | 2439 switch (property->kind()) { |
| 2438 case ObjectLiteral::Property::CONSTANT: | 2440 case ObjectLiteral::Property::CONSTANT: |
| 2439 break; | 2441 break; |
| 2440 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 2442 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 2441 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 2443 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; |
| (...skipping 1151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3593 Load(right); | 3595 Load(right); |
| 3594 Comparison(node, cc, strict, destination()); | 3596 Comparison(node, cc, strict, destination()); |
| 3595 } | 3597 } |
| 3596 | 3598 |
| 3597 | 3599 |
| 3598 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3600 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3599 frame_->PushFunction(); | 3601 frame_->PushFunction(); |
| 3600 } | 3602 } |
| 3601 | 3603 |
| 3602 | 3604 |
| 3603 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3605 void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) { |
| 3604 ASSERT(args->length() == 1); | 3606 ASSERT(args->length() == 1); |
| 3605 | 3607 |
| 3606 // ArgumentsAccessStub expects the key in rdx and the formal | 3608 // ArgumentsAccessStub expects the key in rdx and the formal |
| 3607 // parameter count in rax. | 3609 // parameter count in rax. |
| 3608 Load(args->at(0)); | 3610 Load(args->at(0)); |
| 3609 Result key = frame_->Pop(); | 3611 Result key = frame_->Pop(); |
| 3610 // Explicitly create a constant result. | 3612 // Explicitly create a constant result. |
| 3611 Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); | 3613 Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); |
| 3612 // Call the shared stub to get to arguments[key]. | 3614 // Call the shared stub to get to arguments[key]. |
| 3613 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 3615 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4044 frame_->Push(&result); | 4046 frame_->Push(&result); |
| 4045 } | 4047 } |
| 4046 | 4048 |
| 4047 | 4049 |
| 4048 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { | 4050 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { |
| 4049 ASSERT_EQ(args->length(), 1); | 4051 ASSERT_EQ(args->length(), 1); |
| 4050 | 4052 |
| 4051 // Load the argument on the stack and jump to the runtime. | 4053 // Load the argument on the stack and jump to the runtime. |
| 4052 Load(args->at(0)); | 4054 Load(args->at(0)); |
| 4053 | 4055 |
| 4054 Result answer = frame_->CallRuntime(Runtime::kNumberToString, 1); | 4056 NumberToStringStub stub; |
| 4055 frame_->Push(&answer); | 4057 Result result = frame_->CallStub(&stub, 1); |
| 4058 frame_->Push(&result); |
| 4056 } | 4059 } |
| 4057 | 4060 |
| 4058 | 4061 |
| 4059 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { | 4062 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
| 4060 ASSERT_EQ(args->length(), 1); | 4063 ASSERT_EQ(args->length(), 1); |
| 4061 // Load the argument on the stack and jump to the runtime. | 4064 // Load the argument on the stack and jump to the runtime. |
| 4062 Load(args->at(0)); | 4065 Load(args->at(0)); |
| 4063 Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1); | 4066 Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1); |
| 4064 frame_->Push(&answer); | 4067 frame_->Push(&answer); |
| 4065 } | 4068 } |
| (...skipping 3106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7172 Label next_capture, done; | 7175 Label next_capture, done; |
| 7173 __ movq(rax, Operand(rsp, kPreviousIndexOffset)); | 7176 __ movq(rax, Operand(rsp, kPreviousIndexOffset)); |
| 7174 // Capture register counter starts from number of capture registers and | 7177 // Capture register counter starts from number of capture registers and |
| 7175 // counts down until wraping after zero. | 7178 // counts down until wraping after zero. |
| 7176 __ bind(&next_capture); | 7179 __ bind(&next_capture); |
| 7177 __ subq(rdx, Immediate(1)); | 7180 __ subq(rdx, Immediate(1)); |
| 7178 __ j(negative, &done); | 7181 __ j(negative, &done); |
| 7179 // Read the value from the static offsets vector buffer and make it a smi. | 7182 // Read the value from the static offsets vector buffer and make it a smi. |
| 7180 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | 7183 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
| 7181 __ Integer32ToSmi(rdi, rdi, &runtime); | 7184 __ Integer32ToSmi(rdi, rdi, &runtime); |
| 7182 // Add previous index (from its stack slot) if value is not negative. | |
| 7183 Label capture_negative; | |
| 7184 // Negative flag set by smi convertion above. | |
| 7185 __ j(negative, &capture_negative); | |
| 7186 __ SmiAdd(rdi, rdi, rax, &runtime); // Add previous index. | |
| 7187 __ bind(&capture_negative); | |
| 7188 // Store the smi value in the last match info. | 7185 // Store the smi value in the last match info. |
| 7189 __ movq(FieldOperand(rbx, | 7186 __ movq(FieldOperand(rbx, |
| 7190 rdx, | 7187 rdx, |
| 7191 times_pointer_size, | 7188 times_pointer_size, |
| 7192 RegExpImpl::kFirstCaptureOffset), | 7189 RegExpImpl::kFirstCaptureOffset), |
| 7193 rdi); | 7190 rdi); |
| 7194 __ jmp(&next_capture); | 7191 __ jmp(&next_capture); |
| 7195 __ bind(&done); | 7192 __ bind(&done); |
| 7196 | 7193 |
| 7197 // Return last match info. | 7194 // Return last match info. |
| 7198 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); | 7195 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); |
| 7199 __ ret(4 * kPointerSize); | 7196 __ ret(4 * kPointerSize); |
| 7200 | 7197 |
| 7201 // Do the runtime call to execute the regexp. | 7198 // Do the runtime call to execute the regexp. |
| 7202 __ bind(&runtime); | 7199 __ bind(&runtime); |
| 7203 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 7200 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 7204 #endif // V8_NATIVE_REGEXP | 7201 #endif // V8_NATIVE_REGEXP |
| 7205 } | 7202 } |
| 7206 | 7203 |
| 7207 | 7204 |
| 7205 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, |
| 7206 Register object, |
| 7207 Register result, |
| 7208 Register scratch1, |
| 7209 Register scratch2, |
| 7210 bool object_is_smi, |
| 7211 Label* not_found) { |
| 7212 // Currently only lookup for smis. Check for smi if object is not known to be |
| 7213 // a smi. |
| 7214 if (!object_is_smi) { |
| 7215 __ JumpIfNotSmi(object, not_found); |
| 7216 } |
| 7217 |
| 7218 // Use of registers. Register result is used as a temporary. |
| 7219 Register number_string_cache = result; |
| 7220 Register mask = scratch1; |
| 7221 Register scratch = scratch2; |
| 7222 |
| 7223 // Load the number string cache. |
| 7224 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); |
| 7225 |
| 7226 // Make the hash mask from the length of the number string cache. It |
| 7227 // contains two elements (number and string) for each cache entry. |
| 7228 __ movl(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); |
| 7229 __ shrl(mask, Immediate(1)); // Divide length by two (length is not a smi). |
| 7230 __ subl(mask, Immediate(1)); // Make mask. |
| 7231 |
| 7232 // Calculate the entry in the number string cache. The hash value in the |
| 7233 // number string cache for smis is just the smi value. |
| 7234 __ movq(scratch, object); |
| 7235 __ SmiToInteger32(scratch, scratch); |
| 7236 __ andl(scratch, mask); |
| 7237 |
| 7238 // Each entry in string cache consists of two pointer sized fields, |
| 7239 // but times_twice_pointer_size (multiplication by 16) scale factor |
| 7240 // is not supported by addrmode on x64 platform. |
| 7241 // So we have to premultiply entry index before lookup |
| 7242 __ shl(scratch, Immediate(kPointerSizeLog2 + 1)); |
| 7243 // Check if the entry is the smi we are looking for. |
| 7244 __ cmpq(object, |
| 7245 FieldOperand(number_string_cache, |
| 7246 scratch, |
| 7247 times_1, |
| 7248 FixedArray::kHeaderSize)); |
| 7249 __ j(not_equal, not_found); |
| 7250 |
| 7251 // Get the result from the cache. |
| 7252 __ movq(result, |
| 7253 FieldOperand(number_string_cache, |
| 7254 scratch, |
| 7255 times_1, |
| 7256 FixedArray::kHeaderSize + kPointerSize)); |
| 7257 __ IncrementCounter(&Counters::number_to_string_native, 1); |
| 7258 } |
| 7259 |
| 7260 |
| 7261 void NumberToStringStub::Generate(MacroAssembler* masm) { |
| 7262 Label runtime; |
| 7263 |
| 7264 __ movq(rbx, Operand(rsp, kPointerSize)); |
| 7265 |
| 7266 // Generate code to lookup number in the number string cache. |
| 7267 GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime); |
| 7268 __ ret(1 * kPointerSize); |
| 7269 |
| 7270 __ bind(&runtime); |
| 7271 // Handle number to string in the runtime system if not found in the cache. |
| 7272 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); |
| 7273 } |
| 7274 |
| 7275 |
| 7208 void CompareStub::Generate(MacroAssembler* masm) { | 7276 void CompareStub::Generate(MacroAssembler* masm) { |
| 7209 Label call_builtin, done; | 7277 Label call_builtin, done; |
| 7210 | 7278 |
| 7211 // NOTICE! This code is only reached after a smi-fast-case check, so | 7279 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 7212 // it is certain that at least one operand isn't a smi. | 7280 // it is certain that at least one operand isn't a smi. |
| 7213 | 7281 |
| 7214 if (cc_ == equal) { // Both strict and non-strict. | 7282 if (cc_ == equal) { // Both strict and non-strict. |
| 7215 Label slow; // Fallthrough label. | 7283 Label slow; // Fallthrough label. |
| 7216 // Equality is almost reflexive (everything but NaN), so start by testing | 7284 // Equality is almost reflexive (everything but NaN), so start by testing |
| 7217 // for "identity and not NaN". | 7285 // for "identity and not NaN". |
| (...skipping 1109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8327 const char* op_name = Token::Name(op_); | 8395 const char* op_name = Token::Name(op_); |
| 8328 const char* overwrite_name; | 8396 const char* overwrite_name; |
| 8329 switch (mode_) { | 8397 switch (mode_) { |
| 8330 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 8398 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 8331 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 8399 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 8332 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 8400 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 8333 default: overwrite_name = "UnknownOverwrite"; break; | 8401 default: overwrite_name = "UnknownOverwrite"; break; |
| 8334 } | 8402 } |
| 8335 | 8403 |
| 8336 OS::SNPrintF(Vector<char>(name_, len), | 8404 OS::SNPrintF(Vector<char>(name_, len), |
| 8337 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", | 8405 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s_%s", |
| 8338 op_name, | 8406 op_name, |
| 8339 overwrite_name, | 8407 overwrite_name, |
| 8340 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 8408 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
| 8341 args_in_registers_ ? "RegArgs" : "StackArgs", | 8409 args_in_registers_ ? "RegArgs" : "StackArgs", |
| 8342 args_reversed_ ? "_R" : "", | 8410 args_reversed_ ? "_R" : "", |
| 8343 use_sse3_ ? "SSE3" : "SSE2", | 8411 use_sse3_ ? "SSE3" : "SSE2", |
| 8344 operands_type_.ToString()); | 8412 static_operands_type_.ToString(), |
| 8413 BinaryOpIC::GetName(runtime_operands_type_)); |
| 8345 return name_; | 8414 return name_; |
| 8346 } | 8415 } |
| 8347 | 8416 |
| 8348 | 8417 |
| 8349 void GenericBinaryOpStub::GenerateCall( | 8418 void GenericBinaryOpStub::GenerateCall( |
| 8350 MacroAssembler* masm, | 8419 MacroAssembler* masm, |
| 8351 Register left, | 8420 Register left, |
| 8352 Register right) { | 8421 Register right) { |
| 8353 if (!ArgsInRegistersSupported()) { | 8422 if (!ArgsInRegistersSupported()) { |
| 8354 // Pass arguments on the stack. | 8423 // Pass arguments on the stack. |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8484 return frame->CallStub(this, left, right); | 8553 return frame->CallStub(this, left, right); |
| 8485 } else { | 8554 } else { |
| 8486 frame->Push(left); | 8555 frame->Push(left); |
| 8487 frame->Push(right); | 8556 frame->Push(right); |
| 8488 return frame->CallStub(this, 2); | 8557 return frame->CallStub(this, 2); |
| 8489 } | 8558 } |
| 8490 } | 8559 } |
| 8491 | 8560 |
| 8492 | 8561 |
| 8493 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { | 8562 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
| 8494 // 1. Move arguments into edx, eax except for DIV and MOD, which need the | 8563 // 1. Move arguments into rdx, rax except for DIV and MOD, which need the |
| 8495 // dividend in eax and edx free for the division. Use eax, ebx for those. | 8564 // dividend in rax and rdx free for the division. Use rax, rbx for those. |
| 8496 Comment load_comment(masm, "-- Load arguments"); | 8565 Comment load_comment(masm, "-- Load arguments"); |
| 8497 Register left = rdx; | 8566 Register left = rdx; |
| 8498 Register right = rax; | 8567 Register right = rax; |
| 8499 if (op_ == Token::DIV || op_ == Token::MOD) { | 8568 if (op_ == Token::DIV || op_ == Token::MOD) { |
| 8500 left = rax; | 8569 left = rax; |
| 8501 right = rbx; | 8570 right = rbx; |
| 8502 if (HasArgsInRegisters()) { | 8571 if (HasArgsInRegisters()) { |
| 8503 __ movq(rbx, rax); | 8572 __ movq(rbx, rax); |
| 8504 __ movq(rax, rdx); | 8573 __ movq(rax, rdx); |
| 8505 } | 8574 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8584 UNREACHABLE(); | 8653 UNREACHABLE(); |
| 8585 } | 8654 } |
| 8586 __ movq(rax, left); | 8655 __ movq(rax, left); |
| 8587 break; | 8656 break; |
| 8588 | 8657 |
| 8589 default: | 8658 default: |
| 8590 UNREACHABLE(); | 8659 UNREACHABLE(); |
| 8591 break; | 8660 break; |
| 8592 } | 8661 } |
| 8593 | 8662 |
| 8594 // 4. Emit return of result in eax. | 8663 // 4. Emit return of result in rax. |
| 8595 GenerateReturn(masm); | 8664 GenerateReturn(masm); |
| 8596 | 8665 |
| 8597 // 5. For some operations emit inline code to perform floating point | 8666 // 5. For some operations emit inline code to perform floating point |
| 8598 // operations on known smis (e.g., if the result of the operation | 8667 // operations on known smis (e.g., if the result of the operation |
| 8599 // overflowed the smi range). | 8668 // overflowed the smi range). |
| 8600 switch (op_) { | 8669 switch (op_) { |
| 8601 case Token::ADD: | 8670 case Token::ADD: |
| 8602 case Token::SUB: | 8671 case Token::SUB: |
| 8603 case Token::MUL: | 8672 case Token::MUL: |
| 8604 case Token::DIV: { | 8673 case Token::DIV: { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8645 break; | 8714 break; |
| 8646 | 8715 |
| 8647 default: | 8716 default: |
| 8648 break; | 8717 break; |
| 8649 } | 8718 } |
| 8650 } | 8719 } |
| 8651 | 8720 |
| 8652 | 8721 |
| 8653 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 8722 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| 8654 Label call_runtime; | 8723 Label call_runtime; |
| 8655 if (HasSmiCodeInStub()) { | 8724 |
| 8725 if (ShouldGenerateSmiCode()) { |
| 8656 GenerateSmiCode(masm, &call_runtime); | 8726 GenerateSmiCode(masm, &call_runtime); |
| 8657 } else if (op_ != Token::MOD) { | 8727 } else if (op_ != Token::MOD) { |
| 8658 GenerateLoadArguments(masm); | 8728 if (!HasArgsInRegisters()) { |
| 8729 GenerateLoadArguments(masm); |
| 8730 } |
| 8659 } | 8731 } |
| 8660 // Floating point case. | 8732 // Floating point case. |
| 8661 switch (op_) { | 8733 if (ShouldGenerateFPCode()) { |
| 8662 case Token::ADD: | 8734 switch (op_) { |
| 8663 case Token::SUB: | 8735 case Token::ADD: |
| 8664 case Token::MUL: | 8736 case Token::SUB: |
| 8665 case Token::DIV: { | 8737 case Token::MUL: |
| 8666 // rax: y | 8738 case Token::DIV: { |
| 8667 // rdx: x | 8739 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
| 8668 if (operands_type_.IsNumber()) { | 8740 HasSmiCodeInStub()) { |
| 8741 // Execution reaches this point when the first non-smi argument occurs |
| 8742 // (and only if smi code is generated). This is the right moment to |
| 8743 // patch to HEAP_NUMBERS state. The transition is attempted only for |
| 8744 // the four basic operations. The stub stays in the DEFAULT state |
| 8745 // forever for all other operations (also if smi code is skipped). |
| 8746 GenerateTypeTransition(masm); |
| 8747 } |
| 8748 |
| 8749 Label not_floats; |
| 8750 // rax: y |
| 8751 // rdx: x |
| 8752 if (static_operands_type_.IsNumber()) { |
| 8669 if (FLAG_debug_code) { | 8753 if (FLAG_debug_code) { |
| 8670 // Assert at runtime that inputs are only numbers. | 8754 // Assert at runtime that inputs are only numbers. |
| 8671 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); | 8755 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); |
| 8672 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); | 8756 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); |
| 8673 } | 8757 } |
| 8674 } else { | 8758 } else { |
| 8675 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); | 8759 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); |
| 8676 } | 8760 } |
| 8677 // Fast-case: Both operands are numbers. | 8761 // Fast-case: Both operands are numbers. |
| 8678 // xmm4 and xmm5 are volatile XMM registers. | 8762 // xmm4 and xmm5 are volatile XMM registers. |
| 8679 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); | 8763 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); |
| 8680 | 8764 |
| 8681 switch (op_) { | 8765 switch (op_) { |
| 8682 case Token::ADD: __ addsd(xmm4, xmm5); break; | 8766 case Token::ADD: __ addsd(xmm4, xmm5); break; |
| 8683 case Token::SUB: __ subsd(xmm4, xmm5); break; | 8767 case Token::SUB: __ subsd(xmm4, xmm5); break; |
| 8684 case Token::MUL: __ mulsd(xmm4, xmm5); break; | 8768 case Token::MUL: __ mulsd(xmm4, xmm5); break; |
| 8685 case Token::DIV: __ divsd(xmm4, xmm5); break; | 8769 case Token::DIV: __ divsd(xmm4, xmm5); break; |
| 8686 default: UNREACHABLE(); | 8770 default: UNREACHABLE(); |
| 8687 } | 8771 } |
| 8688 // Allocate a heap number, if needed. | 8772 // Allocate a heap number, if needed. |
| 8689 Label skip_allocation; | 8773 Label skip_allocation; |
| 8690 OverwriteMode mode = mode_; | 8774 OverwriteMode mode = mode_; |
| 8691 if (HasArgsReversed()) { | 8775 if (HasArgsReversed()) { |
| 8692 if (mode == OVERWRITE_RIGHT) { | 8776 if (mode == OVERWRITE_RIGHT) { |
| 8693 mode = OVERWRITE_LEFT; | 8777 mode = OVERWRITE_LEFT; |
| 8694 } else if (mode == OVERWRITE_LEFT) { | 8778 } else if (mode == OVERWRITE_LEFT) { |
| 8695 mode = OVERWRITE_RIGHT; | 8779 mode = OVERWRITE_RIGHT; |
| 8696 } | 8780 } |
| 8697 } | 8781 } |
| 8698 switch (mode) { | 8782 switch (mode) { |
| 8699 case OVERWRITE_LEFT: | |
| 8700 __ JumpIfNotSmi(rdx, &skip_allocation); | |
| 8701 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | |
| 8702 __ movq(rdx, rbx); | |
| 8703 __ bind(&skip_allocation); | |
| 8704 __ movq(rax, rdx); | |
| 8705 break; | |
| 8706 case OVERWRITE_RIGHT: | |
| 8707 // If the argument in rax is already an object, we skip the | |
| 8708 // allocation of a heap number. | |
| 8709 __ JumpIfNotSmi(rax, &skip_allocation); | |
| 8710 // Fall through! | |
| 8711 case NO_OVERWRITE: | |
| 8712 // Allocate a heap number for the result. Keep rax and rdx intact | |
| 8713 // for the possible runtime call. | |
| 8714 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | |
| 8715 __ movq(rax, rbx); | |
| 8716 __ bind(&skip_allocation); | |
| 8717 break; | |
| 8718 default: UNREACHABLE(); | |
| 8719 } | |
| 8720 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); | |
| 8721 GenerateReturn(masm); | |
| 8722 } | |
| 8723 case Token::MOD: { | |
| 8724 // For MOD we go directly to runtime in the non-smi case. | |
| 8725 break; | |
| 8726 } | |
| 8727 case Token::BIT_OR: | |
| 8728 case Token::BIT_AND: | |
| 8729 case Token::BIT_XOR: | |
| 8730 case Token::SAR: | |
| 8731 case Token::SHL: | |
| 8732 case Token::SHR: { | |
| 8733 Label skip_allocation, non_smi_result; | |
| 8734 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | |
| 8735 switch (op_) { | |
| 8736 case Token::BIT_OR: __ orl(rax, rcx); break; | |
| 8737 case Token::BIT_AND: __ andl(rax, rcx); break; | |
| 8738 case Token::BIT_XOR: __ xorl(rax, rcx); break; | |
| 8739 case Token::SAR: __ sarl_cl(rax); break; | |
| 8740 case Token::SHL: __ shll_cl(rax); break; | |
| 8741 case Token::SHR: __ shrl_cl(rax); break; | |
| 8742 default: UNREACHABLE(); | |
| 8743 } | |
| 8744 if (op_ == Token::SHR) { | |
| 8745 // Check if result is non-negative. This can only happen for a shift | |
| 8746 // by zero, which also doesn't update the sign flag. | |
| 8747 __ testl(rax, rax); | |
| 8748 __ j(negative, &non_smi_result); | |
| 8749 } | |
| 8750 __ JumpIfNotValidSmiValue(rax, &non_smi_result); | |
| 8751 // Tag smi result, if possible, and return. | |
| 8752 __ Integer32ToSmi(rax, rax); | |
| 8753 GenerateReturn(masm); | |
| 8754 | |
| 8755 // All ops except SHR return a signed int32 that we load in a HeapNumber. | |
| 8756 if (op_ != Token::SHR && non_smi_result.is_linked()) { | |
| 8757 __ bind(&non_smi_result); | |
| 8758 // Allocate a heap number if needed. | |
| 8759 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result | |
| 8760 switch (mode_) { | |
| 8761 case OVERWRITE_LEFT: | 8783 case OVERWRITE_LEFT: |
| 8784 __ JumpIfNotSmi(rdx, &skip_allocation); |
| 8785 __ AllocateHeapNumber(rbx, rcx, &call_runtime); |
| 8786 __ movq(rdx, rbx); |
| 8787 __ bind(&skip_allocation); |
| 8788 __ movq(rax, rdx); |
| 8789 break; |
| 8762 case OVERWRITE_RIGHT: | 8790 case OVERWRITE_RIGHT: |
| 8763 // If the operand was an object, we skip the | 8791 // If the argument in rax is already an object, we skip the |
| 8764 // allocation of a heap number. | 8792 // allocation of a heap number. |
| 8765 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? | |
| 8766 1 * kPointerSize : 2 * kPointerSize)); | |
| 8767 __ JumpIfNotSmi(rax, &skip_allocation); | 8793 __ JumpIfNotSmi(rax, &skip_allocation); |
| 8768 // Fall through! | 8794 // Fall through! |
| 8769 case NO_OVERWRITE: | 8795 case NO_OVERWRITE: |
| 8770 __ AllocateHeapNumber(rax, rcx, &call_runtime); | 8796 // Allocate a heap number for the result. Keep rax and rdx intact |
| 8797 // for the possible runtime call. |
| 8798 __ AllocateHeapNumber(rbx, rcx, &call_runtime); |
| 8799 __ movq(rax, rbx); |
| 8771 __ bind(&skip_allocation); | 8800 __ bind(&skip_allocation); |
| 8772 break; | 8801 break; |
| 8773 default: UNREACHABLE(); | 8802 default: UNREACHABLE(); |
| 8774 } | 8803 } |
| 8775 // Store the result in the HeapNumber and return. | 8804 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); |
| 8776 __ movq(Operand(rsp, 1 * kPointerSize), rbx); | |
| 8777 __ fild_s(Operand(rsp, 1 * kPointerSize)); | |
| 8778 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | |
| 8779 GenerateReturn(masm); | 8805 GenerateReturn(masm); |
| 8780 } | 8806 __ bind(¬_floats); |
| 8781 | 8807 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
| 8782 // SHR should return uint32 - go to runtime for non-smi/negative result. | 8808 !HasSmiCodeInStub()) { |
| 8783 if (op_ == Token::SHR) { | 8809 // Execution reaches this point when the first non-number argument |
| 8784 __ bind(&non_smi_result); | 8810 // occurs (and only if smi code is skipped from the stub, otherwise |
| 8785 } | 8811 // the patching has already been done earlier in this case branch). |
| 8786 break; | 8812 // A perfect moment to try patching to STRINGS for ADD operation. |
| 8813 if (op_ == Token::ADD) { |
| 8814 GenerateTypeTransition(masm); |
| 8815 } |
| 8816 } |
| 8817 break; |
| 8818 } |
| 8819 case Token::MOD: { |
| 8820 // For MOD we go directly to runtime in the non-smi case. |
| 8821 break; |
| 8822 } |
| 8823 case Token::BIT_OR: |
| 8824 case Token::BIT_AND: |
| 8825 case Token::BIT_XOR: |
| 8826 case Token::SAR: |
| 8827 case Token::SHL: |
| 8828 case Token::SHR: { |
| 8829 Label skip_allocation, non_smi_result; |
| 8830 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); |
| 8831 switch (op_) { |
| 8832 case Token::BIT_OR: __ orl(rax, rcx); break; |
| 8833 case Token::BIT_AND: __ andl(rax, rcx); break; |
| 8834 case Token::BIT_XOR: __ xorl(rax, rcx); break; |
| 8835 case Token::SAR: __ sarl_cl(rax); break; |
| 8836 case Token::SHL: __ shll_cl(rax); break; |
| 8837 case Token::SHR: __ shrl_cl(rax); break; |
| 8838 default: UNREACHABLE(); |
| 8839 } |
| 8840 if (op_ == Token::SHR) { |
| 8841 // Check if result is non-negative. This can only happen for a shift |
| 8842 // by zero, which also doesn't update the sign flag. |
| 8843 __ testl(rax, rax); |
| 8844 __ j(negative, &non_smi_result); |
| 8845 } |
| 8846 __ JumpIfNotValidSmiValue(rax, &non_smi_result); |
| 8847 // Tag smi result, if possible, and return. |
| 8848 __ Integer32ToSmi(rax, rax); |
| 8849 GenerateReturn(masm); |
| 8850 |
| 8851 // All ops except SHR return a signed int32 that we load in |
| 8852 // a HeapNumber. |
| 8853 if (op_ != Token::SHR && non_smi_result.is_linked()) { |
| 8854 __ bind(&non_smi_result); |
| 8855 // Allocate a heap number if needed. |
| 8856 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result |
| 8857 switch (mode_) { |
| 8858 case OVERWRITE_LEFT: |
| 8859 case OVERWRITE_RIGHT: |
| 8860 // If the operand was an object, we skip the |
| 8861 // allocation of a heap number. |
| 8862 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? |
| 8863 1 * kPointerSize : 2 * kPointerSize)); |
| 8864 __ JumpIfNotSmi(rax, &skip_allocation); |
| 8865 // Fall through! |
| 8866 case NO_OVERWRITE: |
| 8867 __ AllocateHeapNumber(rax, rcx, &call_runtime); |
| 8868 __ bind(&skip_allocation); |
| 8869 break; |
| 8870 default: UNREACHABLE(); |
| 8871 } |
| 8872 // Store the result in the HeapNumber and return. |
| 8873 __ movq(Operand(rsp, 1 * kPointerSize), rbx); |
| 8874 __ fild_s(Operand(rsp, 1 * kPointerSize)); |
| 8875 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 8876 GenerateReturn(masm); |
| 8877 } |
| 8878 |
| 8879 // SHR should return uint32 - go to runtime for non-smi/negative result. |
| 8880 if (op_ == Token::SHR) { |
| 8881 __ bind(&non_smi_result); |
| 8882 } |
| 8883 break; |
| 8884 } |
| 8885 default: UNREACHABLE(); break; |
| 8787 } | 8886 } |
| 8788 default: UNREACHABLE(); break; | |
| 8789 } | 8887 } |
| 8790 | 8888 |
| 8791 // If all else fails, use the runtime system to get the correct | 8889 // If all else fails, use the runtime system to get the correct |
| 8792 // result. If arguments was passed in registers now place them on the | 8890 // result. If arguments was passed in registers now place them on the |
| 8793 // stack in the correct order below the return address. | 8891 // stack in the correct order below the return address. |
| 8794 __ bind(&call_runtime); | 8892 __ bind(&call_runtime); |
| 8893 |
| 8795 if (HasArgsInRegisters()) { | 8894 if (HasArgsInRegisters()) { |
| 8796 __ pop(rcx); | 8895 GenerateRegisterArgsPush(masm); |
| 8797 if (HasArgsReversed()) { | |
| 8798 __ push(rax); | |
| 8799 __ push(rdx); | |
| 8800 } else { | |
| 8801 __ push(rdx); | |
| 8802 __ push(rax); | |
| 8803 } | |
| 8804 __ push(rcx); | |
| 8805 } | 8896 } |
| 8897 |
| 8806 switch (op_) { | 8898 switch (op_) { |
| 8807 case Token::ADD: { | 8899 case Token::ADD: { |
| 8900 // Registers containing left and right operands respectively. |
| 8901 Register lhs, rhs; |
| 8902 |
| 8903 if (HasArgsReversed()) { |
| 8904 lhs = rax; |
| 8905 rhs = rdx; |
| 8906 } else { |
| 8907 lhs = rdx; |
| 8908 rhs = rax; |
| 8909 } |
| 8910 |
| 8808 // Test for string arguments before calling runtime. | 8911 // Test for string arguments before calling runtime. |
| 8809 Label not_strings, both_strings, not_string1, string1; | 8912 Label not_strings, both_strings, not_string1, string1, string1_smi2; |
| 8913 |
| 8914 // If this stub has already generated FP-specific code then the arguments |
| 8915 // are already in rdx, rax |
| 8916 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
| 8917 GenerateLoadArguments(masm); |
| 8918 } |
| 8919 |
| 8810 Condition is_smi; | 8920 Condition is_smi; |
| 8811 Result answer; | 8921 is_smi = masm->CheckSmi(lhs); |
| 8812 is_smi = masm->CheckSmi(rdx); | |
| 8813 __ j(is_smi, ¬_string1); | 8922 __ j(is_smi, ¬_string1); |
| 8814 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); | 8923 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8); |
| 8815 __ j(above_equal, ¬_string1); | 8924 __ j(above_equal, ¬_string1); |
| 8816 | 8925 |
| 8817 // First argument is a a string, test second. | 8926 // First argument is a a string, test second. |
| 8818 is_smi = masm->CheckSmi(rax); | 8927 is_smi = masm->CheckSmi(rhs); |
| 8819 __ j(is_smi, &string1); | 8928 __ j(is_smi, &string1_smi2); |
| 8820 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); | 8929 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9); |
| 8821 __ j(above_equal, &string1); | 8930 __ j(above_equal, &string1); |
| 8822 | 8931 |
| 8823 // First and second argument are strings. | 8932 // First and second argument are strings. |
| 8824 StringAddStub stub(NO_STRING_CHECK_IN_STUB); | 8933 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); |
| 8825 __ TailCallStub(&stub); | 8934 __ TailCallStub(&string_add_stub); |
| 8935 |
| 8936 __ bind(&string1_smi2); |
| 8937 // First argument is a string, second is a smi. Try to lookup the number |
| 8938 // string for the smi in the number string cache. |
| 8939 NumberToStringStub::GenerateLookupNumberStringCache( |
| 8940 masm, rhs, rbx, rcx, r8, true, &string1); |
| 8941 |
| 8942 // Replace second argument on stack and tailcall string add stub to make |
| 8943 // the result. |
| 8944 __ movq(Operand(rsp, 1 * kPointerSize), rbx); |
| 8945 __ TailCallStub(&string_add_stub); |
| 8826 | 8946 |
| 8827 // Only first argument is a string. | 8947 // Only first argument is a string. |
| 8828 __ bind(&string1); | 8948 __ bind(&string1); |
| 8829 __ InvokeBuiltin( | 8949 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); |
| 8830 HasArgsReversed() ? | |
| 8831 Builtins::STRING_ADD_RIGHT : | |
| 8832 Builtins::STRING_ADD_LEFT, | |
| 8833 JUMP_FUNCTION); | |
| 8834 | 8950 |
| 8835 // First argument was not a string, test second. | 8951 // First argument was not a string, test second. |
| 8836 __ bind(¬_string1); | 8952 __ bind(¬_string1); |
| 8837 is_smi = masm->CheckSmi(rax); | 8953 is_smi = masm->CheckSmi(rhs); |
| 8838 __ j(is_smi, ¬_strings); | 8954 __ j(is_smi, ¬_strings); |
| 8839 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); | 8955 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, rhs); |
| 8840 __ j(above_equal, ¬_strings); | 8956 __ j(above_equal, ¬_strings); |
| 8841 | 8957 |
| 8842 // Only second argument is a string. | 8958 // Only second argument is a string. |
| 8843 __ InvokeBuiltin( | 8959 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); |
| 8844 HasArgsReversed() ? | |
| 8845 Builtins::STRING_ADD_LEFT : | |
| 8846 Builtins::STRING_ADD_RIGHT, | |
| 8847 JUMP_FUNCTION); | |
| 8848 | 8960 |
| 8849 __ bind(¬_strings); | 8961 __ bind(¬_strings); |
| 8850 // Neither argument is a string. | 8962 // Neither argument is a string. |
| 8851 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | 8963 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); |
| 8852 break; | 8964 break; |
| 8853 } | 8965 } |
| 8854 case Token::SUB: | 8966 case Token::SUB: |
| 8855 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | 8967 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); |
| 8856 break; | 8968 break; |
| 8857 case Token::MUL: | 8969 case Token::MUL: |
| (...skipping 19 matching lines...) Expand all Loading... |
| 8877 break; | 8989 break; |
| 8878 case Token::SHL: | 8990 case Token::SHL: |
| 8879 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | 8991 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); |
| 8880 break; | 8992 break; |
| 8881 case Token::SHR: | 8993 case Token::SHR: |
| 8882 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 8994 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
| 8883 break; | 8995 break; |
| 8884 default: | 8996 default: |
| 8885 UNREACHABLE(); | 8997 UNREACHABLE(); |
| 8886 } | 8998 } |
| 8999 |
| 9000 // TODO(kaznacheev) Remove this (along with clearing) if it does not harm |
| 9001 // performance. |
| 9002 // Generate an unreachable reference to the DEFAULT stub so that it can be |
| 9003 // found at the end of this stub when clearing ICs at GC. |
| 9004 if (runtime_operands_type_ != BinaryOpIC::DEFAULT) { |
| 9005 GenericBinaryOpStub uninit(MinorKey(), BinaryOpIC::DEFAULT); |
| 9006 __ TailCallStub(&uninit); |
| 9007 } |
| 8887 } | 9008 } |
| 8888 | 9009 |
| 8889 | 9010 |
| 8890 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { | 9011 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
| 8891 // If arguments are not passed in registers read them from the stack. | 9012 ASSERT(!HasArgsInRegisters()); |
| 8892 if (!HasArgsInRegisters()) { | 9013 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 8893 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 9014 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
| 8894 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); | |
| 8895 } | |
| 8896 } | 9015 } |
| 8897 | 9016 |
| 8898 | 9017 |
| 8899 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { | 9018 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { |
| 8900 // If arguments are not passed in registers remove them from the stack before | 9019 // If arguments are not passed in registers remove them from the stack before |
| 8901 // returning. | 9020 // returning. |
| 8902 if (!HasArgsInRegisters()) { | 9021 if (!HasArgsInRegisters()) { |
| 8903 __ ret(2 * kPointerSize); // Remove both operands | 9022 __ ret(2 * kPointerSize); // Remove both operands |
| 8904 } else { | 9023 } else { |
| 8905 __ ret(0); | 9024 __ ret(0); |
| 8906 } | 9025 } |
| 8907 } | 9026 } |
| 8908 | 9027 |
| 8909 | 9028 |
| 9029 void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| 9030 ASSERT(HasArgsInRegisters()); |
| 9031 __ pop(rcx); |
| 9032 if (HasArgsReversed()) { |
| 9033 __ push(rax); |
| 9034 __ push(rdx); |
| 9035 } else { |
| 9036 __ push(rdx); |
| 9037 __ push(rax); |
| 9038 } |
| 9039 __ push(rcx); |
| 9040 } |
| 9041 |
| 9042 |
| 9043 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 9044 Label get_result; |
| 9045 |
| 9046 // Keep a copy of operands on the stack and make sure they are also in |
| 9047 // rdx, rax. |
| 9048 if (HasArgsInRegisters()) { |
| 9049 GenerateRegisterArgsPush(masm); |
| 9050 } else { |
| 9051 GenerateLoadArguments(masm); |
| 9052 } |
| 9053 |
| 9054 // Internal frame is necessary to handle exceptions properly. |
| 9055 __ EnterInternalFrame(); |
| 9056 |
| 9057 // Push arguments on stack if the stub expects them there. |
| 9058 if (!HasArgsInRegisters()) { |
| 9059 __ push(rdx); |
| 9060 __ push(rax); |
| 9061 } |
| 9062 // Call the stub proper to get the result in rax. |
| 9063 __ call(&get_result); |
| 9064 __ LeaveInternalFrame(); |
| 9065 |
| 9066 // Left and right arguments are already on stack. |
| 9067 __ pop(rcx); |
| 9068 // Push the operation result. The tail call to BinaryOp_Patch will |
| 9069 // return it to the original caller.. |
| 9070 __ push(rax); |
| 9071 |
| 9072 // Push this stub's key. |
| 9073 __ movq(rax, Immediate(MinorKey())); |
| 9074 __ Integer32ToSmi(rax, rax); |
| 9075 __ push(rax); |
| 9076 |
| 9077 // Although the operation and the type info are encoded into the key, |
| 9078 // the encoding is opaque, so push them too. |
| 9079 __ movq(rax, Immediate(op_)); |
| 9080 __ Integer32ToSmi(rax, rax); |
| 9081 __ push(rax); |
| 9082 |
| 9083 __ movq(rax, Immediate(runtime_operands_type_)); |
| 9084 __ Integer32ToSmi(rax, rax); |
| 9085 __ push(rax); |
| 9086 |
| 9087 __ push(rcx); |
| 9088 |
| 9089 // Perform patching to an appropriate fast case and return the result. |
| 9090 __ TailCallExternalReference( |
| 9091 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), |
| 9092 6, |
| 9093 1); |
| 9094 |
| 9095 // The entry point for the result calculation is assumed to be immediately |
| 9096 // after this sequence. |
| 9097 __ bind(&get_result); |
| 9098 } |
| 9099 |
| 9100 |
| 8910 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { | 9101 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
| 8911 return Handle<Code>::null(); | 9102 GenericBinaryOpStub stub(key, type_info); |
| 9103 return stub.GetCode(); |
| 8912 } | 9104 } |
| 8913 | 9105 |
| 8914 | 9106 |
| 8915 int CompareStub::MinorKey() { | 9107 int CompareStub::MinorKey() { |
| 8916 // Encode the three parameters in a unique 16 bit value. | 9108 // Encode the three parameters in a unique 16 bit value. |
| 8917 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); | 9109 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); |
| 8918 int nnn_value = (never_nan_nan_ ? 2 : 0); | 9110 int nnn_value = (never_nan_nan_ ? 2 : 0); |
| 8919 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. | 9111 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. |
| 8920 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); | 9112 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); |
| 8921 } | 9113 } |
| (...skipping 874 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9796 // Call the function from C++. | 9988 // Call the function from C++. |
| 9797 return FUNCTION_CAST<ModuloFunction>(buffer); | 9989 return FUNCTION_CAST<ModuloFunction>(buffer); |
| 9798 } | 9990 } |
| 9799 | 9991 |
| 9800 #endif | 9992 #endif |
| 9801 | 9993 |
| 9802 | 9994 |
| 9803 #undef __ | 9995 #undef __ |
| 9804 | 9996 |
| 9805 } } // namespace v8::internal | 9997 } } // namespace v8::internal |
| OLD | NEW |