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