| Index: src/x64/fast-codegen-x64.cc | 
| =================================================================== | 
| --- src/x64/fast-codegen-x64.cc	(revision 3181) | 
| +++ src/x64/fast-codegen-x64.cc	(working copy) | 
| @@ -91,27 +91,36 @@ | 
| // Emit a 'return undefined' in case control fell off the end of the | 
| // body. | 
| __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 
| +  } | 
| +  { Comment cmnt(masm_, "Return sequence"); | 
| SetReturnPosition(fun); | 
| -    if (FLAG_trace) { | 
| -      __ push(rax); | 
| -      __ CallRuntime(Runtime::kTraceExit, 1); | 
| -    } | 
| -    __ RecordJSReturn(); | 
|  | 
| -    // Do not use the leave instruction here because it is too short to | 
| -    // patch with the code required by the debugger. | 
| -    __ movq(rsp, rbp); | 
| -    __ pop(rbp); | 
| -    __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 
| +    if (return_label_.is_bound()) { | 
| +      __ jmp(&return_label_); | 
| +    } else { | 
| +      __ bind(&return_label_); | 
| + | 
| +      if (FLAG_trace) { | 
| +        __ push(rax); | 
| +        __ CallRuntime(Runtime::kTraceExit, 1); | 
| +      } | 
| +      __ RecordJSReturn(); | 
| + | 
| +      // Do not use the leave instruction here because it is too short to | 
| +      // patch with the code required by the debugger. | 
| +      __ movq(rsp, rbp); | 
| +      __ pop(rbp); | 
| +      __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 
| #ifdef ENABLE_DEBUGGER_SUPPORT | 
| -    // Add padding that will be overwritten by a debugger breakpoint.  We | 
| -    // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 | 
| -    // (3 + 1 + 3). | 
| -    const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 
| -    for (int i = 0; i < kPadding; ++i) { | 
| -      masm_->int3(); | 
| +      // Add padding that will be overwritten by a debugger breakpoint.  We | 
| +      // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 | 
| +      // (3 + 1 + 3). | 
| +      const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 
| +      for (int i = 0; i < kPadding; ++i) { | 
| +        masm_->int3(); | 
| +      } | 
| +#endif | 
| } | 
| -#endif | 
| } | 
| } | 
|  | 
| @@ -179,26 +188,32 @@ | 
| __ pop(rax); | 
| } | 
|  | 
| -  if (FLAG_trace) { | 
| -    __ push(rax); | 
| -    __ CallRuntime(Runtime::kTraceExit, 1); | 
| -  } | 
| +  if (return_label_.is_bound()) { | 
| +    __ jmp(&return_label_); | 
| +  } else { | 
| +    __ bind(&return_label_); | 
|  | 
| -  __ RecordJSReturn(); | 
| -  // Do not use the leave instruction here because it is too short to | 
| -  // patch with the code required by the debugger. | 
| -  __ movq(rsp, rbp); | 
| -  __ pop(rbp); | 
| -  __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); | 
| +    if (FLAG_trace) { | 
| +      __ push(rax); | 
| +      __ CallRuntime(Runtime::kTraceExit, 1); | 
| +    } | 
| + | 
| +    __ RecordJSReturn(); | 
| +    // Do not use the leave instruction here because it is too short to | 
| +    // patch with the code required by the debugger. | 
| +    __ movq(rsp, rbp); | 
| +    __ pop(rbp); | 
| +    __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); | 
| #ifdef ENABLE_DEBUGGER_SUPPORT | 
| -  // Add padding that will be overwritten by a debugger breakpoint.  We | 
| -  // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 | 
| -  // (3 + 1 + 3). | 
| -  const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 
| -  for (int i = 0; i < kPadding; ++i) { | 
| -    masm_->int3(); | 
| +    // Add padding that will be overwritten by a debugger breakpoint.  We | 
| +    // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 | 
| +    // (3 + 1 + 3). | 
| +    const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 
| +    for (int i = 0; i < kPadding; ++i) { | 
| +      masm_->int3(); | 
| +    } | 
| +#endif | 
| } | 
| -#endif | 
| } | 
|  | 
|  | 
| @@ -495,6 +510,8 @@ | 
| Visit(rhs); | 
| __ pop(rax); | 
| } | 
| +    // Record position for debugger. | 
| +    SetSourcePosition(expr->position()); | 
| __ Move(rcx, var->name()); | 
| __ push(CodeGenerator::GlobalObject()); | 
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 
| @@ -544,6 +561,7 @@ | 
| // Evaluate receiver. | 
| Visit(expr->obj()); | 
|  | 
| + | 
| if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && | 
| !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { | 
| // Do a NAMED property load. | 
| @@ -569,27 +587,20 @@ | 
| } | 
|  | 
|  | 
| -void FastCodeGenerator::VisitCall(Call* expr) { | 
| -  Expression* fun = expr->expression(); | 
| +void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { | 
| +  // Code common for calls using the IC. | 
| ZoneList<Expression*>* args = expr->arguments(); | 
| -  Variable* var = fun->AsVariableProxy()->AsVariable(); | 
| -  ASSERT(var != NULL && !var->is_this() && var->is_global()); | 
| -  ASSERT(!var->is_possibly_eval()); | 
| - | 
| -  __ Push(var->name()); | 
| -  // Push global object (receiver). | 
| -  __ push(CodeGenerator::GlobalObject()); | 
| int arg_count = args->length(); | 
| for (int i = 0; i < arg_count; i++) { | 
| Visit(args->at(i)); | 
| ASSERT_EQ(Expression::kValue, args->at(i)->context()); | 
| } | 
| -  // Record source position for debugger | 
| +  // Record source position for debugger. | 
| SetSourcePosition(expr->position()); | 
| // Call the IC initialization code. | 
| Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 
| NOT_IN_LOOP); | 
| -  __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 
| +  __ call(ic, reloc_info); | 
| // Restore context register. | 
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 
| // Discard the function left on TOS. | 
| @@ -597,6 +608,80 @@ | 
| } | 
|  | 
|  | 
| +void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 
| +  // Code common for calls using the call stub. | 
| +  ZoneList<Expression*>* args = expr->arguments(); | 
| +  int arg_count = args->length(); | 
| +  for (int i = 0; i < arg_count; i++) { | 
| +    Visit(args->at(i)); | 
| +  } | 
| +  // Record source position for debugger. | 
| +  SetSourcePosition(expr->position()); | 
| +  CallFunctionStub stub(arg_count, NOT_IN_LOOP); | 
| +  __ CallStub(&stub); | 
| +  // Restore context register. | 
| +  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 
| +  // Discard the function left on TOS. | 
| +  DropAndMove(expr->context(), rax); | 
| +} | 
| + | 
| + | 
| +void FastCodeGenerator::VisitCall(Call* expr) { | 
| +  Expression* fun = expr->expression(); | 
| + | 
| +  if (fun->AsProperty() != NULL) { | 
| +    // Call on a property. | 
| +    Property* prop = fun->AsProperty(); | 
| +    Literal* key = prop->key()->AsLiteral(); | 
| +    if (key != NULL && key->handle()->IsSymbol()) { | 
| +      // Call on a named property: foo.x(1,2,3) | 
| +      __ Push(key->handle()); | 
| +      Visit(prop->obj()); | 
| +      // Use call IC | 
| +      EmitCallWithIC(expr, RelocInfo::CODE_TARGET); | 
| +    } else { | 
| +      // Call on a keyed property: foo[key](1,2,3) | 
| +      // Use a keyed load IC followed by a call IC. | 
| +      Visit(prop->obj()); | 
| +      Visit(prop->key()); | 
| +      // Record source position of property. | 
| +      SetSourcePosition(prop->position()); | 
| +      Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 
| +      __ call(ic, RelocInfo::CODE_TARGET); | 
| +      // By emitting a nop we make sure that we do not have a "test eax,..." | 
| +      // instruction after the call it is treated specially by the LoadIC code. | 
| +      __ nop(); | 
| +      // Drop key left on the stack by IC. | 
| +      __ addq(rsp, Immediate(kPointerSize)); | 
| +      // Pop receiver. | 
| +      __ pop(rbx); | 
| +      // Push result (function). | 
| +      __ push(rax); | 
| +      // Push receiver object on stack. | 
| +      if (prop->is_synthetic()) { | 
| +        __ push(CodeGenerator::GlobalObject()); | 
| +      } else { | 
| +        __ push(rbx); | 
| +      } | 
| +      EmitCallWithStub(expr); | 
| +    } | 
| +  } else if (fun->AsVariableProxy()->AsVariable() != NULL) { | 
| +    // Call on a global variable | 
| +    Variable* var = fun->AsVariableProxy()->AsVariable(); | 
| +    ASSERT(var != NULL && !var->is_this() && var->is_global()); | 
| +    ASSERT(!var->is_possibly_eval()); | 
| +    __ Push(var->name()); | 
| +    // Push global object (receiver). | 
| +    __ push(CodeGenerator::GlobalObject()); | 
| +    EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT); | 
| +  } else { | 
| +    // Calls we cannot handle right now. | 
| +    // Should bailout in the CodeGenSelector. | 
| +    UNREACHABLE(); | 
| +  } | 
| +} | 
| + | 
| + | 
| void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 
| Comment cmnt(masm_, "[ CallNew"); | 
| // According to ECMA-262, section 11.2.2, page 44, the function | 
|  |