| Index: src/a64/code-stubs-a64.cc
|
| diff --git a/src/a64/code-stubs-a64.cc b/src/a64/code-stubs-a64.cc
|
| index dcc8c1167c14400f63bc6b48bf0407b84d1a097b..f9dbf847d90e55322322f06f28152f7360a195c5 100644
|
| --- a/src/a64/code-stubs-a64.cc
|
| +++ b/src/a64/code-stubs-a64.cc
|
| @@ -189,6 +189,20 @@ void CompareNilICStub::InitializeInterfaceDescriptor(
|
| }
|
|
|
|
|
| +void BinaryOpStub::InitializeInterfaceDescriptor(
|
| + Isolate* isolate,
|
| + CodeStubInterfaceDescriptor* descriptor) {
|
| + // x1: left operand
|
| + // x0: right operand
|
| + static Register registers[] = { x1, x0 };
|
| + descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]);
|
| + 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,
|
| @@ -959,701 +973,6 @@ void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
|
| }
|
|
|
|
|
| -void BinaryOpStub::Initialize() {
|
| - // Nothing to do here.
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateTypeTransition");
|
| - Label get_result;
|
| -
|
| - __ Mov(x12, Operand(Smi::FromInt(MinorKey())));
|
| - __ Push(x1, x0, x12);
|
| -
|
| - __ TailCallExternalReference(
|
| - ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()),
|
| - 3,
|
| - 1);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(
|
| - MacroAssembler* masm) {
|
| - UNIMPLEMENTED();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
|
| - Token::Value op) {
|
| - ASM_LOCATION("BinaryOpStub_GenerateSmiSmiOperation");
|
| - Register left = x1;
|
| - Register right = x0;
|
| - Register scratch1 = x10;
|
| - Register scratch2 = x11;
|
| - // Note that 'result' aliases 'right'. The code below must care not to
|
| - // overwrite 'right' before it is certain it won't be needed.
|
| - Register result = x0;
|
| -
|
| - // Adapt the code below if that does not hold.
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - STATIC_ASSERT(kSmiShift == 32);
|
| -
|
| - // TODO(alexandre): The code below mostly uses 64-bits operations, knowing
|
| - // that the input are Smis.
|
| - // Use of 32-bits instructions should be investigated. For example maybe speed
|
| - // or power consumption could be improved.
|
| -
|
| - Label overflow, not_smi_result;
|
| - switch (op) {
|
| - case Token::ADD:
|
| - __ Adds(result, left, right); // Add optimistically.
|
| - __ B(vs, &overflow);
|
| - __ Ret();
|
| - __ Bind(&overflow);
|
| - // Revert optimistic add.
|
| - __ Sub(right, result, left);
|
| - break;
|
| -
|
| - case Token::SUB:
|
| - // Subtract optimistically.
|
| - __ Subs(result, left, right);
|
| - __ B(vs, &overflow);
|
| - __ Ret();
|
| - __ Bind(&overflow);
|
| - // Revert optimistic subtract.
|
| - __ Sub(right, left, result);
|
| - break;
|
| -
|
| - case Token::MUL: {
|
| - Label not_minus_zero;
|
| -
|
| - // Use smulh to avoid shifting right the inputs.
|
| - // scratch1 = bits<127:64> of left * right.
|
| - __ Smulh(scratch1, left, right);
|
| -
|
| - // Check if the result is a Smi.
|
| - __ Cbnz(scratch1, ¬_minus_zero);
|
| -
|
| - // Check for minus zero.
|
| - // Exclusive or the arguments and check the sign bit of the result.
|
| - __ Eor(scratch2, left, right);
|
| - __ Tbnz(scratch2, kXSignBit, ¬_smi_result);
|
| -
|
| - // At this point, the result is zero, which needs no smi conversion.
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - __ Mov(result, scratch1);
|
| - __ Ret();
|
| -
|
| - __ Bind(¬_minus_zero);
|
| - // Check if the result is a signed 32 bits.
|
| - // It is if bits 63-31 are sign bits.
|
| - __ Cls(scratch2, scratch1);
|
| - __ Cmp(scratch2, kXRegSize - kSmiShift);
|
| - __ B(lt, ¬_smi_result);
|
| -
|
| - // Tag the result.
|
| - __ SmiTag(result, scratch1);
|
| - __ Ret();
|
| - break;
|
| - }
|
| -
|
| - case Token::DIV: {
|
| - // Check for division by zero.
|
| - __ Cbz(right, ¬_smi_result);
|
| - // Try integer division.
|
| - // If the remainder is not zero jump the result is not a Smi.
|
| - __ Sdiv(scratch1, left, right);
|
| - // scratch2 = quotient * right.
|
| - __ Mul(scratch2, scratch1, right);
|
| - __ Cmp(scratch2, left);
|
| - __ B(ne, ¬_smi_result);
|
| - // Check for -0 (result is zero and right is negative).
|
| - Label not_minus_zero;
|
| - __ Cbnz(scratch1, ¬_minus_zero);
|
| - __ Tbnz(right, kXSignBit, ¬_smi_result);
|
| - __ Bind(¬_minus_zero);
|
| - // Check for minus_int / -1.
|
| - __ Eor(scratch2, scratch1, 1L << 31);
|
| - __ Cbz(scratch2, ¬_smi_result);
|
| - // Tag the result and return.
|
| - __ SmiTag(result, scratch1);
|
| - __ Ret();
|
| - break;
|
| - }
|
| -
|
| - case Token::MOD: {
|
| - Label not_minus_zero;
|
| - // Check for division by zero.
|
| - __ Cbz(right, ¬_smi_result);
|
| - // Compute:
|
| - // modulo = left - quotient * right
|
| - __ Sdiv(scratch1, left, right);
|
| - __ Msub(scratch1, scratch1, right, left);
|
| - __ Cbnz(scratch1, ¬_minus_zero);
|
| - // Check if the result should be minus zero.
|
| - __ Tbnz(left, kXSignBit, ¬_smi_result);
|
| - __ Bind(¬_minus_zero);
|
| - __ Mov(result, scratch1);
|
| - __ Ret();
|
| - break;
|
| - }
|
| -
|
| - case Token::BIT_OR:
|
| - __ Orr(result, left, right);
|
| - __ Ret();
|
| - break;
|
| -
|
| - case Token::BIT_AND:
|
| - __ And(result, left, right);
|
| - __ Ret();
|
| - break;
|
| -
|
| - case Token::BIT_XOR:
|
| - __ Eor(result, left, right);
|
| - __ Ret();
|
| - break;
|
| -
|
| - // For shift operations, only the 5 least significant bits of the rhs
|
| - // are used (see ECMA-262 11.7.1 and following).
|
| - // We would like to use the implicit masking operation performed by the
|
| - // shift instructions, but that would require using W registers and thus
|
| - // untagging.
|
| - case Token::SAR:
|
| - __ Ubfx(right, right, kSmiShift, 5);
|
| - __ Asr(result, left, right);
|
| - __ Bic(result, result, kSmiShiftMask);
|
| - __ Ret();
|
| - break;
|
| -
|
| - case Token::SHR: {
|
| - __ Ubfx(scratch1, right, kSmiShift, 5);
|
| - // SHR must not yield a negative value. This can only happen if left is
|
| - // negative and we shift right by zero.
|
| - Label right_not_zero;
|
| - __ Cbnz(scratch1, &right_not_zero);
|
| - __ Tbnz(left, kXSignBit, ¬_smi_result);
|
| - __ Bind(&right_not_zero);
|
| - __ Lsr(result, left, scratch1);
|
| - __ Bic(result, result, kSmiShiftMask);
|
| - __ Ret();
|
| - break;
|
| - }
|
| -
|
| - case Token::SHL:
|
| - __ Ubfx(scratch1, right, kSmiShift, 5);
|
| - __ Lsl(result, left, scratch1);
|
| - __ Ret();
|
| - break;
|
| -
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -
|
| - __ Bind(¬_smi_result);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
|
| - Register result,
|
| - Register heap_number_map,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Label* gc_required,
|
| - OverwriteMode mode);
|
| -
|
| -
|
| -void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
| - BinaryOpIC::TypeInfo left_type,
|
| - BinaryOpIC::TypeInfo right_type,
|
| - bool smi_operands,
|
| - Label* not_numbers,
|
| - Label* gc_required,
|
| - Label* miss,
|
| - Token::Value op,
|
| - OverwriteMode mode) {
|
| - ASM_LOCATION("BinaryOpStub_GenerateFPOperation");
|
| -
|
| - Register result = x0;
|
| - FPRegister result_d = d0;
|
| - Register right = x0;
|
| - Register left = x1;
|
| - Register heap_result = x21;
|
| -
|
| - ASSERT(smi_operands || (not_numbers != NULL));
|
| - if (smi_operands) {
|
| - __ AssertSmi(left);
|
| - __ AssertSmi(right);
|
| - }
|
| - if (left_type == BinaryOpIC::SMI) {
|
| - __ JumpIfNotSmi(left, miss);
|
| - }
|
| - if (right_type == BinaryOpIC::SMI) {
|
| - __ JumpIfNotSmi(right, miss);
|
| - }
|
| -
|
| - Register heap_number_map = x2;
|
| - __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
|
| -
|
| - switch (op) {
|
| - case Token::ADD:
|
| - case Token::SUB:
|
| - case Token::MUL:
|
| - case Token::DIV:
|
| - case Token::MOD: {
|
| - FPRegister left_d = d0;
|
| - FPRegister right_d = d1;
|
| - Label do_operation;
|
| -
|
| - __ SmiUntagToDouble(left_d, left, kSpeculativeUntag);
|
| - __ SmiUntagToDouble(right_d, right, kSpeculativeUntag);
|
| -
|
| - if (!smi_operands) {
|
| - if (left_type != BinaryOpIC::SMI) {
|
| - Label left_done;
|
| - Label* left_not_heap =
|
| - (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
|
| - __ JumpIfSmi(left, &left_done);
|
| -
|
| - // Left not smi: load if heap number.
|
| - __ JumpIfNotHeapNumber(left, left_not_heap, heap_number_map);
|
| - __ Ldr(left_d, FieldMemOperand(left, HeapNumber::kValueOffset));
|
| - __ Bind(&left_done);
|
| - }
|
| -
|
| - if (right_type != BinaryOpIC::SMI) {
|
| - Label* right_not_heap =
|
| - (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
|
| - __ JumpIfSmi(right, &do_operation);
|
| -
|
| - // Right not smi: load if heap number.
|
| - __ JumpIfNotHeapNumber(right, right_not_heap, heap_number_map);
|
| - __ Ldr(right_d, FieldMemOperand(right, HeapNumber::kValueOffset));
|
| - }
|
| - }
|
| -
|
| - // Left and right are doubles in left_d and right_d. Calculate the result.
|
| - __ Bind(&do_operation);
|
| -
|
| - BinaryOpStub_GenerateHeapResultAllocation(
|
| - masm, heap_result, heap_number_map, x10, x11, gc_required, mode);
|
| -
|
| - switch (op) {
|
| - case Token::ADD: __ Fadd(result_d, left_d, right_d); break;
|
| - case Token::SUB: __ Fsub(result_d, left_d, right_d); break;
|
| - case Token::MUL: __ Fmul(result_d, left_d, right_d); break;
|
| - case Token::DIV: __ Fdiv(result_d, left_d, right_d); break;
|
| - case Token::MOD: {
|
| - Register saved_lr = x20;
|
| - __ Mov(saved_lr, lr);
|
| - AllowExternalCallThatCantCauseGC scope(masm);
|
| - __ CallCFunction(
|
| - ExternalReference::double_fp_operation(op, masm->isolate()),
|
| - 0, 2);
|
| - __ Mov(lr, saved_lr);
|
| - break;
|
| - }
|
| - default: UNREACHABLE();
|
| - }
|
| -
|
| - __ Str(result_d, FieldMemOperand(heap_result, HeapNumber::kValueOffset));
|
| - __ Mov(result, heap_result);
|
| - __ Ret();
|
| - break;
|
| - }
|
| -
|
| - case Token::BIT_OR:
|
| - case Token::BIT_XOR:
|
| - case Token::BIT_AND:
|
| - case Token::SAR:
|
| - case Token::SHR:
|
| - case Token::SHL: {
|
| - Label do_operation, result_not_smi;
|
| -
|
| - if (!smi_operands) {
|
| - Label left_is_smi;
|
| - // Convert heap number operands to smis.
|
| - if (left_type != BinaryOpIC::SMI) {
|
| - __ JumpIfSmi(left, &left_is_smi);
|
| - __ JumpIfNotHeapNumber(left, not_numbers, heap_number_map);
|
| - __ HeapNumberECMA262ToInt32(left, left, x10, x11, d0,
|
| - MacroAssembler::SMI);
|
| - }
|
| - __ Bind(&left_is_smi);
|
| - if (right_type != BinaryOpIC::SMI) {
|
| - __ JumpIfSmi(right, &do_operation);
|
| - __ JumpIfNotHeapNumber(right, not_numbers, heap_number_map);
|
| - __ HeapNumberECMA262ToInt32(right, right, x10, x11, d0,
|
| - MacroAssembler::SMI);
|
| - }
|
| - }
|
| -
|
| - // Left and right are smis. Calculate the result.
|
| - __ Bind(&do_operation);
|
| - switch (op) {
|
| - case Token::BIT_OR: __ Orr(result, left, right); break;
|
| - case Token::BIT_XOR: __ Eor(result, left, right); break;
|
| - case Token::BIT_AND: __ And(result, left, right); break;
|
| -
|
| - // For shift operations, only the 5 least significant bits of the rhs
|
| - // are used (see ECMA-262 11.7.1 and following).
|
| - // We would like to use the implicit masking operation performed by the
|
| - // shift instructions, but that would require using W registers and thus
|
| - // untagging.
|
| - case Token::SAR:
|
| - __ Ubfx(right, right, kSmiShift, 5);
|
| - __ Asr(result, left, right);
|
| - // Clear bits shifted right.
|
| - __ Bic(result, result, kSmiShiftMask);
|
| - break;
|
| - case Token::SHL:
|
| - __ Ubfx(right, right, kSmiShift, 5);
|
| - __ Lsl(result, left, right);
|
| - break;
|
| - case Token::SHR: {
|
| - Label ok;
|
| - // SHR must always yield a positive result.
|
| - // This is a problem if right is zero and left is negative.
|
| - __ Ubfx(right, right, kSmiShift, 5);
|
| - __ Cbnz(right, &ok);
|
| - __ Cmp(left, 0);
|
| - __ B(mi, &result_not_smi);
|
| - __ Bind(&ok);
|
| - __ Lsr(result, left, right);
|
| - // Clear bits shifted right.
|
| - __ Bic(result, result, kSmiShiftMask);
|
| - break;
|
| - }
|
| - default: UNREACHABLE();
|
| - }
|
| - __ Ret();
|
| -
|
| - __ Bind(&result_not_smi);
|
| - // We know the operation was shift right, the left operand is negative,
|
| - // and the right is zero. The result will be the left operand cast to a
|
| - // positive value, as a heap number.
|
| - __ Ucvtf(result_d, left, kSmiShift);
|
| - if (smi_operands) {
|
| - __ AllocateHeapNumber(heap_result, gc_required, x10, x11,
|
| - heap_number_map);
|
| - } else {
|
| - BinaryOpStub_GenerateHeapResultAllocation(masm, heap_result,
|
| - heap_number_map, x10, x11,
|
| - gc_required, mode);
|
| - }
|
| -
|
| - // Nothing can go wrong now, so move the heap number to the result
|
| - // register.
|
| - __ Mov(result, heap_result);
|
| -
|
| - // Now store the double result into the allocated heap number, and return.
|
| - __ Str(result_d, FieldMemOperand(result, HeapNumber::kValueOffset));
|
| - __ Ret();
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| -// Generate the smi code. If the operation on smis are successful this return is
|
| -// generated. If the result is not a smi and heap number allocation is not
|
| -// requested the code falls through. If number allocation is requested but a
|
| -// heap number cannot be allocated the code jumps to the label gc_required.
|
| -void BinaryOpStub_GenerateSmiCode(
|
| - MacroAssembler* masm,
|
| - Label* use_runtime,
|
| - Label* gc_required,
|
| - Token::Value op,
|
| - BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
|
| - OverwriteMode mode) {
|
| - ASM_LOCATION("BinaryOpStub_GenerateSmiCode");
|
| - Label not_smis;
|
| -
|
| - Register left = x1;
|
| - Register right = x0;
|
| -
|
| - // Perform combined smi check on both operands.
|
| - __ JumpIfEitherNotSmi(left, right, ¬_smis);
|
| -
|
| - // If the smi-smi operation results in a smi, the result is returned from the
|
| - // code generated for the operation. Otherwise, execution falls through to
|
| - // the following code.
|
| - BinaryOpStub_GenerateSmiSmiOperation(masm, op);
|
| -
|
| - // If heap number results are allowed, generate the result in an allocated
|
| - // heap number.
|
| - if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) {
|
| - BinaryOpStub_GenerateFPOperation(masm, BinaryOpIC::UNINITIALIZED,
|
| - BinaryOpIC::UNINITIALIZED, true,
|
| - use_runtime, gc_required, ¬_smis, op,
|
| - mode);
|
| - }
|
| -
|
| - __ Bind(¬_smis);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateSmiStub");
|
| - 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.
|
| - __ CompareAndBranch(x0, Operand(Smi::FromInt(fixed_right_arg_value())), ne,
|
| - &right_arg_changed);
|
| - }
|
| -
|
| -#ifdef DEBUG
|
| - Register saved_left = x18;
|
| - Register saved_right = x19;
|
| - if (masm->emit_debug_code()) {
|
| - __ Mov(saved_left, x1);
|
| - __ Mov(saved_right, x0);
|
| - }
|
| -#endif
|
| -
|
| - if (result_type_ == BinaryOpIC::UNINITIALIZED ||
|
| - result_type_ == BinaryOpIC::SMI) {
|
| - // Only allow smi results. No allocation should take place, so we don't need
|
| - // a label for gc.
|
| - BinaryOpStub_GenerateSmiCode(masm, &call_runtime, NULL, op_,
|
| - NO_HEAPNUMBER_RESULTS, mode_);
|
| - } else {
|
| - // Allow heap number result and don't make a transition if a heap number
|
| - // cannot be allocated.
|
| - BinaryOpStub_GenerateSmiCode(masm, &call_runtime, &call_runtime, op_,
|
| - ALLOW_HEAPNUMBER_RESULTS, mode_);
|
| - }
|
| -
|
| - // Code falls through if the result is not returned as either a smi or heap
|
| - // number.
|
| - __ Bind(&right_arg_changed);
|
| - GenerateTypeTransition(masm);
|
| -
|
| - __ Bind(&call_runtime);
|
| -#ifdef DEBUG
|
| - if (masm->emit_debug_code()) {
|
| - __ Cmp(saved_left, x1);
|
| - __ Assert(eq, kLhsHasBeenClobbered);
|
| - __ Cmp(saved_right, x0);
|
| - __ Assert(eq, kRhsHasBeenClobbered);
|
| - }
|
| -#endif
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - GenerateRegisterArgsPush(masm);
|
| - GenerateCallRuntime(masm);
|
| - }
|
| - __ Ret();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateBothStringStub");
|
| - ASSERT((left_type_ == BinaryOpIC::STRING) &&
|
| - (right_type_ == BinaryOpIC::STRING));
|
| - ASSERT(op_ == Token::ADD);
|
| - Label call_transition;
|
| -
|
| - // If both arguments are strings, call the string add stub. Otherwise, do a
|
| - // transition.
|
| -
|
| - Register left = x1;
|
| - Register right = x0;
|
| -
|
| - // Test if left operand is a smi or string.
|
| - __ JumpIfSmi(left, &call_transition);
|
| - __ JumpIfObjectType(left, x2, x2, FIRST_NONSTRING_TYPE, &call_transition, ge);
|
| -
|
| - // Test if right operand is a smi or string.
|
| - __ JumpIfSmi(right, &call_transition);
|
| - __ JumpIfObjectType(right, x2, x2, FIRST_NONSTRING_TYPE, &call_transition,
|
| - ge);
|
| -
|
| - StringAddStub string_add_stub(
|
| - static_cast<StringAddFlags>(STRING_ADD_CHECK_NONE |
|
| - STRING_ADD_ERECT_FRAME));
|
| - GenerateRegisterArgsPush(masm);
|
| - __ TailCallStub(&string_add_stub);
|
| -
|
| - __ Bind(&call_transition);
|
| - GenerateTypeTransition(masm);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
| - // On a64 the smis are 32 bits, so we should never see the INT32 type.
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateOddballStub");
|
| - Register right = x0;
|
| - Register left = x1;
|
| -
|
| - 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;
|
| - __ JumpIfNotRoot(left, Heap::kUndefinedValueRootIndex, &check);
|
| - if (Token::IsBitOp(op_)) {
|
| - __ Mov(left, 0);
|
| - } else {
|
| - __ LoadRoot(left, Heap::kNanValueRootIndex);
|
| - }
|
| - __ B(&done);
|
| -
|
| - __ Bind(&check);
|
| - __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &done);
|
| - if (Token::IsBitOp(op_)) {
|
| - __ Mov(right, 0);
|
| - } else {
|
| - __ LoadRoot(right, Heap::kNanValueRootIndex);
|
| - }
|
| -
|
| - __ Bind(&done);
|
| -
|
| - GenerateNumberStub(masm);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateNumberStub");
|
| - Label call_runtime, transition;
|
| -
|
| - BinaryOpStub_GenerateFPOperation(masm, left_type_, right_type_, false,
|
| - &transition, &call_runtime, &transition,
|
| - op_, mode_);
|
| -
|
| - __ Bind(&transition);
|
| - GenerateTypeTransition(masm);
|
| -
|
| - __ Bind(&call_runtime);
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - GenerateRegisterArgsPush(masm);
|
| - GenerateCallRuntime(masm);
|
| - }
|
| - __ Ret();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateGeneric");
|
| - Label call_runtime, call_string_add_or_runtime, transition;
|
| -
|
| - BinaryOpStub_GenerateSmiCode(masm, &call_runtime, &call_runtime, op_,
|
| - ALLOW_HEAPNUMBER_RESULTS, mode_);
|
| -
|
| - BinaryOpStub_GenerateFPOperation(masm, left_type_, right_type_, false,
|
| - &call_string_add_or_runtime, &call_runtime,
|
| - &transition, op_, mode_);
|
| -
|
| - __ Bind(&transition);
|
| - GenerateTypeTransition(masm);
|
| -
|
| - __ 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();
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateAddStrings");
|
| - ASSERT(op_ == Token::ADD);
|
| - Label left_not_string, call_runtime;
|
| -
|
| - Register left = x1;
|
| - Register right = x0;
|
| -
|
| - // Check if left argument is a string.
|
| - __ JumpIfSmi(left, &left_not_string);
|
| - __ JumpIfObjectType(left, x2, x2, FIRST_NONSTRING_TYPE, &left_not_string, ge);
|
| -
|
| - StringAddStub string_add_left_stub(
|
| - static_cast<StringAddFlags>(STRING_ADD_CHECK_RIGHT |
|
| - STRING_ADD_ERECT_FRAME));
|
| - GenerateRegisterArgsPush(masm);
|
| - __ TailCallStub(&string_add_left_stub);
|
| -
|
| - // Left operand is not a string, test right.
|
| - __ Bind(&left_not_string);
|
| - __ JumpIfSmi(right, &call_runtime);
|
| - __ JumpIfObjectType(right, x2, x2, FIRST_NONSTRING_TYPE, &call_runtime, ge);
|
| -
|
| - StringAddStub string_add_right_stub(
|
| - static_cast<StringAddFlags>(STRING_ADD_CHECK_LEFT |
|
| - STRING_ADD_ERECT_FRAME));
|
| - GenerateRegisterArgsPush(masm);
|
| - __ TailCallStub(&string_add_right_stub);
|
| -
|
| - // Neither argument is a string.
|
| - __ Bind(&call_runtime);
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
|
| - Register result,
|
| - Register heap_number_map,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Label* gc_required,
|
| - OverwriteMode mode) {
|
| - ASM_LOCATION("BinaryOpStub::GenerateHeapResultAllocation");
|
| - ASSERT(!AreAliased(result, heap_number_map, scratch1, scratch2));
|
| -
|
| - if ((mode == OVERWRITE_LEFT) || (mode == OVERWRITE_RIGHT)) {
|
| - Label skip_allocation, allocated;
|
| - Register overwritable_operand = (mode == OVERWRITE_LEFT) ? x1 : x0;
|
| - if (masm->emit_debug_code()) {
|
| - // Check that the overwritable operand is a Smi or a HeapNumber.
|
| - Label ok;
|
| - __ JumpIfSmi(overwritable_operand, &ok);
|
| - __ JumpIfHeapNumber(overwritable_operand, &ok);
|
| - __ Abort(kExpectedSmiOrHeapNumber);
|
| - __ Bind(&ok);
|
| - }
|
| - // If the overwritable operand is already a HeapNumber, we can skip
|
| - // allocation of a heap number.
|
| - __ JumpIfNotSmi(overwritable_operand, &skip_allocation);
|
| - // Allocate a heap number for the result.
|
| - __ AllocateHeapNumber(result, gc_required, scratch1, scratch2,
|
| - heap_number_map);
|
| - __ B(&allocated);
|
| - __ Bind(&skip_allocation);
|
| - // Use object holding the overwritable operand for result.
|
| - __ Mov(result, overwritable_operand);
|
| - __ Bind(&allocated);
|
| - } else {
|
| - ASSERT(mode == NO_OVERWRITE);
|
| - __ AllocateHeapNumber(result, gc_required, scratch1, scratch2,
|
| - heap_number_map);
|
| - }
|
| -}
|
| -
|
| -
|
| -void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
|
| - __ Push(x1, x0);
|
| -}
|
| -
|
| -
|
| void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
| // Untagged case:
|
| // Input: double in d0
|
| @@ -2141,6 +1460,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
|
| RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
|
| ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
|
| CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
|
| + BinaryOpStub::GenerateAheadOfTime(isolate);
|
| }
|
|
|
|
|
|
|