Author: [email protected]
Date: Thu Jun 18 04:46:38 2009
New Revision: 2217

Modified:
    branches/bleeding_edge/src/ia32/assembler-ia32.cc
    branches/bleeding_edge/src/ia32/codegen-ia32.cc
    branches/bleeding_edge/src/x64/codegen-x64.cc
    branches/bleeding_edge/src/x64/macro-assembler-x64.cc
    branches/bleeding_edge/src/x64/macro-assembler-x64.h
    branches/bleeding_edge/src/x64/virtual-frame-x64.cc

Log:
X64 implementation: Add function literals and function calls.
Review URL: http://codereview.chromium.org/131029

Modified: branches/bleeding_edge/src/ia32/assembler-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/assembler-ia32.cc   (original)
+++ branches/bleeding_edge/src/ia32/assembler-ia32.cc   Thu Jun 18 04:46:38  
2009
@@ -1417,7 +1417,7 @@
  }


-void Assembler::call(Handle<Code> code,  RelocInfo::Mode rmode) {
+void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
    WriteRecordedPositions();
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;

Modified: branches/bleeding_edge/src/ia32/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/codegen-ia32.cc     (original)
+++ branches/bleeding_edge/src/ia32/codegen-ia32.cc     Thu Jun 18 04:46:38 2009
@@ -7163,7 +7163,6 @@
  }


-
  void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
    // eax holds the exception.


Modified: branches/bleeding_edge/src/x64/codegen-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/codegen-x64.cc       (original)
+++ branches/bleeding_edge/src/x64/codegen-x64.cc       Thu Jun 18 04:46:38 2009
@@ -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,12 +1779,59 @@


  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);
  }


-void InstanceofStub::Generate(MacroAssembler* masm) {
+// 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) {

Modified: branches/bleeding_edge/src/x64/macro-assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/macro-assembler-x64.cc       (original)
+++ branches/bleeding_edge/src/x64/macro-assembler-x64.cc       Thu Jun 18  
04:46:38 2009
@@ -206,6 +206,44 @@
  }


+void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript  
id) {
+  bool resolved;
+  Handle<Code> code = ResolveBuiltin(id, &resolved);
+
+  const char* name = Builtins::GetName(id);
+  int argc = Builtins::GetArgumentsCount(id);
+
+  movq(target, code, RelocInfo::EXTERNAL_REFERENCE);  // Is external  
reference?
+  if (!resolved) {
+    uint32_t flags =
+        Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
+        Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
+        Bootstrapper::FixupFlagsUseCodeObject::encode(true);
+    Unresolved entry = { pc_offset() - sizeof(intptr_t), flags, name };
+    unresolved_.Add(entry);
+  }
+  addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+}
+
+
+Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
+                                            bool* resolved) {
+  // Move the builtin function into the temporary function slot by
+  // reading it from the builtins object. NOTE: We should be able to
+  // reduce this to two instructions by putting the function table in
+  // the global object instead of the "builtins" object and by using a
+  // real register for the function.
+  movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  movq(rdx, FieldOperand(rdx, GlobalObject::kBuiltinsOffset));
+  int builtins_offset =
+      JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
+  movq(rdi, FieldOperand(rdx, builtins_offset));
+
+
+  return Builtins::GetCode(id, resolved);
+}
+
+
  void MacroAssembler::Set(Register dst, int64_t x) {
    if (is_int32(x)) {
      movq(dst, Immediate(x));
@@ -241,6 +279,14 @@
  }


+void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode)  
{
+  WriteRecordedPositions();
+  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  movq(kScratchRegister, code_object, rmode);
+  jmp(kScratchRegister);
+}
+
+
  void MacroAssembler::Call(ExternalReference ext) {
    movq(kScratchRegister, ext);
    call(kScratchRegister);
@@ -249,6 +295,14 @@

  void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
    movq(kScratchRegister, destination, rmode);
+  call(kScratchRegister);
+}
+
+
+void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode)  
{
+  WriteRecordedPositions();
+  ASSERT(RelocInfo::IsCodeTarget(rmode));
+  movq(kScratchRegister, code_object, rmode);
    call(kScratchRegister);
  }


Modified: branches/bleeding_edge/src/x64/macro-assembler-x64.h
==============================================================================
--- branches/bleeding_edge/src/x64/macro-assembler-x64.h        (original)
+++ branches/bleeding_edge/src/x64/macro-assembler-x64.h        Thu Jun 18  
04:46:38 2009
@@ -161,8 +161,11 @@
    // Control Flow
    void Jump(Address destination, RelocInfo::Mode rmode);
    void Jump(ExternalReference ext);
+  void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
+
    void Call(Address destination, RelocInfo::Mode rmode);
    void Call(ExternalReference ext);
+  void Call(Handle<Code> code_object, RelocInfo::Mode rmode);

    // Compare object type for heap object.
    // Incoming register is heap_object and outgoing register is map.

Modified: branches/bleeding_edge/src/x64/virtual-frame-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/virtual-frame-x64.cc (original)
+++ branches/bleeding_edge/src/x64/virtual-frame-x64.cc Thu Jun 18 04:46:38  
2009
@@ -137,6 +137,26 @@
  }


