| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 2216)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -103,7 +103,15 @@
|
| void CodeGenerator::TestCodeGenerator() {
|
| // Compile a function from a string, and run it.
|
| Handle<JSFunction> test_function = Compiler::Compile(
|
| - Factory::NewStringFromAscii(CStrVector("39; 42;")),
|
| + Factory::NewStringFromAscii(CStrVector(
|
| + "39;"
|
| + "(function(){return 43})();"
|
| + "42;"
|
| + // "function foo(x, y){return x;};"
|
| + "43;"
|
| + // "foo(2,3);"
|
| + "44;"
|
| + "(function(){return (function(){return 47})()})();")),
|
| Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
|
| 0,
|
| 0,
|
| @@ -132,7 +140,7 @@
|
| &pending_exceptions);
|
| // Function compiles and runs, but returns a JSFunction object.
|
| CHECK(result->IsSmi());
|
| - CHECK_EQ(42, Smi::cast(*result)->value());
|
| + CHECK_EQ(47, Smi::cast(*result)->value());
|
| }
|
|
|
|
|
| @@ -370,15 +378,44 @@
|
| UNIMPLEMENTED();
|
| }
|
|
|
| -void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* a) {
|
| - UNIMPLEMENTED();
|
| +
|
| +void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
|
| + // Call the runtime to instantiate the function boilerplate object.
|
| + // 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.
|
| + ASSERT(boilerplate->IsBoilerplate());
|
| + frame_->SyncRange(0, frame_->element_count() - 1);
|
| +
|
| + // Push the boilerplate on the stack.
|
| + __ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
|
| + frame_->EmitPush(kScratchRegister);
|
| +
|
| + // Create a new closure.
|
| + frame_->EmitPush(rsi);
|
| + Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
|
| + frame_->Push(&result);
|
| }
|
|
|
| +
|
| +void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
|
| + Comment cmnt(masm_, "[ FunctionLiteral");
|
| +
|
| + // Build the function boilerplate and instantiate it.
|
| + Handle<JSFunction> boilerplate = BuildBoilerplate(node);
|
| + // Check for stack-overflow exception.
|
| + if (HasStackOverflow()) return;
|
| + InstantiateBoilerplate(boilerplate);
|
| +}
|
| +
|
| +
|
| void CodeGenerator::VisitFunctionBoilerplateLiteral(
|
| - FunctionBoilerplateLiteral* a) {
|
| - UNIMPLEMENTED();
|
| + FunctionBoilerplateLiteral* node) {
|
| + Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
|
| + InstantiateBoilerplate(node->boilerplate());
|
| }
|
|
|
| +
|
| void CodeGenerator::VisitConditional(Conditional* a) {
|
| UNIMPLEMENTED();
|
| }
|
| @@ -521,10 +558,153 @@
|
| UNIMPLEMENTED();
|
| }
|
|
|
| -void CodeGenerator::VisitCall(Call* a) {
|
| - UNIMPLEMENTED();
|
| +
|
| +void CodeGenerator::VisitCall(Call* node) {
|
| + Comment cmnt(masm_, "[ Call");
|
| +
|
| + ZoneList<Expression*>* args = node->arguments();
|
| +
|
| + CodeForStatementPosition(node);
|
| +
|
| + // Check if the function is a variable or a property.
|
| + Expression* function = node->expression();
|
| + Variable* var = function->AsVariableProxy()->AsVariable();
|
| + Property* property = function->AsProperty();
|
| +
|
| + // ------------------------------------------------------------------------
|
| + // Fast-case: Use inline caching.
|
| + // ---
|
| + // According to ECMA-262, section 11.2.3, page 44, the function to call
|
| + // must be resolved after the arguments have been evaluated. The IC code
|
| + // automatically handles this by loading the arguments before the function
|
| + // is resolved in cache misses (this also holds for megamorphic calls).
|
| + // ------------------------------------------------------------------------
|
| +
|
| + if (var != NULL && !var->is_this() && var->is_global()) {
|
| + // ----------------------------------
|
| + // JavaScript example: 'foo(1, 2, 3)' // foo is global
|
| + // ----------------------------------
|
| +
|
| + // Push the name of the function and the receiver onto the stack.
|
| + frame_->Push(var->name());
|
| +
|
| + // Pass the global object as the receiver and let the IC stub
|
| + // patch the stack to use the global proxy as 'this' in the
|
| + // invoked function.
|
| + LoadGlobal();
|
| +
|
| + // Load the arguments.
|
| + int arg_count = args->length();
|
| + for (int i = 0; i < arg_count; i++) {
|
| + Load(args->at(i));
|
| + }
|
| +
|
| + // Call the IC initialization code.
|
| + CodeForSourcePosition(node->position());
|
| + Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT,
|
| + arg_count,
|
| + loop_nesting());
|
| + frame_->RestoreContextRegister();
|
| + // Replace the function on the stack with the result.
|
| + frame_->SetElementAt(0, &result);
|
| + } else if (var != NULL && var->slot() != NULL &&
|
| + var->slot()->type() == Slot::LOOKUP) {
|
| + // TODO(X64): Enable calls of non-global functions.
|
| + UNIMPLEMENTED();
|
| + /*
|
| + // ----------------------------------
|
| + // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
|
| + // ----------------------------------
|
| +
|
| + // Load the function from the context. Sync the frame so we can
|
| + // push the arguments directly into place.
|
| + frame_->SyncRange(0, frame_->element_count() - 1);
|
| + frame_->EmitPush(esi);
|
| + frame_->EmitPush(Immediate(var->name()));
|
| + frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
|
| + // The runtime call returns a pair of values in eax and edx. The
|
| + // looked-up function is in eax and the receiver is in edx. These
|
| + // register references are not ref counted here. We spill them
|
| + // eagerly since they are arguments to an inevitable call (and are
|
| + // not sharable by the arguments).
|
| + ASSERT(!allocator()->is_used(eax));
|
| + frame_->EmitPush(eax);
|
| +
|
| + // Load the receiver.
|
| + ASSERT(!allocator()->is_used(edx));
|
| + frame_->EmitPush(edx);
|
| +
|
| + // Call the function.
|
| + CallWithArguments(args, node->position());
|
| + */
|
| + } else if (property != NULL) {
|
| + UNIMPLEMENTED();
|
| + /*
|
| + // Check if the key is a literal string.
|
| + Literal* literal = property->key()->AsLiteral();
|
| +
|
| + if (literal != NULL && literal->handle()->IsSymbol()) {
|
| + // ------------------------------------------------------------------
|
| + // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
|
| + // ------------------------------------------------------------------
|
| +
|
| + // Push the name of the function and the receiver onto the stack.
|
| + frame_->Push(literal->handle());
|
| + Load(property->obj());
|
| +
|
| + // Load the arguments.
|
| + int arg_count = args->length();
|
| + for (int i = 0; i < arg_count; i++) {
|
| + Load(args->at(i));
|
| + }
|
| +
|
| + // Call the IC initialization code.
|
| + CodeForSourcePosition(node->position());
|
| + Result result =
|
| + frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting());
|
| + frame_->RestoreContextRegister();
|
| + // Replace the function on the stack with the result.
|
| + frame_->SetElementAt(0, &result);
|
| +
|
| + } else {
|
| + // -------------------------------------------
|
| + // JavaScript example: 'array[index](1, 2, 3)'
|
| + // -------------------------------------------
|
| +
|
| + // Load the function to call from the property through a reference.
|
| + Reference ref(this, property);
|
| + ref.GetValue(NOT_INSIDE_TYPEOF);
|
| +
|
| + // Pass receiver to called function.
|
| + if (property->is_synthetic()) {
|
| + // Use global object as receiver.
|
| + LoadGlobalReceiver();
|
| + } else {
|
| + // The reference's size is non-negative.
|
| + frame_->PushElementAt(ref.size());
|
| + }
|
| +
|
| + // Call the function.
|
| + CallWithArguments(args, node->position());
|
| + }
|
| + */
|
| + } else {
|
| + // ----------------------------------
|
| + // JavaScript example: 'foo(1, 2, 3)' // foo is not global
|
| + // ----------------------------------
|
| +
|
| + // Load the function.
|
| + Load(function);
|
| +
|
| + // Pass the global proxy as the receiver.
|
| + LoadGlobalReceiver();
|
| +
|
| + // Call the function.
|
| + CallWithArguments(args, node->position());
|
| + }
|
| }
|
|
|
| +
|
| void CodeGenerator::VisitCallEval(CallEval* a) {
|
| UNIMPLEMENTED();
|
| }
|
| @@ -537,6 +717,7 @@
|
| UNIMPLEMENTED();
|
| }
|
|
|
| +
|
| void CodeGenerator::VisitUnaryOperation(UnaryOperation* a) {
|
| UNIMPLEMENTED();
|
| }
|
| @@ -1216,6 +1397,16 @@
|
| }
|
| }
|
|
|
| +
|
| +void CodeGenerator::LoadGlobalReceiver() {
|
| + Result temp = allocator_->Allocate();
|
| + Register reg = temp.reg();
|
| + __ movq(reg, GlobalObject());
|
| + __ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
|
| + frame_->Push(&temp);
|
| +}
|
| +
|
| +
|
| #undef __
|
|
|
| // End of CodeGenerator implementation.
|
| @@ -1588,14 +1779,61 @@
|
|
|
|
|
| void CallFunctionStub::Generate(MacroAssembler* masm) {
|
| + Label slow;
|
| +
|
| + // Get the function to call from the stack.
|
| + // +2 ~ receiver, return address
|
| + __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
|
| +
|
| + // Check that the function really is a JavaScript function.
|
| + __ testq(rdi, Immediate(kSmiTagMask));
|
| + __ j(zero, &slow);
|
| + // Goto slow case if we do not have a function.
|
| + __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
| + __ j(not_equal, &slow);
|
| +
|
| + // Fast-case: Just invoke the function.
|
| + ParameterCount actual(argc_);
|
| + __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
|
| +
|
| + // Slow-case: Non-function called.
|
| + __ bind(&slow);
|
| + __ Set(rax, argc_);
|
| + __ Set(rbx, 0);
|
| + __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
|
| + Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
|
| + __ Jump(adaptor, RelocInfo::CODE_TARGET);
|
| }
|
|
|
|
|
| +// Call the function just below TOS on the stack with the given
|
| +// arguments. The receiver is the TOS.
|
| +void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
|
| + int position) {
|
| + // Push the arguments ("left-to-right") on the stack.
|
| + int arg_count = args->length();
|
| + for (int i = 0; i < arg_count; i++) {
|
| + Load(args->at(i));
|
| + }
|
| +
|
| + // Record the position for debugging purposes.
|
| + CodeForSourcePosition(position);
|
| +
|
| + // Use the shared code stub to call the function.
|
| + InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
| + CallFunctionStub call_function(arg_count, in_loop);
|
| + Result answer = frame_->CallStub(&call_function, arg_count + 1);
|
| + // Restore context and replace function on the stack with the
|
| + // result of the stub invocation.
|
| + frame_->RestoreContextRegister();
|
| + frame_->SetElementAt(0, &answer);
|
| +}
|
| +
|
| +
|
| void InstanceofStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
|
|
| -
|
| void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
|
| // The displacement is used for skipping the return address and the
|
| // frame pointer on the stack. It is the offset of the last
|
|
|