| OLD | NEW | 
|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 //     * Redistributions of source code must retain the above copyright | 6 //     * Redistributions of source code must retain the above copyright | 
| 7 //       notice, this list of conditions and the following disclaimer. | 7 //       notice, this list of conditions and the following disclaimer. | 
| 8 //     * Redistributions in binary form must reproduce the above | 8 //     * Redistributions in binary form must reproduce the above | 
| 9 //       copyright notice, this list of conditions and the following | 9 //       copyright notice, this list of conditions and the following | 
| 10 //       disclaimer in the documentation and/or other materials provided | 10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 84   } | 84   } | 
| 85 | 85 | 
| 86   { Comment cmnt(masm_, "[ Body"); | 86   { Comment cmnt(masm_, "[ Body"); | 
| 87     VisitStatements(fun->body()); | 87     VisitStatements(fun->body()); | 
| 88   } | 88   } | 
| 89 | 89 | 
| 90   { Comment cmnt(masm_, "[ return <undefined>;"); | 90   { Comment cmnt(masm_, "[ return <undefined>;"); | 
| 91     // Emit a 'return undefined' in case control fell off the end of the | 91     // Emit a 'return undefined' in case control fell off the end of the | 
| 92     // body. | 92     // body. | 
| 93     __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 93     __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 
|  | 94   } | 
|  | 95   { Comment cmnt(masm_, "Return sequence"); | 
| 94     SetReturnPosition(fun); | 96     SetReturnPosition(fun); | 
| 95     if (FLAG_trace) { | 97 | 
| 96       __ push(rax); | 98     if (return_label_.is_bound()) { | 
| 97       __ CallRuntime(Runtime::kTraceExit, 1); | 99       __ jmp(&return_label_); | 
|  | 100     } else { | 
|  | 101       __ bind(&return_label_); | 
|  | 102 | 
|  | 103       if (FLAG_trace) { | 
|  | 104         __ push(rax); | 
|  | 105         __ CallRuntime(Runtime::kTraceExit, 1); | 
|  | 106       } | 
|  | 107       __ RecordJSReturn(); | 
|  | 108 | 
|  | 109       // Do not use the leave instruction here because it is too short to | 
|  | 110       // patch with the code required by the debugger. | 
|  | 111       __ movq(rsp, rbp); | 
|  | 112       __ pop(rbp); | 
|  | 113       __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 
|  | 114 #ifdef ENABLE_DEBUGGER_SUPPORT | 
|  | 115       // Add padding that will be overwritten by a debugger breakpoint.  We | 
|  | 116       // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 | 
|  | 117       // (3 + 1 + 3). | 
|  | 118       const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 
|  | 119       for (int i = 0; i < kPadding; ++i) { | 
|  | 120         masm_->int3(); | 
|  | 121       } | 
|  | 122 #endif | 
| 98     } | 123     } | 
| 99     __ RecordJSReturn(); |  | 
| 100 |  | 
| 101     // Do not use the leave instruction here because it is too short to |  | 
| 102     // patch with the code required by the debugger. |  | 
| 103     __ movq(rsp, rbp); |  | 
| 104     __ pop(rbp); |  | 
| 105     __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |  | 
| 106 #ifdef ENABLE_DEBUGGER_SUPPORT |  | 
| 107     // Add padding that will be overwritten by a debugger breakpoint.  We |  | 
| 108     // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 |  | 
| 109     // (3 + 1 + 3). |  | 
| 110     const int kPadding = Debug::kX64JSReturnSequenceLength - 7; |  | 
| 111     for (int i = 0; i < kPadding; ++i) { |  | 
| 112       masm_->int3(); |  | 
| 113     } |  | 
| 114 #endif |  | 
| 115   } | 124   } | 
| 116 } | 125 } | 
| 117 | 126 | 
| 118 | 127 | 
| 119 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { | 128 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { | 
| 120   switch (context) { | 129   switch (context) { | 
| 121     case Expression::kUninitialized: | 130     case Expression::kUninitialized: | 
| 122       UNREACHABLE(); | 131       UNREACHABLE(); | 
| 123     case Expression::kEffect: | 132     case Expression::kEffect: | 
| 124       break; | 133       break; | 
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 172   SetStatementPosition(stmt); | 181   SetStatementPosition(stmt); | 
| 173   Expression* expr = stmt->expression(); | 182   Expression* expr = stmt->expression(); | 
| 174   if (expr->AsLiteral() != NULL) { | 183   if (expr->AsLiteral() != NULL) { | 
| 175     __ Move(rax, expr->AsLiteral()->handle()); | 184     __ Move(rax, expr->AsLiteral()->handle()); | 
| 176   } else { | 185   } else { | 
| 177     Visit(expr); | 186     Visit(expr); | 
| 178     ASSERT_EQ(Expression::kValue, expr->context()); | 187     ASSERT_EQ(Expression::kValue, expr->context()); | 
| 179     __ pop(rax); | 188     __ pop(rax); | 
| 180   } | 189   } | 
| 181 | 190 | 
| 182   if (FLAG_trace) { | 191   if (return_label_.is_bound()) { | 
| 183     __ push(rax); | 192     __ jmp(&return_label_); | 
| 184     __ CallRuntime(Runtime::kTraceExit, 1); | 193   } else { | 
|  | 194     __ bind(&return_label_); | 
|  | 195 | 
|  | 196     if (FLAG_trace) { | 
|  | 197       __ push(rax); | 
|  | 198       __ CallRuntime(Runtime::kTraceExit, 1); | 
|  | 199     } | 
|  | 200 | 
|  | 201     __ RecordJSReturn(); | 
|  | 202     // Do not use the leave instruction here because it is too short to | 
|  | 203     // patch with the code required by the debugger. | 
|  | 204     __ movq(rsp, rbp); | 
|  | 205     __ pop(rbp); | 
|  | 206     __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); | 
|  | 207 #ifdef ENABLE_DEBUGGER_SUPPORT | 
|  | 208     // Add padding that will be overwritten by a debugger breakpoint.  We | 
|  | 209     // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 | 
|  | 210     // (3 + 1 + 3). | 
|  | 211     const int kPadding = Debug::kX64JSReturnSequenceLength - 7; | 
|  | 212     for (int i = 0; i < kPadding; ++i) { | 
|  | 213       masm_->int3(); | 
|  | 214     } | 
|  | 215 #endif | 
| 185   } | 216   } | 
| 186 |  | 
| 187   __ RecordJSReturn(); |  | 
| 188   // Do not use the leave instruction here because it is too short to |  | 
| 189   // patch with the code required by the debugger. |  | 
| 190   __ movq(rsp, rbp); |  | 
| 191   __ pop(rbp); |  | 
| 192   __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); |  | 
| 193 #ifdef ENABLE_DEBUGGER_SUPPORT |  | 
| 194   // Add padding that will be overwritten by a debugger breakpoint.  We |  | 
| 195   // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 |  | 
| 196   // (3 + 1 + 3). |  | 
| 197   const int kPadding = Debug::kX64JSReturnSequenceLength - 7; |  | 
| 198   for (int i = 0; i < kPadding; ++i) { |  | 
| 199     masm_->int3(); |  | 
| 200   } |  | 
| 201 #endif |  | 
| 202 } | 217 } | 
| 203 | 218 | 
| 204 | 219 | 
| 205 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 220 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 
| 206   Comment cmnt(masm_, "[ FunctionLiteral"); | 221   Comment cmnt(masm_, "[ FunctionLiteral"); | 
| 207 | 222 | 
| 208   // Build the function boilerplate and instantiate it. | 223   // Build the function boilerplate and instantiate it. | 
| 209   Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 224   Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 
| 210   if (HasStackOverflow()) return; | 225   if (HasStackOverflow()) return; | 
| 211 | 226 | 
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 488     // on the stack. | 503     // on the stack. | 
| 489 | 504 | 
| 490     // Code for the right-hand-side expression depends on its type. | 505     // Code for the right-hand-side expression depends on its type. | 
| 491     if (rhs->AsLiteral() != NULL) { | 506     if (rhs->AsLiteral() != NULL) { | 
| 492       __ Move(rax, rhs->AsLiteral()->handle()); | 507       __ Move(rax, rhs->AsLiteral()->handle()); | 
| 493     } else { | 508     } else { | 
| 494       ASSERT_EQ(Expression::kValue, rhs->context()); | 509       ASSERT_EQ(Expression::kValue, rhs->context()); | 
| 495       Visit(rhs); | 510       Visit(rhs); | 
| 496       __ pop(rax); | 511       __ pop(rax); | 
| 497     } | 512     } | 
|  | 513     // Record position for debugger. | 
|  | 514     SetSourcePosition(expr->position()); | 
| 498     __ Move(rcx, var->name()); | 515     __ Move(rcx, var->name()); | 
| 499     __ push(CodeGenerator::GlobalObject()); | 516     __ push(CodeGenerator::GlobalObject()); | 
| 500     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 517     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 
| 501     __ Call(ic, RelocInfo::CODE_TARGET); | 518     __ Call(ic, RelocInfo::CODE_TARGET); | 
| 502     // Overwrite the global object on the stack with the result if needed. | 519     // Overwrite the global object on the stack with the result if needed. | 
| 503     DropAndMove(expr->context(), rax); | 520     DropAndMove(expr->context(), rax); | 
| 504   } else { | 521   } else { | 
| 505     // Local or parameter assignment. | 522     // Local or parameter assignment. | 
| 506 | 523 | 
| 507     // Code for the right-hand-side expression depends on its type. | 524     // Code for the right-hand-side expression depends on its type. | 
| (...skipping 29 matching lines...) Expand all  Loading... | 
| 537   Comment cmnt(masm_, "[ Property"); | 554   Comment cmnt(masm_, "[ Property"); | 
| 538   Expression* key = expr->key(); | 555   Expression* key = expr->key(); | 
| 539   uint32_t dummy; | 556   uint32_t dummy; | 
| 540 | 557 | 
| 541   // Record the source position for the property load. | 558   // Record the source position for the property load. | 
| 542   SetSourcePosition(expr->position()); | 559   SetSourcePosition(expr->position()); | 
| 543 | 560 | 
| 544   // Evaluate receiver. | 561   // Evaluate receiver. | 
| 545   Visit(expr->obj()); | 562   Visit(expr->obj()); | 
| 546 | 563 | 
|  | 564 | 
| 547   if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && | 565   if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && | 
| 548       !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { | 566       !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { | 
| 549     // Do a NAMED property load. | 567     // Do a NAMED property load. | 
| 550     // The IC expects the property name in rcx and the receiver on the stack. | 568     // The IC expects the property name in rcx and the receiver on the stack. | 
| 551     __ Move(rcx, key->AsLiteral()->handle()); | 569     __ Move(rcx, key->AsLiteral()->handle()); | 
| 552     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 570     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 
| 553     __ call(ic, RelocInfo::CODE_TARGET); | 571     __ call(ic, RelocInfo::CODE_TARGET); | 
| 554     // By emitting a nop we make sure that we do not have a "test rax,..." | 572     // By emitting a nop we make sure that we do not have a "test rax,..." | 
| 555     // instruction after the call it is treated specially by the LoadIC code. | 573     // instruction after the call it is treated specially by the LoadIC code. | 
| 556     __ nop(); | 574     __ nop(); | 
| 557   } else { | 575   } else { | 
| 558     // Do a KEYED property load. | 576     // Do a KEYED property load. | 
| 559     Visit(expr->key()); | 577     Visit(expr->key()); | 
| 560     Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 578     Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 
| 561     __ call(ic, RelocInfo::CODE_TARGET); | 579     __ call(ic, RelocInfo::CODE_TARGET); | 
| 562     // By emitting a nop we make sure that we do not have a "test rax,..." | 580     // By emitting a nop we make sure that we do not have a "test rax,..." | 
| 563     // instruction after the call it is treated specially by the LoadIC code. | 581     // instruction after the call it is treated specially by the LoadIC code. | 
| 564     __ nop(); | 582     __ nop(); | 
| 565     // Drop key left on the stack by IC. | 583     // Drop key left on the stack by IC. | 
| 566     __ addq(rsp, Immediate(kPointerSize)); | 584     __ addq(rsp, Immediate(kPointerSize)); | 
| 567   } | 585   } | 
| 568   DropAndMove(expr->context(), rax); | 586   DropAndMove(expr->context(), rax); | 
| 569 } | 587 } | 
| 570 | 588 | 
| 571 | 589 | 
| 572 void FastCodeGenerator::VisitCall(Call* expr) { | 590 void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { | 
| 573   Expression* fun = expr->expression(); | 591   // Code common for calls using the IC. | 
| 574   ZoneList<Expression*>* args = expr->arguments(); | 592   ZoneList<Expression*>* args = expr->arguments(); | 
| 575   Variable* var = fun->AsVariableProxy()->AsVariable(); |  | 
| 576   ASSERT(var != NULL && !var->is_this() && var->is_global()); |  | 
| 577   ASSERT(!var->is_possibly_eval()); |  | 
| 578 |  | 
| 579   __ Push(var->name()); |  | 
| 580   // Push global object (receiver). |  | 
| 581   __ push(CodeGenerator::GlobalObject()); |  | 
| 582   int arg_count = args->length(); | 593   int arg_count = args->length(); | 
| 583   for (int i = 0; i < arg_count; i++) { | 594   for (int i = 0; i < arg_count; i++) { | 
| 584     Visit(args->at(i)); | 595     Visit(args->at(i)); | 
| 585     ASSERT_EQ(Expression::kValue, args->at(i)->context()); | 596     ASSERT_EQ(Expression::kValue, args->at(i)->context()); | 
| 586   } | 597   } | 
| 587   // Record source position for debugger | 598   // Record source position for debugger. | 
| 588   SetSourcePosition(expr->position()); | 599   SetSourcePosition(expr->position()); | 
| 589   // Call the IC initialization code. | 600   // Call the IC initialization code. | 
| 590   Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 601   Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 
| 591                                                          NOT_IN_LOOP); | 602                                                          NOT_IN_LOOP); | 
| 592   __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 603   __ call(ic, reloc_info); | 
| 593   // Restore context register. | 604   // Restore context register. | 
| 594   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 605   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 
| 595   // Discard the function left on TOS. | 606   // Discard the function left on TOS. | 
| 596   DropAndMove(expr->context(), rax); | 607   DropAndMove(expr->context(), rax); | 
| 597 } | 608 } | 
| 598 | 609 | 
| 599 | 610 | 
|  | 611 void FastCodeGenerator::EmitCallWithStub(Call* expr) { | 
|  | 612   // Code common for calls using the call stub. | 
|  | 613   ZoneList<Expression*>* args = expr->arguments(); | 
|  | 614   int arg_count = args->length(); | 
|  | 615   for (int i = 0; i < arg_count; i++) { | 
|  | 616     Visit(args->at(i)); | 
|  | 617   } | 
|  | 618   // Record source position for debugger. | 
|  | 619   SetSourcePosition(expr->position()); | 
|  | 620   CallFunctionStub stub(arg_count, NOT_IN_LOOP); | 
|  | 621   __ CallStub(&stub); | 
|  | 622   // Restore context register. | 
|  | 623   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 
|  | 624   // Discard the function left on TOS. | 
|  | 625   DropAndMove(expr->context(), rax); | 
|  | 626 } | 
|  | 627 | 
|  | 628 | 
|  | 629 void FastCodeGenerator::VisitCall(Call* expr) { | 
|  | 630   Expression* fun = expr->expression(); | 
|  | 631 | 
|  | 632   if (fun->AsProperty() != NULL) { | 
|  | 633     // Call on a property. | 
|  | 634     Property* prop = fun->AsProperty(); | 
|  | 635     Literal* key = prop->key()->AsLiteral(); | 
|  | 636     if (key != NULL && key->handle()->IsSymbol()) { | 
|  | 637       // Call on a named property: foo.x(1,2,3) | 
|  | 638       __ Push(key->handle()); | 
|  | 639       Visit(prop->obj()); | 
|  | 640       // Use call IC | 
|  | 641       EmitCallWithIC(expr, RelocInfo::CODE_TARGET); | 
|  | 642     } else { | 
|  | 643       // Call on a keyed property: foo[key](1,2,3) | 
|  | 644       // Use a keyed load IC followed by a call IC. | 
|  | 645       Visit(prop->obj()); | 
|  | 646       Visit(prop->key()); | 
|  | 647       // Record source position of property. | 
|  | 648       SetSourcePosition(prop->position()); | 
|  | 649       Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 
|  | 650       __ call(ic, RelocInfo::CODE_TARGET); | 
|  | 651       // By emitting a nop we make sure that we do not have a "test eax,..." | 
|  | 652       // instruction after the call it is treated specially by the LoadIC code. | 
|  | 653       __ nop(); | 
|  | 654       // Drop key left on the stack by IC. | 
|  | 655       __ addq(rsp, Immediate(kPointerSize)); | 
|  | 656       // Pop receiver. | 
|  | 657       __ pop(rbx); | 
|  | 658       // Push result (function). | 
|  | 659       __ push(rax); | 
|  | 660       // Push receiver object on stack. | 
|  | 661       if (prop->is_synthetic()) { | 
|  | 662         __ push(CodeGenerator::GlobalObject()); | 
|  | 663       } else { | 
|  | 664         __ push(rbx); | 
|  | 665       } | 
|  | 666       EmitCallWithStub(expr); | 
|  | 667     } | 
|  | 668   } else if (fun->AsVariableProxy()->AsVariable() != NULL) { | 
|  | 669     // Call on a global variable | 
|  | 670     Variable* var = fun->AsVariableProxy()->AsVariable(); | 
|  | 671     ASSERT(var != NULL && !var->is_this() && var->is_global()); | 
|  | 672     ASSERT(!var->is_possibly_eval()); | 
|  | 673     __ Push(var->name()); | 
|  | 674     // Push global object (receiver). | 
|  | 675     __ push(CodeGenerator::GlobalObject()); | 
|  | 676     EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT); | 
|  | 677   } else { | 
|  | 678     // Calls we cannot handle right now. | 
|  | 679     // Should bailout in the CodeGenSelector. | 
|  | 680     UNREACHABLE(); | 
|  | 681   } | 
|  | 682 } | 
|  | 683 | 
|  | 684 | 
| 600 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 685 void FastCodeGenerator::VisitCallNew(CallNew* expr) { | 
| 601   Comment cmnt(masm_, "[ CallNew"); | 686   Comment cmnt(masm_, "[ CallNew"); | 
| 602   // According to ECMA-262, section 11.2.2, page 44, the function | 687   // According to ECMA-262, section 11.2.2, page 44, the function | 
| 603   // expression in new calls must be evaluated before the | 688   // expression in new calls must be evaluated before the | 
| 604   // arguments. | 689   // arguments. | 
| 605   // Push function on the stack. | 690   // Push function on the stack. | 
| 606   Visit(expr->expression()); | 691   Visit(expr->expression()); | 
| 607   ASSERT_EQ(Expression::kValue, expr->expression()->context()); | 692   ASSERT_EQ(Expression::kValue, expr->expression()->context()); | 
| 608   // If location is value, already on the stack, | 693   // If location is value, already on the stack, | 
| 609 | 694 | 
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 783   } | 868   } | 
| 784   // Save or discard the right-hand value as needed. | 869   // Save or discard the right-hand value as needed. | 
| 785   Visit(right); | 870   Visit(right); | 
| 786   ASSERT_EQ(context, right->context()); | 871   ASSERT_EQ(context, right->context()); | 
| 787 | 872 | 
| 788   __ bind(&done); | 873   __ bind(&done); | 
| 789 } | 874 } | 
| 790 | 875 | 
| 791 | 876 | 
| 792 } }  // namespace v8::internal | 877 } }  // namespace v8::internal | 
| OLD | NEW | 
|---|