| Index: src/x64/lithium-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/lithium-codegen-x64.cc (revision 6703)
|
| +++ src/x64/lithium-codegen-x64.cc (working copy)
|
| @@ -593,7 +593,56 @@
|
|
|
|
|
| void LCodeGen::DoCallStub(LCallStub* instr) {
|
| - Abort("Unimplemented: %s", "DoCallStub");
|
| + ASSERT(ToRegister(instr->result()).is(rax));
|
| + switch (instr->hydrogen()->major_key()) {
|
| + case CodeStub::RegExpConstructResult: {
|
| + RegExpConstructResultStub stub;
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + case CodeStub::RegExpExec: {
|
| + RegExpExecStub stub;
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + case CodeStub::SubString: {
|
| + SubStringStub stub;
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + case CodeStub::StringCharAt: {
|
| + // TODO(1116): Add StringCharAt stub to x64.
|
| + Abort("Unimplemented: %s", "StringCharAt Stub");
|
| + break;
|
| + }
|
| + case CodeStub::MathPow: {
|
| + // TODO(1115): Add MathPow stub to x64.
|
| + Abort("Unimplemented: %s", "MathPow Stub");
|
| + break;
|
| + }
|
| + case CodeStub::NumberToString: {
|
| + NumberToStringStub stub;
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + case CodeStub::StringAdd: {
|
| + StringAddStub stub(NO_STRING_ADD_FLAGS);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + case CodeStub::StringCompare: {
|
| + StringCompareStub stub;
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + case CodeStub::TranscendentalCache: {
|
| + TranscendentalCacheStub stub(instr->transcendental_type());
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
| @@ -608,13 +657,94 @@
|
|
|
|
|
| void LCodeGen::DoDivI(LDivI* instr) {
|
| - Abort("Unimplemented: %s", "DoDivI");}
|
| + LOperand* right = instr->InputAt(1);
|
| + ASSERT(ToRegister(instr->result()).is(rax));
|
| + ASSERT(ToRegister(instr->InputAt(0)).is(rax));
|
| + ASSERT(!ToRegister(instr->InputAt(1)).is(rax));
|
| + ASSERT(!ToRegister(instr->InputAt(1)).is(rdx));
|
|
|
| + Register left_reg = rax;
|
|
|
| + // Check for x / 0.
|
| + Register right_reg = ToRegister(right);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
| + __ testl(right_reg, right_reg);
|
| + DeoptimizeIf(zero, instr->environment());
|
| + }
|
| +
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + NearLabel left_not_zero;
|
| + __ testl(left_reg, left_reg);
|
| + __ j(not_zero, &left_not_zero);
|
| + __ testl(right_reg, right_reg);
|
| + DeoptimizeIf(sign, instr->environment());
|
| + __ bind(&left_not_zero);
|
| + }
|
| +
|
| + // Check for (-kMinInt / -1).
|
| + if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
| + NearLabel left_not_min_int;
|
| + __ cmpl(left_reg, Immediate(kMinInt));
|
| + __ j(not_zero, &left_not_min_int);
|
| + __ cmpl(right_reg, Immediate(-1));
|
| + DeoptimizeIf(zero, instr->environment());
|
| + __ bind(&left_not_min_int);
|
| + }
|
| +
|
| + // Sign extend to rdx.
|
| + __ cdq();
|
| + __ idivl(right_reg);
|
| +
|
| + // Deoptimize if remainder is not 0.
|
| + __ testl(rdx, rdx);
|
| + DeoptimizeIf(not_zero, instr->environment());
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoMulI(LMulI* instr) {
|
| - Abort("Unimplemented: %s", "DoMultI");}
|
| + Register left = ToRegister(instr->InputAt(0));
|
| + LOperand* right = instr->InputAt(1);
|
|
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + __ movl(kScratchRegister, left);
|
| + }
|
|
|
| + if (right->IsConstantOperand()) {
|
| + int right_value = ToInteger32(LConstantOperand::cast(right));
|
| + __ imull(left, left, Immediate(right_value));
|
| + } else if (right->IsStackSlot()) {
|
| + __ imull(left, ToOperand(right));
|
| + } else {
|
| + __ imull(left, ToRegister(right));
|
| + }
|
| +
|
| + if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
| + DeoptimizeIf(overflow, instr->environment());
|
| + }
|
| +
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + // Bail out if the result is supposed to be negative zero.
|
| + NearLabel done;
|
| + __ testl(left, left);
|
| + __ j(not_zero, &done);
|
| + if (right->IsConstantOperand()) {
|
| + if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
|
| + DeoptimizeIf(no_condition, instr->environment());
|
| + }
|
| + } else if (right->IsStackSlot()) {
|
| + __ or_(kScratchRegister, ToOperand(right));
|
| + DeoptimizeIf(sign, instr->environment());
|
| + } else {
|
| + // Test the non-zero operand for negative sign.
|
| + __ or_(kScratchRegister, ToRegister(right));
|
| + DeoptimizeIf(sign, instr->environment());
|
| + }
|
| + __ bind(&done);
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoBitI(LBitI* instr) {
|
| LOperand* left = instr->InputAt(0);
|
| LOperand* right = instr->InputAt(1);
|
| @@ -810,7 +940,13 @@
|
|
|
|
|
| void LCodeGen::DoThrow(LThrow* instr) {
|
| - Abort("Unimplemented: %s", "DoThrow");
|
| + __ push(ToRegister(instr->InputAt(0)));
|
| + CallRuntime(Runtime::kThrow, 1, instr);
|
| +
|
| + if (FLAG_debug_code) {
|
| + Comment("Unreachable code.");
|
| + __ int3();
|
| + }
|
| }
|
|
|
|
|
| @@ -844,8 +980,7 @@
|
| ASSERT(ToRegister(instr->InputAt(1)).is(rax));
|
| ASSERT(ToRegister(instr->result()).is(rax));
|
|
|
| - GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, NO_GENERIC_BINARY_FLAGS);
|
| - stub.SetArgsInRegisters();
|
| + TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -963,7 +1098,11 @@
|
|
|
|
|
| void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
|
| - Abort("Unimplemented: %s", "DoDeferredStackCheck");
|
| + __ Pushad();
|
| + __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
|
| + RecordSafepointWithRegisters(
|
| + instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| + __ Popad();
|
| }
|
|
|
|
|
| @@ -1022,9 +1161,9 @@
|
| __ cmpl(ToOperand(left), Immediate(value));
|
| }
|
| } else if (right->IsRegister()) {
|
| - __ cmpq(ToRegister(left), ToRegister(right));
|
| + __ cmpl(ToRegister(left), ToRegister(right));
|
| } else {
|
| - __ cmpq(ToRegister(left), ToOperand(right));
|
| + __ cmpl(ToRegister(left), ToOperand(right));
|
| }
|
| }
|
|
|
| @@ -1511,12 +1650,23 @@
|
| }
|
| __ movq(rsp, rbp);
|
| __ pop(rbp);
|
| - __ ret((ParameterCount() + 1) * kPointerSize);
|
| + __ Ret((ParameterCount() + 1) * kPointerSize, rcx);
|
| }
|
|
|
|
|
| void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
|
| - Abort("Unimplemented: %s", "DoLoadGlobal");
|
| + Register result = ToRegister(instr->result());
|
| + if (result.is(rax)) {
|
| + __ load_rax(instr->hydrogen()->cell().location(),
|
| + RelocInfo::GLOBAL_PROPERTY_CELL);
|
| + } else {
|
| + __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL);
|
| + __ movq(result, Operand(result, 0));
|
| + }
|
| + if (instr->hydrogen()->check_hole_value()) {
|
| + __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
|
| + DeoptimizeIf(equal, instr->environment());
|
| + }
|
| }
|
|
|
|
|
| @@ -1534,9 +1684,7 @@
|
| // been deleted from the property dictionary. In that case, we need
|
| // to update the property details in the property dictionary to mark
|
| // it as no longer deleted. We deoptimize in that case.
|
| - __ movq(temp,
|
| - Handle<Object>::cast(instr->hydrogen()->cell()),
|
| - RelocInfo::GLOBAL_PROPERTY_CELL);
|
| + __ movq(temp, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL);
|
| if (check_hole) {
|
| __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex);
|
| DeoptimizeIf(equal, instr->environment());
|
| @@ -1563,7 +1711,12 @@
|
|
|
|
|
| void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
|
| - Abort("Unimplemented: %s", "DoLoadNamedGeneric");
|
| + ASSERT(ToRegister(instr->object()).is(rax));
|
| + ASSERT(ToRegister(instr->result()).is(rax));
|
| +
|
| + __ Move(rcx, instr->name());
|
| + Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
| + CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
|
|
| @@ -1855,7 +2008,33 @@
|
|
|
|
|
| void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
| - Abort("Unimplemented: %s", "DoStoreKeyedFastElement");
|
| + Register value = ToRegister(instr->value());
|
| + Register elements = ToRegister(instr->object());
|
| + Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
|
| +
|
| + // Do the store.
|
| + if (instr->key()->IsConstantOperand()) {
|
| + ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
|
| + LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
|
| + int offset =
|
| + ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
|
| + __ movq(FieldOperand(elements, offset), value);
|
| + } else {
|
| + __ movq(FieldOperand(elements,
|
| + key,
|
| + times_pointer_size,
|
| + FixedArray::kHeaderSize),
|
| + value);
|
| + }
|
| +
|
| + if (instr->hydrogen()->NeedsWriteBarrier()) {
|
| + // Compute address of modified element and store it into key register.
|
| + __ lea(key, FieldOperand(elements,
|
| + key,
|
| + times_pointer_size,
|
| + FixedArray::kHeaderSize));
|
| + __ RecordWrite(elements, key, value);
|
| + }
|
| }
|
|
|
|
|
| @@ -1926,12 +2105,21 @@
|
|
|
|
|
| void LCodeGen::DoSmiTag(LSmiTag* instr) {
|
| - Abort("Unimplemented: %s", "DoSmiTag");
|
| + ASSERT(instr->InputAt(0)->Equals(instr->result()));
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
|
| + __ Integer32ToSmi(input, input);
|
| }
|
|
|
|
|
| void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
|
| - Abort("Unimplemented: %s", "DoSmiUntag");
|
| + ASSERT(instr->InputAt(0)->Equals(instr->result()));
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + if (instr->needs_check()) {
|
| + Condition is_smi = __ CheckSmi(input);
|
| + DeoptimizeIf(NegateCondition(is_smi), instr->environment());
|
| + }
|
| + __ SmiToInteger32(input, input);
|
| }
|
|
|
|
|
| @@ -2110,7 +2298,14 @@
|
|
|
|
|
| void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
|
| - Abort("Unimplemented: %s", "LoadHeapObject");
|
| + if (Heap::InNewSpace(*object)) {
|
| + Handle<JSGlobalPropertyCell> cell =
|
| + Factory::NewJSGlobalPropertyCell(object);
|
| + __ movq(result, cell, RelocInfo::GLOBAL_PROPERTY_CELL);
|
| + __ movq(result, Operand(result, 0));
|
| + } else {
|
| + __ Move(result, object);
|
| + }
|
| }
|
|
|
|
|
| @@ -2219,6 +2414,54 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + NearLabel true_label;
|
| + NearLabel false_label;
|
| + NearLabel done;
|
| +
|
| + EmitIsConstructCall(result);
|
| + __ j(equal, &true_label);
|
| +
|
| + __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&true_label);
|
| + __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| +
|
| +
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
|
| + Register temp = ToRegister(instr->TempAt(0));
|
| + int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| + int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| +
|
| + EmitIsConstructCall(temp);
|
| + EmitBranch(true_block, false_block, equal);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::EmitIsConstructCall(Register temp) {
|
| + // Get the frame pointer for the calling frame.
|
| + __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
|
| +
|
| + // Skip the arguments adaptor frame if it exists.
|
| + NearLabel check_frame_marker;
|
| + __ SmiCompare(Operand(temp, StandardFrameConstants::kContextOffset),
|
| + Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| + __ j(not_equal, &check_frame_marker);
|
| + __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset));
|
| +
|
| + // Check the marker in the calling frame.
|
| + __ bind(&check_frame_marker);
|
| + __ SmiCompare(Operand(temp, StandardFrameConstants::kMarkerOffset),
|
| + Smi::FromInt(StackFrame::CONSTRUCT));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
|
|