Chromium Code Reviews| Index: src/x64/codegen-x64.cc |
| =================================================================== |
| --- src/x64/codegen-x64.cc (revision 2254) |
| +++ src/x64/codegen-x64.cc (working copy) |
| @@ -123,10 +123,21 @@ |
| } |
| -void CodeGenerator::DeclareGlobals(Handle<FixedArray> a) { |
| - UNIMPLEMENTED(); |
| +void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| + // Call the runtime to declare the globals. The inevitable call |
| + // will sync frame elements to memory anyway, so we do it eagerly to |
| + // allow us to push the arguments directly into place. |
| + frame_->SyncRange(0, frame_->element_count() - 1); |
| + |
| + __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); |
| + frame_->EmitPush(kScratchRegister); |
| + frame_->EmitPush(rsi); // The context is the second argument. |
| + frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| + Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| + // Return value is ignored. |
| } |
| + |
| void CodeGenerator::TestCodeGenerator() { |
| // Compile a function from a string, and run it. |
| @@ -286,10 +297,35 @@ |
| // Ignore the return value. |
| } |
| #endif |
| + VisitStatements(body); |
| + |
| + // Handle the return from the function. |
| + if (has_valid_frame()) { |
| + // If there is a valid frame, control flow can fall off the end of |
| + // the body. In that case there is an implicit return statement. |
| + ASSERT(!function_return_is_shadowed_); |
| + CodeForReturnPosition(function); |
| + frame_->PrepareForReturn(); |
| + Result undefined(Factory::undefined_value()); |
| + if (function_return_.is_bound()) { |
| + function_return_.Jump(&undefined); |
| + } else { |
| + function_return_.Bind(&undefined); |
| + GenerateReturnSequence(&undefined); |
| + } |
| + } else if (function_return_.is_linked()) { |
| + // If the return target has dangling jumps to it, then we have not |
| + // yet generated the return sequence. This can happen when (a) |
| + // control does not flow off the end of the body so we did not |
| + // compile an artificial return statement just above, and (b) there |
| + // are return statements in the body but (c) they are all shadowed. |
| + Result return_value; |
| + function_return_.Bind(&return_value); |
| + GenerateReturnSequence(&return_value); |
| + } |
| } |
| + } |
| - VisitStatements(body); |
| - } |
| // Adjust for function-level loop nesting. |
| loop_nesting_ -= function->loop_nesting(); |
| @@ -1319,13 +1355,77 @@ |
| } |
| -void CodeGenerator::VisitCallNew(CallNew* a) { |
| - UNIMPLEMENTED(); |
| +void CodeGenerator::VisitCallNew(CallNew* node) { |
| + Comment cmnt(masm_, "[ CallNew"); |
| + CodeForStatementPosition(node); |
| + |
| + // According to ECMA-262, section 11.2.2, page 44, the function |
| + // expression in new calls must be evaluated before the |
| + // arguments. This is different from ordinary calls, where the |
| + // actual function to call is resolved after the arguments have been |
| + // evaluated. |
| + |
| + // Compute function to call and use the global object as the |
| + // receiver. There is no need to use the global proxy here because |
| + // it will always be replaced with a newly allocated object. |
| + Load(node->expression()); |
| + LoadGlobal(); |
| + |
| + // Push the arguments ("left-to-right") on the stack. |
| + ZoneList<Expression*>* args = node->arguments(); |
| + int arg_count = args->length(); |
| + for (int i = 0; i < arg_count; i++) { |
| + Load(args->at(i)); |
| + } |
| + |
| + // Call the construct call builtin that handles allocation and |
| + // constructor invocation. |
| + CodeForSourcePosition(node->position()); |
| + Result result = frame_->CallConstructor(arg_count); |
| + // Replace the function on the stack with the result. |
| + frame_->SetElementAt(0, &result); |
| } |
| -void CodeGenerator::VisitCallRuntime(CallRuntime* a) { |
| - UNIMPLEMENTED(); |
| +void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| + if (CheckForInlineRuntimeCall(node)) { |
| + return; |
| + } |
| + |
| + ZoneList<Expression*>* args = node->arguments(); |
| + Comment cmnt(masm_, "[ CallRuntime"); |
| + Runtime::Function* function = node->function(); |
| + |
| + if (function == NULL) { |
| + // Prepare stack for calling JS runtime function. |
| + frame_->Push(node->name()); |
| + // Push the builtins object found in the current global object. |
| + Result temp = allocator()->Allocate(); |
|
William Hesse
2009/06/24 07:55:57
Use kScratchRegister here.
Mads Ager (chromium)
2009/06/24 08:18:50
Done.
|
| + ASSERT(temp.is_valid()); |
| + __ movq(temp.reg(), GlobalObject()); |
| + __ movq(temp.reg(), |
| + FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); |
| + frame_->Push(&temp); |
| + } |
| + |
| + // Push the arguments ("left-to-right"). |
| + int arg_count = args->length(); |
| + for (int i = 0; i < arg_count; i++) { |
| + Load(args->at(i)); |
| + } |
| + |
| + if (function == NULL) { |
| + // Call the JS runtime function. |
| + Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, |
| + arg_count, |
| + loop_nesting_); |
| + frame_->RestoreContextRegister(); |
| + frame_->SetElementAt(0, &answer); |
| + } else { |
| + // Call the C runtime function. |
| + Result answer = frame_->CallRuntime(function, arg_count); |
| + frame_->Push(&answer); |
| + } |
| } |
| @@ -1345,10 +1445,12 @@ |
| UNIMPLEMENTED(); |
| } |
| -void CodeGenerator::VisitThisFunction(ThisFunction* a) { |
| - UNIMPLEMENTED(); |
| + |
| +void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| + frame_->PushFunction(); |
| } |
| + |
| void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| UNIMPLEMENTED(); |
| } |
| @@ -1542,7 +1644,7 @@ |
| ASSERT(kSmiTag == 0); |
| __ testq(value.reg(), value.reg()); |
| dest->false_target()->Branch(zero); |
| - __ testq(value.reg(), Immediate(kSmiTagMask)); |
| + __ testl(value.reg(), Immediate(kSmiTagMask)); |
|
William Hesse
2009/06/24 07:55:57
We have many of these throughout the code, and hav
Mads Ager (chromium)
2009/06/24 08:18:50
We were using it inconsistently before. There was
|
| dest->true_target()->Branch(zero); |
| // Call the stub for all other cases. |
| @@ -2056,7 +2158,7 @@ |
| GetName()); |
| // Check that the receiver is a heap object. |
| - __ testq(receiver.reg(), Immediate(kSmiTagMask)); |
| + __ testl(receiver.reg(), Immediate(kSmiTagMask)); |
| deferred->Branch(zero); |
| __ bind(deferred->patch_site()); |
| @@ -2370,8 +2472,8 @@ |
| // Check for negative zero result. |
| __ NegativeZeroTest(rax, rcx, slow); // use ecx = x | y |
| // Tag the result and store it in register rax. |
| - ASSERT(kSmiTagSize == kTimes2); // adjust code if not the case |
| - __ lea(rax, Operand(rax, rax, kTimes1, kSmiTag)); |
| + ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| + __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
| break; |
| case Token::MOD: |
| @@ -2435,8 +2537,8 @@ |
| UNREACHABLE(); |
| } |
| // Tag the result and store it in register eax. |
| - ASSERT(kSmiTagSize == kTimes2); // adjust code if not the case |
| - __ lea(rax, Operand(rax, rax, kTimes1, kSmiTag)); |
| + ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| + __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
| break; |
| default: |
| @@ -2518,7 +2620,7 @@ |
| __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); |
| // Check that the function really is a JavaScript function. |
| - __ testq(rdi, Immediate(kSmiTagMask)); |
| + __ testl(rdi, Immediate(kSmiTagMask)); |
| __ j(zero, &slow); |
| // Goto slow case if we do not have a function. |
| __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| @@ -2583,7 +2685,7 @@ |
| // Patch the arguments.length and the parameters pointer. |
| __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| __ movq(Operand(rsp, 1 * kPointerSize), rcx); |
| - __ lea(rdx, Operand(rdx, rcx, kTimes4, kDisplacement)); |
| + __ lea(rdx, Operand(rdx, rcx, times_4, kDisplacement)); |
| __ movq(Operand(rsp, 2 * kPointerSize), rdx); |
| // Do the runtime call to allocate the arguments object. |
| @@ -2621,9 +2723,9 @@ |
| // Shifting code depends on SmiEncoding being equivalent to left shift: |
| // we multiply by four to get pointer alignment. |
| ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| - __ lea(rbx, Operand(rbp, rax, kTimes4, 0)); |
| + __ lea(rbx, Operand(rbp, rax, times_4, 0)); |
| __ neg(rdx); |
| - __ movq(rax, Operand(rbx, rdx, kTimes4, kDisplacement)); |
| + __ movq(rax, Operand(rbx, rdx, times_4, kDisplacement)); |
| __ Ret(); |
| // Arguments adaptor case: Check index against actual arguments |
| @@ -2638,9 +2740,9 @@ |
| // Shifting code depends on SmiEncoding being equivalent to left shift: |
| // we multiply by four to get pointer alignment. |
| ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| - __ lea(rbx, Operand(rbx, rcx, kTimes4, 0)); |
| + __ lea(rbx, Operand(rbx, rcx, times_4, 0)); |
| __ neg(rdx); |
| - __ movq(rax, Operand(rbx, rdx, kTimes4, kDisplacement)); |
| + __ movq(rax, Operand(rbx, rdx, times_4, kDisplacement)); |
| __ Ret(); |
| // Slow-case: Handle non-smi or out-of-bounds access to arguments |