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 |