+void VirtualFrame::SaveContextRegister() {
+  ASSERT(elements_[context_index()].is_memory());
+  __ movq(Operand(rbp, fp_relative(context_index())), rsi);
+}
+
+
+void VirtualFrame::RestoreContextRegister() {
+  ASSERT(elements_[context_index()].is_memory());
+  __ movq(rsi, Operand(rbp, fp_relative(context_index())));
+}
+
+
+void VirtualFrame::PushReceiverSlotAddress() {
+  Result temp = cgen()->allocator()->Allocate();
+  ASSERT(temp.is_valid());
+  __ lea(temp.reg(), ParameterAt(-1));
+  Push(&temp);
+}
+
+
  void VirtualFrame::EmitPop(Register reg) {
    ASSERT(stack_pointer_ == element_count() - 1);
    stack_pointer_--;
@@ -433,13 +453,65 @@
  }


-Result VirtualFrame::RawCallStub(CodeStub* a) {
-  UNIMPLEMENTED();
-  return Result(NULL);
+Result VirtualFrame::RawCallStub(CodeStub* stub) {
+  ASSERT(cgen()->HasValidEntryRegisters());
+  __ CallStub(stub);
+  Result result = cgen()->allocator()->Allocate(rax);
+  ASSERT(result.is_valid());
+  return result;
  }

-void VirtualFrame::SyncElementBelowStackPointer(int a) {
-  UNIMPLEMENTED();
+
+void VirtualFrame::SyncElementBelowStackPointer(int index) {
+  // Emit code to write elements below the stack pointer to their
+  // (already allocated) stack address.
+  ASSERT(index <= stack_pointer_);
+  FrameElement element = elements_[index];
+  ASSERT(!element.is_synced());
+  switch (element.type()) {
+    case FrameElement::INVALID:
+      break;
+
+    case FrameElement::MEMORY:
+      // This function should not be called with synced elements.
+      // (memory elements are always synced).
+      UNREACHABLE();
+      break;
+
+    case FrameElement::REGISTER:
+      __ movq(Operand(rbp, fp_relative(index)), element.reg());
+      break;
+
+    case FrameElement::CONSTANT:
+      if (element.handle()->IsSmi()) {
+        if (CodeGeneratorScope::Current()->IsUnsafeSmi(element.handle())) {
+          CodeGeneratorScope::Current()->LoadUnsafeSmi(kScratchRegister,
+                                                       element.handle());
+        } else {
+          __ movq(kScratchRegister, element.handle(), RelocInfo::NONE);
+        }
+      } else {
+        __ movq(kScratchRegister,
+                 element.handle(),
+                 RelocInfo::EMBEDDED_OBJECT);
+      }
+      __ movq(Operand(rbp, fp_relative(index)), kScratchRegister);
+      break;
+
+    case FrameElement::COPY: {
+      int backing_index = element.index();
+      FrameElement backing_element = elements_[backing_index];
+      if (backing_element.is_memory()) {
+        __ movq(kScratchRegister, Operand(rbp,  
fp_relative(backing_index)));
+        __ movq(Operand(rbp, fp_relative(index)), kScratchRegister);
+      } else {
+        ASSERT(backing_element.is_register());
+        __ movq(Operand(rbp, fp_relative(index)), backing_element.reg());
+      }
+      break;
+    }
+  }
+  elements_[index].set_sync();
  }


@@ -518,6 +590,55 @@
      if (!elements_[i].is_synced()) SyncElementBelowStackPointer(i);
    }
  }
+
+//------------------------------------------------------------------------------
+// Virtual frame stub and IC calling functions.
+
+Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
+                                       RelocInfo::Mode rmode) {
+  ASSERT(cgen()->HasValidEntryRegisters());
+  __ Call(code, rmode);
+  Result result = cgen()->allocator()->Allocate(rax);
+  ASSERT(result.is_valid());
+  return result;
+}
+
+
+Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
+  PrepareForCall(arg_count, arg_count);
+  ASSERT(cgen()->HasValidEntryRegisters());
+  __ CallRuntime(f, arg_count);
+  Result result = cgen()->allocator()->Allocate(rax);
+  ASSERT(result.is_valid());
+  return result;
+}
+
+
+Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
+  PrepareForCall(arg_count, arg_count);
+  ASSERT(cgen()->HasValidEntryRegisters());
+  __ CallRuntime(id, arg_count);
+  Result result = cgen()->allocator()->Allocate(rax);
+  ASSERT(result.is_valid());
+  return result;
+}
+
+
+Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
+                                int arg_count,
+                                int loop_nesting) {
+  // Arguments, receiver, and function name are on top of the frame.
+  // The IC expects them on the stack.  It does not drop the function
+  // name slot (but it does drop the rest).
+  InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
+  Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
+  // Spill args, receiver, and function.  The call will drop args and
+  // receiver.
+  PrepareForCall(arg_count + 2, arg_count + 1);
+  return RawCallCodeObject(ic, mode);
+}
+
+


  #undef __

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to