| Index: src/x64/code-stubs-x64.cc
|
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
| index 1896c00f92a4eefd29202473204f5ca86ca5ec4a..62b376f657724cafab7cd3a92f39b5368bec9484 100644
|
| --- a/src/x64/code-stubs-x64.cc
|
| +++ b/src/x64/code-stubs-x64.cc
|
| @@ -155,6 +155,18 @@ void TransitionElementsKindStub::InitializeInterfaceDescriptor(
|
| }
|
|
|
|
|
| +void BinaryOpStub::InitializeInterfaceDescriptor(
|
| + Isolate* isolate,
|
| + CodeStubInterfaceDescriptor* descriptor) {
|
| + static Register registers[] = { rdx, rax };
|
| + descriptor->register_param_count_ = 2;
|
| + descriptor->register_params_ = registers;
|
| + descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss);
|
| + descriptor->SetMissHandler(
|
| + ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate));
|
| +}
|
| +
|
| +
|
| static void InitializeArrayConstructorDescriptor(
|
| Isolate* isolate,
|
| CodeStubInterfaceDescriptor* descriptor,
|
| @@ -447,35 +459,8 @@ class FloatingPointHelper : public AllStatic {
|
| // If the operands are not both numbers, jump to not_numbers.
|
| // Leaves rdx and rax unchanged. SmiOperands assumes both are smis.
|
| // NumberOperands assumes both are smis or heap numbers.
|
| - static void LoadSSE2SmiOperands(MacroAssembler* masm);
|
| static void LoadSSE2UnknownOperands(MacroAssembler* masm,
|
| Label* not_numbers);
|
| -
|
| - // Takes the operands in rdx and rax and loads them as integers in rax
|
| - // and rcx.
|
| - static void LoadAsIntegers(MacroAssembler* masm,
|
| - Label* operand_conversion_failure,
|
| - Register heap_number_map);
|
| -
|
| - // Tries to convert two values to smis losslessly.
|
| - // This fails if either argument is not a Smi nor a HeapNumber,
|
| - // or if it's a HeapNumber with a value that can't be converted
|
| - // losslessly to a Smi. In that case, control transitions to the
|
| - // on_not_smis label.
|
| - // On success, either control goes to the on_success label (if one is
|
| - // provided), or it falls through at the end of the code (if on_success
|
| - // is NULL).
|
| - // On success, both first and second holds Smi tagged values.
|
| - // One of first or second must be non-Smi when entering.
|
| - static void NumbersToSmis(MacroAssembler* masm,
|
| - Register first,
|
| - Register second,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Register scratch3,
|
| - Label* on_success,
|
| - Label* on_not_smis,
|
| - ConvertUndefined convert_undefined);
|
| };
|
|
|
|
|
| @@ -563,569 +548,6 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
|
|
| -void BinaryOpStub::Initialize() {}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
|
| - __ PopReturnAddressTo(rcx);
|
| - __ push(rdx);
|
| - __ push(rax);
|
| - // Left and right arguments are now on top.
|
| - __ Push(Smi::FromInt(MinorKey()));
|
| -
|
| - __ PushReturnAddressFrom(rcx);
|
| -
|
| - // Patch the caller to an appropriate specialized stub and return the
|
| - // operation result to the caller of the stub.
|
| - __ TailCallExternalReference(
|
| - ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
|
| - masm->isolate()),
|
| - 3,
|
| - 1);
|
| -}
|
| -
|
| -
|
| -static void BinaryOpStub_GenerateSmiCode(
|
| - MacroAssembler* masm,
|
| - Label* slow,
|
| - BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
|
| - Token::Value op) {
|
| -
|
| - // Arguments to BinaryOpStub are in rdx and rax.
|
| - const Register left = rdx;
|
| - const Register right = rax;
|
| -
|
| - // We only generate heapnumber answers for overflowing calculations
|
| - // for the four basic arithmetic operations and logical right shift by 0.
|
| - bool generate_inline_heapnumber_results =
|
| - (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) &&
|
| - (op == Token::ADD || op == Token::SUB ||
|
| - op == Token::MUL || op == Token::DIV || op == Token::SHR);
|
| -
|
| - // Smi check of both operands. If op is BIT_OR, the check is delayed
|
| - // until after the OR operation.
|
| - Label not_smis;
|
| - Label use_fp_on_smis;
|
| - Label fail;
|
| -
|
| - if (op != Token::BIT_OR) {
|
| - Comment smi_check_comment(masm, "-- Smi check arguments");
|
| - __ JumpIfNotBothSmi(left, right, ¬_smis);
|
| - }
|
| -
|
| - Label smi_values;
|
| - __ bind(&smi_values);
|
| - // Perform the operation.
|
| - Comment perform_smi(masm, "-- Perform smi operation");
|
| - switch (op) {
|
| - case Token::ADD:
|
| - ASSERT(right.is(rax));
|
| - __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative.
|
| - break;
|
| -
|
| - case Token::SUB:
|
| - __ SmiSub(left, left, right, &use_fp_on_smis);
|
| - __ movq(rax, left);
|
| - break;
|
| -
|
| - case Token::MUL:
|
| - ASSERT(right.is(rax));
|
| - __ SmiMul(right, right, left, &use_fp_on_smis); // MUL is commutative.
|
| - break;
|
| -
|
| - case Token::DIV:
|
| - // SmiDiv will not accept left in rdx or right in rax.
|
| - __ movq(rbx, rax);
|
| - __ movq(rcx, rdx);
|
| - __ SmiDiv(rax, rcx, rbx, &use_fp_on_smis);
|
| - break;
|
| -
|
| - case Token::MOD:
|
| - // SmiMod will not accept left in rdx or right in rax.
|
| - __ movq(rbx, rax);
|
| - __ movq(rcx, rdx);
|
| - __ SmiMod(rax, rcx, rbx, &use_fp_on_smis);
|
| - break;
|
| -
|
| - case Token::BIT_OR: {
|
| - ASSERT(right.is(rax));
|
| - __ SmiOrIfSmis(right, right, left, ¬_smis); // BIT_OR is commutative.
|
| - break;
|
| - }
|
| - case Token::BIT_XOR:
|
| - ASSERT(right.is(rax));
|
| - __ SmiXor(right, right, left); // BIT_XOR is commutative.
|
| - break;
|
| -
|
| - case Token::BIT_AND:
|
| - ASSERT(right.is(rax));
|
| - __ SmiAnd(right, right, left); // BIT_AND is commutative.
|
| - break;
|
| -
|
| - case Token::SHL:
|
| - __ SmiShiftLeft(left, left, right);
|
| - __ movq(rax, left);
|
| - break;
|
| -
|
| - case Token::SAR:
|
| - __ SmiShiftArithmeticRight(left, left, right);
|
| - __ movq(rax, left);
|
| - break;
|
| -
|
| - case Token::SHR:
|
| - __ SmiShiftLogicalRight(left, left, right, &use_fp_on_smis);
|
| - __ movq(rax, left);
|
| - break;
|
| -
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -
|
| - // 5. Emit return of result in rax. Some operations have registers pushed.
|
| - __ ret(0);
|
| -
|
| - if (use_fp_on_smis.is_linked()) {
|
| - // 6. For some operations emit inline code to perform floating point
|
| - // operations on known smis (e.g., if the result of the operation
|
| - // overflowed the smi range).
|
| - __ bind(&use_fp_on_smis);
|
| - if (op == Token::DIV || op == Token::MOD) {
|
| - // Restore left and right to rdx and rax.
|
| - __ movq(rdx, rcx);
|
| - __ movq(rax, rbx);
|
| - }
|
| -
|
| - if (generate_inline_heapnumber_results) {
|
| - __ AllocateHeapNumber(rcx, rbx, slow);
|
| - Comment perform_float(masm, "-- Perform float operation on smis");
|
| - if (op == Token::SHR) {
|
| - __ SmiToInteger32(left, left);
|
| - __ cvtqsi2sd(xmm0, left);
|
| - } else {
|
| - FloatingPointHelper::LoadSSE2SmiOperands(masm);
|
| - switch (op) {
|
| - case Token::ADD: __ addsd(xmm0, xmm1); break;
|
| - case Token::SUB: __ subsd(xmm0, xmm1); break;
|
| - case Token::MUL: __ mulsd(xmm0, xmm1); break;
|
| - case Token::DIV: __ divsd(xmm0, xmm1); break;
|
| - default: UNREACHABLE();
|
| - }
|
| - }
|
| - __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
|
| - __ movq(rax, rcx);
|
| - __ ret(0);
|
| - } else {
|
| - __ jmp(&fail);
|
| - }
|
| - }
|
| -
|
| - // 7. Non-smi operands reach the end of the code generated by
|
| - // GenerateSmiCode, and fall through to subsequent code,
|
| - // with the operands in rdx and rax.
|
| - // But first we check if non-smi values are HeapNumbers holding
|
| - // values that could be smi.
|
| - __ bind(¬_smis);
|
| - Comment done_comment(masm, "-- Enter non-smi code");
|
| - FloatingPointHelper::ConvertUndefined convert_undefined =
|
| - FloatingPointHelper::BAILOUT_ON_UNDEFINED;
|
| - // This list must be in sync with BinaryOpPatch() behavior in ic.cc.
|
| - if (op == Token::BIT_AND ||
|
| - op == Token::BIT_OR ||
|
| - op == Token::BIT_XOR ||
|
| - op == Token::SAR ||
|
| - op == Token::SHL ||
|
| - op == Token::SHR) {
|
| - convert_undefined = FloatingPointHelper::CONVERT_UNDEFINED_TO_ZERO;
|
| - }
|
| - FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx,
|
| - &smi_values, &fail, convert_undefined);
|
| - __ jmp(&smi_values);
|
| - __ bind(&fail);
|
| -}
|
| -
|
| -
|
| -static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
|
| - Label* alloc_failure,
|
| - OverwriteMode mode);
|
| -
|
| -
|
| -static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm,
|
| - Label* allocation_failure,
|
| - Label* non_numeric_failure,
|
| - Token::Value op,
|
| - OverwriteMode mode) {
|
| - switch (op) {
|
| - case Token::ADD:
|
| - case Token::SUB:
|
| - case Token::MUL:
|
| - case Token::DIV: {
|
| - FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure);
|
| -
|
| - switch (op) {
|
| - case Token::ADD: __ addsd(xmm0, xmm1); break;
|
| - case Token::SUB: __ subsd(xmm0, xmm1); break;
|
| - case Token::MUL: __ mulsd(xmm0, xmm1); break;
|
| - case Token::DIV: __ divsd(xmm0, xmm1); break;
|
| - default: UNREACHABLE();
|
| - }
|
| - BinaryOpStub_GenerateHeapResultAllocation(
|
| - masm, allocation_failure, mode);
|
| - __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
|
| - __ ret(0);
|
| - break;
|
| - }
|
| - case Token::MOD: {
|
| - // For MOD we jump to the allocation_failure label, to call runtime.
|
| - __ jmp(allocation_failure);
|
| - break;
|
| - }
|
| - case Token::BIT_OR:
|
| - case Token::BIT_AND:
|
| - case Token::BIT_XOR:
|
| - case Token::SAR:
|
| - case Token::SHL:
|
| - case Token::SHR: {
|
| - Label non_smi_shr_result;
|
| - Register heap_number_map = r9;
|
| - __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
|
| - FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure,
|
| - heap_number_map);
|
| - switch (op) {
|
| - case Token::BIT_OR: __ orl(rax, rcx); break;
|
| - case Token::BIT_AND: __ andl(rax, rcx); break;
|
| - case Token::BIT_XOR: __ xorl(rax, rcx); break;
|
| - case Token::SAR: __ sarl_cl(rax); break;
|
| - case Token::SHL: __ shll_cl(rax); break;
|
| - case Token::SHR: {
|
| - __ shrl_cl(rax);
|
| - // Check if result is negative. This can only happen for a shift
|
| - // by zero.
|
| - __ testl(rax, rax);
|
| - __ j(negative, &non_smi_shr_result);
|
| - break;
|
| - }
|
| - default: UNREACHABLE();
|
| - }
|
| - STATIC_ASSERT(kSmiValueSize == 32);
|
| - // Tag smi result and return.
|
| - __ Integer32ToSmi(rax, rax);
|
| - __ Ret();
|
| -
|
| - // Logical shift right can produce an unsigned int32 that is not
|
| - // an int32, and so is not in the smi range. Allocate a heap number
|
| - // in that case.
|
| - if (op == Token::SHR) {
|
| - __ bind(&non_smi_shr_result);
|
| - Label allocation_failed;
|
| - __ movl(rbx, rax); // rbx holds result value (uint32 value as int64).
|
| - // Allocate heap number in new space.
|
| - // Not using AllocateHeapNumber macro in order to reuse
|
| - // already loaded heap_number_map.
|
| - __ Allocate(HeapNumber::kSize, rax, rdx, no_reg, &allocation_failed,
|
| - TAG_OBJECT);
|
| - // Set the map.
|
| - __ AssertRootValue(heap_number_map,
|
| - Heap::kHeapNumberMapRootIndex,
|
| - kHeapNumberMapRegisterClobbered);
|
| - __ movq(FieldOperand(rax, HeapObject::kMapOffset),
|
| - heap_number_map);
|
| - __ cvtqsi2sd(xmm0, rbx);
|
| - __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
|
| - __ Ret();
|
| -
|
| - __ bind(&allocation_failed);
|
| - // We need tagged values in rdx and rax for the following code,
|
| - // not int32 in rax and rcx.
|
| - __ Integer32ToSmi(rax, rcx);
|
| - __ Integer32ToSmi(rdx, rbx);
|
| - __ jmp(allocation_failure);
|
| - }
|
| - break;
|
| - }
|
| - default: UNREACHABLE(); break;
|
| - }
|
| - // No fall-through from this generated code.
|
| - if (FLAG_debug_code) {
|
| - __ Abort(kUnexpectedFallThroughInBinaryStubGenerateFloatingPointCode);
|
| - }
|
| -}
|
| -
|
| -
|
| -static void BinaryOpStub_GenerateRegisterArgsPushUnderReturn(
|
| - MacroAssembler* masm) {
|
| - // Push arguments, but ensure they are under the return address
|
| - // for a tail call.
|
| - __ PopReturnAddressTo(rcx);
|
| - __ push(rdx);
|
| - __ push(rax);
|
| - __ PushReturnAddressFrom(rcx);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
|
| - ASSERT(op_ == Token::ADD);
|
| - Label left_not_string, call_runtime;
|
| -
|
| - // Registers containing left and right operands respectively.
|
| - Register left = rdx;
|
| - Register right = rax;
|
| -
|
| - // Test if left operand is a string.
|
| - __ JumpIfSmi(left, &left_not_string, Label::kNear);
|
| - __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
|
| - __ j(above_equal, &left_not_string, Label::kNear);
|
| - StringAddStub string_add_left_stub(
|
| - (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME));
|
| - BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm);
|
| - __ TailCallStub(&string_add_left_stub);
|
| -
|
| - // Left operand is not a string, test right.
|
| - __ bind(&left_not_string);
|
| - __ JumpIfSmi(right, &call_runtime, Label::kNear);
|
| - __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
|
| - __ j(above_equal, &call_runtime, Label::kNear);
|
| -
|
| - StringAddStub string_add_right_stub(
|
| - (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME));
|
| - BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm);
|
| - __ TailCallStub(&string_add_right_stub);
|
| -
|
| - // Neither argument is a string.
|
| - __ bind(&call_runtime);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
|
| - Label right_arg_changed, call_runtime;
|
| -
|
| - if (op_ == Token::MOD && encoded_right_arg_.has_value) {
|
| - // It is guaranteed that the value will fit into a Smi, because if it
|
| - // didn't, we wouldn't be here, see BinaryOp_Patch.
|
| - __ Cmp(rax, Smi::FromInt(fixed_right_arg_value()));
|
| - __ j(not_equal, &right_arg_changed);
|
| - }
|
| -
|
| - if (result_type_ == BinaryOpIC::UNINITIALIZED ||
|
| - result_type_ == BinaryOpIC::SMI) {
|
| - // Only allow smi results.
|
| - BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_);
|
| - } else {
|
| - // Allow heap number result and don't make a transition if a heap number
|
| - // cannot be allocated.
|
| - BinaryOpStub_GenerateSmiCode(
|
| - masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
|
| - }
|
| -
|
| - // Code falls through if the result is not returned as either a smi or heap
|
| - // number.
|
| - __ bind(&right_arg_changed);
|
| - GenerateTypeTransition(masm);
|
| -
|
| - if (call_runtime.is_linked()) {
|
| - __ bind(&call_runtime);
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - GenerateRegisterArgsPush(masm);
|
| - GenerateCallRuntime(masm);
|
| - }
|
| - __ Ret();
|
| - }
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
| - // The int32 case is identical to the Smi case. We avoid creating this
|
| - // ic state on x64.
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
|
| - Label call_runtime;
|
| - ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
|
| - ASSERT(op_ == Token::ADD);
|
| - // If both arguments are strings, call the string add stub.
|
| - // Otherwise, do a transition.
|
| -
|
| - // Registers containing left and right operands respectively.
|
| - Register left = rdx;
|
| - Register right = rax;
|
| -
|
| - // Test if left operand is a string.
|
| - __ JumpIfSmi(left, &call_runtime);
|
| - __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
|
| - __ j(above_equal, &call_runtime);
|
| -
|
| - // Test if right operand is a string.
|
| - __ JumpIfSmi(right, &call_runtime);
|
| - __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
|
| - __ j(above_equal, &call_runtime);
|
| -
|
| - StringAddStub string_add_stub(
|
| - (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME));
|
| - BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm);
|
| - __ TailCallStub(&string_add_stub);
|
| -
|
| - __ bind(&call_runtime);
|
| - GenerateTypeTransition(masm);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
|
| - Label call_runtime;
|
| -
|
| - if (op_ == Token::ADD) {
|
| - // Handle string addition here, because it is the only operation
|
| - // that does not do a ToNumber conversion on the operands.
|
| - GenerateAddStrings(masm);
|
| - }
|
| -
|
| - // Convert oddball arguments to numbers.
|
| - Label check, done;
|
| - __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
|
| - __ j(not_equal, &check, Label::kNear);
|
| - if (Token::IsBitOp(op_)) {
|
| - __ xor_(rdx, rdx);
|
| - } else {
|
| - __ LoadRoot(rdx, Heap::kNanValueRootIndex);
|
| - }
|
| - __ jmp(&done, Label::kNear);
|
| - __ bind(&check);
|
| - __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
|
| - __ j(not_equal, &done, Label::kNear);
|
| - if (Token::IsBitOp(op_)) {
|
| - __ xor_(rax, rax);
|
| - } else {
|
| - __ LoadRoot(rax, Heap::kNanValueRootIndex);
|
| - }
|
| - __ bind(&done);
|
| -
|
| - GenerateNumberStub(masm);
|
| -}
|
| -
|
| -
|
| -static void BinaryOpStub_CheckSmiInput(MacroAssembler* masm,
|
| - Register input,
|
| - Label* fail) {
|
| - Label ok;
|
| - __ JumpIfSmi(input, &ok, Label::kNear);
|
| - Register heap_number_map = r8;
|
| - Register scratch1 = r9;
|
| - Register scratch2 = r10;
|
| - // HeapNumbers containing 32bit integer values are also allowed.
|
| - __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
|
| - __ cmpq(FieldOperand(input, HeapObject::kMapOffset), heap_number_map);
|
| - __ j(not_equal, fail);
|
| - __ movsd(xmm0, FieldOperand(input, HeapNumber::kValueOffset));
|
| - // Convert, convert back, and compare the two doubles' bits.
|
| - __ cvttsd2siq(scratch2, xmm0);
|
| - __ Cvtlsi2sd(xmm1, scratch2);
|
| - __ movq(scratch1, xmm0);
|
| - __ movq(scratch2, xmm1);
|
| - __ cmpq(scratch1, scratch2);
|
| - __ j(not_equal, fail);
|
| - __ bind(&ok);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
|
| - Label gc_required, not_number;
|
| -
|
| - // It could be that only SMIs have been seen at either the left
|
| - // or the right operand. For precise type feedback, patch the IC
|
| - // again if this changes.
|
| - if (left_type_ == BinaryOpIC::SMI) {
|
| - BinaryOpStub_CheckSmiInput(masm, rdx, ¬_number);
|
| - }
|
| - if (right_type_ == BinaryOpIC::SMI) {
|
| - BinaryOpStub_CheckSmiInput(masm, rax, ¬_number);
|
| - }
|
| -
|
| - BinaryOpStub_GenerateFloatingPointCode(
|
| - masm, &gc_required, ¬_number, op_, mode_);
|
| -
|
| - __ bind(¬_number);
|
| - GenerateTypeTransition(masm);
|
| -
|
| - __ bind(&gc_required);
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - GenerateRegisterArgsPush(masm);
|
| - GenerateCallRuntime(masm);
|
| - }
|
| - __ Ret();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
|
| - Label call_runtime, call_string_add_or_runtime;
|
| -
|
| - BinaryOpStub_GenerateSmiCode(
|
| - masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
|
| -
|
| - BinaryOpStub_GenerateFloatingPointCode(
|
| - masm, &call_runtime, &call_string_add_or_runtime, op_, mode_);
|
| -
|
| - __ bind(&call_string_add_or_runtime);
|
| - if (op_ == Token::ADD) {
|
| - GenerateAddStrings(masm);
|
| - }
|
| -
|
| - __ bind(&call_runtime);
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - GenerateRegisterArgsPush(masm);
|
| - GenerateCallRuntime(masm);
|
| - }
|
| - __ Ret();
|
| -}
|
| -
|
| -
|
| -static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
|
| - Label* alloc_failure,
|
| - OverwriteMode mode) {
|
| - Label skip_allocation;
|
| - switch (mode) {
|
| - case OVERWRITE_LEFT: {
|
| - // If the argument in rdx is already an object, we skip the
|
| - // allocation of a heap number.
|
| - __ JumpIfNotSmi(rdx, &skip_allocation);
|
| - // Allocate a heap number for the result. Keep rax and rdx intact
|
| - // for the possible runtime call.
|
| - __ AllocateHeapNumber(rbx, rcx, alloc_failure);
|
| - // Now rdx can be overwritten losing one of the arguments as we are
|
| - // now done and will not need it any more.
|
| - __ movq(rdx, rbx);
|
| - __ bind(&skip_allocation);
|
| - // Use object in rdx as a result holder
|
| - __ movq(rax, rdx);
|
| - break;
|
| - }
|
| - case OVERWRITE_RIGHT:
|
| - // If the argument in rax is already an object, we skip the
|
| - // allocation of a heap number.
|
| - __ JumpIfNotSmi(rax, &skip_allocation);
|
| - // Fall through!
|
| - case NO_OVERWRITE:
|
| - // Allocate a heap number for the result. Keep rax and rdx intact
|
| - // for the possible runtime call.
|
| - __ AllocateHeapNumber(rbx, rcx, alloc_failure);
|
| - // Now rax can be overwritten losing one of the arguments as we are
|
| - // now done and will not need it any more.
|
| - __ movq(rax, rbx);
|
| - __ bind(&skip_allocation);
|
| - break;
|
| - default: UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
|
| - __ push(rdx);
|
| - __ push(rax);
|
| -}
|
| -
|
| -
|
| void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
| // TAGGED case:
|
| // Input:
|
| @@ -1432,67 +854,6 @@ void TranscendentalCacheStub::GenerateOperation(
|
| }
|
|
|
|
|
| -// Input: rdx, rax are the left and right objects of a bit op.
|
| -// Output: rax, rcx are left and right integers for a bit op.
|
| -// Jump to conversion_failure: rdx and rax are unchanged.
|
| -void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
|
| - Label* conversion_failure,
|
| - Register heap_number_map) {
|
| - // Check float operands.
|
| - Label arg1_is_object, check_undefined_arg1;
|
| - Label arg2_is_object, check_undefined_arg2;
|
| - Label load_arg2, done;
|
| -
|
| - __ JumpIfNotSmi(rdx, &arg1_is_object);
|
| - __ SmiToInteger32(r8, rdx);
|
| - __ jmp(&load_arg2);
|
| -
|
| - // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
|
| - __ bind(&check_undefined_arg1);
|
| - __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
|
| - __ j(not_equal, conversion_failure);
|
| - __ Set(r8, 0);
|
| - __ jmp(&load_arg2);
|
| -
|
| - __ bind(&arg1_is_object);
|
| - __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map);
|
| - __ j(not_equal, &check_undefined_arg1);
|
| - // Get the untagged integer version of the rdx heap number in r8.
|
| - __ TruncateHeapNumberToI(r8, rdx);
|
| -
|
| - // Here r8 has the untagged integer, rax has a Smi or a heap number.
|
| - __ bind(&load_arg2);
|
| - // Test if arg2 is a Smi.
|
| - __ JumpIfNotSmi(rax, &arg2_is_object);
|
| - __ SmiToInteger32(rcx, rax);
|
| - __ jmp(&done);
|
| -
|
| - // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
|
| - __ bind(&check_undefined_arg2);
|
| - __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
|
| - __ j(not_equal, conversion_failure);
|
| - __ Set(rcx, 0);
|
| - __ jmp(&done);
|
| -
|
| - __ bind(&arg2_is_object);
|
| - __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map);
|
| - __ j(not_equal, &check_undefined_arg2);
|
| - // Get the untagged integer version of the rax heap number in rcx.
|
| - __ TruncateHeapNumberToI(rcx, rax);
|
| -
|
| - __ bind(&done);
|
| - __ movl(rax, r8);
|
| -}
|
| -
|
| -
|
| -void FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) {
|
| - __ SmiToInteger32(kScratchRegister, rdx);
|
| - __ Cvtlsi2sd(xmm0, kScratchRegister);
|
| - __ SmiToInteger32(kScratchRegister, rax);
|
| - __ Cvtlsi2sd(xmm1, kScratchRegister);
|
| -}
|
| -
|
| -
|
| void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
|
| Label* not_numbers) {
|
| Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done;
|
| @@ -1523,83 +884,6 @@ void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
|
| }
|
|
|
|
|
| -void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
|
| - Register first,
|
| - Register second,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Register scratch3,
|
| - Label* on_success,
|
| - Label* on_not_smis,
|
| - ConvertUndefined convert_undefined) {
|
| - Register heap_number_map = scratch3;
|
| - Register smi_result = scratch1;
|
| - Label done, maybe_undefined_first, maybe_undefined_second, first_done;
|
| -
|
| - __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
|
| -
|
| - Label first_smi;
|
| - __ JumpIfSmi(first, &first_smi, Label::kNear);
|
| - __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map);
|
| - __ j(not_equal,
|
| - (convert_undefined == CONVERT_UNDEFINED_TO_ZERO)
|
| - ? &maybe_undefined_first
|
| - : on_not_smis);
|
| - // Convert HeapNumber to smi if possible.
|
| - __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset));
|
| - __ movq(scratch2, xmm0);
|
| - __ cvttsd2siq(smi_result, xmm0);
|
| - // Check if conversion was successful by converting back and
|
| - // comparing to the original double's bits.
|
| - __ Cvtlsi2sd(xmm1, smi_result);
|
| - __ movq(kScratchRegister, xmm1);
|
| - __ cmpq(scratch2, kScratchRegister);
|
| - __ j(not_equal, on_not_smis);
|
| - __ Integer32ToSmi(first, smi_result);
|
| -
|
| - __ bind(&first_done);
|
| - __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done);
|
| - __ bind(&first_smi);
|
| - __ AssertNotSmi(second);
|
| - __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map);
|
| - __ j(not_equal,
|
| - (convert_undefined == CONVERT_UNDEFINED_TO_ZERO)
|
| - ? &maybe_undefined_second
|
| - : on_not_smis);
|
| - // Convert second to smi, if possible.
|
| - __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset));
|
| - __ movq(scratch2, xmm0);
|
| - __ cvttsd2siq(smi_result, xmm0);
|
| - __ Cvtlsi2sd(xmm1, smi_result);
|
| - __ movq(kScratchRegister, xmm1);
|
| - __ cmpq(scratch2, kScratchRegister);
|
| - __ j(not_equal, on_not_smis);
|
| - __ Integer32ToSmi(second, smi_result);
|
| - if (on_success != NULL) {
|
| - __ jmp(on_success);
|
| - } else {
|
| - __ jmp(&done);
|
| - }
|
| -
|
| - __ bind(&maybe_undefined_first);
|
| - __ CompareRoot(first, Heap::kUndefinedValueRootIndex);
|
| - __ j(not_equal, on_not_smis);
|
| - __ xor_(first, first);
|
| - __ jmp(&first_done);
|
| -
|
| - __ bind(&maybe_undefined_second);
|
| - __ CompareRoot(second, Heap::kUndefinedValueRootIndex);
|
| - __ j(not_equal, on_not_smis);
|
| - __ xor_(second, second);
|
| - if (on_success != NULL) {
|
| - __ jmp(on_success);
|
| - }
|
| - // Else: fall through.
|
| -
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void MathPowStub::Generate(MacroAssembler* masm) {
|
| const Register exponent = rdx;
|
| const Register base = rax;
|
| @@ -3466,6 +2750,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
|
| RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
|
| ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
|
| CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
|
| + BinaryOpStub::GenerateAheadOfTime(isolate);
|
| }
|
|
|
|
|
|
|