| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 #endif | 70 #endif |
| 71 | 71 |
| 72 __ push(ebp); // Caller's frame pointer. | 72 __ push(ebp); // Caller's frame pointer. |
| 73 __ mov(ebp, esp); | 73 __ mov(ebp, esp); |
| 74 __ push(esi); // Callee's context. | 74 __ push(esi); // Callee's context. |
| 75 __ push(edi); // Callee's JS Function. | 75 __ push(edi); // Callee's JS Function. |
| 76 | 76 |
| 77 { Comment cmnt(masm_, "[ Allocate locals"); | 77 { Comment cmnt(masm_, "[ Allocate locals"); |
| 78 int locals_count = scope()->num_stack_slots(); | 78 int locals_count = scope()->num_stack_slots(); |
| 79 if (locals_count == 1) { | 79 if (locals_count == 1) { |
| 80 __ push(Immediate(FACTORY->undefined_value())); | 80 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 81 } else if (locals_count > 1) { | 81 } else if (locals_count > 1) { |
| 82 __ mov(eax, Immediate(FACTORY->undefined_value())); | 82 __ mov(eax, Immediate(isolate()->factory()->undefined_value())); |
| 83 for (int i = 0; i < locals_count; i++) { | 83 for (int i = 0; i < locals_count; i++) { |
| 84 __ push(eax); | 84 __ push(eax); |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 } | 87 } |
| 88 | 88 |
| 89 bool function_in_register = true; | 89 bool function_in_register = true; |
| 90 | 90 |
| 91 // Possibly allocate a local context. | 91 // Possibly allocate a local context. |
| 92 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 92 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 } | 185 } |
| 186 | 186 |
| 187 { Comment cmnt(masm_, "[ Body"); | 187 { Comment cmnt(masm_, "[ Body"); |
| 188 ASSERT(loop_depth() == 0); | 188 ASSERT(loop_depth() == 0); |
| 189 VisitStatements(function()->body()); | 189 VisitStatements(function()->body()); |
| 190 ASSERT(loop_depth() == 0); | 190 ASSERT(loop_depth() == 0); |
| 191 } | 191 } |
| 192 | 192 |
| 193 { Comment cmnt(masm_, "[ return <undefined>;"); | 193 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 194 // Emit a 'return undefined' in case control fell off the end of the body. | 194 // Emit a 'return undefined' in case control fell off the end of the body. |
| 195 __ mov(eax, FACTORY->undefined_value()); | 195 __ mov(eax, isolate()->factory()->undefined_value()); |
| 196 EmitReturnSequence(); | 196 EmitReturnSequence(); |
| 197 } | 197 } |
| 198 } | 198 } |
| 199 | 199 |
| 200 | 200 |
| 201 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { | 201 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { |
| 202 Comment cmnt(masm_, "[ Stack check"); | 202 Comment cmnt(masm_, "[ Stack check"); |
| 203 NearLabel ok; | 203 NearLabel ok; |
| 204 ExternalReference stack_limit = ExternalReference::address_of_stack_limit(); | 204 ExternalReference stack_limit = ExternalReference::address_of_stack_limit(); |
| 205 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 205 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 ASSERT(materialize_true == materialize_false); | 401 ASSERT(materialize_true == materialize_false); |
| 402 __ bind(materialize_true); | 402 __ bind(materialize_true); |
| 403 } | 403 } |
| 404 | 404 |
| 405 | 405 |
| 406 void FullCodeGenerator::AccumulatorValueContext::Plug( | 406 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 407 Label* materialize_true, | 407 Label* materialize_true, |
| 408 Label* materialize_false) const { | 408 Label* materialize_false) const { |
| 409 NearLabel done; | 409 NearLabel done; |
| 410 __ bind(materialize_true); | 410 __ bind(materialize_true); |
| 411 __ mov(result_register(), FACTORY->true_value()); | 411 __ mov(result_register(), isolate()->factory()->true_value()); |
| 412 __ jmp(&done); | 412 __ jmp(&done); |
| 413 __ bind(materialize_false); | 413 __ bind(materialize_false); |
| 414 __ mov(result_register(), FACTORY->false_value()); | 414 __ mov(result_register(), isolate()->factory()->false_value()); |
| 415 __ bind(&done); | 415 __ bind(&done); |
| 416 } | 416 } |
| 417 | 417 |
| 418 | 418 |
| 419 void FullCodeGenerator::StackValueContext::Plug( | 419 void FullCodeGenerator::StackValueContext::Plug( |
| 420 Label* materialize_true, | 420 Label* materialize_true, |
| 421 Label* materialize_false) const { | 421 Label* materialize_false) const { |
| 422 NearLabel done; | 422 NearLabel done; |
| 423 __ bind(materialize_true); | 423 __ bind(materialize_true); |
| 424 __ push(Immediate(FACTORY->true_value())); | 424 __ push(Immediate(isolate()->factory()->true_value())); |
| 425 __ jmp(&done); | 425 __ jmp(&done); |
| 426 __ bind(materialize_false); | 426 __ bind(materialize_false); |
| 427 __ push(Immediate(FACTORY->false_value())); | 427 __ push(Immediate(isolate()->factory()->false_value())); |
| 428 __ bind(&done); | 428 __ bind(&done); |
| 429 } | 429 } |
| 430 | 430 |
| 431 | 431 |
| 432 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, | 432 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
| 433 Label* materialize_false) const { | 433 Label* materialize_false) const { |
| 434 ASSERT(materialize_true == true_label_); | 434 ASSERT(materialize_true == true_label_); |
| 435 ASSERT(materialize_false == false_label_); | 435 ASSERT(materialize_false == false_label_); |
| 436 } | 436 } |
| 437 | 437 |
| 438 | 438 |
| 439 void FullCodeGenerator::EffectContext::Plug(bool flag) const { | 439 void FullCodeGenerator::EffectContext::Plug(bool flag) const { |
| 440 } | 440 } |
| 441 | 441 |
| 442 | 442 |
| 443 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { | 443 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { |
| 444 Handle<Object> value = | 444 Handle<Object> value = flag |
| 445 flag ? FACTORY->true_value() : FACTORY->false_value(); | 445 ? isolate()->factory()->true_value() |
| 446 : isolate()->factory()->false_value(); |
| 446 __ mov(result_register(), value); | 447 __ mov(result_register(), value); |
| 447 } | 448 } |
| 448 | 449 |
| 449 | 450 |
| 450 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 451 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
| 451 Handle<Object> value = | 452 Handle<Object> value = flag |
| 452 flag ? FACTORY->true_value() : FACTORY->false_value(); | 453 ? isolate()->factory()->true_value() |
| 454 : isolate()->factory()->false_value(); |
| 453 __ push(Immediate(value)); | 455 __ push(Immediate(value)); |
| 454 } | 456 } |
| 455 | 457 |
| 456 | 458 |
| 457 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 459 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
| 458 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, | 460 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, |
| 459 true, | 461 true, |
| 460 true_label_, | 462 true_label_, |
| 461 false_label_); | 463 false_label_); |
| 462 if (flag) { | 464 if (flag) { |
| 463 if (true_label_ != fall_through_) __ jmp(true_label_); | 465 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 464 } else { | 466 } else { |
| 465 if (false_label_ != fall_through_) __ jmp(false_label_); | 467 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 466 } | 468 } |
| 467 } | 469 } |
| 468 | 470 |
| 469 | 471 |
| 470 void FullCodeGenerator::DoTest(Label* if_true, | 472 void FullCodeGenerator::DoTest(Label* if_true, |
| 471 Label* if_false, | 473 Label* if_false, |
| 472 Label* fall_through) { | 474 Label* fall_through) { |
| 473 // Emit the inlined tests assumed by the stub. | 475 // Emit the inlined tests assumed by the stub. |
| 474 __ cmp(result_register(), FACTORY->undefined_value()); | 476 __ cmp(result_register(), isolate()->factory()->undefined_value()); |
| 475 __ j(equal, if_false); | 477 __ j(equal, if_false); |
| 476 __ cmp(result_register(), FACTORY->true_value()); | 478 __ cmp(result_register(), isolate()->factory()->true_value()); |
| 477 __ j(equal, if_true); | 479 __ j(equal, if_true); |
| 478 __ cmp(result_register(), FACTORY->false_value()); | 480 __ cmp(result_register(), isolate()->factory()->false_value()); |
| 479 __ j(equal, if_false); | 481 __ j(equal, if_false); |
| 480 ASSERT_EQ(0, kSmiTag); | 482 ASSERT_EQ(0, kSmiTag); |
| 481 __ test(result_register(), Operand(result_register())); | 483 __ test(result_register(), Operand(result_register())); |
| 482 __ j(zero, if_false); | 484 __ j(zero, if_false); |
| 483 __ test(result_register(), Immediate(kSmiTagMask)); | 485 __ test(result_register(), Immediate(kSmiTagMask)); |
| 484 __ j(zero, if_true); | 486 __ j(zero, if_true); |
| 485 | 487 |
| 486 // Call the ToBoolean stub for all other cases. | 488 // Call the ToBoolean stub for all other cases. |
| 487 ToBooleanStub stub; | 489 ToBooleanStub stub; |
| 488 __ push(result_register()); | 490 __ push(result_register()); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 NearLabel skip; | 564 NearLabel skip; |
| 563 if (should_normalize) __ jmp(&skip); | 565 if (should_normalize) __ jmp(&skip); |
| 564 | 566 |
| 565 ForwardBailoutStack* current = forward_bailout_stack_; | 567 ForwardBailoutStack* current = forward_bailout_stack_; |
| 566 while (current != NULL) { | 568 while (current != NULL) { |
| 567 PrepareForBailout(current->expr(), state); | 569 PrepareForBailout(current->expr(), state); |
| 568 current = current->parent(); | 570 current = current->parent(); |
| 569 } | 571 } |
| 570 | 572 |
| 571 if (should_normalize) { | 573 if (should_normalize) { |
| 572 __ cmp(eax, FACTORY->true_value()); | 574 __ cmp(eax, isolate()->factory()->true_value()); |
| 573 Split(equal, if_true, if_false, NULL); | 575 Split(equal, if_true, if_false, NULL); |
| 574 __ bind(&skip); | 576 __ bind(&skip); |
| 575 } | 577 } |
| 576 } | 578 } |
| 577 | 579 |
| 578 | 580 |
| 579 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 581 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 580 Variable::Mode mode, | 582 Variable::Mode mode, |
| 581 FunctionLiteral* function) { | 583 FunctionLiteral* function) { |
| 582 Comment cmnt(masm_, "[ Declaration"); | 584 Comment cmnt(masm_, "[ Declaration"); |
| 583 ASSERT(variable != NULL); // Must have been resolved. | 585 ASSERT(variable != NULL); // Must have been resolved. |
| 584 Slot* slot = variable->AsSlot(); | 586 Slot* slot = variable->AsSlot(); |
| 585 Property* prop = variable->AsProperty(); | 587 Property* prop = variable->AsProperty(); |
| 586 if (slot != NULL) { | 588 if (slot != NULL) { |
| 587 switch (slot->type()) { | 589 switch (slot->type()) { |
| 588 case Slot::PARAMETER: | 590 case Slot::PARAMETER: |
| 589 case Slot::LOCAL: | 591 case Slot::LOCAL: |
| 590 if (mode == Variable::CONST) { | 592 if (mode == Variable::CONST) { |
| 591 __ mov(Operand(ebp, SlotOffset(slot)), | 593 __ mov(Operand(ebp, SlotOffset(slot)), |
| 592 Immediate(FACTORY->the_hole_value())); | 594 Immediate(isolate()->factory()->the_hole_value())); |
| 593 } else if (function != NULL) { | 595 } else if (function != NULL) { |
| 594 VisitForAccumulatorValue(function); | 596 VisitForAccumulatorValue(function); |
| 595 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 597 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| 596 } | 598 } |
| 597 break; | 599 break; |
| 598 | 600 |
| 599 case Slot::CONTEXT: | 601 case Slot::CONTEXT: |
| 600 // We bypass the general EmitSlotSearch because we know more about | 602 // We bypass the general EmitSlotSearch because we know more about |
| 601 // this specific context. | 603 // this specific context. |
| 602 | 604 |
| 603 // The variable in the decl always resides in the current context. | 605 // The variable in the decl always resides in the current context. |
| 604 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 606 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 605 if (FLAG_debug_code) { | 607 if (FLAG_debug_code) { |
| 606 // Check if we have the correct context pointer. | 608 // Check if we have the correct context pointer. |
| 607 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | 609 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 608 __ cmp(ebx, Operand(esi)); | 610 __ cmp(ebx, Operand(esi)); |
| 609 __ Check(equal, "Unexpected declaration in current context."); | 611 __ Check(equal, "Unexpected declaration in current context."); |
| 610 } | 612 } |
| 611 if (mode == Variable::CONST) { | 613 if (mode == Variable::CONST) { |
| 612 __ mov(ContextOperand(esi, slot->index()), | 614 __ mov(ContextOperand(esi, slot->index()), |
| 613 Immediate(FACTORY->the_hole_value())); | 615 Immediate(isolate()->factory()->the_hole_value())); |
| 614 // No write barrier since the hole value is in old space. | 616 // No write barrier since the hole value is in old space. |
| 615 } else if (function != NULL) { | 617 } else if (function != NULL) { |
| 616 VisitForAccumulatorValue(function); | 618 VisitForAccumulatorValue(function); |
| 617 __ mov(ContextOperand(esi, slot->index()), result_register()); | 619 __ mov(ContextOperand(esi, slot->index()), result_register()); |
| 618 int offset = Context::SlotOffset(slot->index()); | 620 int offset = Context::SlotOffset(slot->index()); |
| 619 __ mov(ebx, esi); | 621 __ mov(ebx, esi); |
| 620 __ RecordWrite(ebx, offset, result_register(), ecx); | 622 __ RecordWrite(ebx, offset, result_register(), ecx); |
| 621 } | 623 } |
| 622 break; | 624 break; |
| 623 | 625 |
| 624 case Slot::LOOKUP: { | 626 case Slot::LOOKUP: { |
| 625 __ push(esi); | 627 __ push(esi); |
| 626 __ push(Immediate(variable->name())); | 628 __ push(Immediate(variable->name())); |
| 627 // Declaration nodes are always introduced in one of two modes. | 629 // Declaration nodes are always introduced in one of two modes. |
| 628 ASSERT(mode == Variable::VAR || mode == Variable::CONST); | 630 ASSERT(mode == Variable::VAR || mode == Variable::CONST); |
| 629 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; | 631 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; |
| 630 __ push(Immediate(Smi::FromInt(attr))); | 632 __ push(Immediate(Smi::FromInt(attr))); |
| 631 // Push initial value, if any. | 633 // Push initial value, if any. |
| 632 // Note: For variables we must not push an initial value (such as | 634 // Note: For variables we must not push an initial value (such as |
| 633 // 'undefined') because we may have a (legal) redeclaration and we | 635 // 'undefined') because we may have a (legal) redeclaration and we |
| 634 // must not destroy the current value. | 636 // must not destroy the current value. |
| 635 if (mode == Variable::CONST) { | 637 if (mode == Variable::CONST) { |
| 636 __ push(Immediate(FACTORY->the_hole_value())); | 638 __ push(Immediate(isolate()->factory()->the_hole_value())); |
| 637 } else if (function != NULL) { | 639 } else if (function != NULL) { |
| 638 VisitForStackValue(function); | 640 VisitForStackValue(function); |
| 639 } else { | 641 } else { |
| 640 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 642 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
| 641 } | 643 } |
| 642 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 644 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 643 break; | 645 break; |
| 644 } | 646 } |
| 645 } | 647 } |
| 646 | 648 |
| 647 } else if (prop != NULL) { | 649 } else if (prop != NULL) { |
| 648 if (function != NULL || mode == Variable::CONST) { | 650 if (function != NULL || mode == Variable::CONST) { |
| 649 // We are declaring a function or constant that rewrites to a | 651 // We are declaring a function or constant that rewrites to a |
| 650 // property. Use (keyed) IC to set the initial value. | 652 // property. Use (keyed) IC to set the initial value. |
| 651 VisitForStackValue(prop->obj()); | 653 VisitForStackValue(prop->obj()); |
| 652 if (function != NULL) { | 654 if (function != NULL) { |
| 653 VisitForStackValue(prop->key()); | 655 VisitForStackValue(prop->key()); |
| 654 VisitForAccumulatorValue(function); | 656 VisitForAccumulatorValue(function); |
| 655 __ pop(ecx); | 657 __ pop(ecx); |
| 656 } else { | 658 } else { |
| 657 VisitForAccumulatorValue(prop->key()); | 659 VisitForAccumulatorValue(prop->key()); |
| 658 __ mov(ecx, result_register()); | 660 __ mov(ecx, result_register()); |
| 659 __ mov(result_register(), FACTORY->the_hole_value()); | 661 __ mov(result_register(), isolate()->factory()->the_hole_value()); |
| 660 } | 662 } |
| 661 __ pop(edx); | 663 __ pop(edx); |
| 662 | 664 |
| 663 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 665 Handle<Code> ic(isolate()->builtins()->builtin( |
| 664 Builtins::KeyedStoreIC_Initialize)); | 666 Builtins::KeyedStoreIC_Initialize)); |
| 665 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 667 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 666 } | 668 } |
| 667 } | 669 } |
| 668 } | 670 } |
| 669 | 671 |
| 670 | 672 |
| 671 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 673 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 672 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 674 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 673 } | 675 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 SetStatementPosition(stmt); | 771 SetStatementPosition(stmt); |
| 770 | 772 |
| 771 Label loop, exit; | 773 Label loop, exit; |
| 772 ForIn loop_statement(this, stmt); | 774 ForIn loop_statement(this, stmt); |
| 773 increment_loop_depth(); | 775 increment_loop_depth(); |
| 774 | 776 |
| 775 // Get the object to enumerate over. Both SpiderMonkey and JSC | 777 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 776 // ignore null and undefined in contrast to the specification; see | 778 // ignore null and undefined in contrast to the specification; see |
| 777 // ECMA-262 section 12.6.4. | 779 // ECMA-262 section 12.6.4. |
| 778 VisitForAccumulatorValue(stmt->enumerable()); | 780 VisitForAccumulatorValue(stmt->enumerable()); |
| 779 __ cmp(eax, FACTORY->undefined_value()); | 781 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 780 __ j(equal, &exit); | 782 __ j(equal, &exit); |
| 781 __ cmp(eax, FACTORY->null_value()); | 783 __ cmp(eax, isolate()->factory()->null_value()); |
| 782 __ j(equal, &exit); | 784 __ j(equal, &exit); |
| 783 | 785 |
| 784 // Convert the object to a JS object. | 786 // Convert the object to a JS object. |
| 785 NearLabel convert, done_convert; | 787 NearLabel convert, done_convert; |
| 786 __ test(eax, Immediate(kSmiTagMask)); | 788 __ test(eax, Immediate(kSmiTagMask)); |
| 787 __ j(zero, &convert); | 789 __ j(zero, &convert); |
| 788 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 790 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 789 __ j(above_equal, &done_convert); | 791 __ j(above_equal, &done_convert); |
| 790 __ bind(&convert); | 792 __ bind(&convert); |
| 791 __ push(eax); | 793 __ push(eax); |
| 792 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 794 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 793 __ bind(&done_convert); | 795 __ bind(&done_convert); |
| 794 __ push(eax); | 796 __ push(eax); |
| 795 | 797 |
| 796 // Check cache validity in generated code. This is a fast case for | 798 // Check cache validity in generated code. This is a fast case for |
| 797 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 799 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 798 // guarantee cache validity, call the runtime system to check cache | 800 // guarantee cache validity, call the runtime system to check cache |
| 799 // validity or get the property names in a fixed array. | 801 // validity or get the property names in a fixed array. |
| 800 Label next, call_runtime; | 802 Label next, call_runtime; |
| 801 __ mov(ecx, eax); | 803 __ mov(ecx, eax); |
| 802 __ bind(&next); | 804 __ bind(&next); |
| 803 | 805 |
| 804 // Check that there are no elements. Register ecx contains the | 806 // Check that there are no elements. Register ecx contains the |
| 805 // current JS object we've reached through the prototype chain. | 807 // current JS object we've reached through the prototype chain. |
| 806 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset), | 808 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset), |
| 807 FACTORY->empty_fixed_array()); | 809 isolate()->factory()->empty_fixed_array()); |
| 808 __ j(not_equal, &call_runtime); | 810 __ j(not_equal, &call_runtime); |
| 809 | 811 |
| 810 // Check that instance descriptors are not empty so that we can | 812 // Check that instance descriptors are not empty so that we can |
| 811 // check for an enum cache. Leave the map in ebx for the subsequent | 813 // check for an enum cache. Leave the map in ebx for the subsequent |
| 812 // prototype load. | 814 // prototype load. |
| 813 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | 815 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 814 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); | 816 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); |
| 815 __ cmp(edx, FACTORY->empty_descriptor_array()); | 817 __ cmp(edx, isolate()->factory()->empty_descriptor_array()); |
| 816 __ j(equal, &call_runtime); | 818 __ j(equal, &call_runtime); |
| 817 | 819 |
| 818 // Check that there in an enum cache in the non-empty instance | 820 // Check that there in an enum cache in the non-empty instance |
| 819 // descriptors (edx). This is the case if the next enumeration | 821 // descriptors (edx). This is the case if the next enumeration |
| 820 // index field does not contain a smi. | 822 // index field does not contain a smi. |
| 821 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 823 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 822 __ test(edx, Immediate(kSmiTagMask)); | 824 __ test(edx, Immediate(kSmiTagMask)); |
| 823 __ j(zero, &call_runtime); | 825 __ j(zero, &call_runtime); |
| 824 | 826 |
| 825 // For all objects but the receiver, check that the cache is empty. | 827 // For all objects but the receiver, check that the cache is empty. |
| 826 NearLabel check_prototype; | 828 NearLabel check_prototype; |
| 827 __ cmp(ecx, Operand(eax)); | 829 __ cmp(ecx, Operand(eax)); |
| 828 __ j(equal, &check_prototype); | 830 __ j(equal, &check_prototype); |
| 829 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 831 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 830 __ cmp(edx, FACTORY->empty_fixed_array()); | 832 __ cmp(edx, isolate()->factory()->empty_fixed_array()); |
| 831 __ j(not_equal, &call_runtime); | 833 __ j(not_equal, &call_runtime); |
| 832 | 834 |
| 833 // Load the prototype from the map and loop if non-null. | 835 // Load the prototype from the map and loop if non-null. |
| 834 __ bind(&check_prototype); | 836 __ bind(&check_prototype); |
| 835 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 837 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
| 836 __ cmp(ecx, FACTORY->null_value()); | 838 __ cmp(ecx, isolate()->factory()->null_value()); |
| 837 __ j(not_equal, &next); | 839 __ j(not_equal, &next); |
| 838 | 840 |
| 839 // The enum cache is valid. Load the map of the object being | 841 // The enum cache is valid. Load the map of the object being |
| 840 // iterated over and use the cache for the iteration. | 842 // iterated over and use the cache for the iteration. |
| 841 NearLabel use_cache; | 843 NearLabel use_cache; |
| 842 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 844 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 843 __ jmp(&use_cache); | 845 __ jmp(&use_cache); |
| 844 | 846 |
| 845 // Get the set of properties to enumerate. | 847 // Get the set of properties to enumerate. |
| 846 __ bind(&call_runtime); | 848 __ bind(&call_runtime); |
| 847 __ push(eax); // Duplicate the enumerable object on the stack. | 849 __ push(eax); // Duplicate the enumerable object on the stack. |
| 848 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 850 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 849 | 851 |
| 850 // If we got a map from the runtime call, we can do a fast | 852 // If we got a map from the runtime call, we can do a fast |
| 851 // modification check. Otherwise, we got a fixed array, and we have | 853 // modification check. Otherwise, we got a fixed array, and we have |
| 852 // to do a slow check. | 854 // to do a slow check. |
| 853 NearLabel fixed_array; | 855 NearLabel fixed_array; |
| 854 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), FACTORY->meta_map()); | 856 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 857 isolate()->factory()->meta_map()); |
| 855 __ j(not_equal, &fixed_array); | 858 __ j(not_equal, &fixed_array); |
| 856 | 859 |
| 857 // We got a map in register eax. Get the enumeration cache from it. | 860 // We got a map in register eax. Get the enumeration cache from it. |
| 858 __ bind(&use_cache); | 861 __ bind(&use_cache); |
| 859 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); | 862 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); |
| 860 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 863 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 861 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 864 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 862 | 865 |
| 863 // Setup the four remaining stack slots. | 866 // Setup the four remaining stack slots. |
| 864 __ push(eax); // Map. | 867 __ push(eax); // Map. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 948 scope()->is_function_scope() && | 951 scope()->is_function_scope() && |
| 949 info->num_literals() == 0 && | 952 info->num_literals() == 0 && |
| 950 !pretenure) { | 953 !pretenure) { |
| 951 FastNewClosureStub stub; | 954 FastNewClosureStub stub; |
| 952 __ push(Immediate(info)); | 955 __ push(Immediate(info)); |
| 953 __ CallStub(&stub); | 956 __ CallStub(&stub); |
| 954 } else { | 957 } else { |
| 955 __ push(esi); | 958 __ push(esi); |
| 956 __ push(Immediate(info)); | 959 __ push(Immediate(info)); |
| 957 __ push(Immediate(pretenure | 960 __ push(Immediate(pretenure |
| 958 ? FACTORY->true_value() | 961 ? isolate()->factory()->true_value() |
| 959 : FACTORY->false_value())); | 962 : isolate()->factory()->false_value())); |
| 960 __ CallRuntime(Runtime::kNewClosure, 3); | 963 __ CallRuntime(Runtime::kNewClosure, 3); |
| 961 } | 964 } |
| 962 context()->Plug(eax); | 965 context()->Plug(eax); |
| 963 } | 966 } |
| 964 | 967 |
| 965 | 968 |
| 966 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 969 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 967 Comment cmnt(masm_, "[ VariableProxy"); | 970 Comment cmnt(masm_, "[ VariableProxy"); |
| 968 EmitVariableLoad(expr->var()); | 971 EmitVariableLoad(expr->var()); |
| 969 } | 972 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 if (s != NULL && s->is_eval_scope()) { | 1004 if (s != NULL && s->is_eval_scope()) { |
| 1002 // Loop up the context chain. There is no frame effect so it is | 1005 // Loop up the context chain. There is no frame effect so it is |
| 1003 // safe to use raw labels here. | 1006 // safe to use raw labels here. |
| 1004 NearLabel next, fast; | 1007 NearLabel next, fast; |
| 1005 if (!context.is(temp)) { | 1008 if (!context.is(temp)) { |
| 1006 __ mov(temp, context); | 1009 __ mov(temp, context); |
| 1007 } | 1010 } |
| 1008 __ bind(&next); | 1011 __ bind(&next); |
| 1009 // Terminate at global context. | 1012 // Terminate at global context. |
| 1010 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), | 1013 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), |
| 1011 Immediate(FACTORY->global_context_map())); | 1014 Immediate(isolate()->factory()->global_context_map())); |
| 1012 __ j(equal, &fast); | 1015 __ j(equal, &fast); |
| 1013 // Check that extension is NULL. | 1016 // Check that extension is NULL. |
| 1014 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); | 1017 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 1015 __ j(not_equal, slow); | 1018 __ j(not_equal, slow); |
| 1016 // Load next context in chain. | 1019 // Load next context in chain. |
| 1017 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); | 1020 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); |
| 1018 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1021 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 1019 __ jmp(&next); | 1022 __ jmp(&next); |
| 1020 __ bind(&fast); | 1023 __ bind(&fast); |
| 1021 } | 1024 } |
| 1022 | 1025 |
| 1023 // All extension objects were empty and it is safe to use a global | 1026 // All extension objects were empty and it is safe to use a global |
| 1024 // load IC call. | 1027 // load IC call. |
| 1025 __ mov(eax, GlobalObjectOperand()); | 1028 __ mov(eax, GlobalObjectOperand()); |
| 1026 __ mov(ecx, slot->var()->name()); | 1029 __ mov(ecx, slot->var()->name()); |
| 1027 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1030 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1028 Builtins::LoadIC_Initialize)); | 1031 Builtins::LoadIC_Initialize)); |
| 1029 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1032 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 1030 ? RelocInfo::CODE_TARGET | 1033 ? RelocInfo::CODE_TARGET |
| 1031 : RelocInfo::CODE_TARGET_CONTEXT; | 1034 : RelocInfo::CODE_TARGET_CONTEXT; |
| 1032 EmitCallIC(ic, mode); | 1035 EmitCallIC(ic, mode); |
| 1033 } | 1036 } |
| 1034 | 1037 |
| 1035 | 1038 |
| 1036 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( | 1039 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 1037 Slot* slot, | 1040 Slot* slot, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); | 1079 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 1077 __ jmp(done); | 1080 __ jmp(done); |
| 1078 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 1081 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 1079 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); | 1082 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); |
| 1080 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | 1083 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 1081 if (potential_slot != NULL) { | 1084 if (potential_slot != NULL) { |
| 1082 // Generate fast case for locals that rewrite to slots. | 1085 // Generate fast case for locals that rewrite to slots. |
| 1083 __ mov(eax, | 1086 __ mov(eax, |
| 1084 ContextSlotOperandCheckExtensions(potential_slot, slow)); | 1087 ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1085 if (potential_slot->var()->mode() == Variable::CONST) { | 1088 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1086 __ cmp(eax, FACTORY->the_hole_value()); | 1089 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1087 __ j(not_equal, done); | 1090 __ j(not_equal, done); |
| 1088 __ mov(eax, FACTORY->undefined_value()); | 1091 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1089 } | 1092 } |
| 1090 __ jmp(done); | 1093 __ jmp(done); |
| 1091 } else if (rewrite != NULL) { | 1094 } else if (rewrite != NULL) { |
| 1092 // Generate fast case for calls of an argument function. | 1095 // Generate fast case for calls of an argument function. |
| 1093 Property* property = rewrite->AsProperty(); | 1096 Property* property = rewrite->AsProperty(); |
| 1094 if (property != NULL) { | 1097 if (property != NULL) { |
| 1095 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1098 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1096 Literal* key_literal = property->key()->AsLiteral(); | 1099 Literal* key_literal = property->key()->AsLiteral(); |
| 1097 if (obj_proxy != NULL && | 1100 if (obj_proxy != NULL && |
| 1098 key_literal != NULL && | 1101 key_literal != NULL && |
| 1099 obj_proxy->IsArguments() && | 1102 obj_proxy->IsArguments() && |
| 1100 key_literal->handle()->IsSmi()) { | 1103 key_literal->handle()->IsSmi()) { |
| 1101 // Load arguments object if there are no eval-introduced | 1104 // Load arguments object if there are no eval-introduced |
| 1102 // variables. Then load the argument from the arguments | 1105 // variables. Then load the argument from the arguments |
| 1103 // object using keyed load. | 1106 // object using keyed load. |
| 1104 __ mov(edx, | 1107 __ mov(edx, |
| 1105 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | 1108 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), |
| 1106 slow)); | 1109 slow)); |
| 1107 __ mov(eax, Immediate(key_literal->handle())); | 1110 __ mov(eax, Immediate(key_literal->handle())); |
| 1108 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1111 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1109 Builtins::KeyedLoadIC_Initialize)); | 1112 Builtins::KeyedLoadIC_Initialize)); |
| 1110 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1113 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1111 __ jmp(done); | 1114 __ jmp(done); |
| 1112 } | 1115 } |
| 1113 } | 1116 } |
| 1114 } | 1117 } |
| 1115 } | 1118 } |
| 1116 } | 1119 } |
| 1117 | 1120 |
| 1118 | 1121 |
| 1119 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1122 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1120 // Four cases: non-this global variables, lookup slots, all other | 1123 // Four cases: non-this global variables, lookup slots, all other |
| 1121 // types of slots, and parameters that rewrite to explicit property | 1124 // types of slots, and parameters that rewrite to explicit property |
| 1122 // accesses on the arguments object. | 1125 // accesses on the arguments object. |
| 1123 Slot* slot = var->AsSlot(); | 1126 Slot* slot = var->AsSlot(); |
| 1124 Property* property = var->AsProperty(); | 1127 Property* property = var->AsProperty(); |
| 1125 | 1128 |
| 1126 if (var->is_global() && !var->is_this()) { | 1129 if (var->is_global() && !var->is_this()) { |
| 1127 Comment cmnt(masm_, "Global variable"); | 1130 Comment cmnt(masm_, "Global variable"); |
| 1128 // Use inline caching. Variable name is passed in ecx and the global | 1131 // Use inline caching. Variable name is passed in ecx and the global |
| 1129 // object on the stack. | 1132 // object on the stack. |
| 1130 __ mov(eax, GlobalObjectOperand()); | 1133 __ mov(eax, GlobalObjectOperand()); |
| 1131 __ mov(ecx, var->name()); | 1134 __ mov(ecx, var->name()); |
| 1132 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1135 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1133 Builtins::LoadIC_Initialize)); | 1136 Builtins::LoadIC_Initialize)); |
| 1134 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1137 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1135 context()->Plug(eax); | 1138 context()->Plug(eax); |
| 1136 | 1139 |
| 1137 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1140 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1138 Label done, slow; | 1141 Label done, slow; |
| 1139 | 1142 |
| 1140 // Generate code for loading from variables potentially shadowed | 1143 // Generate code for loading from variables potentially shadowed |
| 1141 // by eval-introduced variables. | 1144 // by eval-introduced variables. |
| 1142 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1145 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1153 } else if (slot != NULL) { | 1156 } else if (slot != NULL) { |
| 1154 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1157 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1155 ? "Context slot" | 1158 ? "Context slot" |
| 1156 : "Stack slot"); | 1159 : "Stack slot"); |
| 1157 if (var->mode() == Variable::CONST) { | 1160 if (var->mode() == Variable::CONST) { |
| 1158 // Constants may be the hole value if they have not been initialized. | 1161 // Constants may be the hole value if they have not been initialized. |
| 1159 // Unhole them. | 1162 // Unhole them. |
| 1160 NearLabel done; | 1163 NearLabel done; |
| 1161 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1164 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1162 __ mov(eax, slot_operand); | 1165 __ mov(eax, slot_operand); |
| 1163 __ cmp(eax, FACTORY->the_hole_value()); | 1166 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1164 __ j(not_equal, &done); | 1167 __ j(not_equal, &done); |
| 1165 __ mov(eax, FACTORY->undefined_value()); | 1168 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1166 __ bind(&done); | 1169 __ bind(&done); |
| 1167 context()->Plug(eax); | 1170 context()->Plug(eax); |
| 1168 } else { | 1171 } else { |
| 1169 context()->Plug(slot); | 1172 context()->Plug(slot); |
| 1170 } | 1173 } |
| 1171 | 1174 |
| 1172 } else { | 1175 } else { |
| 1173 Comment cmnt(masm_, "Rewritten parameter"); | 1176 Comment cmnt(masm_, "Rewritten parameter"); |
| 1174 ASSERT_NOT_NULL(property); | 1177 ASSERT_NOT_NULL(property); |
| 1175 // Rewritten parameter accesses are of the form "slot[literal]". | 1178 // Rewritten parameter accesses are of the form "slot[literal]". |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1186 | 1189 |
| 1187 // Assert that the key is a smi. | 1190 // Assert that the key is a smi. |
| 1188 Literal* key_literal = property->key()->AsLiteral(); | 1191 Literal* key_literal = property->key()->AsLiteral(); |
| 1189 ASSERT_NOT_NULL(key_literal); | 1192 ASSERT_NOT_NULL(key_literal); |
| 1190 ASSERT(key_literal->handle()->IsSmi()); | 1193 ASSERT(key_literal->handle()->IsSmi()); |
| 1191 | 1194 |
| 1192 // Load the key. | 1195 // Load the key. |
| 1193 __ mov(eax, Immediate(key_literal->handle())); | 1196 __ mov(eax, Immediate(key_literal->handle())); |
| 1194 | 1197 |
| 1195 // Do a keyed property load. | 1198 // Do a keyed property load. |
| 1196 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1199 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1197 Builtins::KeyedLoadIC_Initialize)); | 1200 Builtins::KeyedLoadIC_Initialize)); |
| 1198 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1201 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1199 | 1202 |
| 1200 // Drop key and object left on the stack by IC. | 1203 // Drop key and object left on the stack by IC. |
| 1201 context()->Plug(eax); | 1204 context()->Plug(eax); |
| 1202 } | 1205 } |
| 1203 } | 1206 } |
| 1204 | 1207 |
| 1205 | 1208 |
| 1206 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1209 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1207 Comment cmnt(masm_, "[ RegExpLiteral"); | 1210 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1208 NearLabel materialized; | 1211 NearLabel materialized; |
| 1209 // Registers will be used as follows: | 1212 // Registers will be used as follows: |
| 1210 // edi = JS function. | 1213 // edi = JS function. |
| 1211 // ecx = literals array. | 1214 // ecx = literals array. |
| 1212 // ebx = regexp literal. | 1215 // ebx = regexp literal. |
| 1213 // eax = regexp literal clone. | 1216 // eax = regexp literal clone. |
| 1214 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1217 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1215 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 1218 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| 1216 int literal_offset = | 1219 int literal_offset = |
| 1217 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 1220 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 1218 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 1221 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| 1219 __ cmp(ebx, FACTORY->undefined_value()); | 1222 __ cmp(ebx, isolate()->factory()->undefined_value()); |
| 1220 __ j(not_equal, &materialized); | 1223 __ j(not_equal, &materialized); |
| 1221 | 1224 |
| 1222 // Create regexp literal using runtime function | 1225 // Create regexp literal using runtime function |
| 1223 // Result will be in eax. | 1226 // Result will be in eax. |
| 1224 __ push(ecx); | 1227 __ push(ecx); |
| 1225 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 1228 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 1226 __ push(Immediate(expr->pattern())); | 1229 __ push(Immediate(expr->pattern())); |
| 1227 __ push(Immediate(expr->flags())); | 1230 __ push(Immediate(expr->flags())); |
| 1228 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 1231 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 1229 __ mov(ebx, eax); | 1232 __ mov(ebx, eax); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 switch (property->kind()) { | 1295 switch (property->kind()) { |
| 1293 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1296 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1294 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1297 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1295 // Fall through. | 1298 // Fall through. |
| 1296 case ObjectLiteral::Property::COMPUTED: | 1299 case ObjectLiteral::Property::COMPUTED: |
| 1297 if (key->handle()->IsSymbol()) { | 1300 if (key->handle()->IsSymbol()) { |
| 1298 if (property->emit_store()) { | 1301 if (property->emit_store()) { |
| 1299 VisitForAccumulatorValue(value); | 1302 VisitForAccumulatorValue(value); |
| 1300 __ mov(ecx, Immediate(key->handle())); | 1303 __ mov(ecx, Immediate(key->handle())); |
| 1301 __ mov(edx, Operand(esp, 0)); | 1304 __ mov(edx, Operand(esp, 0)); |
| 1302 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1305 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1303 Builtins::StoreIC_Initialize)); | 1306 Builtins::StoreIC_Initialize)); |
| 1304 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1307 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1305 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1308 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1306 } else { | 1309 } else { |
| 1307 VisitForEffect(value); | 1310 VisitForEffect(value); |
| 1308 } | 1311 } |
| 1309 break; | 1312 break; |
| 1310 } | 1313 } |
| 1311 // Fall through. | 1314 // Fall through. |
| 1312 case ObjectLiteral::Property::PROTOTYPE: | 1315 case ObjectLiteral::Property::PROTOTYPE: |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1347 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 1345 Comment cmnt(masm_, "[ ArrayLiteral"); | 1348 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 1346 | 1349 |
| 1347 ZoneList<Expression*>* subexprs = expr->values(); | 1350 ZoneList<Expression*>* subexprs = expr->values(); |
| 1348 int length = subexprs->length(); | 1351 int length = subexprs->length(); |
| 1349 | 1352 |
| 1350 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1353 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1351 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); | 1354 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
| 1352 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 1355 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 1353 __ push(Immediate(expr->constant_elements())); | 1356 __ push(Immediate(expr->constant_elements())); |
| 1354 if (expr->constant_elements()->map() == HEAP->fixed_cow_array_map()) { | 1357 if (expr->constant_elements()->map() == |
| 1358 isolate()->heap()->fixed_cow_array_map()) { |
| 1355 ASSERT(expr->depth() == 1); | 1359 ASSERT(expr->depth() == 1); |
| 1356 FastCloneShallowArrayStub stub( | 1360 FastCloneShallowArrayStub stub( |
| 1357 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); | 1361 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); |
| 1358 __ CallStub(&stub); | 1362 __ CallStub(&stub); |
| 1359 __ IncrementCounter(COUNTERS->cow_arrays_created_stub(), 1); | 1363 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1); |
| 1360 } else if (expr->depth() > 1) { | 1364 } else if (expr->depth() > 1) { |
| 1361 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); | 1365 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 1362 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 1366 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 1363 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 1367 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
| 1364 } else { | 1368 } else { |
| 1365 FastCloneShallowArrayStub stub( | 1369 FastCloneShallowArrayStub stub( |
| 1366 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); | 1370 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); |
| 1367 __ CallStub(&stub); | 1371 __ CallStub(&stub); |
| 1368 } | 1372 } |
| 1369 | 1373 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1535 EmitKeyedPropertyAssignment(expr); | 1539 EmitKeyedPropertyAssignment(expr); |
| 1536 break; | 1540 break; |
| 1537 } | 1541 } |
| 1538 } | 1542 } |
| 1539 | 1543 |
| 1540 | 1544 |
| 1541 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1545 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 1542 SetSourcePosition(prop->position()); | 1546 SetSourcePosition(prop->position()); |
| 1543 Literal* key = prop->key()->AsLiteral(); | 1547 Literal* key = prop->key()->AsLiteral(); |
| 1544 __ mov(ecx, Immediate(key->handle())); | 1548 __ mov(ecx, Immediate(key->handle())); |
| 1545 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1549 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1546 Builtins::LoadIC_Initialize)); | 1550 Builtins::LoadIC_Initialize)); |
| 1547 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1551 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1548 } | 1552 } |
| 1549 | 1553 |
| 1550 | 1554 |
| 1551 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1555 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1552 SetSourcePosition(prop->position()); | 1556 SetSourcePosition(prop->position()); |
| 1553 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1557 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1554 Builtins::KeyedLoadIC_Initialize)); | 1558 Builtins::KeyedLoadIC_Initialize)); |
| 1555 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1559 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1556 } | 1560 } |
| 1557 | 1561 |
| 1558 | 1562 |
| 1559 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, | 1563 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, |
| 1560 OverwriteMode mode, | 1564 OverwriteMode mode, |
| 1561 bool left_is_constant_smi, | 1565 bool left_is_constant_smi, |
| 1562 Smi* value) { | 1566 Smi* value) { |
| 1563 NearLabel call_stub; | 1567 NearLabel call_stub; |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1882 EffectContext context(this); | 1886 EffectContext context(this); |
| 1883 EmitVariableAssignment(var, Token::ASSIGN); | 1887 EmitVariableAssignment(var, Token::ASSIGN); |
| 1884 break; | 1888 break; |
| 1885 } | 1889 } |
| 1886 case NAMED_PROPERTY: { | 1890 case NAMED_PROPERTY: { |
| 1887 __ push(eax); // Preserve value. | 1891 __ push(eax); // Preserve value. |
| 1888 VisitForAccumulatorValue(prop->obj()); | 1892 VisitForAccumulatorValue(prop->obj()); |
| 1889 __ mov(edx, eax); | 1893 __ mov(edx, eax); |
| 1890 __ pop(eax); // Restore value. | 1894 __ pop(eax); // Restore value. |
| 1891 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1895 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1892 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1896 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1893 Builtins::StoreIC_Initialize)); | 1897 Builtins::StoreIC_Initialize)); |
| 1894 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1898 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1895 break; | 1899 break; |
| 1896 } | 1900 } |
| 1897 case KEYED_PROPERTY: { | 1901 case KEYED_PROPERTY: { |
| 1898 __ push(eax); // Preserve value. | 1902 __ push(eax); // Preserve value. |
| 1899 VisitForStackValue(prop->obj()); | 1903 VisitForStackValue(prop->obj()); |
| 1900 VisitForAccumulatorValue(prop->key()); | 1904 VisitForAccumulatorValue(prop->key()); |
| 1901 __ mov(ecx, eax); | 1905 __ mov(ecx, eax); |
| 1902 __ pop(edx); | 1906 __ pop(edx); |
| 1903 __ pop(eax); // Restore value. | 1907 __ pop(eax); // Restore value. |
| 1904 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1908 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1905 Builtins::KeyedStoreIC_Initialize)); | 1909 Builtins::KeyedStoreIC_Initialize)); |
| 1906 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1910 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1907 break; | 1911 break; |
| 1908 } | 1912 } |
| 1909 } | 1913 } |
| 1910 } | 1914 } |
| 1911 | 1915 |
| 1912 | 1916 |
| 1913 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1917 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1914 Token::Value op) { | 1918 Token::Value op) { |
| 1915 // Left-hand sides that rewrite to explicit property accesses do not reach | 1919 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1916 // here. | 1920 // here. |
| 1917 ASSERT(var != NULL); | 1921 ASSERT(var != NULL); |
| 1918 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1922 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1919 | 1923 |
| 1920 if (var->is_global()) { | 1924 if (var->is_global()) { |
| 1921 ASSERT(!var->is_this()); | 1925 ASSERT(!var->is_this()); |
| 1922 // Assignment to a global variable. Use inline caching for the | 1926 // Assignment to a global variable. Use inline caching for the |
| 1923 // assignment. Right-hand-side value is passed in eax, variable name in | 1927 // assignment. Right-hand-side value is passed in eax, variable name in |
| 1924 // ecx, and the global object on the stack. | 1928 // ecx, and the global object on the stack. |
| 1925 __ mov(ecx, var->name()); | 1929 __ mov(ecx, var->name()); |
| 1926 __ mov(edx, GlobalObjectOperand()); | 1930 __ mov(edx, GlobalObjectOperand()); |
| 1927 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 1931 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1928 Builtins::StoreIC_Initialize)); | 1932 Builtins::StoreIC_Initialize)); |
| 1929 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1933 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1930 | 1934 |
| 1931 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { | 1935 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { |
| 1932 // Perform the assignment for non-const variables and for initialization | 1936 // Perform the assignment for non-const variables and for initialization |
| 1933 // of const variables. Const assignments are simply skipped. | 1937 // of const variables. Const assignments are simply skipped. |
| 1934 Label done; | 1938 Label done; |
| 1935 Slot* slot = var->AsSlot(); | 1939 Slot* slot = var->AsSlot(); |
| 1936 switch (slot->type()) { | 1940 switch (slot->type()) { |
| 1937 case Slot::PARAMETER: | 1941 case Slot::PARAMETER: |
| 1938 case Slot::LOCAL: | 1942 case Slot::LOCAL: |
| 1939 if (op == Token::INIT_CONST) { | 1943 if (op == Token::INIT_CONST) { |
| 1940 // Detect const reinitialization by checking for the hole value. | 1944 // Detect const reinitialization by checking for the hole value. |
| 1941 __ mov(edx, Operand(ebp, SlotOffset(slot))); | 1945 __ mov(edx, Operand(ebp, SlotOffset(slot))); |
| 1942 __ cmp(edx, FACTORY->the_hole_value()); | 1946 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1943 __ j(not_equal, &done); | 1947 __ j(not_equal, &done); |
| 1944 } | 1948 } |
| 1945 // Perform the assignment. | 1949 // Perform the assignment. |
| 1946 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 1950 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 1947 break; | 1951 break; |
| 1948 | 1952 |
| 1949 case Slot::CONTEXT: { | 1953 case Slot::CONTEXT: { |
| 1950 MemOperand target = EmitSlotSearch(slot, ecx); | 1954 MemOperand target = EmitSlotSearch(slot, ecx); |
| 1951 if (op == Token::INIT_CONST) { | 1955 if (op == Token::INIT_CONST) { |
| 1952 // Detect const reinitialization by checking for the hole value. | 1956 // Detect const reinitialization by checking for the hole value. |
| 1953 __ mov(edx, target); | 1957 __ mov(edx, target); |
| 1954 __ cmp(edx, FACTORY->the_hole_value()); | 1958 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1955 __ j(not_equal, &done); | 1959 __ j(not_equal, &done); |
| 1956 } | 1960 } |
| 1957 // Perform the assignment and issue the write barrier. | 1961 // Perform the assignment and issue the write barrier. |
| 1958 __ mov(target, eax); | 1962 __ mov(target, eax); |
| 1959 // The value of the assignment is in eax. RecordWrite clobbers its | 1963 // The value of the assignment is in eax. RecordWrite clobbers its |
| 1960 // register arguments. | 1964 // register arguments. |
| 1961 __ mov(edx, eax); | 1965 __ mov(edx, eax); |
| 1962 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 1966 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 1963 __ RecordWrite(ecx, offset, edx, ebx); | 1967 __ RecordWrite(ecx, offset, edx, ebx); |
| 1964 break; | 1968 break; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2002 } | 2006 } |
| 2003 | 2007 |
| 2004 // Record source code position before IC call. | 2008 // Record source code position before IC call. |
| 2005 SetSourcePosition(expr->position()); | 2009 SetSourcePosition(expr->position()); |
| 2006 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 2010 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 2007 if (expr->ends_initialization_block()) { | 2011 if (expr->ends_initialization_block()) { |
| 2008 __ mov(edx, Operand(esp, 0)); | 2012 __ mov(edx, Operand(esp, 0)); |
| 2009 } else { | 2013 } else { |
| 2010 __ pop(edx); | 2014 __ pop(edx); |
| 2011 } | 2015 } |
| 2012 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 2016 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2013 Builtins::StoreIC_Initialize)); | 2017 Builtins::StoreIC_Initialize)); |
| 2014 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2018 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2015 | 2019 |
| 2016 // If the assignment ends an initialization block, revert to fast case. | 2020 // If the assignment ends an initialization block, revert to fast case. |
| 2017 if (expr->ends_initialization_block()) { | 2021 if (expr->ends_initialization_block()) { |
| 2018 __ push(eax); // Result of assignment, saved even if not needed. | 2022 __ push(eax); // Result of assignment, saved even if not needed. |
| 2019 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 2023 __ push(Operand(esp, kPointerSize)); // Receiver is under value. |
| 2020 __ CallRuntime(Runtime::kToFastProperties, 1); | 2024 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2021 __ pop(eax); | 2025 __ pop(eax); |
| 2022 context()->DropAndPlug(1, eax); | 2026 context()->DropAndPlug(1, eax); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2041 } | 2045 } |
| 2042 | 2046 |
| 2043 __ pop(ecx); | 2047 __ pop(ecx); |
| 2044 if (expr->ends_initialization_block()) { | 2048 if (expr->ends_initialization_block()) { |
| 2045 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. | 2049 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. |
| 2046 } else { | 2050 } else { |
| 2047 __ pop(edx); | 2051 __ pop(edx); |
| 2048 } | 2052 } |
| 2049 // Record source code position before IC call. | 2053 // Record source code position before IC call. |
| 2050 SetSourcePosition(expr->position()); | 2054 SetSourcePosition(expr->position()); |
| 2051 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 2055 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2052 Builtins::KeyedStoreIC_Initialize)); | 2056 Builtins::KeyedStoreIC_Initialize)); |
| 2053 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2057 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2054 | 2058 |
| 2055 // If the assignment ends an initialization block, revert to fast case. | 2059 // If the assignment ends an initialization block, revert to fast case. |
| 2056 if (expr->ends_initialization_block()) { | 2060 if (expr->ends_initialization_block()) { |
| 2057 __ pop(edx); | 2061 __ pop(edx); |
| 2058 __ push(eax); // Result of assignment, saved even if not needed. | 2062 __ push(eax); // Result of assignment, saved even if not needed. |
| 2059 __ push(edx); | 2063 __ push(edx); |
| 2060 __ CallRuntime(Runtime::kToFastProperties, 1); | 2064 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2061 __ pop(eax); | 2065 __ pop(eax); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2091 int arg_count = args->length(); | 2095 int arg_count = args->length(); |
| 2092 { PreservePositionScope scope(masm()->positions_recorder()); | 2096 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2093 for (int i = 0; i < arg_count; i++) { | 2097 for (int i = 0; i < arg_count; i++) { |
| 2094 VisitForStackValue(args->at(i)); | 2098 VisitForStackValue(args->at(i)); |
| 2095 } | 2099 } |
| 2096 __ Set(ecx, Immediate(name)); | 2100 __ Set(ecx, Immediate(name)); |
| 2097 } | 2101 } |
| 2098 // Record source position of the IC call. | 2102 // Record source position of the IC call. |
| 2099 SetSourcePosition(expr->position()); | 2103 SetSourcePosition(expr->position()); |
| 2100 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2104 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2101 Handle<Code> ic = ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, | 2105 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( |
| 2102 in_loop); | 2106 arg_count, in_loop); |
| 2103 EmitCallIC(ic, mode); | 2107 EmitCallIC(ic, mode); |
| 2104 RecordJSReturnSite(expr); | 2108 RecordJSReturnSite(expr); |
| 2105 // Restore context register. | 2109 // Restore context register. |
| 2106 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2110 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2107 context()->Plug(eax); | 2111 context()->Plug(eax); |
| 2108 } | 2112 } |
| 2109 | 2113 |
| 2110 | 2114 |
| 2111 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2115 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2112 Expression* key, | 2116 Expression* key, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2124 ZoneList<Expression*>* args = expr->arguments(); | 2128 ZoneList<Expression*>* args = expr->arguments(); |
| 2125 int arg_count = args->length(); | 2129 int arg_count = args->length(); |
| 2126 { PreservePositionScope scope(masm()->positions_recorder()); | 2130 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2127 for (int i = 0; i < arg_count; i++) { | 2131 for (int i = 0; i < arg_count; i++) { |
| 2128 VisitForStackValue(args->at(i)); | 2132 VisitForStackValue(args->at(i)); |
| 2129 } | 2133 } |
| 2130 } | 2134 } |
| 2131 // Record source position of the IC call. | 2135 // Record source position of the IC call. |
| 2132 SetSourcePosition(expr->position()); | 2136 SetSourcePosition(expr->position()); |
| 2133 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2137 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2134 Handle<Code> ic = ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, | 2138 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( |
| 2135 in_loop); | 2139 arg_count, in_loop); |
| 2136 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. | 2140 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. |
| 2137 EmitCallIC(ic, mode); | 2141 EmitCallIC(ic, mode); |
| 2138 RecordJSReturnSite(expr); | 2142 RecordJSReturnSite(expr); |
| 2139 // Restore context register. | 2143 // Restore context register. |
| 2140 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2144 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2141 context()->DropAndPlug(1, eax); // Drop the key still on the stack. | 2145 context()->DropAndPlug(1, eax); // Drop the key still on the stack. |
| 2142 } | 2146 } |
| 2143 | 2147 |
| 2144 | 2148 |
| 2145 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2149 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2177 if (var != NULL && var->is_possibly_eval()) { | 2181 if (var != NULL && var->is_possibly_eval()) { |
| 2178 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 2182 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 2179 // resolve the function we need to call and the receiver of the | 2183 // resolve the function we need to call and the receiver of the |
| 2180 // call. Then we call the resolved function using the given | 2184 // call. Then we call the resolved function using the given |
| 2181 // arguments. | 2185 // arguments. |
| 2182 ZoneList<Expression*>* args = expr->arguments(); | 2186 ZoneList<Expression*>* args = expr->arguments(); |
| 2183 int arg_count = args->length(); | 2187 int arg_count = args->length(); |
| 2184 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 2188 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
| 2185 VisitForStackValue(fun); | 2189 VisitForStackValue(fun); |
| 2186 // Reserved receiver slot. | 2190 // Reserved receiver slot. |
| 2187 __ push(Immediate(FACTORY->undefined_value())); | 2191 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2188 | 2192 |
| 2189 // Push the arguments. | 2193 // Push the arguments. |
| 2190 for (int i = 0; i < arg_count; i++) { | 2194 for (int i = 0; i < arg_count; i++) { |
| 2191 VisitForStackValue(args->at(i)); | 2195 VisitForStackValue(args->at(i)); |
| 2192 } | 2196 } |
| 2193 | 2197 |
| 2194 // Push copy of the function - found below the arguments. | 2198 // Push copy of the function - found below the arguments. |
| 2195 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); | 2199 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2196 | 2200 |
| 2197 // Push copy of the first argument or undefined if it doesn't exist. | 2201 // Push copy of the first argument or undefined if it doesn't exist. |
| 2198 if (arg_count > 0) { | 2202 if (arg_count > 0) { |
| 2199 __ push(Operand(esp, arg_count * kPointerSize)); | 2203 __ push(Operand(esp, arg_count * kPointerSize)); |
| 2200 } else { | 2204 } else { |
| 2201 __ push(Immediate(FACTORY->undefined_value())); | 2205 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2202 } | 2206 } |
| 2203 | 2207 |
| 2204 // Push the receiver of the enclosing function and do runtime call. | 2208 // Push the receiver of the enclosing function and do runtime call. |
| 2205 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2209 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 2206 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); | 2210 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); |
| 2207 | 2211 |
| 2208 // The runtime call returns a pair of values in eax (function) and | 2212 // The runtime call returns a pair of values in eax (function) and |
| 2209 // edx (receiver). Touch up the stack with the right values. | 2213 // edx (receiver). Touch up the stack with the right values. |
| 2210 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); | 2214 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
| 2211 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | 2215 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2278 VisitForStackValue(prop->obj()); | 2282 VisitForStackValue(prop->obj()); |
| 2279 } | 2283 } |
| 2280 if (prop->is_synthetic()) { | 2284 if (prop->is_synthetic()) { |
| 2281 { PreservePositionScope scope(masm()->positions_recorder()); | 2285 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2282 VisitForAccumulatorValue(prop->key()); | 2286 VisitForAccumulatorValue(prop->key()); |
| 2283 } | 2287 } |
| 2284 // Record source code position for IC call. | 2288 // Record source code position for IC call. |
| 2285 SetSourcePosition(prop->position()); | 2289 SetSourcePosition(prop->position()); |
| 2286 __ pop(edx); // We do not need to keep the receiver. | 2290 __ pop(edx); // We do not need to keep the receiver. |
| 2287 | 2291 |
| 2288 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 2292 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2289 Builtins::KeyedLoadIC_Initialize)); | 2293 Builtins::KeyedLoadIC_Initialize)); |
| 2290 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2294 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2291 // Push result (function). | 2295 // Push result (function). |
| 2292 __ push(eax); | 2296 __ push(eax); |
| 2293 // Push Global receiver. | 2297 // Push Global receiver. |
| 2294 __ mov(ecx, GlobalObjectOperand()); | 2298 __ mov(ecx, GlobalObjectOperand()); |
| 2295 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | 2299 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); |
| 2296 EmitCallWithStub(expr); | 2300 EmitCallWithStub(expr); |
| 2297 } else { | 2301 } else { |
| 2298 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | 2302 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 2299 } | 2303 } |
| 2300 } | 2304 } |
| 2301 } else { | 2305 } else { |
| 2302 // Call to some other expression. If the expression is an anonymous | 2306 // Call to some other expression. If the expression is an anonymous |
| 2303 // function literal not called in a loop, mark it as one that should | 2307 // function literal not called in a loop, mark it as one that should |
| 2304 // also use the full code generator. | 2308 // also use the full code generator. |
| 2305 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2309 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 2306 if (lit != NULL && | 2310 if (lit != NULL && |
| 2307 lit->name()->Equals(HEAP->empty_string()) && | 2311 lit->name()->Equals(isolate()->heap()->empty_string()) && |
| 2308 loop_depth() == 0) { | 2312 loop_depth() == 0) { |
| 2309 lit->set_try_full_codegen(true); | 2313 lit->set_try_full_codegen(true); |
| 2310 } | 2314 } |
| 2311 { PreservePositionScope scope(masm()->positions_recorder()); | 2315 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2312 VisitForStackValue(fun); | 2316 VisitForStackValue(fun); |
| 2313 } | 2317 } |
| 2314 // Load global receiver object. | 2318 // Load global receiver object. |
| 2315 __ mov(ebx, GlobalObjectOperand()); | 2319 __ mov(ebx, GlobalObjectOperand()); |
| 2316 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 2320 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 2317 // Emit function call. | 2321 // Emit function call. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2344 } | 2348 } |
| 2345 | 2349 |
| 2346 // Call the construct call builtin that handles allocation and | 2350 // Call the construct call builtin that handles allocation and |
| 2347 // constructor invocation. | 2351 // constructor invocation. |
| 2348 SetSourcePosition(expr->position()); | 2352 SetSourcePosition(expr->position()); |
| 2349 | 2353 |
| 2350 // Load function and argument count into edi and eax. | 2354 // Load function and argument count into edi and eax. |
| 2351 __ Set(eax, Immediate(arg_count)); | 2355 __ Set(eax, Immediate(arg_count)); |
| 2352 __ mov(edi, Operand(esp, arg_count * kPointerSize)); | 2356 __ mov(edi, Operand(esp, arg_count * kPointerSize)); |
| 2353 | 2357 |
| 2354 Handle<Code> construct_builtin(Isolate::Current()->builtins()->builtin( | 2358 Handle<Code> construct_builtin(isolate()->builtins()->builtin( |
| 2355 Builtins::JSConstructCall)); | 2359 Builtins::JSConstructCall)); |
| 2356 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 2360 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
| 2357 context()->Plug(eax); | 2361 context()->Plug(eax); |
| 2358 } | 2362 } |
| 2359 | 2363 |
| 2360 | 2364 |
| 2361 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { | 2365 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { |
| 2362 ASSERT(args->length() == 1); | 2366 ASSERT(args->length() == 1); |
| 2363 | 2367 |
| 2364 VisitForAccumulatorValue(args->at(0)); | 2368 VisitForAccumulatorValue(args->at(0)); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2405 | 2409 |
| 2406 Label materialize_true, materialize_false; | 2410 Label materialize_true, materialize_false; |
| 2407 Label* if_true = NULL; | 2411 Label* if_true = NULL; |
| 2408 Label* if_false = NULL; | 2412 Label* if_false = NULL; |
| 2409 Label* fall_through = NULL; | 2413 Label* fall_through = NULL; |
| 2410 context()->PrepareTest(&materialize_true, &materialize_false, | 2414 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2411 &if_true, &if_false, &fall_through); | 2415 &if_true, &if_false, &fall_through); |
| 2412 | 2416 |
| 2413 __ test(eax, Immediate(kSmiTagMask)); | 2417 __ test(eax, Immediate(kSmiTagMask)); |
| 2414 __ j(zero, if_false); | 2418 __ j(zero, if_false); |
| 2415 __ cmp(eax, FACTORY->null_value()); | 2419 __ cmp(eax, isolate()->factory()->null_value()); |
| 2416 __ j(equal, if_true); | 2420 __ j(equal, if_true); |
| 2417 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2421 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2418 // Undetectable objects behave like undefined when tested with typeof. | 2422 // Undetectable objects behave like undefined when tested with typeof. |
| 2419 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); | 2423 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 2420 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 2424 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 2421 __ j(not_zero, if_false); | 2425 __ j(not_zero, if_false); |
| 2422 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 2426 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 2423 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 2427 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 2424 __ j(below, if_false); | 2428 __ j(below, if_false); |
| 2425 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 2429 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2684 __ j(not_equal, &non_function_constructor); | 2688 __ j(not_equal, &non_function_constructor); |
| 2685 | 2689 |
| 2686 // eax now contains the constructor function. Grab the | 2690 // eax now contains the constructor function. Grab the |
| 2687 // instance class name from there. | 2691 // instance class name from there. |
| 2688 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); | 2692 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
| 2689 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); | 2693 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); |
| 2690 __ jmp(&done); | 2694 __ jmp(&done); |
| 2691 | 2695 |
| 2692 // Functions have class 'Function'. | 2696 // Functions have class 'Function'. |
| 2693 __ bind(&function); | 2697 __ bind(&function); |
| 2694 __ mov(eax, FACTORY->function_class_symbol()); | 2698 __ mov(eax, isolate()->factory()->function_class_symbol()); |
| 2695 __ jmp(&done); | 2699 __ jmp(&done); |
| 2696 | 2700 |
| 2697 // Objects with a non-function constructor have class 'Object'. | 2701 // Objects with a non-function constructor have class 'Object'. |
| 2698 __ bind(&non_function_constructor); | 2702 __ bind(&non_function_constructor); |
| 2699 __ mov(eax, FACTORY->Object_symbol()); | 2703 __ mov(eax, isolate()->factory()->Object_symbol()); |
| 2700 __ jmp(&done); | 2704 __ jmp(&done); |
| 2701 | 2705 |
| 2702 // Non-JS objects have class null. | 2706 // Non-JS objects have class null. |
| 2703 __ bind(&null); | 2707 __ bind(&null); |
| 2704 __ mov(eax, FACTORY->null_value()); | 2708 __ mov(eax, isolate()->factory()->null_value()); |
| 2705 | 2709 |
| 2706 // All done. | 2710 // All done. |
| 2707 __ bind(&done); | 2711 __ bind(&done); |
| 2708 | 2712 |
| 2709 context()->Plug(eax); | 2713 context()->Plug(eax); |
| 2710 } | 2714 } |
| 2711 | 2715 |
| 2712 | 2716 |
| 2713 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { | 2717 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { |
| 2714 // Conditionally generate a log call. | 2718 // Conditionally generate a log call. |
| 2715 // Args: | 2719 // Args: |
| 2716 // 0 (literal string): The type of logging (corresponds to the flags). | 2720 // 0 (literal string): The type of logging (corresponds to the flags). |
| 2717 // This is used to determine whether or not to generate the log call. | 2721 // This is used to determine whether or not to generate the log call. |
| 2718 // 1 (string): Format string. Access the string at argument index 2 | 2722 // 1 (string): Format string. Access the string at argument index 2 |
| 2719 // with '%2s' (see Logger::LogRuntime for all the formats). | 2723 // with '%2s' (see Logger::LogRuntime for all the formats). |
| 2720 // 2 (array): Arguments to the format string. | 2724 // 2 (array): Arguments to the format string. |
| 2721 ASSERT_EQ(args->length(), 3); | 2725 ASSERT_EQ(args->length(), 3); |
| 2722 #ifdef ENABLE_LOGGING_AND_PROFILING | 2726 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2723 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { | 2727 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { |
| 2724 VisitForStackValue(args->at(1)); | 2728 VisitForStackValue(args->at(1)); |
| 2725 VisitForStackValue(args->at(2)); | 2729 VisitForStackValue(args->at(2)); |
| 2726 __ CallRuntime(Runtime::kLog, 2); | 2730 __ CallRuntime(Runtime::kLog, 2); |
| 2727 } | 2731 } |
| 2728 #endif | 2732 #endif |
| 2729 // Finally, we're expected to leave a value on the top of the stack. | 2733 // Finally, we're expected to leave a value on the top of the stack. |
| 2730 __ mov(eax, FACTORY->undefined_value()); | 2734 __ mov(eax, isolate()->factory()->undefined_value()); |
| 2731 context()->Plug(eax); | 2735 context()->Plug(eax); |
| 2732 } | 2736 } |
| 2733 | 2737 |
| 2734 | 2738 |
| 2735 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { | 2739 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { |
| 2736 ASSERT(args->length() == 0); | 2740 ASSERT(args->length() == 0); |
| 2737 | 2741 |
| 2738 Label slow_allocate_heapnumber; | 2742 Label slow_allocate_heapnumber; |
| 2739 Label heapnumber_allocated; | 2743 Label heapnumber_allocated; |
| 2740 | 2744 |
| 2741 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); | 2745 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); |
| 2742 __ jmp(&heapnumber_allocated); | 2746 __ jmp(&heapnumber_allocated); |
| 2743 | 2747 |
| 2744 __ bind(&slow_allocate_heapnumber); | 2748 __ bind(&slow_allocate_heapnumber); |
| 2745 // Allocate a heap number. | 2749 // Allocate a heap number. |
| 2746 __ CallRuntime(Runtime::kNumberAlloc, 0); | 2750 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 2747 __ mov(edi, eax); | 2751 __ mov(edi, eax); |
| 2748 | 2752 |
| 2749 __ bind(&heapnumber_allocated); | 2753 __ bind(&heapnumber_allocated); |
| 2750 | 2754 |
| 2751 __ PrepareCallCFunction(0, ebx); | 2755 __ PrepareCallCFunction(0, ebx); |
| 2752 __ CallCFunction(ExternalReference::random_uint32_function(), 0); | 2756 __ CallCFunction(ExternalReference::random_uint32_function(), 0); |
| 2753 | 2757 |
| 2754 // Convert 32 random bits in eax to 0.(32 random bits) in a double | 2758 // Convert 32 random bits in eax to 0.(32 random bits) in a double |
| 2755 // by computing: | 2759 // by computing: |
| 2756 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 2760 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 2757 // This is implemented on both SSE2 and FPU. | 2761 // This is implemented on both SSE2 and FPU. |
| 2758 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { | 2762 if (isolate()->cpu_features()->IsSupported(SSE2)) { |
| 2759 CpuFeatures::Scope fscope(SSE2); | 2763 CpuFeatures::Scope fscope(SSE2); |
| 2760 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 2764 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 2761 __ movd(xmm1, Operand(ebx)); | 2765 __ movd(xmm1, Operand(ebx)); |
| 2762 __ movd(xmm0, Operand(eax)); | 2766 __ movd(xmm0, Operand(eax)); |
| 2763 __ cvtss2sd(xmm1, xmm1); | 2767 __ cvtss2sd(xmm1, xmm1); |
| 2764 __ pxor(xmm0, xmm1); | 2768 __ pxor(xmm0, xmm1); |
| 2765 __ subsd(xmm0, xmm1); | 2769 __ subsd(xmm0, xmm1); |
| 2766 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); | 2770 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); |
| 2767 } else { | 2771 } else { |
| 2768 // 0x4130000000000000 is 1.0 x 2^20 as a double. | 2772 // 0x4130000000000000 is 1.0 x 2^20 as a double. |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2917 &need_conversion, | 2921 &need_conversion, |
| 2918 &need_conversion, | 2922 &need_conversion, |
| 2919 &index_out_of_range, | 2923 &index_out_of_range, |
| 2920 STRING_INDEX_IS_NUMBER); | 2924 STRING_INDEX_IS_NUMBER); |
| 2921 generator.GenerateFast(masm_); | 2925 generator.GenerateFast(masm_); |
| 2922 __ jmp(&done); | 2926 __ jmp(&done); |
| 2923 | 2927 |
| 2924 __ bind(&index_out_of_range); | 2928 __ bind(&index_out_of_range); |
| 2925 // When the index is out of range, the spec requires us to return | 2929 // When the index is out of range, the spec requires us to return |
| 2926 // NaN. | 2930 // NaN. |
| 2927 __ Set(result, Immediate(FACTORY->nan_value())); | 2931 __ Set(result, Immediate(isolate()->factory()->nan_value())); |
| 2928 __ jmp(&done); | 2932 __ jmp(&done); |
| 2929 | 2933 |
| 2930 __ bind(&need_conversion); | 2934 __ bind(&need_conversion); |
| 2931 // Move the undefined value into the result register, which will | 2935 // Move the undefined value into the result register, which will |
| 2932 // trigger conversion. | 2936 // trigger conversion. |
| 2933 __ Set(result, Immediate(FACTORY->undefined_value())); | 2937 __ Set(result, Immediate(isolate()->factory()->undefined_value())); |
| 2934 __ jmp(&done); | 2938 __ jmp(&done); |
| 2935 | 2939 |
| 2936 NopRuntimeCallHelper call_helper; | 2940 NopRuntimeCallHelper call_helper; |
| 2937 generator.GenerateSlow(masm_, call_helper); | 2941 generator.GenerateSlow(masm_, call_helper); |
| 2938 | 2942 |
| 2939 __ bind(&done); | 2943 __ bind(&done); |
| 2940 context()->Plug(result); | 2944 context()->Plug(result); |
| 2941 } | 2945 } |
| 2942 | 2946 |
| 2943 | 2947 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2966 &need_conversion, | 2970 &need_conversion, |
| 2967 &need_conversion, | 2971 &need_conversion, |
| 2968 &index_out_of_range, | 2972 &index_out_of_range, |
| 2969 STRING_INDEX_IS_NUMBER); | 2973 STRING_INDEX_IS_NUMBER); |
| 2970 generator.GenerateFast(masm_); | 2974 generator.GenerateFast(masm_); |
| 2971 __ jmp(&done); | 2975 __ jmp(&done); |
| 2972 | 2976 |
| 2973 __ bind(&index_out_of_range); | 2977 __ bind(&index_out_of_range); |
| 2974 // When the index is out of range, the spec requires us to return | 2978 // When the index is out of range, the spec requires us to return |
| 2975 // the empty string. | 2979 // the empty string. |
| 2976 __ Set(result, Immediate(FACTORY->empty_string())); | 2980 __ Set(result, Immediate(isolate()->factory()->empty_string())); |
| 2977 __ jmp(&done); | 2981 __ jmp(&done); |
| 2978 | 2982 |
| 2979 __ bind(&need_conversion); | 2983 __ bind(&need_conversion); |
| 2980 // Move smi zero into the result register, which will trigger | 2984 // Move smi zero into the result register, which will trigger |
| 2981 // conversion. | 2985 // conversion. |
| 2982 __ Set(result, Immediate(Smi::FromInt(0))); | 2986 __ Set(result, Immediate(Smi::FromInt(0))); |
| 2983 __ jmp(&done); | 2987 __ jmp(&done); |
| 2984 | 2988 |
| 2985 NopRuntimeCallHelper call_helper; | 2989 NopRuntimeCallHelper call_helper; |
| 2986 generator.GenerateSlow(masm_, call_helper); | 2990 generator.GenerateSlow(masm_, call_helper); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3102 // has no indexed interceptor. | 3106 // has no indexed interceptor. |
| 3103 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp); | 3107 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp); |
| 3104 __ j(below, &slow_case); | 3108 __ j(below, &slow_case); |
| 3105 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), | 3109 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), |
| 3106 KeyedLoadIC::kSlowCaseBitFieldMask); | 3110 KeyedLoadIC::kSlowCaseBitFieldMask); |
| 3107 __ j(not_zero, &slow_case); | 3111 __ j(not_zero, &slow_case); |
| 3108 | 3112 |
| 3109 // Check the object's elements are in fast case and writable. | 3113 // Check the object's elements are in fast case and writable. |
| 3110 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); | 3114 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); |
| 3111 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), | 3115 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), |
| 3112 Immediate(FACTORY->fixed_array_map())); | 3116 Immediate(isolate()->factory()->fixed_array_map())); |
| 3113 __ j(not_equal, &slow_case); | 3117 __ j(not_equal, &slow_case); |
| 3114 | 3118 |
| 3115 // Check that both indices are smis. | 3119 // Check that both indices are smis. |
| 3116 __ mov(index_1, Operand(esp, 1 * kPointerSize)); | 3120 __ mov(index_1, Operand(esp, 1 * kPointerSize)); |
| 3117 __ mov(index_2, Operand(esp, 0)); | 3121 __ mov(index_2, Operand(esp, 0)); |
| 3118 __ mov(temp, index_1); | 3122 __ mov(temp, index_1); |
| 3119 __ or_(temp, Operand(index_2)); | 3123 __ or_(temp, Operand(index_2)); |
| 3120 __ test(temp, Immediate(kSmiTagMask)); | 3124 __ test(temp, Immediate(kSmiTagMask)); |
| 3121 __ j(not_zero, &slow_case); | 3125 __ j(not_zero, &slow_case); |
| 3122 | 3126 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3133 Label new_space; | 3137 Label new_space; |
| 3134 __ InNewSpace(elements, temp, equal, &new_space); | 3138 __ InNewSpace(elements, temp, equal, &new_space); |
| 3135 | 3139 |
| 3136 __ mov(object, elements); | 3140 __ mov(object, elements); |
| 3137 __ RecordWriteHelper(object, index_1, temp); | 3141 __ RecordWriteHelper(object, index_1, temp); |
| 3138 __ RecordWriteHelper(elements, index_2, temp); | 3142 __ RecordWriteHelper(elements, index_2, temp); |
| 3139 | 3143 |
| 3140 __ bind(&new_space); | 3144 __ bind(&new_space); |
| 3141 // We are done. Drop elements from the stack, and return undefined. | 3145 // We are done. Drop elements from the stack, and return undefined. |
| 3142 __ add(Operand(esp), Immediate(3 * kPointerSize)); | 3146 __ add(Operand(esp), Immediate(3 * kPointerSize)); |
| 3143 __ mov(eax, FACTORY->undefined_value()); | 3147 __ mov(eax, isolate()->factory()->undefined_value()); |
| 3144 __ jmp(&done); | 3148 __ jmp(&done); |
| 3145 | 3149 |
| 3146 __ bind(&slow_case); | 3150 __ bind(&slow_case); |
| 3147 __ CallRuntime(Runtime::kSwapElements, 3); | 3151 __ CallRuntime(Runtime::kSwapElements, 3); |
| 3148 | 3152 |
| 3149 __ bind(&done); | 3153 __ bind(&done); |
| 3150 context()->Plug(eax); | 3154 context()->Plug(eax); |
| 3151 } | 3155 } |
| 3152 | 3156 |
| 3153 | 3157 |
| 3154 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { | 3158 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { |
| 3155 ASSERT_EQ(2, args->length()); | 3159 ASSERT_EQ(2, args->length()); |
| 3156 | 3160 |
| 3157 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3161 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 3158 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); | 3162 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
| 3159 | 3163 |
| 3160 Handle<FixedArray> jsfunction_result_caches( | 3164 Handle<FixedArray> jsfunction_result_caches( |
| 3161 Isolate::Current()->global_context()->jsfunction_result_caches()); | 3165 isolate()->global_context()->jsfunction_result_caches()); |
| 3162 if (jsfunction_result_caches->length() <= cache_id) { | 3166 if (jsfunction_result_caches->length() <= cache_id) { |
| 3163 __ Abort("Attempt to use undefined cache."); | 3167 __ Abort("Attempt to use undefined cache."); |
| 3164 __ mov(eax, FACTORY->undefined_value()); | 3168 __ mov(eax, isolate()->factory()->undefined_value()); |
| 3165 context()->Plug(eax); | 3169 context()->Plug(eax); |
| 3166 return; | 3170 return; |
| 3167 } | 3171 } |
| 3168 | 3172 |
| 3169 VisitForAccumulatorValue(args->at(1)); | 3173 VisitForAccumulatorValue(args->at(1)); |
| 3170 | 3174 |
| 3171 Register key = eax; | 3175 Register key = eax; |
| 3172 Register cache = ebx; | 3176 Register cache = ebx; |
| 3173 Register tmp = ecx; | 3177 Register tmp = ecx; |
| 3174 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX)); | 3178 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX)); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3220 __ j(zero, &fail); | 3224 __ j(zero, &fail); |
| 3221 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); | 3225 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
| 3222 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); | 3226 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); |
| 3223 __ j(not_equal, &fail); | 3227 __ j(not_equal, &fail); |
| 3224 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); | 3228 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); |
| 3225 __ j(not_equal, &fail); | 3229 __ j(not_equal, &fail); |
| 3226 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | 3230 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); |
| 3227 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | 3231 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); |
| 3228 __ j(equal, &ok); | 3232 __ j(equal, &ok); |
| 3229 __ bind(&fail); | 3233 __ bind(&fail); |
| 3230 __ mov(eax, Immediate(FACTORY->false_value())); | 3234 __ mov(eax, Immediate(isolate()->factory()->false_value())); |
| 3231 __ jmp(&done); | 3235 __ jmp(&done); |
| 3232 __ bind(&ok); | 3236 __ bind(&ok); |
| 3233 __ mov(eax, Immediate(FACTORY->true_value())); | 3237 __ mov(eax, Immediate(isolate()->factory()->true_value())); |
| 3234 __ bind(&done); | 3238 __ bind(&done); |
| 3235 | 3239 |
| 3236 context()->Plug(eax); | 3240 context()->Plug(eax); |
| 3237 } | 3241 } |
| 3238 | 3242 |
| 3239 | 3243 |
| 3240 void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) { | 3244 void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) { |
| 3241 ASSERT(args->length() == 1); | 3245 ASSERT(args->length() == 1); |
| 3242 | 3246 |
| 3243 VisitForAccumulatorValue(args->at(0)); | 3247 VisitForAccumulatorValue(args->at(0)); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3320 // Check that the array has fast elements. | 3324 // Check that the array has fast elements. |
| 3321 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 3325 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 3322 1 << Map::kHasFastElements); | 3326 1 << Map::kHasFastElements); |
| 3323 __ j(zero, &bailout); | 3327 __ j(zero, &bailout); |
| 3324 | 3328 |
| 3325 // If the array is empty, return the empty string. | 3329 // If the array is empty, return the empty string. |
| 3326 __ mov(scratch, FieldOperand(array, JSArray::kLengthOffset)); | 3330 __ mov(scratch, FieldOperand(array, JSArray::kLengthOffset)); |
| 3327 __ sar(scratch, 1); | 3331 __ sar(scratch, 1); |
| 3328 Label non_trivial; | 3332 Label non_trivial; |
| 3329 __ j(not_zero, &non_trivial); | 3333 __ j(not_zero, &non_trivial); |
| 3330 __ mov(result, FACTORY->empty_string()); | 3334 __ mov(result, isolate()->factory()->empty_string()); |
| 3331 __ jmp(&done); | 3335 __ jmp(&done); |
| 3332 | 3336 |
| 3333 __ bind(&non_trivial); | 3337 __ bind(&non_trivial); |
| 3334 __ mov(array_length, scratch); | 3338 __ mov(array_length, scratch); |
| 3335 | 3339 |
| 3336 __ mov(scratch, FieldOperand(array, JSArray::kElementsOffset)); | 3340 __ mov(scratch, FieldOperand(array, JSArray::kElementsOffset)); |
| 3337 __ mov(elements, scratch); | 3341 __ mov(elements, scratch); |
| 3338 | 3342 |
| 3339 // End of array's live range. | 3343 // End of array's live range. |
| 3340 result_pos = array; | 3344 result_pos = array; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3444 __ j(not_equal, &bailout); | 3448 __ j(not_equal, &bailout); |
| 3445 | 3449 |
| 3446 // Append current to the result. | 3450 // Append current to the result. |
| 3447 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 3451 __ AppendStringToTopOfNewSpace(current_string, current_string_length, |
| 3448 result_pos, scratch, scratch_2, result, | 3452 result_pos, scratch, scratch_2, result, |
| 3449 padding_chars, &bailout); | 3453 padding_chars, &bailout); |
| 3450 __ add(Operand(index), Immediate(1)); | 3454 __ add(Operand(index), Immediate(1)); |
| 3451 __ jmp(&loop); // End while (index < length). | 3455 __ jmp(&loop); // End while (index < length). |
| 3452 | 3456 |
| 3453 __ bind(&bailout); | 3457 __ bind(&bailout); |
| 3454 __ mov(result, FACTORY->undefined_value()); | 3458 __ mov(result, isolate()->factory()->undefined_value()); |
| 3455 __ bind(&done); | 3459 __ bind(&done); |
| 3456 __ mov(eax, result); | 3460 __ mov(eax, result); |
| 3457 // Drop temp values from the stack, and restore context register. | 3461 // Drop temp values from the stack, and restore context register. |
| 3458 __ add(Operand(esp), Immediate(5 * kPointerSize)); | 3462 __ add(Operand(esp), Immediate(5 * kPointerSize)); |
| 3459 | 3463 |
| 3460 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3464 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3461 context()->Plug(eax); | 3465 context()->Plug(eax); |
| 3462 } | 3466 } |
| 3463 | 3467 |
| 3464 | 3468 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3482 // Push the arguments ("left-to-right"). | 3486 // Push the arguments ("left-to-right"). |
| 3483 int arg_count = args->length(); | 3487 int arg_count = args->length(); |
| 3484 for (int i = 0; i < arg_count; i++) { | 3488 for (int i = 0; i < arg_count; i++) { |
| 3485 VisitForStackValue(args->at(i)); | 3489 VisitForStackValue(args->at(i)); |
| 3486 } | 3490 } |
| 3487 | 3491 |
| 3488 if (expr->is_jsruntime()) { | 3492 if (expr->is_jsruntime()) { |
| 3489 // Call the JS runtime function via a call IC. | 3493 // Call the JS runtime function via a call IC. |
| 3490 __ Set(ecx, Immediate(expr->name())); | 3494 __ Set(ecx, Immediate(expr->name())); |
| 3491 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 3495 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 3492 Handle<Code> ic = ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, | 3496 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( |
| 3493 in_loop); | 3497 arg_count, in_loop); |
| 3494 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3498 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3495 // Restore context register. | 3499 // Restore context register. |
| 3496 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3500 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3497 } else { | 3501 } else { |
| 3498 // Call the C runtime function. | 3502 // Call the C runtime function. |
| 3499 __ CallRuntime(expr->function(), arg_count); | 3503 __ CallRuntime(expr->function(), arg_count); |
| 3500 } | 3504 } |
| 3501 context()->Plug(eax); | 3505 context()->Plug(eax); |
| 3502 } | 3506 } |
| 3503 | 3507 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3540 } | 3544 } |
| 3541 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3545 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3542 context()->Plug(eax); | 3546 context()->Plug(eax); |
| 3543 } | 3547 } |
| 3544 break; | 3548 break; |
| 3545 } | 3549 } |
| 3546 | 3550 |
| 3547 case Token::VOID: { | 3551 case Token::VOID: { |
| 3548 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 3552 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 3549 VisitForEffect(expr->expression()); | 3553 VisitForEffect(expr->expression()); |
| 3550 context()->Plug(FACTORY->undefined_value()); | 3554 context()->Plug(isolate()->factory()->undefined_value()); |
| 3551 break; | 3555 break; |
| 3552 } | 3556 } |
| 3553 | 3557 |
| 3554 case Token::NOT: { | 3558 case Token::NOT: { |
| 3555 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3559 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 3556 | 3560 |
| 3557 Label materialize_true, materialize_false; | 3561 Label materialize_true, materialize_false; |
| 3558 Label* if_true = NULL; | 3562 Label* if_true = NULL; |
| 3559 Label* if_false = NULL; | 3563 Label* if_false = NULL; |
| 3560 Label* fall_through = NULL; | 3564 Label* fall_through = NULL; |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3776 } | 3780 } |
| 3777 } else { | 3781 } else { |
| 3778 // Perform the assignment as if via '='. | 3782 // Perform the assignment as if via '='. |
| 3779 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3783 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3780 Token::ASSIGN); | 3784 Token::ASSIGN); |
| 3781 } | 3785 } |
| 3782 break; | 3786 break; |
| 3783 case NAMED_PROPERTY: { | 3787 case NAMED_PROPERTY: { |
| 3784 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 3788 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 3785 __ pop(edx); | 3789 __ pop(edx); |
| 3786 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 3790 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3787 Builtins::StoreIC_Initialize)); | 3791 Builtins::StoreIC_Initialize)); |
| 3788 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3792 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3789 if (expr->is_postfix()) { | 3793 if (expr->is_postfix()) { |
| 3790 if (!context()->IsEffect()) { | 3794 if (!context()->IsEffect()) { |
| 3791 context()->PlugTOS(); | 3795 context()->PlugTOS(); |
| 3792 } | 3796 } |
| 3793 } else { | 3797 } else { |
| 3794 context()->Plug(eax); | 3798 context()->Plug(eax); |
| 3795 } | 3799 } |
| 3796 break; | 3800 break; |
| 3797 } | 3801 } |
| 3798 case KEYED_PROPERTY: { | 3802 case KEYED_PROPERTY: { |
| 3799 __ pop(ecx); | 3803 __ pop(ecx); |
| 3800 __ pop(edx); | 3804 __ pop(edx); |
| 3801 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 3805 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3802 Builtins::KeyedStoreIC_Initialize)); | 3806 Builtins::KeyedStoreIC_Initialize)); |
| 3803 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3807 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3804 if (expr->is_postfix()) { | 3808 if (expr->is_postfix()) { |
| 3805 // Result is on the stack | 3809 // Result is on the stack |
| 3806 if (!context()->IsEffect()) { | 3810 if (!context()->IsEffect()) { |
| 3807 context()->PlugTOS(); | 3811 context()->PlugTOS(); |
| 3808 } | 3812 } |
| 3809 } else { | 3813 } else { |
| 3810 context()->Plug(eax); | 3814 context()->Plug(eax); |
| 3811 } | 3815 } |
| 3812 break; | 3816 break; |
| 3813 } | 3817 } |
| 3814 } | 3818 } |
| 3815 } | 3819 } |
| 3816 | 3820 |
| 3817 | 3821 |
| 3818 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3822 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3819 VariableProxy* proxy = expr->AsVariableProxy(); | 3823 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3820 ASSERT(!context()->IsEffect()); | 3824 ASSERT(!context()->IsEffect()); |
| 3821 ASSERT(!context()->IsTest()); | 3825 ASSERT(!context()->IsTest()); |
| 3822 | 3826 |
| 3823 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3827 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3824 Comment cmnt(masm_, "Global variable"); | 3828 Comment cmnt(masm_, "Global variable"); |
| 3825 __ mov(eax, GlobalObjectOperand()); | 3829 __ mov(eax, GlobalObjectOperand()); |
| 3826 __ mov(ecx, Immediate(proxy->name())); | 3830 __ mov(ecx, Immediate(proxy->name())); |
| 3827 Handle<Code> ic(Isolate::Current()->builtins()->builtin( | 3831 Handle<Code> ic(isolate()->builtins()->builtin( |
| 3828 Builtins::LoadIC_Initialize)); | 3832 Builtins::LoadIC_Initialize)); |
| 3829 // Use a regular load, not a contextual load, to avoid a reference | 3833 // Use a regular load, not a contextual load, to avoid a reference |
| 3830 // error. | 3834 // error. |
| 3831 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3835 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3832 PrepareForBailout(expr, TOS_REG); | 3836 PrepareForBailout(expr, TOS_REG); |
| 3833 context()->Plug(eax); | 3837 context()->Plug(eax); |
| 3834 } else if (proxy != NULL && | 3838 } else if (proxy != NULL && |
| 3835 proxy->var()->AsSlot() != NULL && | 3839 proxy->var()->AsSlot() != NULL && |
| 3836 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3840 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 3837 Label done, slow; | 3841 Label done, slow; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3871 if (!right_literal_value->IsString()) return false; | 3875 if (!right_literal_value->IsString()) return false; |
| 3872 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3876 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3873 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3877 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3874 Handle<String> check = Handle<String>::cast(right_literal_value); | 3878 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3875 | 3879 |
| 3876 { AccumulatorValueContext context(this); | 3880 { AccumulatorValueContext context(this); |
| 3877 VisitForTypeofValue(left_unary->expression()); | 3881 VisitForTypeofValue(left_unary->expression()); |
| 3878 } | 3882 } |
| 3879 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3883 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3880 | 3884 |
| 3881 if (check->Equals(HEAP->number_symbol())) { | 3885 if (check->Equals(isolate()->heap()->number_symbol())) { |
| 3882 __ test(eax, Immediate(kSmiTagMask)); | 3886 __ test(eax, Immediate(kSmiTagMask)); |
| 3883 __ j(zero, if_true); | 3887 __ j(zero, if_true); |
| 3884 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3888 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3885 FACTORY->heap_number_map()); | 3889 isolate()->factory()->heap_number_map()); |
| 3886 Split(equal, if_true, if_false, fall_through); | 3890 Split(equal, if_true, if_false, fall_through); |
| 3887 } else if (check->Equals(HEAP->string_symbol())) { | 3891 } else if (check->Equals(isolate()->heap()->string_symbol())) { |
| 3888 __ test(eax, Immediate(kSmiTagMask)); | 3892 __ test(eax, Immediate(kSmiTagMask)); |
| 3889 __ j(zero, if_false); | 3893 __ j(zero, if_false); |
| 3890 // Check for undetectable objects => false. | 3894 // Check for undetectable objects => false. |
| 3891 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3895 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3892 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3896 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3893 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3897 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 3894 __ j(not_zero, if_false); | 3898 __ j(not_zero, if_false); |
| 3895 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); | 3899 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); |
| 3896 Split(below, if_true, if_false, fall_through); | 3900 Split(below, if_true, if_false, fall_through); |
| 3897 } else if (check->Equals(HEAP->boolean_symbol())) { | 3901 } else if (check->Equals(isolate()->heap()->boolean_symbol())) { |
| 3898 __ cmp(eax, FACTORY->true_value()); | 3902 __ cmp(eax, isolate()->factory()->true_value()); |
| 3899 __ j(equal, if_true); | 3903 __ j(equal, if_true); |
| 3900 __ cmp(eax, FACTORY->false_value()); | 3904 __ cmp(eax, isolate()->factory()->false_value()); |
| 3901 Split(equal, if_true, if_false, fall_through); | 3905 Split(equal, if_true, if_false, fall_through); |
| 3902 } else if (check->Equals(HEAP->undefined_symbol())) { | 3906 } else if (check->Equals(isolate()->heap()->undefined_symbol())) { |
| 3903 __ cmp(eax, FACTORY->undefined_value()); | 3907 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 3904 __ j(equal, if_true); | 3908 __ j(equal, if_true); |
| 3905 __ test(eax, Immediate(kSmiTagMask)); | 3909 __ test(eax, Immediate(kSmiTagMask)); |
| 3906 __ j(zero, if_false); | 3910 __ j(zero, if_false); |
| 3907 // Check for undetectable objects => true. | 3911 // Check for undetectable objects => true. |
| 3908 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3912 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3909 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3913 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3910 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3914 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 3911 Split(not_zero, if_true, if_false, fall_through); | 3915 Split(not_zero, if_true, if_false, fall_through); |
| 3912 } else if (check->Equals(HEAP->function_symbol())) { | 3916 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
| 3913 __ test(eax, Immediate(kSmiTagMask)); | 3917 __ test(eax, Immediate(kSmiTagMask)); |
| 3914 __ j(zero, if_false); | 3918 __ j(zero, if_false); |
| 3915 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); | 3919 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); |
| 3916 __ j(equal, if_true); | 3920 __ j(equal, if_true); |
| 3917 // Regular expressions => 'function' (they are callable). | 3921 // Regular expressions => 'function' (they are callable). |
| 3918 __ CmpInstanceType(edx, JS_REGEXP_TYPE); | 3922 __ CmpInstanceType(edx, JS_REGEXP_TYPE); |
| 3919 Split(equal, if_true, if_false, fall_through); | 3923 Split(equal, if_true, if_false, fall_through); |
| 3920 } else if (check->Equals(HEAP->object_symbol())) { | 3924 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
| 3921 __ test(eax, Immediate(kSmiTagMask)); | 3925 __ test(eax, Immediate(kSmiTagMask)); |
| 3922 __ j(zero, if_false); | 3926 __ j(zero, if_false); |
| 3923 __ cmp(eax, FACTORY->null_value()); | 3927 __ cmp(eax, isolate()->factory()->null_value()); |
| 3924 __ j(equal, if_true); | 3928 __ j(equal, if_true); |
| 3925 // Regular expressions => 'function', not 'object'. | 3929 // Regular expressions => 'function', not 'object'. |
| 3926 __ CmpObjectType(eax, JS_REGEXP_TYPE, edx); | 3930 __ CmpObjectType(eax, JS_REGEXP_TYPE, edx); |
| 3927 __ j(equal, if_false); | 3931 __ j(equal, if_false); |
| 3928 // Check for undetectable objects => false. | 3932 // Check for undetectable objects => false. |
| 3929 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3933 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3930 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3934 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 3931 __ j(not_zero, if_false); | 3935 __ j(not_zero, if_false); |
| 3932 // Check for JS objects => true. | 3936 // Check for JS objects => true. |
| 3933 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3937 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3966 context()->Plug(if_true, if_false); | 3970 context()->Plug(if_true, if_false); |
| 3967 return; | 3971 return; |
| 3968 } | 3972 } |
| 3969 | 3973 |
| 3970 VisitForStackValue(expr->left()); | 3974 VisitForStackValue(expr->left()); |
| 3971 switch (expr->op()) { | 3975 switch (expr->op()) { |
| 3972 case Token::IN: | 3976 case Token::IN: |
| 3973 VisitForStackValue(expr->right()); | 3977 VisitForStackValue(expr->right()); |
| 3974 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3978 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 3975 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 3979 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 3976 __ cmp(eax, FACTORY->true_value()); | 3980 __ cmp(eax, isolate()->factory()->true_value()); |
| 3977 Split(equal, if_true, if_false, fall_through); | 3981 Split(equal, if_true, if_false, fall_through); |
| 3978 break; | 3982 break; |
| 3979 | 3983 |
| 3980 case Token::INSTANCEOF: { | 3984 case Token::INSTANCEOF: { |
| 3981 VisitForStackValue(expr->right()); | 3985 VisitForStackValue(expr->right()); |
| 3982 InstanceofStub stub; | 3986 InstanceofStub stub; |
| 3983 __ CallStub(&stub); | 3987 __ CallStub(&stub); |
| 3984 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3988 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3985 __ test(eax, Operand(eax)); | 3989 __ test(eax, Operand(eax)); |
| 3986 // The stub returns 0 for true. | 3990 // The stub returns 0 for true. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4058 Label materialize_true, materialize_false; | 4062 Label materialize_true, materialize_false; |
| 4059 Label* if_true = NULL; | 4063 Label* if_true = NULL; |
| 4060 Label* if_false = NULL; | 4064 Label* if_false = NULL; |
| 4061 Label* fall_through = NULL; | 4065 Label* fall_through = NULL; |
| 4062 context()->PrepareTest(&materialize_true, &materialize_false, | 4066 context()->PrepareTest(&materialize_true, &materialize_false, |
| 4063 &if_true, &if_false, &fall_through); | 4067 &if_true, &if_false, &fall_through); |
| 4064 | 4068 |
| 4065 VisitForAccumulatorValue(expr->expression()); | 4069 VisitForAccumulatorValue(expr->expression()); |
| 4066 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4070 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4067 | 4071 |
| 4068 __ cmp(eax, FACTORY->null_value()); | 4072 __ cmp(eax, isolate()->factory()->null_value()); |
| 4069 if (expr->is_strict()) { | 4073 if (expr->is_strict()) { |
| 4070 Split(equal, if_true, if_false, fall_through); | 4074 Split(equal, if_true, if_false, fall_through); |
| 4071 } else { | 4075 } else { |
| 4072 __ j(equal, if_true); | 4076 __ j(equal, if_true); |
| 4073 __ cmp(eax, FACTORY->undefined_value()); | 4077 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 4074 __ j(equal, if_true); | 4078 __ j(equal, if_true); |
| 4075 __ test(eax, Immediate(kSmiTagMask)); | 4079 __ test(eax, Immediate(kSmiTagMask)); |
| 4076 __ j(zero, if_false); | 4080 __ j(zero, if_false); |
| 4077 // It can be an undetectable object. | 4081 // It can be an undetectable object. |
| 4078 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4082 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4079 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); | 4083 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4080 __ test(edx, Immediate(1 << Map::kIsUndetectable)); | 4084 __ test(edx, Immediate(1 << Map::kIsUndetectable)); |
| 4081 Split(not_zero, if_true, if_false, fall_through); | 4085 Split(not_zero, if_true, if_false, fall_through); |
| 4082 } | 4086 } |
| 4083 context()->Plug(if_true, if_false); | 4087 context()->Plug(if_true, if_false); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4098 Register FullCodeGenerator::context_register() { | 4102 Register FullCodeGenerator::context_register() { |
| 4099 return esi; | 4103 return esi; |
| 4100 } | 4104 } |
| 4101 | 4105 |
| 4102 | 4106 |
| 4103 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { | 4107 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { |
| 4104 ASSERT(mode == RelocInfo::CODE_TARGET || | 4108 ASSERT(mode == RelocInfo::CODE_TARGET || |
| 4105 mode == RelocInfo::CODE_TARGET_CONTEXT); | 4109 mode == RelocInfo::CODE_TARGET_CONTEXT); |
| 4106 switch (ic->kind()) { | 4110 switch (ic->kind()) { |
| 4107 case Code::LOAD_IC: | 4111 case Code::LOAD_IC: |
| 4108 __ IncrementCounter(COUNTERS->named_load_full(), 1); | 4112 __ IncrementCounter(isolate()->counters()->named_load_full(), 1); |
| 4109 break; | 4113 break; |
| 4110 case Code::KEYED_LOAD_IC: | 4114 case Code::KEYED_LOAD_IC: |
| 4111 __ IncrementCounter(COUNTERS->keyed_load_full(), 1); | 4115 __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1); |
| 4112 break; | 4116 break; |
| 4113 case Code::STORE_IC: | 4117 case Code::STORE_IC: |
| 4114 __ IncrementCounter(COUNTERS->named_store_full(), 1); | 4118 __ IncrementCounter(isolate()->counters()->named_store_full(), 1); |
| 4115 break; | 4119 break; |
| 4116 case Code::KEYED_STORE_IC: | 4120 case Code::KEYED_STORE_IC: |
| 4117 __ IncrementCounter(COUNTERS->keyed_store_full(), 1); | 4121 __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1); |
| 4118 default: | 4122 default: |
| 4119 break; | 4123 break; |
| 4120 } | 4124 } |
| 4121 | 4125 |
| 4122 __ call(ic, mode); | 4126 __ call(ic, mode); |
| 4123 | 4127 |
| 4124 // Crankshaft doesn't need patching of inlined loads and stores. | 4128 // Crankshaft doesn't need patching of inlined loads and stores. |
| 4125 // When compiling the snapshot we need to produce code that works | 4129 // When compiling the snapshot we need to produce code that works |
| 4126 // with and without Crankshaft. | 4130 // with and without Crankshaft. |
| 4127 if (V8::UseCrankshaft() && !Serializer::enabled()) { | 4131 if (V8::UseCrankshaft() && !Serializer::enabled()) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4185 // And return. | 4189 // And return. |
| 4186 __ ret(0); | 4190 __ ret(0); |
| 4187 } | 4191 } |
| 4188 | 4192 |
| 4189 | 4193 |
| 4190 #undef __ | 4194 #undef __ |
| 4191 | 4195 |
| 4192 } } // namespace v8::internal | 4196 } } // namespace v8::internal |
| 4193 | 4197 |
| 4194 #endif // V8_TARGET_ARCH_IA32 | 4198 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |