| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 #endif | 122 #endif |
| 123 | 123 |
| 124 __ push(ebp); // Caller's frame pointer. | 124 __ push(ebp); // Caller's frame pointer. |
| 125 __ mov(ebp, esp); | 125 __ mov(ebp, esp); |
| 126 __ push(esi); // Callee's context. | 126 __ push(esi); // Callee's context. |
| 127 __ push(edi); // Callee's JS Function. | 127 __ push(edi); // Callee's JS Function. |
| 128 | 128 |
| 129 { Comment cmnt(masm_, "[ Allocate locals"); | 129 { Comment cmnt(masm_, "[ Allocate locals"); |
| 130 int locals_count = scope()->num_stack_slots(); | 130 int locals_count = scope()->num_stack_slots(); |
| 131 if (locals_count == 1) { | 131 if (locals_count == 1) { |
| 132 __ push(Immediate(Factory::undefined_value())); | 132 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 133 } else if (locals_count > 1) { | 133 } else if (locals_count > 1) { |
| 134 __ mov(eax, Immediate(Factory::undefined_value())); | 134 __ mov(eax, Immediate(isolate()->factory()->undefined_value())); |
| 135 for (int i = 0; i < locals_count; i++) { | 135 for (int i = 0; i < locals_count; i++) { |
| 136 __ push(eax); | 136 __ push(eax); |
| 137 } | 137 } |
| 138 } | 138 } |
| 139 } | 139 } |
| 140 | 140 |
| 141 bool function_in_register = true; | 141 bool function_in_register = true; |
| 142 | 142 |
| 143 // Possibly allocate a local context. | 143 // Possibly allocate a local context. |
| 144 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 144 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 { Comment cmnt(masm_, "[ Body"); | 245 { Comment cmnt(masm_, "[ Body"); |
| 246 ASSERT(loop_depth() == 0); | 246 ASSERT(loop_depth() == 0); |
| 247 VisitStatements(function()->body()); | 247 VisitStatements(function()->body()); |
| 248 ASSERT(loop_depth() == 0); | 248 ASSERT(loop_depth() == 0); |
| 249 } | 249 } |
| 250 } | 250 } |
| 251 | 251 |
| 252 // Always emit a 'return undefined' in case control fell off the end of | 252 // Always emit a 'return undefined' in case control fell off the end of |
| 253 // the body. | 253 // the body. |
| 254 { Comment cmnt(masm_, "[ return <undefined>;"); | 254 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 255 __ mov(eax, Factory::undefined_value()); | 255 __ mov(eax, isolate()->factory()->undefined_value()); |
| 256 EmitReturnSequence(); | 256 EmitReturnSequence(); |
| 257 } | 257 } |
| 258 } | 258 } |
| 259 | 259 |
| 260 | 260 |
| 261 void FullCodeGenerator::ClearAccumulator() { | 261 void FullCodeGenerator::ClearAccumulator() { |
| 262 __ Set(eax, Immediate(Smi::FromInt(0))); | 262 __ Set(eax, Immediate(Smi::FromInt(0))); |
| 263 } | 263 } |
| 264 | 264 |
| 265 | 265 |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 ASSERT(materialize_true == materialize_false); | 460 ASSERT(materialize_true == materialize_false); |
| 461 __ bind(materialize_true); | 461 __ bind(materialize_true); |
| 462 } | 462 } |
| 463 | 463 |
| 464 | 464 |
| 465 void FullCodeGenerator::AccumulatorValueContext::Plug( | 465 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 466 Label* materialize_true, | 466 Label* materialize_true, |
| 467 Label* materialize_false) const { | 467 Label* materialize_false) const { |
| 468 NearLabel done; | 468 NearLabel done; |
| 469 __ bind(materialize_true); | 469 __ bind(materialize_true); |
| 470 __ mov(result_register(), Factory::true_value()); | 470 __ mov(result_register(), isolate()->factory()->true_value()); |
| 471 __ jmp(&done); | 471 __ jmp(&done); |
| 472 __ bind(materialize_false); | 472 __ bind(materialize_false); |
| 473 __ mov(result_register(), Factory::false_value()); | 473 __ mov(result_register(), isolate()->factory()->false_value()); |
| 474 __ bind(&done); | 474 __ bind(&done); |
| 475 } | 475 } |
| 476 | 476 |
| 477 | 477 |
| 478 void FullCodeGenerator::StackValueContext::Plug( | 478 void FullCodeGenerator::StackValueContext::Plug( |
| 479 Label* materialize_true, | 479 Label* materialize_true, |
| 480 Label* materialize_false) const { | 480 Label* materialize_false) const { |
| 481 NearLabel done; | 481 NearLabel done; |
| 482 __ bind(materialize_true); | 482 __ bind(materialize_true); |
| 483 __ push(Immediate(Factory::true_value())); | 483 __ push(Immediate(isolate()->factory()->true_value())); |
| 484 __ jmp(&done); | 484 __ jmp(&done); |
| 485 __ bind(materialize_false); | 485 __ bind(materialize_false); |
| 486 __ push(Immediate(Factory::false_value())); | 486 __ push(Immediate(isolate()->factory()->false_value())); |
| 487 __ bind(&done); | 487 __ bind(&done); |
| 488 } | 488 } |
| 489 | 489 |
| 490 | 490 |
| 491 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, | 491 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
| 492 Label* materialize_false) const { | 492 Label* materialize_false) const { |
| 493 ASSERT(materialize_true == true_label_); | 493 ASSERT(materialize_true == true_label_); |
| 494 ASSERT(materialize_false == false_label_); | 494 ASSERT(materialize_false == false_label_); |
| 495 } | 495 } |
| 496 | 496 |
| 497 | 497 |
| 498 void FullCodeGenerator::EffectContext::Plug(bool flag) const { | 498 void FullCodeGenerator::EffectContext::Plug(bool flag) const { |
| 499 } | 499 } |
| 500 | 500 |
| 501 | 501 |
| 502 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { | 502 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { |
| 503 Handle<Object> value = | 503 Handle<Object> value = flag |
| 504 flag ? Factory::true_value() : Factory::false_value(); | 504 ? isolate()->factory()->true_value() |
| 505 : isolate()->factory()->false_value(); |
| 505 __ mov(result_register(), value); | 506 __ mov(result_register(), value); |
| 506 } | 507 } |
| 507 | 508 |
| 508 | 509 |
| 509 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 510 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
| 510 Handle<Object> value = | 511 Handle<Object> value = flag |
| 511 flag ? Factory::true_value() : Factory::false_value(); | 512 ? isolate()->factory()->true_value() |
| 513 : isolate()->factory()->false_value(); |
| 512 __ push(Immediate(value)); | 514 __ push(Immediate(value)); |
| 513 } | 515 } |
| 514 | 516 |
| 515 | 517 |
| 516 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 518 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
| 517 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, | 519 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 518 true, | 520 true, |
| 519 true_label_, | 521 true_label_, |
| 520 false_label_); | 522 false_label_); |
| 521 if (flag) { | 523 if (flag) { |
| 522 if (true_label_ != fall_through_) __ jmp(true_label_); | 524 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 523 } else { | 525 } else { |
| 524 if (false_label_ != fall_through_) __ jmp(false_label_); | 526 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 525 } | 527 } |
| 526 } | 528 } |
| 527 | 529 |
| 528 | 530 |
| 529 void FullCodeGenerator::DoTest(Label* if_true, | 531 void FullCodeGenerator::DoTest(Label* if_true, |
| 530 Label* if_false, | 532 Label* if_false, |
| 531 Label* fall_through) { | 533 Label* fall_through) { |
| 532 // Emit the inlined tests assumed by the stub. | 534 // Emit the inlined tests assumed by the stub. |
| 533 __ cmp(result_register(), Factory::undefined_value()); | 535 __ cmp(result_register(), isolate()->factory()->undefined_value()); |
| 534 __ j(equal, if_false); | 536 __ j(equal, if_false); |
| 535 __ cmp(result_register(), Factory::true_value()); | 537 __ cmp(result_register(), isolate()->factory()->true_value()); |
| 536 __ j(equal, if_true); | 538 __ j(equal, if_true); |
| 537 __ cmp(result_register(), Factory::false_value()); | 539 __ cmp(result_register(), isolate()->factory()->false_value()); |
| 538 __ j(equal, if_false); | 540 __ j(equal, if_false); |
| 539 STATIC_ASSERT(kSmiTag == 0); | 541 STATIC_ASSERT(kSmiTag == 0); |
| 540 __ test(result_register(), Operand(result_register())); | 542 __ test(result_register(), Operand(result_register())); |
| 541 __ j(zero, if_false); | 543 __ j(zero, if_false); |
| 542 __ test(result_register(), Immediate(kSmiTagMask)); | 544 __ test(result_register(), Immediate(kSmiTagMask)); |
| 543 __ j(zero, if_true); | 545 __ j(zero, if_true); |
| 544 | 546 |
| 545 // Call the ToBoolean stub for all other cases. | 547 // Call the ToBoolean stub for all other cases. |
| 546 ToBooleanStub stub; | 548 ToBooleanStub stub; |
| 547 __ push(result_register()); | 549 __ push(result_register()); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 NearLabel skip; | 624 NearLabel skip; |
| 623 if (should_normalize) __ jmp(&skip); | 625 if (should_normalize) __ jmp(&skip); |
| 624 | 626 |
| 625 ForwardBailoutStack* current = forward_bailout_stack_; | 627 ForwardBailoutStack* current = forward_bailout_stack_; |
| 626 while (current != NULL) { | 628 while (current != NULL) { |
| 627 PrepareForBailout(current->expr(), state); | 629 PrepareForBailout(current->expr(), state); |
| 628 current = current->parent(); | 630 current = current->parent(); |
| 629 } | 631 } |
| 630 | 632 |
| 631 if (should_normalize) { | 633 if (should_normalize) { |
| 632 __ cmp(eax, Factory::true_value()); | 634 __ cmp(eax, isolate()->factory()->true_value()); |
| 633 Split(equal, if_true, if_false, NULL); | 635 Split(equal, if_true, if_false, NULL); |
| 634 __ bind(&skip); | 636 __ bind(&skip); |
| 635 } | 637 } |
| 636 } | 638 } |
| 637 | 639 |
| 638 | 640 |
| 639 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 641 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 640 Variable::Mode mode, | 642 Variable::Mode mode, |
| 641 FunctionLiteral* function) { | 643 FunctionLiteral* function) { |
| 642 Comment cmnt(masm_, "[ Declaration"); | 644 Comment cmnt(masm_, "[ Declaration"); |
| 643 ASSERT(variable != NULL); // Must have been resolved. | 645 ASSERT(variable != NULL); // Must have been resolved. |
| 644 Slot* slot = variable->AsSlot(); | 646 Slot* slot = variable->AsSlot(); |
| 645 Property* prop = variable->AsProperty(); | 647 Property* prop = variable->AsProperty(); |
| 646 | 648 |
| 647 if (slot != NULL) { | 649 if (slot != NULL) { |
| 648 switch (slot->type()) { | 650 switch (slot->type()) { |
| 649 case Slot::PARAMETER: | 651 case Slot::PARAMETER: |
| 650 case Slot::LOCAL: | 652 case Slot::LOCAL: |
| 651 if (mode == Variable::CONST) { | 653 if (mode == Variable::CONST) { |
| 652 __ mov(Operand(ebp, SlotOffset(slot)), | 654 __ mov(Operand(ebp, SlotOffset(slot)), |
| 653 Immediate(Factory::the_hole_value())); | 655 Immediate(isolate()->factory()->the_hole_value())); |
| 654 } else if (function != NULL) { | 656 } else if (function != NULL) { |
| 655 VisitForAccumulatorValue(function); | 657 VisitForAccumulatorValue(function); |
| 656 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 658 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| 657 } | 659 } |
| 658 break; | 660 break; |
| 659 | 661 |
| 660 case Slot::CONTEXT: | 662 case Slot::CONTEXT: |
| 661 // We bypass the general EmitSlotSearch because we know more about | 663 // We bypass the general EmitSlotSearch because we know more about |
| 662 // this specific context. | 664 // this specific context. |
| 663 | 665 |
| 664 // The variable in the decl always resides in the current function | 666 // The variable in the decl always resides in the current function |
| 665 // context. | 667 // context. |
| 666 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 668 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 667 if (FLAG_debug_code) { | 669 if (FLAG_debug_code) { |
| 668 // Check that we're not inside a 'with'. | 670 // Check that we're not inside a 'with'. |
| 669 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | 671 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 670 __ cmp(ebx, Operand(esi)); | 672 __ cmp(ebx, Operand(esi)); |
| 671 __ Check(equal, "Unexpected declaration in current context."); | 673 __ Check(equal, "Unexpected declaration in current context."); |
| 672 } | 674 } |
| 673 if (mode == Variable::CONST) { | 675 if (mode == Variable::CONST) { |
| 674 __ mov(ContextOperand(esi, slot->index()), | 676 __ mov(ContextOperand(esi, slot->index()), |
| 675 Immediate(Factory::the_hole_value())); | 677 Immediate(isolate()->factory()->the_hole_value())); |
| 676 // No write barrier since the hole value is in old space. | 678 // No write barrier since the hole value is in old space. |
| 677 } else if (function != NULL) { | 679 } else if (function != NULL) { |
| 678 VisitForAccumulatorValue(function); | 680 VisitForAccumulatorValue(function); |
| 679 __ mov(ContextOperand(esi, slot->index()), result_register()); | 681 __ mov(ContextOperand(esi, slot->index()), result_register()); |
| 680 int offset = Context::SlotOffset(slot->index()); | 682 int offset = Context::SlotOffset(slot->index()); |
| 681 __ mov(ebx, esi); | 683 __ mov(ebx, esi); |
| 682 __ RecordWrite(ebx, offset, result_register(), ecx); | 684 __ RecordWrite(ebx, offset, result_register(), ecx); |
| 683 } | 685 } |
| 684 break; | 686 break; |
| 685 | 687 |
| 686 case Slot::LOOKUP: { | 688 case Slot::LOOKUP: { |
| 687 __ push(esi); | 689 __ push(esi); |
| 688 __ push(Immediate(variable->name())); | 690 __ push(Immediate(variable->name())); |
| 689 // Declaration nodes are always introduced in one of two modes. | 691 // Declaration nodes are always introduced in one of two modes. |
| 690 ASSERT(mode == Variable::VAR || mode == Variable::CONST); | 692 ASSERT(mode == Variable::VAR || mode == Variable::CONST); |
| 691 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; | 693 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; |
| 692 __ push(Immediate(Smi::FromInt(attr))); | 694 __ push(Immediate(Smi::FromInt(attr))); |
| 693 // Push initial value, if any. | 695 // Push initial value, if any. |
| 694 // Note: For variables we must not push an initial value (such as | 696 // Note: For variables we must not push an initial value (such as |
| 695 // 'undefined') because we may have a (legal) redeclaration and we | 697 // 'undefined') because we may have a (legal) redeclaration and we |
| 696 // must not destroy the current value. | 698 // must not destroy the current value. |
| 697 if (mode == Variable::CONST) { | 699 if (mode == Variable::CONST) { |
| 698 __ push(Immediate(Factory::the_hole_value())); | 700 __ push(Immediate(isolate()->factory()->the_hole_value())); |
| 699 } else if (function != NULL) { | 701 } else if (function != NULL) { |
| 700 VisitForStackValue(function); | 702 VisitForStackValue(function); |
| 701 } else { | 703 } else { |
| 702 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 704 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
| 703 } | 705 } |
| 704 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 706 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 705 break; | 707 break; |
| 706 } | 708 } |
| 707 } | 709 } |
| 708 | 710 |
| 709 } else if (prop != NULL) { | 711 } else if (prop != NULL) { |
| 710 if (function != NULL || mode == Variable::CONST) { | 712 if (function != NULL || mode == Variable::CONST) { |
| 711 // We are declaring a function or constant that rewrites to a | 713 // We are declaring a function or constant that rewrites to a |
| 712 // property. Use (keyed) IC to set the initial value. We cannot | 714 // property. Use (keyed) IC to set the initial value. We cannot |
| 713 // visit the rewrite because it's shared and we risk recording | 715 // visit the rewrite because it's shared and we risk recording |
| 714 // duplicate AST IDs for bailouts from optimized code. | 716 // duplicate AST IDs for bailouts from optimized code. |
| 715 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 717 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 716 { AccumulatorValueContext for_object(this); | 718 { AccumulatorValueContext for_object(this); |
| 717 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | 719 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 718 } | 720 } |
| 719 | 721 |
| 720 if (function != NULL) { | 722 if (function != NULL) { |
| 721 __ push(eax); | 723 __ push(eax); |
| 722 VisitForAccumulatorValue(function); | 724 VisitForAccumulatorValue(function); |
| 723 __ pop(edx); | 725 __ pop(edx); |
| 724 } else { | 726 } else { |
| 725 __ mov(edx, eax); | 727 __ mov(edx, eax); |
| 726 __ mov(eax, Factory::the_hole_value()); | 728 __ mov(eax, isolate()->factory()->the_hole_value()); |
| 727 } | 729 } |
| 728 ASSERT(prop->key()->AsLiteral() != NULL && | 730 ASSERT(prop->key()->AsLiteral() != NULL && |
| 729 prop->key()->AsLiteral()->handle()->IsSmi()); | 731 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 730 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 732 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 731 | 733 |
| 732 Handle<Code> ic(Builtins::builtin( | 734 Handle<Code> ic(isolate()->builtins()->builtin(is_strict_mode() |
| 733 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 735 ? Builtins::KeyedStoreIC_Initialize_Strict |
| 734 : Builtins::KeyedStoreIC_Initialize)); | 736 : Builtins::KeyedStoreIC_Initialize)); |
| 735 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 737 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 736 } | 738 } |
| 737 } | 739 } |
| 738 } | 740 } |
| 739 | 741 |
| 740 | 742 |
| 741 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 743 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 742 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 744 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 743 } | 745 } |
| 744 | 746 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 SetStatementPosition(stmt); | 843 SetStatementPosition(stmt); |
| 842 | 844 |
| 843 Label loop, exit; | 845 Label loop, exit; |
| 844 ForIn loop_statement(this, stmt); | 846 ForIn loop_statement(this, stmt); |
| 845 increment_loop_depth(); | 847 increment_loop_depth(); |
| 846 | 848 |
| 847 // Get the object to enumerate over. Both SpiderMonkey and JSC | 849 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 848 // ignore null and undefined in contrast to the specification; see | 850 // ignore null and undefined in contrast to the specification; see |
| 849 // ECMA-262 section 12.6.4. | 851 // ECMA-262 section 12.6.4. |
| 850 VisitForAccumulatorValue(stmt->enumerable()); | 852 VisitForAccumulatorValue(stmt->enumerable()); |
| 851 __ cmp(eax, Factory::undefined_value()); | 853 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 852 __ j(equal, &exit); | 854 __ j(equal, &exit); |
| 853 __ cmp(eax, Factory::null_value()); | 855 __ cmp(eax, isolate()->factory()->null_value()); |
| 854 __ j(equal, &exit); | 856 __ j(equal, &exit); |
| 855 | 857 |
| 856 // Convert the object to a JS object. | 858 // Convert the object to a JS object. |
| 857 NearLabel convert, done_convert; | 859 NearLabel convert, done_convert; |
| 858 __ test(eax, Immediate(kSmiTagMask)); | 860 __ test(eax, Immediate(kSmiTagMask)); |
| 859 __ j(zero, &convert); | 861 __ j(zero, &convert); |
| 860 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 862 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 861 __ j(above_equal, &done_convert); | 863 __ j(above_equal, &done_convert); |
| 862 __ bind(&convert); | 864 __ bind(&convert); |
| 863 __ push(eax); | 865 __ push(eax); |
| 864 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 866 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 865 __ bind(&done_convert); | 867 __ bind(&done_convert); |
| 866 __ push(eax); | 868 __ push(eax); |
| 867 | 869 |
| 868 // Check cache validity in generated code. This is a fast case for | 870 // Check cache validity in generated code. This is a fast case for |
| 869 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 871 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 870 // guarantee cache validity, call the runtime system to check cache | 872 // guarantee cache validity, call the runtime system to check cache |
| 871 // validity or get the property names in a fixed array. | 873 // validity or get the property names in a fixed array. |
| 872 Label next, call_runtime; | 874 Label next, call_runtime; |
| 873 __ mov(ecx, eax); | 875 __ mov(ecx, eax); |
| 874 __ bind(&next); | 876 __ bind(&next); |
| 875 | 877 |
| 876 // Check that there are no elements. Register ecx contains the | 878 // Check that there are no elements. Register ecx contains the |
| 877 // current JS object we've reached through the prototype chain. | 879 // current JS object we've reached through the prototype chain. |
| 878 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset), | 880 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset), |
| 879 Factory::empty_fixed_array()); | 881 isolate()->factory()->empty_fixed_array()); |
| 880 __ j(not_equal, &call_runtime); | 882 __ j(not_equal, &call_runtime); |
| 881 | 883 |
| 882 // Check that instance descriptors are not empty so that we can | 884 // Check that instance descriptors are not empty so that we can |
| 883 // check for an enum cache. Leave the map in ebx for the subsequent | 885 // check for an enum cache. Leave the map in ebx for the subsequent |
| 884 // prototype load. | 886 // prototype load. |
| 885 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | 887 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 886 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); | 888 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); |
| 887 __ cmp(edx, Factory::empty_descriptor_array()); | 889 __ cmp(edx, isolate()->factory()->empty_descriptor_array()); |
| 888 __ j(equal, &call_runtime); | 890 __ j(equal, &call_runtime); |
| 889 | 891 |
| 890 // Check that there is an enum cache in the non-empty instance | 892 // Check that there is an enum cache in the non-empty instance |
| 891 // descriptors (edx). This is the case if the next enumeration | 893 // descriptors (edx). This is the case if the next enumeration |
| 892 // index field does not contain a smi. | 894 // index field does not contain a smi. |
| 893 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 895 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 894 __ test(edx, Immediate(kSmiTagMask)); | 896 __ test(edx, Immediate(kSmiTagMask)); |
| 895 __ j(zero, &call_runtime); | 897 __ j(zero, &call_runtime); |
| 896 | 898 |
| 897 // For all objects but the receiver, check that the cache is empty. | 899 // For all objects but the receiver, check that the cache is empty. |
| 898 NearLabel check_prototype; | 900 NearLabel check_prototype; |
| 899 __ cmp(ecx, Operand(eax)); | 901 __ cmp(ecx, Operand(eax)); |
| 900 __ j(equal, &check_prototype); | 902 __ j(equal, &check_prototype); |
| 901 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 903 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 902 __ cmp(edx, Factory::empty_fixed_array()); | 904 __ cmp(edx, isolate()->factory()->empty_fixed_array()); |
| 903 __ j(not_equal, &call_runtime); | 905 __ j(not_equal, &call_runtime); |
| 904 | 906 |
| 905 // Load the prototype from the map and loop if non-null. | 907 // Load the prototype from the map and loop if non-null. |
| 906 __ bind(&check_prototype); | 908 __ bind(&check_prototype); |
| 907 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 909 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
| 908 __ cmp(ecx, Factory::null_value()); | 910 __ cmp(ecx, isolate()->factory()->null_value()); |
| 909 __ j(not_equal, &next); | 911 __ j(not_equal, &next); |
| 910 | 912 |
| 911 // The enum cache is valid. Load the map of the object being | 913 // The enum cache is valid. Load the map of the object being |
| 912 // iterated over and use the cache for the iteration. | 914 // iterated over and use the cache for the iteration. |
| 913 NearLabel use_cache; | 915 NearLabel use_cache; |
| 914 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 916 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 915 __ jmp(&use_cache); | 917 __ jmp(&use_cache); |
| 916 | 918 |
| 917 // Get the set of properties to enumerate. | 919 // Get the set of properties to enumerate. |
| 918 __ bind(&call_runtime); | 920 __ bind(&call_runtime); |
| 919 __ push(eax); // Duplicate the enumerable object on the stack. | 921 __ push(eax); // Duplicate the enumerable object on the stack. |
| 920 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 922 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 921 | 923 |
| 922 // If we got a map from the runtime call, we can do a fast | 924 // If we got a map from the runtime call, we can do a fast |
| 923 // modification check. Otherwise, we got a fixed array, and we have | 925 // modification check. Otherwise, we got a fixed array, and we have |
| 924 // to do a slow check. | 926 // to do a slow check. |
| 925 NearLabel fixed_array; | 927 NearLabel fixed_array; |
| 926 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map()); | 928 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 929 isolate()->factory()->meta_map()); |
| 927 __ j(not_equal, &fixed_array); | 930 __ j(not_equal, &fixed_array); |
| 928 | 931 |
| 929 // We got a map in register eax. Get the enumeration cache from it. | 932 // We got a map in register eax. Get the enumeration cache from it. |
| 930 __ bind(&use_cache); | 933 __ bind(&use_cache); |
| 931 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); | 934 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); |
| 932 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 935 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 933 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 936 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 934 | 937 |
| 935 // Setup the four remaining stack slots. | 938 // Setup the four remaining stack slots. |
| 936 __ push(eax); // Map. | 939 __ push(eax); // Map. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 !pretenure && | 1025 !pretenure && |
| 1023 scope()->is_function_scope() && | 1026 scope()->is_function_scope() && |
| 1024 info->num_literals() == 0) { | 1027 info->num_literals() == 0) { |
| 1025 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode); | 1028 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode); |
| 1026 __ push(Immediate(info)); | 1029 __ push(Immediate(info)); |
| 1027 __ CallStub(&stub); | 1030 __ CallStub(&stub); |
| 1028 } else { | 1031 } else { |
| 1029 __ push(esi); | 1032 __ push(esi); |
| 1030 __ push(Immediate(info)); | 1033 __ push(Immediate(info)); |
| 1031 __ push(Immediate(pretenure | 1034 __ push(Immediate(pretenure |
| 1032 ? Factory::true_value() | 1035 ? isolate()->factory()->true_value() |
| 1033 : Factory::false_value())); | 1036 : isolate()->factory()->false_value())); |
| 1034 __ CallRuntime(Runtime::kNewClosure, 3); | 1037 __ CallRuntime(Runtime::kNewClosure, 3); |
| 1035 } | 1038 } |
| 1036 context()->Plug(eax); | 1039 context()->Plug(eax); |
| 1037 } | 1040 } |
| 1038 | 1041 |
| 1039 | 1042 |
| 1040 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 1043 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 1041 Comment cmnt(masm_, "[ VariableProxy"); | 1044 Comment cmnt(masm_, "[ VariableProxy"); |
| 1042 EmitVariableLoad(expr->var()); | 1045 EmitVariableLoad(expr->var()); |
| 1043 } | 1046 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1075 if (s != NULL && s->is_eval_scope()) { | 1078 if (s != NULL && s->is_eval_scope()) { |
| 1076 // Loop up the context chain. There is no frame effect so it is | 1079 // Loop up the context chain. There is no frame effect so it is |
| 1077 // safe to use raw labels here. | 1080 // safe to use raw labels here. |
| 1078 NearLabel next, fast; | 1081 NearLabel next, fast; |
| 1079 if (!context.is(temp)) { | 1082 if (!context.is(temp)) { |
| 1080 __ mov(temp, context); | 1083 __ mov(temp, context); |
| 1081 } | 1084 } |
| 1082 __ bind(&next); | 1085 __ bind(&next); |
| 1083 // Terminate at global context. | 1086 // Terminate at global context. |
| 1084 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), | 1087 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), |
| 1085 Immediate(Factory::global_context_map())); | 1088 Immediate(isolate()->factory()->global_context_map())); |
| 1086 __ j(equal, &fast); | 1089 __ j(equal, &fast); |
| 1087 // Check that extension is NULL. | 1090 // Check that extension is NULL. |
| 1088 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); | 1091 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 1089 __ j(not_equal, slow); | 1092 __ j(not_equal, slow); |
| 1090 // Load next context in chain. | 1093 // Load next context in chain. |
| 1091 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); | 1094 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); |
| 1092 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1095 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 1093 __ jmp(&next); | 1096 __ jmp(&next); |
| 1094 __ bind(&fast); | 1097 __ bind(&fast); |
| 1095 } | 1098 } |
| 1096 | 1099 |
| 1097 // All extension objects were empty and it is safe to use a global | 1100 // All extension objects were empty and it is safe to use a global |
| 1098 // load IC call. | 1101 // load IC call. |
| 1099 __ mov(eax, GlobalObjectOperand()); | 1102 __ mov(eax, GlobalObjectOperand()); |
| 1100 __ mov(ecx, slot->var()->name()); | 1103 __ mov(ecx, slot->var()->name()); |
| 1101 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1104 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1105 Builtins::LoadIC_Initialize)); |
| 1102 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1106 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 1103 ? RelocInfo::CODE_TARGET | 1107 ? RelocInfo::CODE_TARGET |
| 1104 : RelocInfo::CODE_TARGET_CONTEXT; | 1108 : RelocInfo::CODE_TARGET_CONTEXT; |
| 1105 EmitCallIC(ic, mode); | 1109 EmitCallIC(ic, mode); |
| 1106 } | 1110 } |
| 1107 | 1111 |
| 1108 | 1112 |
| 1109 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( | 1113 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 1110 Slot* slot, | 1114 Slot* slot, |
| 1111 Label* slow) { | 1115 Label* slow) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1152 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); | 1156 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 1153 __ jmp(done); | 1157 __ jmp(done); |
| 1154 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 1158 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 1155 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); | 1159 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); |
| 1156 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | 1160 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 1157 if (potential_slot != NULL) { | 1161 if (potential_slot != NULL) { |
| 1158 // Generate fast case for locals that rewrite to slots. | 1162 // Generate fast case for locals that rewrite to slots. |
| 1159 __ mov(eax, | 1163 __ mov(eax, |
| 1160 ContextSlotOperandCheckExtensions(potential_slot, slow)); | 1164 ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1161 if (potential_slot->var()->mode() == Variable::CONST) { | 1165 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1162 __ cmp(eax, Factory::the_hole_value()); | 1166 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1163 __ j(not_equal, done); | 1167 __ j(not_equal, done); |
| 1164 __ mov(eax, Factory::undefined_value()); | 1168 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1165 } | 1169 } |
| 1166 __ jmp(done); | 1170 __ jmp(done); |
| 1167 } else if (rewrite != NULL) { | 1171 } else if (rewrite != NULL) { |
| 1168 // Generate fast case for calls of an argument function. | 1172 // Generate fast case for calls of an argument function. |
| 1169 Property* property = rewrite->AsProperty(); | 1173 Property* property = rewrite->AsProperty(); |
| 1170 if (property != NULL) { | 1174 if (property != NULL) { |
| 1171 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1175 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1172 Literal* key_literal = property->key()->AsLiteral(); | 1176 Literal* key_literal = property->key()->AsLiteral(); |
| 1173 if (obj_proxy != NULL && | 1177 if (obj_proxy != NULL && |
| 1174 key_literal != NULL && | 1178 key_literal != NULL && |
| 1175 obj_proxy->IsArguments() && | 1179 obj_proxy->IsArguments() && |
| 1176 key_literal->handle()->IsSmi()) { | 1180 key_literal->handle()->IsSmi()) { |
| 1177 // Load arguments object if there are no eval-introduced | 1181 // Load arguments object if there are no eval-introduced |
| 1178 // variables. Then load the argument from the arguments | 1182 // variables. Then load the argument from the arguments |
| 1179 // object using keyed load. | 1183 // object using keyed load. |
| 1180 __ mov(edx, | 1184 __ mov(edx, |
| 1181 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | 1185 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), |
| 1182 slow)); | 1186 slow)); |
| 1183 __ mov(eax, Immediate(key_literal->handle())); | 1187 __ mov(eax, Immediate(key_literal->handle())); |
| 1184 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1188 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1189 Builtins::KeyedLoadIC_Initialize)); |
| 1185 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1190 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1186 __ jmp(done); | 1191 __ jmp(done); |
| 1187 } | 1192 } |
| 1188 } | 1193 } |
| 1189 } | 1194 } |
| 1190 } | 1195 } |
| 1191 } | 1196 } |
| 1192 | 1197 |
| 1193 | 1198 |
| 1194 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1199 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1195 // Four cases: non-this global variables, lookup slots, all other | 1200 // Four cases: non-this global variables, lookup slots, all other |
| 1196 // types of slots, and parameters that rewrite to explicit property | 1201 // types of slots, and parameters that rewrite to explicit property |
| 1197 // accesses on the arguments object. | 1202 // accesses on the arguments object. |
| 1198 Slot* slot = var->AsSlot(); | 1203 Slot* slot = var->AsSlot(); |
| 1199 Property* property = var->AsProperty(); | 1204 Property* property = var->AsProperty(); |
| 1200 | 1205 |
| 1201 if (var->is_global() && !var->is_this()) { | 1206 if (var->is_global() && !var->is_this()) { |
| 1202 Comment cmnt(masm_, "Global variable"); | 1207 Comment cmnt(masm_, "Global variable"); |
| 1203 // Use inline caching. Variable name is passed in ecx and the global | 1208 // Use inline caching. Variable name is passed in ecx and the global |
| 1204 // object on the stack. | 1209 // object on the stack. |
| 1205 __ mov(eax, GlobalObjectOperand()); | 1210 __ mov(eax, GlobalObjectOperand()); |
| 1206 __ mov(ecx, var->name()); | 1211 __ mov(ecx, var->name()); |
| 1207 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1212 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1213 Builtins::LoadIC_Initialize)); |
| 1208 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1214 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1209 context()->Plug(eax); | 1215 context()->Plug(eax); |
| 1210 | 1216 |
| 1211 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1217 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1212 Label done, slow; | 1218 Label done, slow; |
| 1213 | 1219 |
| 1214 // Generate code for loading from variables potentially shadowed | 1220 // Generate code for loading from variables potentially shadowed |
| 1215 // by eval-introduced variables. | 1221 // by eval-introduced variables. |
| 1216 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1222 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1217 | 1223 |
| 1218 __ bind(&slow); | 1224 __ bind(&slow); |
| 1219 Comment cmnt(masm_, "Lookup slot"); | 1225 Comment cmnt(masm_, "Lookup slot"); |
| 1220 __ push(esi); // Context. | 1226 __ push(esi); // Context. |
| 1221 __ push(Immediate(var->name())); | 1227 __ push(Immediate(var->name())); |
| 1222 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1228 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1223 __ bind(&done); | 1229 __ bind(&done); |
| 1224 | 1230 |
| 1225 context()->Plug(eax); | 1231 context()->Plug(eax); |
| 1226 | 1232 |
| 1227 } else if (slot != NULL) { | 1233 } else if (slot != NULL) { |
| 1228 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1234 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1229 ? "Context slot" | 1235 ? "Context slot" |
| 1230 : "Stack slot"); | 1236 : "Stack slot"); |
| 1231 if (var->mode() == Variable::CONST) { | 1237 if (var->mode() == Variable::CONST) { |
| 1232 // Constants may be the hole value if they have not been initialized. | 1238 // Constants may be the hole value if they have not been initialized. |
| 1233 // Unhole them. | 1239 // Unhole them. |
| 1234 NearLabel done; | 1240 NearLabel done; |
| 1235 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1241 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1236 __ mov(eax, slot_operand); | 1242 __ mov(eax, slot_operand); |
| 1237 __ cmp(eax, Factory::the_hole_value()); | 1243 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1238 __ j(not_equal, &done); | 1244 __ j(not_equal, &done); |
| 1239 __ mov(eax, Factory::undefined_value()); | 1245 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1240 __ bind(&done); | 1246 __ bind(&done); |
| 1241 context()->Plug(eax); | 1247 context()->Plug(eax); |
| 1242 } else { | 1248 } else { |
| 1243 context()->Plug(slot); | 1249 context()->Plug(slot); |
| 1244 } | 1250 } |
| 1245 | 1251 |
| 1246 } else { | 1252 } else { |
| 1247 Comment cmnt(masm_, "Rewritten parameter"); | 1253 Comment cmnt(masm_, "Rewritten parameter"); |
| 1248 ASSERT_NOT_NULL(property); | 1254 ASSERT_NOT_NULL(property); |
| 1249 // Rewritten parameter accesses are of the form "slot[literal]". | 1255 // Rewritten parameter accesses are of the form "slot[literal]". |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1260 | 1266 |
| 1261 // Assert that the key is a smi. | 1267 // Assert that the key is a smi. |
| 1262 Literal* key_literal = property->key()->AsLiteral(); | 1268 Literal* key_literal = property->key()->AsLiteral(); |
| 1263 ASSERT_NOT_NULL(key_literal); | 1269 ASSERT_NOT_NULL(key_literal); |
| 1264 ASSERT(key_literal->handle()->IsSmi()); | 1270 ASSERT(key_literal->handle()->IsSmi()); |
| 1265 | 1271 |
| 1266 // Load the key. | 1272 // Load the key. |
| 1267 __ mov(eax, Immediate(key_literal->handle())); | 1273 __ mov(eax, Immediate(key_literal->handle())); |
| 1268 | 1274 |
| 1269 // Do a keyed property load. | 1275 // Do a keyed property load. |
| 1270 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1276 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1277 Builtins::KeyedLoadIC_Initialize)); |
| 1271 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1278 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1272 | 1279 |
| 1273 // Drop key and object left on the stack by IC. | 1280 // Drop key and object left on the stack by IC. |
| 1274 context()->Plug(eax); | 1281 context()->Plug(eax); |
| 1275 } | 1282 } |
| 1276 } | 1283 } |
| 1277 | 1284 |
| 1278 | 1285 |
| 1279 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1286 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1280 Comment cmnt(masm_, "[ RegExpLiteral"); | 1287 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1281 NearLabel materialized; | 1288 NearLabel materialized; |
| 1282 // Registers will be used as follows: | 1289 // Registers will be used as follows: |
| 1283 // edi = JS function. | 1290 // edi = JS function. |
| 1284 // ecx = literals array. | 1291 // ecx = literals array. |
| 1285 // ebx = regexp literal. | 1292 // ebx = regexp literal. |
| 1286 // eax = regexp literal clone. | 1293 // eax = regexp literal clone. |
| 1287 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1294 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1288 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 1295 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| 1289 int literal_offset = | 1296 int literal_offset = |
| 1290 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 1297 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 1291 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 1298 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| 1292 __ cmp(ebx, Factory::undefined_value()); | 1299 __ cmp(ebx, isolate()->factory()->undefined_value()); |
| 1293 __ j(not_equal, &materialized); | 1300 __ j(not_equal, &materialized); |
| 1294 | 1301 |
| 1295 // Create regexp literal using runtime function | 1302 // Create regexp literal using runtime function |
| 1296 // Result will be in eax. | 1303 // Result will be in eax. |
| 1297 __ push(ecx); | 1304 __ push(ecx); |
| 1298 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 1305 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 1299 __ push(Immediate(expr->pattern())); | 1306 __ push(Immediate(expr->pattern())); |
| 1300 __ push(Immediate(expr->flags())); | 1307 __ push(Immediate(expr->flags())); |
| 1301 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 1308 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 1302 __ mov(ebx, eax); | 1309 __ mov(ebx, eax); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 switch (property->kind()) { | 1372 switch (property->kind()) { |
| 1366 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1373 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1367 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1374 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1368 // Fall through. | 1375 // Fall through. |
| 1369 case ObjectLiteral::Property::COMPUTED: | 1376 case ObjectLiteral::Property::COMPUTED: |
| 1370 if (key->handle()->IsSymbol()) { | 1377 if (key->handle()->IsSymbol()) { |
| 1371 if (property->emit_store()) { | 1378 if (property->emit_store()) { |
| 1372 VisitForAccumulatorValue(value); | 1379 VisitForAccumulatorValue(value); |
| 1373 __ mov(ecx, Immediate(key->handle())); | 1380 __ mov(ecx, Immediate(key->handle())); |
| 1374 __ mov(edx, Operand(esp, 0)); | 1381 __ mov(edx, Operand(esp, 0)); |
| 1375 Handle<Code> ic(Builtins::builtin( | 1382 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1376 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1383 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1377 : Builtins::StoreIC_Initialize)); | 1384 : Builtins::StoreIC_Initialize)); |
| 1378 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1385 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1379 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1386 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1380 } else { | 1387 } else { |
| 1381 VisitForEffect(value); | 1388 VisitForEffect(value); |
| 1382 } | 1389 } |
| 1383 break; | 1390 break; |
| 1384 } | 1391 } |
| 1385 // Fall through. | 1392 // Fall through. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1419 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1426 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 1420 Comment cmnt(masm_, "[ ArrayLiteral"); | 1427 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 1421 | 1428 |
| 1422 ZoneList<Expression*>* subexprs = expr->values(); | 1429 ZoneList<Expression*>* subexprs = expr->values(); |
| 1423 int length = subexprs->length(); | 1430 int length = subexprs->length(); |
| 1424 | 1431 |
| 1425 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1432 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1426 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); | 1433 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
| 1427 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 1434 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 1428 __ push(Immediate(expr->constant_elements())); | 1435 __ push(Immediate(expr->constant_elements())); |
| 1429 if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) { | 1436 if (expr->constant_elements()->map() == |
| 1437 isolate()->heap()->fixed_cow_array_map()) { |
| 1430 ASSERT(expr->depth() == 1); | 1438 ASSERT(expr->depth() == 1); |
| 1431 FastCloneShallowArrayStub stub( | 1439 FastCloneShallowArrayStub stub( |
| 1432 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); | 1440 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); |
| 1433 __ CallStub(&stub); | 1441 __ CallStub(&stub); |
| 1434 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1); | 1442 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1); |
| 1435 } else if (expr->depth() > 1) { | 1443 } else if (expr->depth() > 1) { |
| 1436 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); | 1444 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 1437 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 1445 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 1438 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 1446 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
| 1439 } else { | 1447 } else { |
| 1440 FastCloneShallowArrayStub stub( | 1448 FastCloneShallowArrayStub stub( |
| 1441 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); | 1449 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); |
| 1442 __ CallStub(&stub); | 1450 __ CallStub(&stub); |
| 1443 } | 1451 } |
| 1444 | 1452 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 EmitKeyedPropertyAssignment(expr); | 1617 EmitKeyedPropertyAssignment(expr); |
| 1610 break; | 1618 break; |
| 1611 } | 1619 } |
| 1612 } | 1620 } |
| 1613 | 1621 |
| 1614 | 1622 |
| 1615 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1623 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 1616 SetSourcePosition(prop->position()); | 1624 SetSourcePosition(prop->position()); |
| 1617 Literal* key = prop->key()->AsLiteral(); | 1625 Literal* key = prop->key()->AsLiteral(); |
| 1618 __ mov(ecx, Immediate(key->handle())); | 1626 __ mov(ecx, Immediate(key->handle())); |
| 1619 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1627 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1628 Builtins::LoadIC_Initialize)); |
| 1620 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1629 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1621 } | 1630 } |
| 1622 | 1631 |
| 1623 | 1632 |
| 1624 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1633 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1625 SetSourcePosition(prop->position()); | 1634 SetSourcePosition(prop->position()); |
| 1626 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1635 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1636 Builtins::KeyedLoadIC_Initialize)); |
| 1627 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1637 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1628 } | 1638 } |
| 1629 | 1639 |
| 1630 | 1640 |
| 1631 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1641 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
| 1632 Token::Value op, | 1642 Token::Value op, |
| 1633 OverwriteMode mode, | 1643 OverwriteMode mode, |
| 1634 Expression* left, | 1644 Expression* left, |
| 1635 Expression* right) { | 1645 Expression* right) { |
| 1636 // Do combined smi check of the operands. Left operand is on the | 1646 // Do combined smi check of the operands. Left operand is on the |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1757 EffectContext context(this); | 1767 EffectContext context(this); |
| 1758 EmitVariableAssignment(var, Token::ASSIGN); | 1768 EmitVariableAssignment(var, Token::ASSIGN); |
| 1759 break; | 1769 break; |
| 1760 } | 1770 } |
| 1761 case NAMED_PROPERTY: { | 1771 case NAMED_PROPERTY: { |
| 1762 __ push(eax); // Preserve value. | 1772 __ push(eax); // Preserve value. |
| 1763 VisitForAccumulatorValue(prop->obj()); | 1773 VisitForAccumulatorValue(prop->obj()); |
| 1764 __ mov(edx, eax); | 1774 __ mov(edx, eax); |
| 1765 __ pop(eax); // Restore value. | 1775 __ pop(eax); // Restore value. |
| 1766 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1776 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1767 Handle<Code> ic(Builtins::builtin( | 1777 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1768 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1778 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1769 : Builtins::StoreIC_Initialize)); | 1779 : Builtins::StoreIC_Initialize)); |
| 1770 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1780 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1771 break; | 1781 break; |
| 1772 } | 1782 } |
| 1773 case KEYED_PROPERTY: { | 1783 case KEYED_PROPERTY: { |
| 1774 __ push(eax); // Preserve value. | 1784 __ push(eax); // Preserve value. |
| 1775 if (prop->is_synthetic()) { | 1785 if (prop->is_synthetic()) { |
| 1776 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1786 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 1777 ASSERT(prop->key()->AsLiteral() != NULL); | 1787 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1778 { AccumulatorValueContext for_object(this); | 1788 { AccumulatorValueContext for_object(this); |
| 1779 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | 1789 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1780 } | 1790 } |
| 1781 __ mov(edx, eax); | 1791 __ mov(edx, eax); |
| 1782 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 1792 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 1783 } else { | 1793 } else { |
| 1784 VisitForStackValue(prop->obj()); | 1794 VisitForStackValue(prop->obj()); |
| 1785 VisitForAccumulatorValue(prop->key()); | 1795 VisitForAccumulatorValue(prop->key()); |
| 1786 __ mov(ecx, eax); | 1796 __ mov(ecx, eax); |
| 1787 __ pop(edx); | 1797 __ pop(edx); |
| 1788 } | 1798 } |
| 1789 __ pop(eax); // Restore value. | 1799 __ pop(eax); // Restore value. |
| 1790 Handle<Code> ic(Builtins::builtin( | 1800 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1791 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 1801 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1792 : Builtins::KeyedStoreIC_Initialize)); | 1802 : Builtins::KeyedStoreIC_Initialize)); |
| 1793 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1803 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1794 break; | 1804 break; |
| 1795 } | 1805 } |
| 1796 } | 1806 } |
| 1797 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1807 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1798 context()->Plug(eax); | 1808 context()->Plug(eax); |
| 1799 } | 1809 } |
| 1800 | 1810 |
| 1801 | 1811 |
| 1802 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1812 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1803 Token::Value op) { | 1813 Token::Value op) { |
| 1804 // Left-hand sides that rewrite to explicit property accesses do not reach | 1814 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1805 // here. | 1815 // here. |
| 1806 ASSERT(var != NULL); | 1816 ASSERT(var != NULL); |
| 1807 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1817 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1808 | 1818 |
| 1809 if (var->is_global()) { | 1819 if (var->is_global()) { |
| 1810 ASSERT(!var->is_this()); | 1820 ASSERT(!var->is_this()); |
| 1811 // Assignment to a global variable. Use inline caching for the | 1821 // Assignment to a global variable. Use inline caching for the |
| 1812 // assignment. Right-hand-side value is passed in eax, variable name in | 1822 // assignment. Right-hand-side value is passed in eax, variable name in |
| 1813 // ecx, and the global object on the stack. | 1823 // ecx, and the global object on the stack. |
| 1814 __ mov(ecx, var->name()); | 1824 __ mov(ecx, var->name()); |
| 1815 __ mov(edx, GlobalObjectOperand()); | 1825 __ mov(edx, GlobalObjectOperand()); |
| 1816 Handle<Code> ic(Builtins::builtin( | 1826 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1817 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1827 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1818 : Builtins::StoreIC_Initialize)); | 1828 : Builtins::StoreIC_Initialize)); |
| 1819 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1829 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1820 | 1830 |
| 1821 } else if (op == Token::INIT_CONST) { | 1831 } else if (op == Token::INIT_CONST) { |
| 1822 // Like var declarations, const declarations are hoisted to function | 1832 // Like var declarations, const declarations are hoisted to function |
| 1823 // scope. However, unlike var initializers, const initializers are able | 1833 // scope. However, unlike var initializers, const initializers are able |
| 1824 // to drill a hole to that function context, even from inside a 'with' | 1834 // to drill a hole to that function context, even from inside a 'with' |
| 1825 // context. We thus bypass the normal static scope lookup. | 1835 // context. We thus bypass the normal static scope lookup. |
| 1826 Slot* slot = var->AsSlot(); | 1836 Slot* slot = var->AsSlot(); |
| 1827 Label skip; | 1837 Label skip; |
| 1828 switch (slot->type()) { | 1838 switch (slot->type()) { |
| 1829 case Slot::PARAMETER: | 1839 case Slot::PARAMETER: |
| 1830 // No const parameters. | 1840 // No const parameters. |
| 1831 UNREACHABLE(); | 1841 UNREACHABLE(); |
| 1832 break; | 1842 break; |
| 1833 case Slot::LOCAL: | 1843 case Slot::LOCAL: |
| 1834 __ mov(edx, Operand(ebp, SlotOffset(slot))); | 1844 __ mov(edx, Operand(ebp, SlotOffset(slot))); |
| 1835 __ cmp(edx, Factory::the_hole_value()); | 1845 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1836 __ j(not_equal, &skip); | 1846 __ j(not_equal, &skip); |
| 1837 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 1847 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 1838 break; | 1848 break; |
| 1839 case Slot::CONTEXT: { | 1849 case Slot::CONTEXT: { |
| 1840 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | 1850 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 1841 __ mov(edx, ContextOperand(ecx, slot->index())); | 1851 __ mov(edx, ContextOperand(ecx, slot->index())); |
| 1842 __ cmp(edx, Factory::the_hole_value()); | 1852 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1843 __ j(not_equal, &skip); | 1853 __ j(not_equal, &skip); |
| 1844 __ mov(ContextOperand(ecx, slot->index()), eax); | 1854 __ mov(ContextOperand(ecx, slot->index()), eax); |
| 1845 int offset = Context::SlotOffset(slot->index()); | 1855 int offset = Context::SlotOffset(slot->index()); |
| 1846 __ mov(edx, eax); // Preserve the stored value in eax. | 1856 __ mov(edx, eax); // Preserve the stored value in eax. |
| 1847 __ RecordWrite(ecx, offset, edx, ebx); | 1857 __ RecordWrite(ecx, offset, edx, ebx); |
| 1848 break; | 1858 break; |
| 1849 } | 1859 } |
| 1850 case Slot::LOOKUP: | 1860 case Slot::LOOKUP: |
| 1851 __ push(eax); | 1861 __ push(eax); |
| 1852 __ push(esi); | 1862 __ push(esi); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1909 } | 1919 } |
| 1910 | 1920 |
| 1911 // Record source code position before IC call. | 1921 // Record source code position before IC call. |
| 1912 SetSourcePosition(expr->position()); | 1922 SetSourcePosition(expr->position()); |
| 1913 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1923 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1914 if (expr->ends_initialization_block()) { | 1924 if (expr->ends_initialization_block()) { |
| 1915 __ mov(edx, Operand(esp, 0)); | 1925 __ mov(edx, Operand(esp, 0)); |
| 1916 } else { | 1926 } else { |
| 1917 __ pop(edx); | 1927 __ pop(edx); |
| 1918 } | 1928 } |
| 1919 Handle<Code> ic(Builtins::builtin( | 1929 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1920 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 1930 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1921 : Builtins::StoreIC_Initialize)); | 1931 : Builtins::StoreIC_Initialize)); |
| 1922 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1932 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1923 | 1933 |
| 1924 // If the assignment ends an initialization block, revert to fast case. | 1934 // If the assignment ends an initialization block, revert to fast case. |
| 1925 if (expr->ends_initialization_block()) { | 1935 if (expr->ends_initialization_block()) { |
| 1926 __ push(eax); // Result of assignment, saved even if not needed. | 1936 __ push(eax); // Result of assignment, saved even if not needed. |
| 1927 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 1937 __ push(Operand(esp, kPointerSize)); // Receiver is under value. |
| 1928 __ CallRuntime(Runtime::kToFastProperties, 1); | 1938 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1929 __ pop(eax); | 1939 __ pop(eax); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1949 } | 1959 } |
| 1950 | 1960 |
| 1951 __ pop(ecx); | 1961 __ pop(ecx); |
| 1952 if (expr->ends_initialization_block()) { | 1962 if (expr->ends_initialization_block()) { |
| 1953 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. | 1963 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. |
| 1954 } else { | 1964 } else { |
| 1955 __ pop(edx); | 1965 __ pop(edx); |
| 1956 } | 1966 } |
| 1957 // Record source code position before IC call. | 1967 // Record source code position before IC call. |
| 1958 SetSourcePosition(expr->position()); | 1968 SetSourcePosition(expr->position()); |
| 1959 Handle<Code> ic(Builtins::builtin( | 1969 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1960 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 1970 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1961 : Builtins::KeyedStoreIC_Initialize)); | 1971 : Builtins::KeyedStoreIC_Initialize)); |
| 1962 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1972 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1963 | 1973 |
| 1964 // If the assignment ends an initialization block, revert to fast case. | 1974 // If the assignment ends an initialization block, revert to fast case. |
| 1965 if (expr->ends_initialization_block()) { | 1975 if (expr->ends_initialization_block()) { |
| 1966 __ pop(edx); | 1976 __ pop(edx); |
| 1967 __ push(eax); // Result of assignment, saved even if not needed. | 1977 __ push(eax); // Result of assignment, saved even if not needed. |
| 1968 __ push(edx); | 1978 __ push(edx); |
| 1969 __ CallRuntime(Runtime::kToFastProperties, 1); | 1979 __ CallRuntime(Runtime::kToFastProperties, 1); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2001 int arg_count = args->length(); | 2011 int arg_count = args->length(); |
| 2002 { PreservePositionScope scope(masm()->positions_recorder()); | 2012 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2003 for (int i = 0; i < arg_count; i++) { | 2013 for (int i = 0; i < arg_count; i++) { |
| 2004 VisitForStackValue(args->at(i)); | 2014 VisitForStackValue(args->at(i)); |
| 2005 } | 2015 } |
| 2006 __ Set(ecx, Immediate(name)); | 2016 __ Set(ecx, Immediate(name)); |
| 2007 } | 2017 } |
| 2008 // Record source position of the IC call. | 2018 // Record source position of the IC call. |
| 2009 SetSourcePosition(expr->position()); | 2019 SetSourcePosition(expr->position()); |
| 2010 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2020 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2011 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop); | 2021 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( |
| 2022 arg_count, in_loop); |
| 2012 EmitCallIC(ic, mode); | 2023 EmitCallIC(ic, mode); |
| 2013 RecordJSReturnSite(expr); | 2024 RecordJSReturnSite(expr); |
| 2014 // Restore context register. | 2025 // Restore context register. |
| 2015 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2026 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2016 context()->Plug(eax); | 2027 context()->Plug(eax); |
| 2017 } | 2028 } |
| 2018 | 2029 |
| 2019 | 2030 |
| 2020 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2031 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2021 Expression* key, | 2032 Expression* key, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2033 ZoneList<Expression*>* args = expr->arguments(); | 2044 ZoneList<Expression*>* args = expr->arguments(); |
| 2034 int arg_count = args->length(); | 2045 int arg_count = args->length(); |
| 2035 { PreservePositionScope scope(masm()->positions_recorder()); | 2046 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2036 for (int i = 0; i < arg_count; i++) { | 2047 for (int i = 0; i < arg_count; i++) { |
| 2037 VisitForStackValue(args->at(i)); | 2048 VisitForStackValue(args->at(i)); |
| 2038 } | 2049 } |
| 2039 } | 2050 } |
| 2040 // Record source position of the IC call. | 2051 // Record source position of the IC call. |
| 2041 SetSourcePosition(expr->position()); | 2052 SetSourcePosition(expr->position()); |
| 2042 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2053 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2043 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop); | 2054 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( |
| 2055 arg_count, in_loop); |
| 2044 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. | 2056 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. |
| 2045 EmitCallIC(ic, mode); | 2057 EmitCallIC(ic, mode); |
| 2046 RecordJSReturnSite(expr); | 2058 RecordJSReturnSite(expr); |
| 2047 // Restore context register. | 2059 // Restore context register. |
| 2048 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2060 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2049 context()->DropAndPlug(1, eax); // Drop the key still on the stack. | 2061 context()->DropAndPlug(1, eax); // Drop the key still on the stack. |
| 2050 } | 2062 } |
| 2051 | 2063 |
| 2052 | 2064 |
| 2053 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2065 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2070 context()->DropAndPlug(1, eax); | 2082 context()->DropAndPlug(1, eax); |
| 2071 } | 2083 } |
| 2072 | 2084 |
| 2073 | 2085 |
| 2074 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, | 2086 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
| 2075 int arg_count) { | 2087 int arg_count) { |
| 2076 // Push copy of the first argument or undefined if it doesn't exist. | 2088 // Push copy of the first argument or undefined if it doesn't exist. |
| 2077 if (arg_count > 0) { | 2089 if (arg_count > 0) { |
| 2078 __ push(Operand(esp, arg_count * kPointerSize)); | 2090 __ push(Operand(esp, arg_count * kPointerSize)); |
| 2079 } else { | 2091 } else { |
| 2080 __ push(Immediate(Factory::undefined_value())); | 2092 __ push(Immediate(FACTORY->undefined_value())); |
| 2081 } | 2093 } |
| 2082 | 2094 |
| 2083 // Push the receiver of the enclosing function. | 2095 // Push the receiver of the enclosing function. |
| 2084 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2096 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 2085 | 2097 |
| 2086 // Push the strict mode flag. | 2098 // Push the strict mode flag. |
| 2087 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 2099 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 2088 | 2100 |
| 2089 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP | 2101 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2090 ? Runtime::kResolvePossiblyDirectEvalNoLookup | 2102 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2106 if (var != NULL && var->is_possibly_eval()) { | 2118 if (var != NULL && var->is_possibly_eval()) { |
| 2107 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 2119 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 2108 // resolve the function we need to call and the receiver of the | 2120 // resolve the function we need to call and the receiver of the |
| 2109 // call. Then we call the resolved function using the given | 2121 // call. Then we call the resolved function using the given |
| 2110 // arguments. | 2122 // arguments. |
| 2111 ZoneList<Expression*>* args = expr->arguments(); | 2123 ZoneList<Expression*>* args = expr->arguments(); |
| 2112 int arg_count = args->length(); | 2124 int arg_count = args->length(); |
| 2113 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 2125 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
| 2114 VisitForStackValue(fun); | 2126 VisitForStackValue(fun); |
| 2115 // Reserved receiver slot. | 2127 // Reserved receiver slot. |
| 2116 __ push(Immediate(Factory::undefined_value())); | 2128 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2117 | 2129 |
| 2118 // Push the arguments. | 2130 // Push the arguments. |
| 2119 for (int i = 0; i < arg_count; i++) { | 2131 for (int i = 0; i < arg_count; i++) { |
| 2120 VisitForStackValue(args->at(i)); | 2132 VisitForStackValue(args->at(i)); |
| 2121 } | 2133 } |
| 2122 | 2134 |
| 2123 // If we know that eval can only be shadowed by eval-introduced | 2135 // If we know that eval can only be shadowed by eval-introduced |
| 2124 // variables we attempt to load the global eval function directly | 2136 // variables we attempt to load the global eval function directly |
| 2125 // in generated code. If we succeed, there is no need to perform a | 2137 // in generated code. If we succeed, there is no need to perform a |
| 2126 // context lookup in the runtime system. | 2138 // context lookup in the runtime system. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2225 MemOperand operand = EmitSlotSearch(slot, edx); | 2237 MemOperand operand = EmitSlotSearch(slot, edx); |
| 2226 __ mov(edx, operand); | 2238 __ mov(edx, operand); |
| 2227 | 2239 |
| 2228 ASSERT(prop->key()->AsLiteral() != NULL); | 2240 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2229 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | 2241 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); |
| 2230 __ mov(eax, prop->key()->AsLiteral()->handle()); | 2242 __ mov(eax, prop->key()->AsLiteral()->handle()); |
| 2231 | 2243 |
| 2232 // Record source code position for IC call. | 2244 // Record source code position for IC call. |
| 2233 SetSourcePosition(prop->position()); | 2245 SetSourcePosition(prop->position()); |
| 2234 | 2246 |
| 2235 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 2247 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2248 Builtins::KeyedLoadIC_Initialize)); |
| 2236 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2249 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2237 // Push result (function). | 2250 // Push result (function). |
| 2238 __ push(eax); | 2251 __ push(eax); |
| 2239 // Push Global receiver. | 2252 // Push Global receiver. |
| 2240 __ mov(ecx, GlobalObjectOperand()); | 2253 __ mov(ecx, GlobalObjectOperand()); |
| 2241 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | 2254 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); |
| 2242 EmitCallWithStub(expr); | 2255 EmitCallWithStub(expr); |
| 2243 } else { | 2256 } else { |
| 2244 { PreservePositionScope scope(masm()->positions_recorder()); | 2257 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2245 VisitForStackValue(prop->obj()); | 2258 VisitForStackValue(prop->obj()); |
| 2246 } | 2259 } |
| 2247 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | 2260 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 2248 } | 2261 } |
| 2249 } | 2262 } |
| 2250 } else { | 2263 } else { |
| 2251 // Call to some other expression. If the expression is an anonymous | 2264 // Call to some other expression. If the expression is an anonymous |
| 2252 // function literal not called in a loop, mark it as one that should | 2265 // function literal not called in a loop, mark it as one that should |
| 2253 // also use the full code generator. | 2266 // also use the full code generator. |
| 2254 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2267 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 2255 if (lit != NULL && | 2268 if (lit != NULL && |
| 2256 lit->name()->Equals(Heap::empty_string()) && | 2269 lit->name()->Equals(isolate()->heap()->empty_string()) && |
| 2257 loop_depth() == 0) { | 2270 loop_depth() == 0) { |
| 2258 lit->set_try_full_codegen(true); | 2271 lit->set_try_full_codegen(true); |
| 2259 } | 2272 } |
| 2260 { PreservePositionScope scope(masm()->positions_recorder()); | 2273 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2261 VisitForStackValue(fun); | 2274 VisitForStackValue(fun); |
| 2262 } | 2275 } |
| 2263 // Load global receiver object. | 2276 // Load global receiver object. |
| 2264 __ mov(ebx, GlobalObjectOperand()); | 2277 __ mov(ebx, GlobalObjectOperand()); |
| 2265 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 2278 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 2266 // Emit function call. | 2279 // Emit function call. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2293 } | 2306 } |
| 2294 | 2307 |
| 2295 // Call the construct call builtin that handles allocation and | 2308 // Call the construct call builtin that handles allocation and |
| 2296 // constructor invocation. | 2309 // constructor invocation. |
| 2297 SetSourcePosition(expr->position()); | 2310 SetSourcePosition(expr->position()); |
| 2298 | 2311 |
| 2299 // Load function and argument count into edi and eax. | 2312 // Load function and argument count into edi and eax. |
| 2300 __ Set(eax, Immediate(arg_count)); | 2313 __ Set(eax, Immediate(arg_count)); |
| 2301 __ mov(edi, Operand(esp, arg_count * kPointerSize)); | 2314 __ mov(edi, Operand(esp, arg_count * kPointerSize)); |
| 2302 | 2315 |
| 2303 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); | 2316 Handle<Code> construct_builtin(isolate()->builtins()->builtin( |
| 2317 Builtins::JSConstructCall)); |
| 2304 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 2318 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
| 2305 context()->Plug(eax); | 2319 context()->Plug(eax); |
| 2306 } | 2320 } |
| 2307 | 2321 |
| 2308 | 2322 |
| 2309 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { | 2323 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { |
| 2310 ASSERT(args->length() == 1); | 2324 ASSERT(args->length() == 1); |
| 2311 | 2325 |
| 2312 VisitForAccumulatorValue(args->at(0)); | 2326 VisitForAccumulatorValue(args->at(0)); |
| 2313 | 2327 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2353 | 2367 |
| 2354 Label materialize_true, materialize_false; | 2368 Label materialize_true, materialize_false; |
| 2355 Label* if_true = NULL; | 2369 Label* if_true = NULL; |
| 2356 Label* if_false = NULL; | 2370 Label* if_false = NULL; |
| 2357 Label* fall_through = NULL; | 2371 Label* fall_through = NULL; |
| 2358 context()->PrepareTest(&materialize_true, &materialize_false, | 2372 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2359 &if_true, &if_false, &fall_through); | 2373 &if_true, &if_false, &fall_through); |
| 2360 | 2374 |
| 2361 __ test(eax, Immediate(kSmiTagMask)); | 2375 __ test(eax, Immediate(kSmiTagMask)); |
| 2362 __ j(zero, if_false); | 2376 __ j(zero, if_false); |
| 2363 __ cmp(eax, Factory::null_value()); | 2377 __ cmp(eax, isolate()->factory()->null_value()); |
| 2364 __ j(equal, if_true); | 2378 __ j(equal, if_true); |
| 2365 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2379 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2366 // Undetectable objects behave like undefined when tested with typeof. | 2380 // Undetectable objects behave like undefined when tested with typeof. |
| 2367 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); | 2381 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 2368 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 2382 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 2369 __ j(not_zero, if_false); | 2383 __ j(not_zero, if_false); |
| 2370 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 2384 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 2371 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 2385 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 2372 __ j(below, if_false); | 2386 __ j(below, if_false); |
| 2373 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 2387 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2632 __ j(not_equal, &non_function_constructor); | 2646 __ j(not_equal, &non_function_constructor); |
| 2633 | 2647 |
| 2634 // eax now contains the constructor function. Grab the | 2648 // eax now contains the constructor function. Grab the |
| 2635 // instance class name from there. | 2649 // instance class name from there. |
| 2636 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); | 2650 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
| 2637 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); | 2651 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); |
| 2638 __ jmp(&done); | 2652 __ jmp(&done); |
| 2639 | 2653 |
| 2640 // Functions have class 'Function'. | 2654 // Functions have class 'Function'. |
| 2641 __ bind(&function); | 2655 __ bind(&function); |
| 2642 __ mov(eax, Factory::function_class_symbol()); | 2656 __ mov(eax, isolate()->factory()->function_class_symbol()); |
| 2643 __ jmp(&done); | 2657 __ jmp(&done); |
| 2644 | 2658 |
| 2645 // Objects with a non-function constructor have class 'Object'. | 2659 // Objects with a non-function constructor have class 'Object'. |
| 2646 __ bind(&non_function_constructor); | 2660 __ bind(&non_function_constructor); |
| 2647 __ mov(eax, Factory::Object_symbol()); | 2661 __ mov(eax, isolate()->factory()->Object_symbol()); |
| 2648 __ jmp(&done); | 2662 __ jmp(&done); |
| 2649 | 2663 |
| 2650 // Non-JS objects have class null. | 2664 // Non-JS objects have class null. |
| 2651 __ bind(&null); | 2665 __ bind(&null); |
| 2652 __ mov(eax, Factory::null_value()); | 2666 __ mov(eax, isolate()->factory()->null_value()); |
| 2653 | 2667 |
| 2654 // All done. | 2668 // All done. |
| 2655 __ bind(&done); | 2669 __ bind(&done); |
| 2656 | 2670 |
| 2657 context()->Plug(eax); | 2671 context()->Plug(eax); |
| 2658 } | 2672 } |
| 2659 | 2673 |
| 2660 | 2674 |
| 2661 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { | 2675 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { |
| 2662 // Conditionally generate a log call. | 2676 // Conditionally generate a log call. |
| 2663 // Args: | 2677 // Args: |
| 2664 // 0 (literal string): The type of logging (corresponds to the flags). | 2678 // 0 (literal string): The type of logging (corresponds to the flags). |
| 2665 // This is used to determine whether or not to generate the log call. | 2679 // This is used to determine whether or not to generate the log call. |
| 2666 // 1 (string): Format string. Access the string at argument index 2 | 2680 // 1 (string): Format string. Access the string at argument index 2 |
| 2667 // with '%2s' (see Logger::LogRuntime for all the formats). | 2681 // with '%2s' (see Logger::LogRuntime for all the formats). |
| 2668 // 2 (array): Arguments to the format string. | 2682 // 2 (array): Arguments to the format string. |
| 2669 ASSERT_EQ(args->length(), 3); | 2683 ASSERT_EQ(args->length(), 3); |
| 2670 #ifdef ENABLE_LOGGING_AND_PROFILING | 2684 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2671 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { | 2685 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { |
| 2672 VisitForStackValue(args->at(1)); | 2686 VisitForStackValue(args->at(1)); |
| 2673 VisitForStackValue(args->at(2)); | 2687 VisitForStackValue(args->at(2)); |
| 2674 __ CallRuntime(Runtime::kLog, 2); | 2688 __ CallRuntime(Runtime::kLog, 2); |
| 2675 } | 2689 } |
| 2676 #endif | 2690 #endif |
| 2677 // Finally, we're expected to leave a value on the top of the stack. | 2691 // Finally, we're expected to leave a value on the top of the stack. |
| 2678 __ mov(eax, Factory::undefined_value()); | 2692 __ mov(eax, isolate()->factory()->undefined_value()); |
| 2679 context()->Plug(eax); | 2693 context()->Plug(eax); |
| 2680 } | 2694 } |
| 2681 | 2695 |
| 2682 | 2696 |
| 2683 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { | 2697 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { |
| 2684 ASSERT(args->length() == 0); | 2698 ASSERT(args->length() == 0); |
| 2685 | 2699 |
| 2686 Label slow_allocate_heapnumber; | 2700 Label slow_allocate_heapnumber; |
| 2687 Label heapnumber_allocated; | 2701 Label heapnumber_allocated; |
| 2688 | 2702 |
| 2689 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); | 2703 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); |
| 2690 __ jmp(&heapnumber_allocated); | 2704 __ jmp(&heapnumber_allocated); |
| 2691 | 2705 |
| 2692 __ bind(&slow_allocate_heapnumber); | 2706 __ bind(&slow_allocate_heapnumber); |
| 2693 // Allocate a heap number. | 2707 // Allocate a heap number. |
| 2694 __ CallRuntime(Runtime::kNumberAlloc, 0); | 2708 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 2695 __ mov(edi, eax); | 2709 __ mov(edi, eax); |
| 2696 | 2710 |
| 2697 __ bind(&heapnumber_allocated); | 2711 __ bind(&heapnumber_allocated); |
| 2698 | 2712 |
| 2699 __ PrepareCallCFunction(0, ebx); | 2713 __ PrepareCallCFunction(0, ebx); |
| 2700 __ CallCFunction(ExternalReference::random_uint32_function(), 0); | 2714 __ CallCFunction(ExternalReference::random_uint32_function(), 0); |
| 2701 | 2715 |
| 2702 // Convert 32 random bits in eax to 0.(32 random bits) in a double | 2716 // Convert 32 random bits in eax to 0.(32 random bits) in a double |
| 2703 // by computing: | 2717 // by computing: |
| 2704 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 2718 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 2705 // This is implemented on both SSE2 and FPU. | 2719 // This is implemented on both SSE2 and FPU. |
| 2706 if (CpuFeatures::IsSupported(SSE2)) { | 2720 if (isolate()->cpu_features()->IsSupported(SSE2)) { |
| 2707 CpuFeatures::Scope fscope(SSE2); | 2721 CpuFeatures::Scope fscope(SSE2); |
| 2708 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 2722 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 2709 __ movd(xmm1, Operand(ebx)); | 2723 __ movd(xmm1, Operand(ebx)); |
| 2710 __ movd(xmm0, Operand(eax)); | 2724 __ movd(xmm0, Operand(eax)); |
| 2711 __ cvtss2sd(xmm1, xmm1); | 2725 __ cvtss2sd(xmm1, xmm1); |
| 2712 __ pxor(xmm0, xmm1); | 2726 __ pxor(xmm0, xmm1); |
| 2713 __ subsd(xmm0, xmm1); | 2727 __ subsd(xmm0, xmm1); |
| 2714 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); | 2728 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); |
| 2715 } else { | 2729 } else { |
| 2716 // 0x4130000000000000 is 1.0 x 2^20 as a double. | 2730 // 0x4130000000000000 is 1.0 x 2^20 as a double. |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2865 &need_conversion, | 2879 &need_conversion, |
| 2866 &need_conversion, | 2880 &need_conversion, |
| 2867 &index_out_of_range, | 2881 &index_out_of_range, |
| 2868 STRING_INDEX_IS_NUMBER); | 2882 STRING_INDEX_IS_NUMBER); |
| 2869 generator.GenerateFast(masm_); | 2883 generator.GenerateFast(masm_); |
| 2870 __ jmp(&done); | 2884 __ jmp(&done); |
| 2871 | 2885 |
| 2872 __ bind(&index_out_of_range); | 2886 __ bind(&index_out_of_range); |
| 2873 // When the index is out of range, the spec requires us to return | 2887 // When the index is out of range, the spec requires us to return |
| 2874 // NaN. | 2888 // NaN. |
| 2875 __ Set(result, Immediate(Factory::nan_value())); | 2889 __ Set(result, Immediate(isolate()->factory()->nan_value())); |
| 2876 __ jmp(&done); | 2890 __ jmp(&done); |
| 2877 | 2891 |
| 2878 __ bind(&need_conversion); | 2892 __ bind(&need_conversion); |
| 2879 // Move the undefined value into the result register, which will | 2893 // Move the undefined value into the result register, which will |
| 2880 // trigger conversion. | 2894 // trigger conversion. |
| 2881 __ Set(result, Immediate(Factory::undefined_value())); | 2895 __ Set(result, Immediate(isolate()->factory()->undefined_value())); |
| 2882 __ jmp(&done); | 2896 __ jmp(&done); |
| 2883 | 2897 |
| 2884 NopRuntimeCallHelper call_helper; | 2898 NopRuntimeCallHelper call_helper; |
| 2885 generator.GenerateSlow(masm_, call_helper); | 2899 generator.GenerateSlow(masm_, call_helper); |
| 2886 | 2900 |
| 2887 __ bind(&done); | 2901 __ bind(&done); |
| 2888 context()->Plug(result); | 2902 context()->Plug(result); |
| 2889 } | 2903 } |
| 2890 | 2904 |
| 2891 | 2905 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2914 &need_conversion, | 2928 &need_conversion, |
| 2915 &need_conversion, | 2929 &need_conversion, |
| 2916 &index_out_of_range, | 2930 &index_out_of_range, |
| 2917 STRING_INDEX_IS_NUMBER); | 2931 STRING_INDEX_IS_NUMBER); |
| 2918 generator.GenerateFast(masm_); | 2932 generator.GenerateFast(masm_); |
| 2919 __ jmp(&done); | 2933 __ jmp(&done); |
| 2920 | 2934 |
| 2921 __ bind(&index_out_of_range); | 2935 __ bind(&index_out_of_range); |
| 2922 // When the index is out of range, the spec requires us to return | 2936 // When the index is out of range, the spec requires us to return |
| 2923 // the empty string. | 2937 // the empty string. |
| 2924 __ Set(result, Immediate(Factory::empty_string())); | 2938 __ Set(result, Immediate(isolate()->factory()->empty_string())); |
| 2925 __ jmp(&done); | 2939 __ jmp(&done); |
| 2926 | 2940 |
| 2927 __ bind(&need_conversion); | 2941 __ bind(&need_conversion); |
| 2928 // Move smi zero into the result register, which will trigger | 2942 // Move smi zero into the result register, which will trigger |
| 2929 // conversion. | 2943 // conversion. |
| 2930 __ Set(result, Immediate(Smi::FromInt(0))); | 2944 __ Set(result, Immediate(Smi::FromInt(0))); |
| 2931 __ jmp(&done); | 2945 __ jmp(&done); |
| 2932 | 2946 |
| 2933 NopRuntimeCallHelper call_helper; | 2947 NopRuntimeCallHelper call_helper; |
| 2934 generator.GenerateSlow(masm_, call_helper); | 2948 generator.GenerateSlow(masm_, call_helper); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3053 // has no indexed interceptor. | 3067 // has no indexed interceptor. |
| 3054 __ CmpObjectType(object, JS_ARRAY_TYPE, temp); | 3068 __ CmpObjectType(object, JS_ARRAY_TYPE, temp); |
| 3055 __ j(not_equal, &slow_case); | 3069 __ j(not_equal, &slow_case); |
| 3056 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), | 3070 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), |
| 3057 KeyedLoadIC::kSlowCaseBitFieldMask); | 3071 KeyedLoadIC::kSlowCaseBitFieldMask); |
| 3058 __ j(not_zero, &slow_case); | 3072 __ j(not_zero, &slow_case); |
| 3059 | 3073 |
| 3060 // Check the object's elements are in fast case and writable. | 3074 // Check the object's elements are in fast case and writable. |
| 3061 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); | 3075 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); |
| 3062 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), | 3076 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), |
| 3063 Immediate(Factory::fixed_array_map())); | 3077 Immediate(isolate()->factory()->fixed_array_map())); |
| 3064 __ j(not_equal, &slow_case); | 3078 __ j(not_equal, &slow_case); |
| 3065 | 3079 |
| 3066 // Check that both indices are smis. | 3080 // Check that both indices are smis. |
| 3067 __ mov(index_1, Operand(esp, 1 * kPointerSize)); | 3081 __ mov(index_1, Operand(esp, 1 * kPointerSize)); |
| 3068 __ mov(index_2, Operand(esp, 0)); | 3082 __ mov(index_2, Operand(esp, 0)); |
| 3069 __ mov(temp, index_1); | 3083 __ mov(temp, index_1); |
| 3070 __ or_(temp, Operand(index_2)); | 3084 __ or_(temp, Operand(index_2)); |
| 3071 __ test(temp, Immediate(kSmiTagMask)); | 3085 __ test(temp, Immediate(kSmiTagMask)); |
| 3072 __ j(not_zero, &slow_case); | 3086 __ j(not_zero, &slow_case); |
| 3073 | 3087 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3091 Label new_space; | 3105 Label new_space; |
| 3092 __ InNewSpace(elements, temp, equal, &new_space); | 3106 __ InNewSpace(elements, temp, equal, &new_space); |
| 3093 | 3107 |
| 3094 __ mov(object, elements); | 3108 __ mov(object, elements); |
| 3095 __ RecordWriteHelper(object, index_1, temp); | 3109 __ RecordWriteHelper(object, index_1, temp); |
| 3096 __ RecordWriteHelper(elements, index_2, temp); | 3110 __ RecordWriteHelper(elements, index_2, temp); |
| 3097 | 3111 |
| 3098 __ bind(&new_space); | 3112 __ bind(&new_space); |
| 3099 // We are done. Drop elements from the stack, and return undefined. | 3113 // We are done. Drop elements from the stack, and return undefined. |
| 3100 __ add(Operand(esp), Immediate(3 * kPointerSize)); | 3114 __ add(Operand(esp), Immediate(3 * kPointerSize)); |
| 3101 __ mov(eax, Factory::undefined_value()); | 3115 __ mov(eax, isolate()->factory()->undefined_value()); |
| 3102 __ jmp(&done); | 3116 __ jmp(&done); |
| 3103 | 3117 |
| 3104 __ bind(&slow_case); | 3118 __ bind(&slow_case); |
| 3105 __ CallRuntime(Runtime::kSwapElements, 3); | 3119 __ CallRuntime(Runtime::kSwapElements, 3); |
| 3106 | 3120 |
| 3107 __ bind(&done); | 3121 __ bind(&done); |
| 3108 context()->Plug(eax); | 3122 context()->Plug(eax); |
| 3109 } | 3123 } |
| 3110 | 3124 |
| 3111 | 3125 |
| 3112 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { | 3126 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { |
| 3113 ASSERT_EQ(2, args->length()); | 3127 ASSERT_EQ(2, args->length()); |
| 3114 | 3128 |
| 3115 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3129 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 3116 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); | 3130 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
| 3117 | 3131 |
| 3118 Handle<FixedArray> jsfunction_result_caches( | 3132 Handle<FixedArray> jsfunction_result_caches( |
| 3119 Top::global_context()->jsfunction_result_caches()); | 3133 isolate()->global_context()->jsfunction_result_caches()); |
| 3120 if (jsfunction_result_caches->length() <= cache_id) { | 3134 if (jsfunction_result_caches->length() <= cache_id) { |
| 3121 __ Abort("Attempt to use undefined cache."); | 3135 __ Abort("Attempt to use undefined cache."); |
| 3122 __ mov(eax, Factory::undefined_value()); | 3136 __ mov(eax, isolate()->factory()->undefined_value()); |
| 3123 context()->Plug(eax); | 3137 context()->Plug(eax); |
| 3124 return; | 3138 return; |
| 3125 } | 3139 } |
| 3126 | 3140 |
| 3127 VisitForAccumulatorValue(args->at(1)); | 3141 VisitForAccumulatorValue(args->at(1)); |
| 3128 | 3142 |
| 3129 Register key = eax; | 3143 Register key = eax; |
| 3130 Register cache = ebx; | 3144 Register cache = ebx; |
| 3131 Register tmp = ecx; | 3145 Register tmp = ecx; |
| 3132 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX)); | 3146 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX)); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3169 __ pop(left); | 3183 __ pop(left); |
| 3170 | 3184 |
| 3171 Label done, fail, ok; | 3185 Label done, fail, ok; |
| 3172 __ cmp(left, Operand(right)); | 3186 __ cmp(left, Operand(right)); |
| 3173 __ j(equal, &ok); | 3187 __ j(equal, &ok); |
| 3174 // Fail if either is a non-HeapObject. | 3188 // Fail if either is a non-HeapObject. |
| 3175 __ mov(tmp, left); | 3189 __ mov(tmp, left); |
| 3176 __ and_(Operand(tmp), right); | 3190 __ and_(Operand(tmp), right); |
| 3177 __ test(Operand(tmp), Immediate(kSmiTagMask)); | 3191 __ test(Operand(tmp), Immediate(kSmiTagMask)); |
| 3178 __ j(zero, &fail); | 3192 __ j(zero, &fail); |
| 3179 __ CmpObjectType(left, JS_REGEXP_TYPE, tmp); | 3193 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
| 3194 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); |
| 3180 __ j(not_equal, &fail); | 3195 __ j(not_equal, &fail); |
| 3181 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); | 3196 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); |
| 3182 __ j(not_equal, &fail); | 3197 __ j(not_equal, &fail); |
| 3183 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | 3198 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); |
| 3184 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | 3199 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); |
| 3185 __ j(equal, &ok); | 3200 __ j(equal, &ok); |
| 3186 __ bind(&fail); | 3201 __ bind(&fail); |
| 3187 __ mov(eax, Immediate(Factory::false_value())); | 3202 __ mov(eax, Immediate(isolate()->factory()->false_value())); |
| 3188 __ jmp(&done); | 3203 __ jmp(&done); |
| 3189 __ bind(&ok); | 3204 __ bind(&ok); |
| 3190 __ mov(eax, Immediate(Factory::true_value())); | 3205 __ mov(eax, Immediate(isolate()->factory()->true_value())); |
| 3191 __ bind(&done); | 3206 __ bind(&done); |
| 3192 | 3207 |
| 3193 context()->Plug(eax); | 3208 context()->Plug(eax); |
| 3194 } | 3209 } |
| 3195 | 3210 |
| 3196 | 3211 |
| 3197 void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) { | 3212 void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) { |
| 3198 ASSERT(args->length() == 1); | 3213 ASSERT(args->length() == 1); |
| 3199 | 3214 |
| 3200 VisitForAccumulatorValue(args->at(0)); | 3215 VisitForAccumulatorValue(args->at(0)); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3273 | 3288 |
| 3274 // Check that the array has fast elements. | 3289 // Check that the array has fast elements. |
| 3275 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 3290 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 3276 1 << Map::kHasFastElements); | 3291 1 << Map::kHasFastElements); |
| 3277 __ j(zero, &bailout); | 3292 __ j(zero, &bailout); |
| 3278 | 3293 |
| 3279 // If the array has length zero, return the empty string. | 3294 // If the array has length zero, return the empty string. |
| 3280 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); | 3295 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3281 __ SmiUntag(array_length); | 3296 __ SmiUntag(array_length); |
| 3282 __ j(not_zero, &non_trivial_array); | 3297 __ j(not_zero, &non_trivial_array); |
| 3283 __ mov(result_operand, Factory::empty_string()); | 3298 __ mov(result_operand, FACTORY->empty_string()); |
| 3284 __ jmp(&done); | 3299 __ jmp(&done); |
| 3285 | 3300 |
| 3286 // Save the array length. | 3301 // Save the array length. |
| 3287 __ bind(&non_trivial_array); | 3302 __ bind(&non_trivial_array); |
| 3288 __ mov(array_length_operand, array_length); | 3303 __ mov(array_length_operand, array_length); |
| 3289 | 3304 |
| 3290 // Save the FixedArray containing array's elements. | 3305 // Save the FixedArray containing array's elements. |
| 3291 // End of array's live range. | 3306 // End of array's live range. |
| 3292 elements = array; | 3307 elements = array; |
| 3293 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); | 3308 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3484 FieldOperand(string, SeqAsciiString::kHeaderSize)); | 3499 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 3485 __ CopyBytes(string, result_pos, string_length, scratch); | 3500 __ CopyBytes(string, result_pos, string_length, scratch); |
| 3486 __ add(Operand(index), Immediate(1)); | 3501 __ add(Operand(index), Immediate(1)); |
| 3487 | 3502 |
| 3488 __ cmp(index, array_length_operand); | 3503 __ cmp(index, array_length_operand); |
| 3489 __ j(less, &loop_3); // End while (index < length). | 3504 __ j(less, &loop_3); // End while (index < length). |
| 3490 __ jmp(&done); | 3505 __ jmp(&done); |
| 3491 | 3506 |
| 3492 | 3507 |
| 3493 __ bind(&bailout); | 3508 __ bind(&bailout); |
| 3494 __ mov(result_operand, Factory::undefined_value()); | 3509 __ mov(result_operand, FACTORY->undefined_value()); |
| 3495 __ bind(&done); | 3510 __ bind(&done); |
| 3496 __ mov(eax, result_operand); | 3511 __ mov(eax, result_operand); |
| 3497 // Drop temp values from the stack, and restore context register. | 3512 // Drop temp values from the stack, and restore context register. |
| 3498 __ add(Operand(esp), Immediate(3 * kPointerSize)); | 3513 __ add(Operand(esp), Immediate(3 * kPointerSize)); |
| 3499 | 3514 |
| 3500 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3515 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3501 context()->Plug(eax); | 3516 context()->Plug(eax); |
| 3502 } | 3517 } |
| 3503 | 3518 |
| 3504 | 3519 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3522 // Push the arguments ("left-to-right"). | 3537 // Push the arguments ("left-to-right"). |
| 3523 int arg_count = args->length(); | 3538 int arg_count = args->length(); |
| 3524 for (int i = 0; i < arg_count; i++) { | 3539 for (int i = 0; i < arg_count; i++) { |
| 3525 VisitForStackValue(args->at(i)); | 3540 VisitForStackValue(args->at(i)); |
| 3526 } | 3541 } |
| 3527 | 3542 |
| 3528 if (expr->is_jsruntime()) { | 3543 if (expr->is_jsruntime()) { |
| 3529 // Call the JS runtime function via a call IC. | 3544 // Call the JS runtime function via a call IC. |
| 3530 __ Set(ecx, Immediate(expr->name())); | 3545 __ Set(ecx, Immediate(expr->name())); |
| 3531 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 3546 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 3532 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop); | 3547 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( |
| 3548 arg_count, in_loop); |
| 3533 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3549 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3534 // Restore context register. | 3550 // Restore context register. |
| 3535 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3551 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3536 } else { | 3552 } else { |
| 3537 // Call the C runtime function. | 3553 // Call the C runtime function. |
| 3538 __ CallRuntime(expr->function(), arg_count); | 3554 __ CallRuntime(expr->function(), arg_count); |
| 3539 } | 3555 } |
| 3540 context()->Plug(eax); | 3556 context()->Plug(eax); |
| 3541 } | 3557 } |
| 3542 | 3558 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3588 // The subexpression may have side effects. | 3604 // The subexpression may have side effects. |
| 3589 VisitForEffect(expr->expression()); | 3605 VisitForEffect(expr->expression()); |
| 3590 context()->Plug(true); | 3606 context()->Plug(true); |
| 3591 } | 3607 } |
| 3592 break; | 3608 break; |
| 3593 } | 3609 } |
| 3594 | 3610 |
| 3595 case Token::VOID: { | 3611 case Token::VOID: { |
| 3596 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 3612 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 3597 VisitForEffect(expr->expression()); | 3613 VisitForEffect(expr->expression()); |
| 3598 context()->Plug(Factory::undefined_value()); | 3614 context()->Plug(isolate()->factory()->undefined_value()); |
| 3599 break; | 3615 break; |
| 3600 } | 3616 } |
| 3601 | 3617 |
| 3602 case Token::NOT: { | 3618 case Token::NOT: { |
| 3603 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3619 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 3604 if (context()->IsEffect()) { | 3620 if (context()->IsEffect()) { |
| 3605 // Unary NOT has no side effects so it's only necessary to visit the | 3621 // Unary NOT has no side effects so it's only necessary to visit the |
| 3606 // subexpression. Match the optimizing compiler by not branching. | 3622 // subexpression. Match the optimizing compiler by not branching. |
| 3607 VisitForEffect(expr->expression()); | 3623 VisitForEffect(expr->expression()); |
| 3608 } else { | 3624 } else { |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3836 // Perform the assignment as if via '='. | 3852 // Perform the assignment as if via '='. |
| 3837 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3853 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3838 Token::ASSIGN); | 3854 Token::ASSIGN); |
| 3839 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3855 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3840 context()->Plug(eax); | 3856 context()->Plug(eax); |
| 3841 } | 3857 } |
| 3842 break; | 3858 break; |
| 3843 case NAMED_PROPERTY: { | 3859 case NAMED_PROPERTY: { |
| 3844 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 3860 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 3845 __ pop(edx); | 3861 __ pop(edx); |
| 3846 Handle<Code> ic(Builtins::builtin( | 3862 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3847 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict | 3863 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 3848 : Builtins::StoreIC_Initialize)); | 3864 : Builtins::StoreIC_Initialize)); |
| 3849 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3865 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3850 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3866 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3851 if (expr->is_postfix()) { | 3867 if (expr->is_postfix()) { |
| 3852 if (!context()->IsEffect()) { | 3868 if (!context()->IsEffect()) { |
| 3853 context()->PlugTOS(); | 3869 context()->PlugTOS(); |
| 3854 } | 3870 } |
| 3855 } else { | 3871 } else { |
| 3856 context()->Plug(eax); | 3872 context()->Plug(eax); |
| 3857 } | 3873 } |
| 3858 break; | 3874 break; |
| 3859 } | 3875 } |
| 3860 case KEYED_PROPERTY: { | 3876 case KEYED_PROPERTY: { |
| 3861 __ pop(ecx); | 3877 __ pop(ecx); |
| 3862 __ pop(edx); | 3878 __ pop(edx); |
| 3863 Handle<Code> ic(Builtins::builtin( | 3879 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3864 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict | 3880 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 3865 : Builtins::KeyedStoreIC_Initialize)); | 3881 : Builtins::KeyedStoreIC_Initialize)); |
| 3866 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3882 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3867 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3883 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3868 if (expr->is_postfix()) { | 3884 if (expr->is_postfix()) { |
| 3869 // Result is on the stack | 3885 // Result is on the stack |
| 3870 if (!context()->IsEffect()) { | 3886 if (!context()->IsEffect()) { |
| 3871 context()->PlugTOS(); | 3887 context()->PlugTOS(); |
| 3872 } | 3888 } |
| 3873 } else { | 3889 } else { |
| 3874 context()->Plug(eax); | 3890 context()->Plug(eax); |
| 3875 } | 3891 } |
| 3876 break; | 3892 break; |
| 3877 } | 3893 } |
| 3878 } | 3894 } |
| 3879 } | 3895 } |
| 3880 | 3896 |
| 3881 | 3897 |
| 3882 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3898 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3883 VariableProxy* proxy = expr->AsVariableProxy(); | 3899 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3884 ASSERT(!context()->IsEffect()); | 3900 ASSERT(!context()->IsEffect()); |
| 3885 ASSERT(!context()->IsTest()); | 3901 ASSERT(!context()->IsTest()); |
| 3886 | 3902 |
| 3887 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3903 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3888 Comment cmnt(masm_, "Global variable"); | 3904 Comment cmnt(masm_, "Global variable"); |
| 3889 __ mov(eax, GlobalObjectOperand()); | 3905 __ mov(eax, GlobalObjectOperand()); |
| 3890 __ mov(ecx, Immediate(proxy->name())); | 3906 __ mov(ecx, Immediate(proxy->name())); |
| 3891 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3907 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3908 Builtins::LoadIC_Initialize)); |
| 3892 // Use a regular load, not a contextual load, to avoid a reference | 3909 // Use a regular load, not a contextual load, to avoid a reference |
| 3893 // error. | 3910 // error. |
| 3894 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3911 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3895 PrepareForBailout(expr, TOS_REG); | 3912 PrepareForBailout(expr, TOS_REG); |
| 3896 context()->Plug(eax); | 3913 context()->Plug(eax); |
| 3897 } else if (proxy != NULL && | 3914 } else if (proxy != NULL && |
| 3898 proxy->var()->AsSlot() != NULL && | 3915 proxy->var()->AsSlot() != NULL && |
| 3899 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3916 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 3900 Label done, slow; | 3917 Label done, slow; |
| 3901 | 3918 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3934 if (!right_literal_value->IsString()) return false; | 3951 if (!right_literal_value->IsString()) return false; |
| 3935 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3952 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3936 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3953 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3937 Handle<String> check = Handle<String>::cast(right_literal_value); | 3954 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3938 | 3955 |
| 3939 { AccumulatorValueContext context(this); | 3956 { AccumulatorValueContext context(this); |
| 3940 VisitForTypeofValue(left_unary->expression()); | 3957 VisitForTypeofValue(left_unary->expression()); |
| 3941 } | 3958 } |
| 3942 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3959 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3943 | 3960 |
| 3944 if (check->Equals(Heap::number_symbol())) { | 3961 if (check->Equals(isolate()->heap()->number_symbol())) { |
| 3945 __ JumpIfSmi(eax, if_true); | 3962 __ JumpIfSmi(eax, if_true); |
| 3946 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3963 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3947 Factory::heap_number_map()); | 3964 isolate()->factory()->heap_number_map()); |
| 3948 Split(equal, if_true, if_false, fall_through); | 3965 Split(equal, if_true, if_false, fall_through); |
| 3949 } else if (check->Equals(Heap::string_symbol())) { | 3966 } else if (check->Equals(isolate()->heap()->string_symbol())) { |
| 3950 __ JumpIfSmi(eax, if_false); | 3967 __ JumpIfSmi(eax, if_false); |
| 3951 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); | 3968 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); |
| 3952 __ j(above_equal, if_false); | 3969 __ j(above_equal, if_false); |
| 3953 // Check for undetectable objects => false. | 3970 // Check for undetectable objects => false. |
| 3954 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 3971 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 3955 1 << Map::kIsUndetectable); | 3972 1 << Map::kIsUndetectable); |
| 3956 Split(zero, if_true, if_false, fall_through); | 3973 Split(zero, if_true, if_false, fall_through); |
| 3957 } else if (check->Equals(Heap::boolean_symbol())) { | 3974 } else if (check->Equals(isolate()->heap()->boolean_symbol())) { |
| 3958 __ cmp(eax, Factory::true_value()); | 3975 __ cmp(eax, isolate()->factory()->true_value()); |
| 3959 __ j(equal, if_true); | 3976 __ j(equal, if_true); |
| 3960 __ cmp(eax, Factory::false_value()); | 3977 __ cmp(eax, isolate()->factory()->false_value()); |
| 3961 Split(equal, if_true, if_false, fall_through); | 3978 Split(equal, if_true, if_false, fall_through); |
| 3962 } else if (check->Equals(Heap::undefined_symbol())) { | 3979 } else if (check->Equals(isolate()->heap()->undefined_symbol())) { |
| 3963 __ cmp(eax, Factory::undefined_value()); | 3980 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 3964 __ j(equal, if_true); | 3981 __ j(equal, if_true); |
| 3965 __ JumpIfSmi(eax, if_false); | 3982 __ JumpIfSmi(eax, if_false); |
| 3966 // Check for undetectable objects => true. | 3983 // Check for undetectable objects => true. |
| 3967 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3984 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3968 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3985 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3969 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3986 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 3970 Split(not_zero, if_true, if_false, fall_through); | 3987 Split(not_zero, if_true, if_false, fall_through); |
| 3971 } else if (check->Equals(Heap::function_symbol())) { | 3988 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
| 3972 __ JumpIfSmi(eax, if_false); | 3989 __ JumpIfSmi(eax, if_false); |
| 3973 __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx); | 3990 __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx); |
| 3974 Split(above_equal, if_true, if_false, fall_through); | 3991 Split(above_equal, if_true, if_false, fall_through); |
| 3975 } else if (check->Equals(Heap::object_symbol())) { | 3992 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
| 3976 __ JumpIfSmi(eax, if_false); | 3993 __ JumpIfSmi(eax, if_false); |
| 3977 __ cmp(eax, Factory::null_value()); | 3994 __ cmp(eax, isolate()->factory()->null_value()); |
| 3978 __ j(equal, if_true); | 3995 __ j(equal, if_true); |
| 3979 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx); | 3996 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx); |
| 3980 __ j(below, if_false); | 3997 __ j(below, if_false); |
| 3981 __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE); | 3998 __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE); |
| 3982 __ j(above_equal, if_false); | 3999 __ j(above_equal, if_false); |
| 3983 // Check for undetectable objects => false. | 4000 // Check for undetectable objects => false. |
| 3984 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 4001 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 3985 1 << Map::kIsUndetectable); | 4002 1 << Map::kIsUndetectable); |
| 3986 Split(zero, if_true, if_false, fall_through); | 4003 Split(zero, if_true, if_false, fall_through); |
| 3987 } else { | 4004 } else { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 4015 context()->Plug(if_true, if_false); | 4032 context()->Plug(if_true, if_false); |
| 4016 return; | 4033 return; |
| 4017 } | 4034 } |
| 4018 | 4035 |
| 4019 VisitForStackValue(expr->left()); | 4036 VisitForStackValue(expr->left()); |
| 4020 switch (expr->op()) { | 4037 switch (expr->op()) { |
| 4021 case Token::IN: | 4038 case Token::IN: |
| 4022 VisitForStackValue(expr->right()); | 4039 VisitForStackValue(expr->right()); |
| 4023 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 4040 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 4024 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 4041 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 4025 __ cmp(eax, Factory::true_value()); | 4042 __ cmp(eax, isolate()->factory()->true_value()); |
| 4026 Split(equal, if_true, if_false, fall_through); | 4043 Split(equal, if_true, if_false, fall_through); |
| 4027 break; | 4044 break; |
| 4028 | 4045 |
| 4029 case Token::INSTANCEOF: { | 4046 case Token::INSTANCEOF: { |
| 4030 VisitForStackValue(expr->right()); | 4047 VisitForStackValue(expr->right()); |
| 4031 InstanceofStub stub(InstanceofStub::kNoFlags); | 4048 InstanceofStub stub(InstanceofStub::kNoFlags); |
| 4032 __ CallStub(&stub); | 4049 __ CallStub(&stub); |
| 4033 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4050 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4034 __ test(eax, Operand(eax)); | 4051 __ test(eax, Operand(eax)); |
| 4035 // The stub returns 0 for true. | 4052 // The stub returns 0 for true. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4108 Label materialize_true, materialize_false; | 4125 Label materialize_true, materialize_false; |
| 4109 Label* if_true = NULL; | 4126 Label* if_true = NULL; |
| 4110 Label* if_false = NULL; | 4127 Label* if_false = NULL; |
| 4111 Label* fall_through = NULL; | 4128 Label* fall_through = NULL; |
| 4112 context()->PrepareTest(&materialize_true, &materialize_false, | 4129 context()->PrepareTest(&materialize_true, &materialize_false, |
| 4113 &if_true, &if_false, &fall_through); | 4130 &if_true, &if_false, &fall_through); |
| 4114 | 4131 |
| 4115 VisitForAccumulatorValue(expr->expression()); | 4132 VisitForAccumulatorValue(expr->expression()); |
| 4116 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4133 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4117 | 4134 |
| 4118 __ cmp(eax, Factory::null_value()); | 4135 __ cmp(eax, isolate()->factory()->null_value()); |
| 4119 if (expr->is_strict()) { | 4136 if (expr->is_strict()) { |
| 4120 Split(equal, if_true, if_false, fall_through); | 4137 Split(equal, if_true, if_false, fall_through); |
| 4121 } else { | 4138 } else { |
| 4122 __ j(equal, if_true); | 4139 __ j(equal, if_true); |
| 4123 __ cmp(eax, Factory::undefined_value()); | 4140 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 4124 __ j(equal, if_true); | 4141 __ j(equal, if_true); |
| 4125 __ test(eax, Immediate(kSmiTagMask)); | 4142 __ test(eax, Immediate(kSmiTagMask)); |
| 4126 __ j(zero, if_false); | 4143 __ j(zero, if_false); |
| 4127 // It can be an undetectable object. | 4144 // It can be an undetectable object. |
| 4128 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4145 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4129 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); | 4146 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4130 __ test(edx, Immediate(1 << Map::kIsUndetectable)); | 4147 __ test(edx, Immediate(1 << Map::kIsUndetectable)); |
| 4131 Split(not_zero, if_true, if_false, fall_through); | 4148 Split(not_zero, if_true, if_false, fall_through); |
| 4132 } | 4149 } |
| 4133 context()->Plug(if_true, if_false); | 4150 context()->Plug(if_true, if_false); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4148 Register FullCodeGenerator::context_register() { | 4165 Register FullCodeGenerator::context_register() { |
| 4149 return esi; | 4166 return esi; |
| 4150 } | 4167 } |
| 4151 | 4168 |
| 4152 | 4169 |
| 4153 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { | 4170 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { |
| 4154 ASSERT(mode == RelocInfo::CODE_TARGET || | 4171 ASSERT(mode == RelocInfo::CODE_TARGET || |
| 4155 mode == RelocInfo::CODE_TARGET_CONTEXT); | 4172 mode == RelocInfo::CODE_TARGET_CONTEXT); |
| 4156 switch (ic->kind()) { | 4173 switch (ic->kind()) { |
| 4157 case Code::LOAD_IC: | 4174 case Code::LOAD_IC: |
| 4158 __ IncrementCounter(&Counters::named_load_full, 1); | 4175 __ IncrementCounter(isolate()->counters()->named_load_full(), 1); |
| 4159 break; | 4176 break; |
| 4160 case Code::KEYED_LOAD_IC: | 4177 case Code::KEYED_LOAD_IC: |
| 4161 __ IncrementCounter(&Counters::keyed_load_full, 1); | 4178 __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1); |
| 4162 break; | 4179 break; |
| 4163 case Code::STORE_IC: | 4180 case Code::STORE_IC: |
| 4164 __ IncrementCounter(&Counters::named_store_full, 1); | 4181 __ IncrementCounter(isolate()->counters()->named_store_full(), 1); |
| 4165 break; | 4182 break; |
| 4166 case Code::KEYED_STORE_IC: | 4183 case Code::KEYED_STORE_IC: |
| 4167 __ IncrementCounter(&Counters::keyed_store_full, 1); | 4184 __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1); |
| 4168 default: | 4185 default: |
| 4169 break; | 4186 break; |
| 4170 } | 4187 } |
| 4171 | 4188 |
| 4172 __ call(ic, mode); | 4189 __ call(ic, mode); |
| 4173 | 4190 |
| 4174 // Crankshaft doesn't need patching of inlined loads and stores. | 4191 // Crankshaft doesn't need patching of inlined loads and stores. |
| 4175 // When compiling the snapshot we need to produce code that works | 4192 // When compiling the snapshot we need to produce code that works |
| 4176 // with and without Crankshaft. | 4193 // with and without Crankshaft. |
| 4177 if (V8::UseCrankshaft() && !Serializer::enabled()) { | 4194 if (V8::UseCrankshaft() && !Serializer::enabled()) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4191 default: | 4208 default: |
| 4192 // Do nothing. | 4209 // Do nothing. |
| 4193 break; | 4210 break; |
| 4194 } | 4211 } |
| 4195 } | 4212 } |
| 4196 | 4213 |
| 4197 | 4214 |
| 4198 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { | 4215 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { |
| 4199 switch (ic->kind()) { | 4216 switch (ic->kind()) { |
| 4200 case Code::LOAD_IC: | 4217 case Code::LOAD_IC: |
| 4201 __ IncrementCounter(&Counters::named_load_full, 1); | 4218 __ IncrementCounter(COUNTERS->named_load_full(), 1); |
| 4202 break; | 4219 break; |
| 4203 case Code::KEYED_LOAD_IC: | 4220 case Code::KEYED_LOAD_IC: |
| 4204 __ IncrementCounter(&Counters::keyed_load_full, 1); | 4221 __ IncrementCounter(COUNTERS->keyed_load_full(), 1); |
| 4205 break; | 4222 break; |
| 4206 case Code::STORE_IC: | 4223 case Code::STORE_IC: |
| 4207 __ IncrementCounter(&Counters::named_store_full, 1); | 4224 __ IncrementCounter(COUNTERS->named_store_full(), 1); |
| 4208 break; | 4225 break; |
| 4209 case Code::KEYED_STORE_IC: | 4226 case Code::KEYED_STORE_IC: |
| 4210 __ IncrementCounter(&Counters::keyed_store_full, 1); | 4227 __ IncrementCounter(COUNTERS->keyed_store_full(), 1); |
| 4211 default: | 4228 default: |
| 4212 break; | 4229 break; |
| 4213 } | 4230 } |
| 4214 | 4231 |
| 4215 __ call(ic, RelocInfo::CODE_TARGET); | 4232 __ call(ic, RelocInfo::CODE_TARGET); |
| 4216 if (patch_site != NULL && patch_site->is_bound()) { | 4233 if (patch_site != NULL && patch_site->is_bound()) { |
| 4217 patch_site->EmitPatchInfo(); | 4234 patch_site->EmitPatchInfo(); |
| 4218 } else { | 4235 } else { |
| 4219 __ nop(); // Signals no inlined code. | 4236 __ nop(); // Signals no inlined code. |
| 4220 } | 4237 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4261 // And return. | 4278 // And return. |
| 4262 __ ret(0); | 4279 __ ret(0); |
| 4263 } | 4280 } |
| 4264 | 4281 |
| 4265 | 4282 |
| 4266 #undef __ | 4283 #undef __ |
| 4267 | 4284 |
| 4268 } } // namespace v8::internal | 4285 } } // namespace v8::internal |
| 4269 | 4286 |
| 4270 #endif // V8_TARGET_ARCH_IA32 | 4287 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |