| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 namespace v8 { | 41 namespace v8 { |
| 42 namespace internal { | 42 namespace internal { |
| 43 | 43 |
| 44 | 44 |
| 45 #define __ ACCESS_MASM(masm_) | 45 #define __ ACCESS_MASM(masm_) |
| 46 | 46 |
| 47 | 47 |
| 48 class JumpPatchSite BASE_EMBEDDED { | 48 class JumpPatchSite BASE_EMBEDDED { |
| 49 public: | 49 public: |
| 50 explicit JumpPatchSite(MacroAssembler* masm) | 50 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { |
| 51 : masm_(masm) { | |
| 52 #ifdef DEBUG | 51 #ifdef DEBUG |
| 53 info_emitted_ = false; | 52 info_emitted_ = false; |
| 54 #endif | 53 #endif |
| 55 } | 54 } |
| 56 | 55 |
| 57 ~JumpPatchSite() { | 56 ~JumpPatchSite() { |
| 58 ASSERT(patch_site_.is_bound() == info_emitted_); | 57 ASSERT(patch_site_.is_bound() == info_emitted_); |
| 59 } | 58 } |
| 60 | 59 |
| 61 void EmitJumpIfNotSmi(Register reg, NearLabel* target) { | 60 void EmitJumpIfNotSmi(Register reg, NearLabel* target) { |
| 62 __ test(reg, Immediate(kSmiTagMask)); | 61 __ test(reg, Immediate(kSmiTagMask)); |
| 63 EmitJump(not_carry, target); // Always taken before patched. | 62 EmitJump(not_carry, target); // Always taken before patched. |
| 64 } | 63 } |
| 65 | 64 |
| 66 void EmitJumpIfSmi(Register reg, NearLabel* target) { | 65 void EmitJumpIfSmi(Register reg, NearLabel* target) { |
| 67 __ test(reg, Immediate(kSmiTagMask)); | 66 __ test(reg, Immediate(kSmiTagMask)); |
| 68 EmitJump(carry, target); // Never taken before patched. | 67 EmitJump(carry, target); // Never taken before patched. |
| 69 } | 68 } |
| 70 | 69 |
| 71 void EmitPatchInfo() { | 70 void EmitPatchInfo() { |
| 72 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); | 71 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); |
| 73 ASSERT(is_int8(delta_to_patch_site)); | 72 ASSERT(is_int8(delta_to_patch_site)); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 #ifdef ENABLE_DEBUGGER_SUPPORT | 315 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 317 // Check that the size of the code used for returning is large enough | 316 // Check that the size of the code used for returning is large enough |
| 318 // for the debugger's requirements. | 317 // for the debugger's requirements. |
| 319 ASSERT(Assembler::kJSReturnSequenceLength <= | 318 ASSERT(Assembler::kJSReturnSequenceLength <= |
| 320 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 319 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 321 #endif | 320 #endif |
| 322 } | 321 } |
| 323 } | 322 } |
| 324 | 323 |
| 325 | 324 |
| 326 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | |
| 327 Token::Value op, Expression* left, Expression* right) { | |
| 328 ASSERT(ShouldInlineSmiCase(op)); | |
| 329 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) { | |
| 330 // We never generate inlined constant smi operations for these. | |
| 331 return kNoConstants; | |
| 332 } else if (right->IsSmiLiteral()) { | |
| 333 return kRightConstant; | |
| 334 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) { | |
| 335 return kLeftConstant; | |
| 336 } else { | |
| 337 return kNoConstants; | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 | |
| 342 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { | 325 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { |
| 343 } | 326 } |
| 344 | 327 |
| 345 | 328 |
| 346 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { | 329 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { |
| 347 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 330 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 348 __ mov(result_register(), slot_operand); | 331 __ mov(result_register(), slot_operand); |
| 349 } | 332 } |
| 350 | 333 |
| 351 | 334 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 void FullCodeGenerator::DoTest(Label* if_true, | 526 void FullCodeGenerator::DoTest(Label* if_true, |
| 544 Label* if_false, | 527 Label* if_false, |
| 545 Label* fall_through) { | 528 Label* fall_through) { |
| 546 // Emit the inlined tests assumed by the stub. | 529 // Emit the inlined tests assumed by the stub. |
| 547 __ cmp(result_register(), isolate()->factory()->undefined_value()); | 530 __ cmp(result_register(), isolate()->factory()->undefined_value()); |
| 548 __ j(equal, if_false); | 531 __ j(equal, if_false); |
| 549 __ cmp(result_register(), isolate()->factory()->true_value()); | 532 __ cmp(result_register(), isolate()->factory()->true_value()); |
| 550 __ j(equal, if_true); | 533 __ j(equal, if_true); |
| 551 __ cmp(result_register(), isolate()->factory()->false_value()); | 534 __ cmp(result_register(), isolate()->factory()->false_value()); |
| 552 __ j(equal, if_false); | 535 __ j(equal, if_false); |
| 553 ASSERT_EQ(0, kSmiTag); | 536 STATIC_ASSERT(kSmiTag == 0); |
| 554 __ test(result_register(), Operand(result_register())); | 537 __ test(result_register(), Operand(result_register())); |
| 555 __ j(zero, if_false); | 538 __ j(zero, if_false); |
| 556 __ test(result_register(), Immediate(kSmiTagMask)); | 539 __ test(result_register(), Immediate(kSmiTagMask)); |
| 557 __ j(zero, if_true); | 540 __ j(zero, if_true); |
| 558 | 541 |
| 559 // Call the ToBoolean stub for all other cases. | 542 // Call the ToBoolean stub for all other cases. |
| 560 ToBooleanStub stub; | 543 ToBooleanStub stub; |
| 561 __ push(result_register()); | 544 __ push(result_register()); |
| 562 __ CallStub(&stub); | 545 __ CallStub(&stub); |
| 563 __ test(eax, Operand(eax)); | 546 __ test(eax, Operand(eax)); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 Register src, | 594 Register src, |
| 612 Register scratch1, | 595 Register scratch1, |
| 613 Register scratch2) { | 596 Register scratch2) { |
| 614 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. | 597 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
| 615 ASSERT(!scratch1.is(src) && !scratch2.is(src)); | 598 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
| 616 MemOperand location = EmitSlotSearch(dst, scratch1); | 599 MemOperand location = EmitSlotSearch(dst, scratch1); |
| 617 __ mov(location, src); | 600 __ mov(location, src); |
| 618 // Emit the write barrier code if the location is in the heap. | 601 // Emit the write barrier code if the location is in the heap. |
| 619 if (dst->type() == Slot::CONTEXT) { | 602 if (dst->type() == Slot::CONTEXT) { |
| 620 int offset = Context::SlotOffset(dst->index()); | 603 int offset = Context::SlotOffset(dst->index()); |
| 604 ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi)); |
| 621 __ RecordWrite(scratch1, offset, src, scratch2); | 605 __ RecordWrite(scratch1, offset, src, scratch2); |
| 622 } | 606 } |
| 623 } | 607 } |
| 624 | 608 |
| 625 | 609 |
| 626 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 610 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
| 627 bool should_normalize, | 611 bool should_normalize, |
| 628 Label* if_true, | 612 Label* if_true, |
| 629 Label* if_false) { | 613 Label* if_false) { |
| 630 // Only prepare for bailouts before splits if we're in a test | 614 // Only prepare for bailouts before splits if we're in a test |
| (...skipping 18 matching lines...) Expand all Loading... |
| 649 } | 633 } |
| 650 | 634 |
| 651 | 635 |
| 652 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 636 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 653 Variable::Mode mode, | 637 Variable::Mode mode, |
| 654 FunctionLiteral* function) { | 638 FunctionLiteral* function) { |
| 655 Comment cmnt(masm_, "[ Declaration"); | 639 Comment cmnt(masm_, "[ Declaration"); |
| 656 ASSERT(variable != NULL); // Must have been resolved. | 640 ASSERT(variable != NULL); // Must have been resolved. |
| 657 Slot* slot = variable->AsSlot(); | 641 Slot* slot = variable->AsSlot(); |
| 658 Property* prop = variable->AsProperty(); | 642 Property* prop = variable->AsProperty(); |
| 643 |
| 659 if (slot != NULL) { | 644 if (slot != NULL) { |
| 660 switch (slot->type()) { | 645 switch (slot->type()) { |
| 661 case Slot::PARAMETER: | 646 case Slot::PARAMETER: |
| 662 case Slot::LOCAL: | 647 case Slot::LOCAL: |
| 663 if (mode == Variable::CONST) { | 648 if (mode == Variable::CONST) { |
| 664 __ mov(Operand(ebp, SlotOffset(slot)), | 649 __ mov(Operand(ebp, SlotOffset(slot)), |
| 665 Immediate(isolate()->factory()->the_hole_value())); | 650 Immediate(isolate()->factory()->the_hole_value())); |
| 666 } else if (function != NULL) { | 651 } else if (function != NULL) { |
| 667 VisitForAccumulatorValue(function); | 652 VisitForAccumulatorValue(function); |
| 668 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 653 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 VisitForAccumulatorValue(function); | 719 VisitForAccumulatorValue(function); |
| 735 __ pop(edx); | 720 __ pop(edx); |
| 736 } else { | 721 } else { |
| 737 __ mov(edx, eax); | 722 __ mov(edx, eax); |
| 738 __ mov(eax, isolate()->factory()->the_hole_value()); | 723 __ mov(eax, isolate()->factory()->the_hole_value()); |
| 739 } | 724 } |
| 740 ASSERT(prop->key()->AsLiteral() != NULL && | 725 ASSERT(prop->key()->AsLiteral() != NULL && |
| 741 prop->key()->AsLiteral()->handle()->IsSmi()); | 726 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 742 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 727 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 743 | 728 |
| 744 Handle<Code> ic(isolate()->builtins()->builtin( | 729 Handle<Code> ic(isolate()->builtins()->builtin(is_strict() |
| 745 Builtins::KeyedStoreIC_Initialize)); | 730 ? Builtins::KeyedStoreIC_Initialize_Strict |
| 731 : Builtins::KeyedStoreIC_Initialize)); |
| 746 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 732 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 747 } | 733 } |
| 748 } | 734 } |
| 749 } | 735 } |
| 750 | 736 |
| 751 | 737 |
| 752 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 738 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 753 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 739 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 754 } | 740 } |
| 755 | 741 |
| 756 | 742 |
| 757 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 743 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 758 // Call the runtime to declare the globals. | 744 // Call the runtime to declare the globals. |
| 759 __ push(esi); // The context is the first argument. | 745 __ push(esi); // The context is the first argument. |
| 760 __ push(Immediate(pairs)); | 746 __ push(Immediate(pairs)); |
| 761 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 747 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 762 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 748 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 749 __ CallRuntime(Runtime::kDeclareGlobals, 4); |
| 763 // Return value is ignored. | 750 // Return value is ignored. |
| 764 } | 751 } |
| 765 | 752 |
| 766 | 753 |
| 767 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 754 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 768 Comment cmnt(masm_, "[ SwitchStatement"); | 755 Comment cmnt(masm_, "[ SwitchStatement"); |
| 769 Breakable nested_statement(this, stmt); | 756 Breakable nested_statement(this, stmt); |
| 770 SetStatementPosition(stmt); | 757 SetStatementPosition(stmt); |
| 771 | 758 |
| 772 // Keep the switch value on the stack until a case matches. | 759 // Keep the switch value on the stack until a case matches. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 __ j(not_equal, &next_test); | 796 __ j(not_equal, &next_test); |
| 810 __ Drop(1); // Switch value is no longer needed. | 797 __ Drop(1); // Switch value is no longer needed. |
| 811 __ jmp(clause->body_target()->entry_label()); | 798 __ jmp(clause->body_target()->entry_label()); |
| 812 __ bind(&slow_case); | 799 __ bind(&slow_case); |
| 813 } | 800 } |
| 814 | 801 |
| 815 // Record position before stub call for type feedback. | 802 // Record position before stub call for type feedback. |
| 816 SetSourcePosition(clause->position()); | 803 SetSourcePosition(clause->position()); |
| 817 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 804 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
| 818 EmitCallIC(ic, &patch_site); | 805 EmitCallIC(ic, &patch_site); |
| 819 | |
| 820 __ test(eax, Operand(eax)); | 806 __ test(eax, Operand(eax)); |
| 821 __ j(not_equal, &next_test); | 807 __ j(not_equal, &next_test); |
| 822 __ Drop(1); // Switch value is no longer needed. | 808 __ Drop(1); // Switch value is no longer needed. |
| 823 __ jmp(clause->body_target()->entry_label()); | 809 __ jmp(clause->body_target()->entry_label()); |
| 824 } | 810 } |
| 825 | 811 |
| 826 // Discard the test value and jump to the default if present, otherwise to | 812 // Discard the test value and jump to the default if present, otherwise to |
| 827 // the end of the statement. | 813 // the end of the statement. |
| 828 __ bind(&next_test); | 814 __ bind(&next_test); |
| 829 __ Drop(1); // Switch value is no longer needed. | 815 __ Drop(1); // Switch value is no longer needed. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 __ j(not_equal, &call_runtime); | 876 __ j(not_equal, &call_runtime); |
| 891 | 877 |
| 892 // Check that instance descriptors are not empty so that we can | 878 // Check that instance descriptors are not empty so that we can |
| 893 // check for an enum cache. Leave the map in ebx for the subsequent | 879 // check for an enum cache. Leave the map in ebx for the subsequent |
| 894 // prototype load. | 880 // prototype load. |
| 895 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | 881 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 896 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); | 882 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); |
| 897 __ cmp(edx, isolate()->factory()->empty_descriptor_array()); | 883 __ cmp(edx, isolate()->factory()->empty_descriptor_array()); |
| 898 __ j(equal, &call_runtime); | 884 __ j(equal, &call_runtime); |
| 899 | 885 |
| 900 // Check that there in an enum cache in the non-empty instance | 886 // Check that there is an enum cache in the non-empty instance |
| 901 // descriptors (edx). This is the case if the next enumeration | 887 // descriptors (edx). This is the case if the next enumeration |
| 902 // index field does not contain a smi. | 888 // index field does not contain a smi. |
| 903 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 889 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 904 __ test(edx, Immediate(kSmiTagMask)); | 890 __ test(edx, Immediate(kSmiTagMask)); |
| 905 __ j(zero, &call_runtime); | 891 __ j(zero, &call_runtime); |
| 906 | 892 |
| 907 // For all objects but the receiver, check that the cache is empty. | 893 // For all objects but the receiver, check that the cache is empty. |
| 908 NearLabel check_prototype; | 894 NearLabel check_prototype; |
| 909 __ cmp(ecx, Operand(eax)); | 895 __ cmp(ecx, Operand(eax)); |
| 910 __ j(equal, &check_prototype); | 896 __ j(equal, &check_prototype); |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1381 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1367 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1382 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1368 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1383 // Fall through. | 1369 // Fall through. |
| 1384 case ObjectLiteral::Property::COMPUTED: | 1370 case ObjectLiteral::Property::COMPUTED: |
| 1385 if (key->handle()->IsSymbol()) { | 1371 if (key->handle()->IsSymbol()) { |
| 1386 if (property->emit_store()) { | 1372 if (property->emit_store()) { |
| 1387 VisitForAccumulatorValue(value); | 1373 VisitForAccumulatorValue(value); |
| 1388 __ mov(ecx, Immediate(key->handle())); | 1374 __ mov(ecx, Immediate(key->handle())); |
| 1389 __ mov(edx, Operand(esp, 0)); | 1375 __ mov(edx, Operand(esp, 0)); |
| 1390 Handle<Code> ic(isolate()->builtins()->builtin( | 1376 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1391 Builtins::StoreIC_Initialize)); | 1377 is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 1378 : Builtins::StoreIC_Initialize)); |
| 1392 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1379 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1393 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1380 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1394 } else { | 1381 } else { |
| 1395 VisitForEffect(value); | 1382 VisitForEffect(value); |
| 1396 } | 1383 } |
| 1397 break; | 1384 break; |
| 1398 } | 1385 } |
| 1399 // Fall through. | 1386 // Fall through. |
| 1400 case ObjectLiteral::Property::PROTOTYPE: | 1387 case ObjectLiteral::Property::PROTOTYPE: |
| 1401 __ push(Operand(esp, 0)); // Duplicate receiver. | 1388 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1402 VisitForStackValue(key); | 1389 VisitForStackValue(key); |
| 1403 VisitForStackValue(value); | 1390 VisitForStackValue(value); |
| 1404 if (property->emit_store()) { | 1391 if (property->emit_store()) { |
| 1405 __ CallRuntime(Runtime::kSetProperty, 3); | 1392 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes |
| 1393 __ CallRuntime(Runtime::kSetProperty, 4); |
| 1406 } else { | 1394 } else { |
| 1407 __ Drop(3); | 1395 __ Drop(3); |
| 1408 } | 1396 } |
| 1409 break; | 1397 break; |
| 1410 case ObjectLiteral::Property::SETTER: | 1398 case ObjectLiteral::Property::SETTER: |
| 1411 case ObjectLiteral::Property::GETTER: | 1399 case ObjectLiteral::Property::GETTER: |
| 1412 __ push(Operand(esp, 0)); // Duplicate receiver. | 1400 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1413 VisitForStackValue(key); | 1401 VisitForStackValue(key); |
| 1414 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 1402 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
| 1415 Smi::FromInt(1) : | 1403 Smi::FromInt(1) : |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1574 } | 1562 } |
| 1575 } | 1563 } |
| 1576 | 1564 |
| 1577 // For property compound assignments we need another deoptimization | 1565 // For property compound assignments we need another deoptimization |
| 1578 // point after the property load. | 1566 // point after the property load. |
| 1579 if (property != NULL) { | 1567 if (property != NULL) { |
| 1580 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); | 1568 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1581 } | 1569 } |
| 1582 | 1570 |
| 1583 Token::Value op = expr->binary_op(); | 1571 Token::Value op = expr->binary_op(); |
| 1584 ConstantOperand constant = ShouldInlineSmiCase(op) | 1572 __ push(eax); // Left operand goes on the stack. |
| 1585 ? GetConstantOperand(op, expr->target(), expr->value()) | 1573 VisitForAccumulatorValue(expr->value()); |
| 1586 : kNoConstants; | |
| 1587 ASSERT(constant == kRightConstant || constant == kNoConstants); | |
| 1588 if (constant == kNoConstants) { | |
| 1589 __ push(eax); // Left operand goes on the stack. | |
| 1590 VisitForAccumulatorValue(expr->value()); | |
| 1591 } | |
| 1592 | 1574 |
| 1593 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1575 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1594 ? OVERWRITE_RIGHT | 1576 ? OVERWRITE_RIGHT |
| 1595 : NO_OVERWRITE; | 1577 : NO_OVERWRITE; |
| 1596 SetSourcePosition(expr->position() + 1); | 1578 SetSourcePosition(expr->position() + 1); |
| 1597 AccumulatorValueContext context(this); | 1579 AccumulatorValueContext context(this); |
| 1598 if (ShouldInlineSmiCase(op)) { | 1580 if (ShouldInlineSmiCase(op)) { |
| 1599 EmitInlineSmiBinaryOp(expr, | 1581 EmitInlineSmiBinaryOp(expr, |
| 1600 op, | 1582 op, |
| 1601 mode, | 1583 mode, |
| 1602 expr->target(), | 1584 expr->target(), |
| 1603 expr->value(), | 1585 expr->value()); |
| 1604 constant); | |
| 1605 } else { | 1586 } else { |
| 1606 EmitBinaryOp(op, mode); | 1587 EmitBinaryOp(op, mode); |
| 1607 } | 1588 } |
| 1608 | 1589 |
| 1609 // Deoptimization point in case the binary operation may have side effects. | 1590 // Deoptimization point in case the binary operation may have side effects. |
| 1610 PrepareForBailout(expr->binary_operation(), TOS_REG); | 1591 PrepareForBailout(expr->binary_operation(), TOS_REG); |
| 1611 } else { | 1592 } else { |
| 1612 VisitForAccumulatorValue(expr->value()); | 1593 VisitForAccumulatorValue(expr->value()); |
| 1613 } | 1594 } |
| 1614 | 1595 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1644 | 1625 |
| 1645 | 1626 |
| 1646 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1627 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1647 SetSourcePosition(prop->position()); | 1628 SetSourcePosition(prop->position()); |
| 1648 Handle<Code> ic(isolate()->builtins()->builtin( | 1629 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1649 Builtins::KeyedLoadIC_Initialize)); | 1630 Builtins::KeyedLoadIC_Initialize)); |
| 1650 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1631 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1651 } | 1632 } |
| 1652 | 1633 |
| 1653 | 1634 |
| 1654 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, | |
| 1655 OverwriteMode mode, | |
| 1656 bool left_is_constant_smi, | |
| 1657 Smi* value) { | |
| 1658 NearLabel call_stub, done; | |
| 1659 __ add(Operand(eax), Immediate(value)); | |
| 1660 __ j(overflow, &call_stub); | |
| 1661 JumpPatchSite patch_site(masm_); | |
| 1662 patch_site.EmitJumpIfSmi(eax, &done); | |
| 1663 | |
| 1664 // Undo the optimistic add operation and call the shared stub. | |
| 1665 __ bind(&call_stub); | |
| 1666 __ sub(Operand(eax), Immediate(value)); | |
| 1667 Token::Value op = Token::ADD; | |
| 1668 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1669 if (left_is_constant_smi) { | |
| 1670 __ mov(edx, Immediate(value)); | |
| 1671 } else { | |
| 1672 __ mov(edx, eax); | |
| 1673 __ mov(eax, Immediate(value)); | |
| 1674 } | |
| 1675 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1676 | |
| 1677 __ bind(&done); | |
| 1678 context()->Plug(eax); | |
| 1679 } | |
| 1680 | |
| 1681 | |
| 1682 void FullCodeGenerator::EmitConstantSmiSub(Expression* expr, | |
| 1683 OverwriteMode mode, | |
| 1684 bool left_is_constant_smi, | |
| 1685 Smi* value) { | |
| 1686 NearLabel call_stub, done; | |
| 1687 if (left_is_constant_smi) { | |
| 1688 __ mov(ecx, eax); | |
| 1689 __ mov(eax, Immediate(value)); | |
| 1690 __ sub(Operand(eax), ecx); | |
| 1691 } else { | |
| 1692 __ sub(Operand(eax), Immediate(value)); | |
| 1693 } | |
| 1694 __ j(overflow, &call_stub); | |
| 1695 JumpPatchSite patch_site(masm_); | |
| 1696 patch_site.EmitJumpIfSmi(eax, &done); | |
| 1697 | |
| 1698 __ bind(&call_stub); | |
| 1699 if (left_is_constant_smi) { | |
| 1700 __ mov(edx, Immediate(value)); | |
| 1701 __ mov(eax, ecx); | |
| 1702 } else { | |
| 1703 __ add(Operand(eax), Immediate(value)); // Undo the subtraction. | |
| 1704 __ mov(edx, eax); | |
| 1705 __ mov(eax, Immediate(value)); | |
| 1706 } | |
| 1707 Token::Value op = Token::SUB; | |
| 1708 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1709 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1710 | |
| 1711 __ bind(&done); | |
| 1712 context()->Plug(eax); | |
| 1713 } | |
| 1714 | |
| 1715 | |
| 1716 void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr, | |
| 1717 Token::Value op, | |
| 1718 OverwriteMode mode, | |
| 1719 Smi* value) { | |
| 1720 NearLabel call_stub, smi_case, done; | |
| 1721 int shift_value = value->value() & 0x1f; | |
| 1722 | |
| 1723 JumpPatchSite patch_site(masm_); | |
| 1724 patch_site.EmitJumpIfSmi(eax, &smi_case); | |
| 1725 | |
| 1726 // Call stub. | |
| 1727 __ bind(&call_stub); | |
| 1728 __ mov(edx, eax); | |
| 1729 __ mov(eax, Immediate(value)); | |
| 1730 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1731 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1732 __ jmp(&done); | |
| 1733 | |
| 1734 // Smi case. | |
| 1735 __ bind(&smi_case); | |
| 1736 switch (op) { | |
| 1737 case Token::SHL: | |
| 1738 if (shift_value != 0) { | |
| 1739 __ mov(edx, eax); | |
| 1740 if (shift_value > 1) { | |
| 1741 __ shl(edx, shift_value - 1); | |
| 1742 } | |
| 1743 // Convert int result to smi, checking that it is in int range. | |
| 1744 ASSERT(kSmiTagSize == 1); // Adjust code if not the case. | |
| 1745 __ add(edx, Operand(edx)); | |
| 1746 __ j(overflow, &call_stub); | |
| 1747 __ mov(eax, edx); // Put result back into eax. | |
| 1748 } | |
| 1749 break; | |
| 1750 case Token::SAR: | |
| 1751 if (shift_value != 0) { | |
| 1752 __ sar(eax, shift_value); | |
| 1753 __ and_(eax, ~kSmiTagMask); | |
| 1754 } | |
| 1755 break; | |
| 1756 case Token::SHR: | |
| 1757 if (shift_value < 2) { | |
| 1758 __ mov(edx, eax); | |
| 1759 __ SmiUntag(edx); | |
| 1760 __ shr(edx, shift_value); | |
| 1761 __ test(edx, Immediate(0xc0000000)); | |
| 1762 __ j(not_zero, &call_stub); | |
| 1763 __ SmiTag(edx); | |
| 1764 __ mov(eax, edx); // Put result back into eax. | |
| 1765 } else { | |
| 1766 __ SmiUntag(eax); | |
| 1767 __ shr(eax, shift_value); | |
| 1768 __ SmiTag(eax); | |
| 1769 } | |
| 1770 break; | |
| 1771 default: | |
| 1772 UNREACHABLE(); | |
| 1773 } | |
| 1774 | |
| 1775 __ bind(&done); | |
| 1776 context()->Plug(eax); | |
| 1777 } | |
| 1778 | |
| 1779 | |
| 1780 void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr, | |
| 1781 Token::Value op, | |
| 1782 OverwriteMode mode, | |
| 1783 Smi* value) { | |
| 1784 NearLabel smi_case, done; | |
| 1785 | |
| 1786 JumpPatchSite patch_site(masm_); | |
| 1787 patch_site.EmitJumpIfSmi(eax, &smi_case); | |
| 1788 | |
| 1789 // The order of the arguments does not matter for bit-ops with a | |
| 1790 // constant operand. | |
| 1791 __ mov(edx, Immediate(value)); | |
| 1792 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1793 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1794 __ jmp(&done); | |
| 1795 | |
| 1796 // Smi case. | |
| 1797 __ bind(&smi_case); | |
| 1798 switch (op) { | |
| 1799 case Token::BIT_OR: | |
| 1800 __ or_(Operand(eax), Immediate(value)); | |
| 1801 break; | |
| 1802 case Token::BIT_XOR: | |
| 1803 __ xor_(Operand(eax), Immediate(value)); | |
| 1804 break; | |
| 1805 case Token::BIT_AND: | |
| 1806 __ and_(Operand(eax), Immediate(value)); | |
| 1807 break; | |
| 1808 default: | |
| 1809 UNREACHABLE(); | |
| 1810 } | |
| 1811 | |
| 1812 __ bind(&done); | |
| 1813 context()->Plug(eax); | |
| 1814 } | |
| 1815 | |
| 1816 | |
| 1817 void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr, | |
| 1818 Token::Value op, | |
| 1819 OverwriteMode mode, | |
| 1820 bool left_is_constant_smi, | |
| 1821 Smi* value) { | |
| 1822 switch (op) { | |
| 1823 case Token::BIT_OR: | |
| 1824 case Token::BIT_XOR: | |
| 1825 case Token::BIT_AND: | |
| 1826 EmitConstantSmiBitOp(expr, op, mode, value); | |
| 1827 break; | |
| 1828 case Token::SHL: | |
| 1829 case Token::SAR: | |
| 1830 case Token::SHR: | |
| 1831 ASSERT(!left_is_constant_smi); | |
| 1832 EmitConstantSmiShiftOp(expr, op, mode, value); | |
| 1833 break; | |
| 1834 case Token::ADD: | |
| 1835 EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value); | |
| 1836 break; | |
| 1837 case Token::SUB: | |
| 1838 EmitConstantSmiSub(expr, mode, left_is_constant_smi, value); | |
| 1839 break; | |
| 1840 default: | |
| 1841 UNREACHABLE(); | |
| 1842 } | |
| 1843 } | |
| 1844 | |
| 1845 | |
| 1846 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1635 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
| 1847 Token::Value op, | 1636 Token::Value op, |
| 1848 OverwriteMode mode, | 1637 OverwriteMode mode, |
| 1849 Expression* left, | 1638 Expression* left, |
| 1850 Expression* right, | 1639 Expression* right) { |
| 1851 ConstantOperand constant) { | |
| 1852 if (constant == kRightConstant) { | |
| 1853 Smi* value = Smi::cast(*right->AsLiteral()->handle()); | |
| 1854 EmitConstantSmiBinaryOp(expr, op, mode, false, value); | |
| 1855 return; | |
| 1856 } else if (constant == kLeftConstant) { | |
| 1857 Smi* value = Smi::cast(*left->AsLiteral()->handle()); | |
| 1858 EmitConstantSmiBinaryOp(expr, op, mode, true, value); | |
| 1859 return; | |
| 1860 } | |
| 1861 | |
| 1862 // Do combined smi check of the operands. Left operand is on the | 1640 // Do combined smi check of the operands. Left operand is on the |
| 1863 // stack. Right operand is in eax. | 1641 // stack. Right operand is in eax. |
| 1864 NearLabel done, smi_case, stub_call; | 1642 NearLabel done, smi_case, stub_call; |
| 1865 __ pop(edx); | 1643 __ pop(edx); |
| 1866 __ mov(ecx, eax); | 1644 __ mov(ecx, eax); |
| 1867 __ or_(eax, Operand(edx)); | 1645 __ or_(eax, Operand(edx)); |
| 1868 JumpPatchSite patch_site(masm_); | 1646 JumpPatchSite patch_site(masm_); |
| 1869 patch_site.EmitJumpIfSmi(eax, &smi_case); | 1647 patch_site.EmitJumpIfSmi(eax, &smi_case); |
| 1870 | 1648 |
| 1871 __ bind(&stub_call); | 1649 __ bind(&stub_call); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1984 EmitVariableAssignment(var, Token::ASSIGN); | 1762 EmitVariableAssignment(var, Token::ASSIGN); |
| 1985 break; | 1763 break; |
| 1986 } | 1764 } |
| 1987 case NAMED_PROPERTY: { | 1765 case NAMED_PROPERTY: { |
| 1988 __ push(eax); // Preserve value. | 1766 __ push(eax); // Preserve value. |
| 1989 VisitForAccumulatorValue(prop->obj()); | 1767 VisitForAccumulatorValue(prop->obj()); |
| 1990 __ mov(edx, eax); | 1768 __ mov(edx, eax); |
| 1991 __ pop(eax); // Restore value. | 1769 __ pop(eax); // Restore value. |
| 1992 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1770 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1993 Handle<Code> ic(isolate()->builtins()->builtin( | 1771 Handle<Code> ic(isolate()->builtins()->builtin( |
| 1994 Builtins::StoreIC_Initialize)); | 1772 is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 1773 : Builtins::StoreIC_Initialize)); |
| 1995 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1774 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1996 break; | 1775 break; |
| 1997 } | 1776 } |
| 1998 case KEYED_PROPERTY: { | 1777 case KEYED_PROPERTY: { |
| 1999 __ push(eax); // Preserve value. | 1778 __ push(eax); // Preserve value. |
| 2000 VisitForStackValue(prop->obj()); | 1779 if (prop->is_synthetic()) { |
| 2001 VisitForAccumulatorValue(prop->key()); | 1780 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2002 __ mov(ecx, eax); | 1781 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2003 __ pop(edx); | 1782 { AccumulatorValueContext for_object(this); |
| 1783 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1784 } |
| 1785 __ mov(edx, eax); |
| 1786 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 1787 } else { |
| 1788 VisitForStackValue(prop->obj()); |
| 1789 VisitForAccumulatorValue(prop->key()); |
| 1790 __ mov(ecx, eax); |
| 1791 __ pop(edx); |
| 1792 } |
| 2004 __ pop(eax); // Restore value. | 1793 __ pop(eax); // Restore value. |
| 2005 Handle<Code> ic(isolate()->builtins()->builtin( | 1794 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2006 Builtins::KeyedStoreIC_Initialize)); | 1795 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1796 : Builtins::KeyedStoreIC_Initialize)); |
| 2007 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1797 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2008 break; | 1798 break; |
| 2009 } | 1799 } |
| 2010 } | 1800 } |
| 2011 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1801 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 2012 context()->Plug(eax); | 1802 context()->Plug(eax); |
| 2013 } | 1803 } |
| 2014 | 1804 |
| 2015 | 1805 |
| 2016 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1806 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2017 Token::Value op) { | 1807 Token::Value op) { |
| 2018 // Left-hand sides that rewrite to explicit property accesses do not reach | 1808 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 2019 // here. | 1809 // here. |
| 2020 ASSERT(var != NULL); | 1810 ASSERT(var != NULL); |
| 2021 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1811 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 2022 | 1812 |
| 2023 if (var->is_global()) { | 1813 if (var->is_global()) { |
| 2024 ASSERT(!var->is_this()); | 1814 ASSERT(!var->is_this()); |
| 2025 // Assignment to a global variable. Use inline caching for the | 1815 // Assignment to a global variable. Use inline caching for the |
| 2026 // assignment. Right-hand-side value is passed in eax, variable name in | 1816 // assignment. Right-hand-side value is passed in eax, variable name in |
| 2027 // ecx, and the global object on the stack. | 1817 // ecx, and the global object on the stack. |
| 2028 __ mov(ecx, var->name()); | 1818 __ mov(ecx, var->name()); |
| 2029 __ mov(edx, GlobalObjectOperand()); | 1819 __ mov(edx, GlobalObjectOperand()); |
| 2030 Handle<Code> ic(isolate()->builtins()->builtin( | 1820 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2031 Builtins::StoreIC_Initialize)); | 1821 is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 2032 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1822 : Builtins::StoreIC_Initialize)); |
| 1823 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 2033 | 1824 |
| 2034 } else if (op == Token::INIT_CONST) { | 1825 } else if (op == Token::INIT_CONST) { |
| 2035 // Like var declarations, const declarations are hoisted to function | 1826 // Like var declarations, const declarations are hoisted to function |
| 2036 // scope. However, unlike var initializers, const initializers are able | 1827 // scope. However, unlike var initializers, const initializers are able |
| 2037 // to drill a hole to that function context, even from inside a 'with' | 1828 // to drill a hole to that function context, even from inside a 'with' |
| 2038 // context. We thus bypass the normal static scope lookup. | 1829 // context. We thus bypass the normal static scope lookup. |
| 2039 Slot* slot = var->AsSlot(); | 1830 Slot* slot = var->AsSlot(); |
| 2040 Label skip; | 1831 Label skip; |
| 2041 switch (slot->type()) { | 1832 switch (slot->type()) { |
| 2042 case Slot::PARAMETER: | 1833 case Slot::PARAMETER: |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 int offset = Context::SlotOffset(slot->index()); | 1881 int offset = Context::SlotOffset(slot->index()); |
| 2091 __ RecordWrite(ecx, offset, edx, ebx); | 1882 __ RecordWrite(ecx, offset, edx, ebx); |
| 2092 break; | 1883 break; |
| 2093 } | 1884 } |
| 2094 | 1885 |
| 2095 case Slot::LOOKUP: | 1886 case Slot::LOOKUP: |
| 2096 // Call the runtime for the assignment. | 1887 // Call the runtime for the assignment. |
| 2097 __ push(eax); // Value. | 1888 __ push(eax); // Value. |
| 2098 __ push(esi); // Context. | 1889 __ push(esi); // Context. |
| 2099 __ push(Immediate(var->name())); | 1890 __ push(Immediate(var->name())); |
| 2100 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 1891 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 1892 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2101 break; | 1893 break; |
| 2102 } | 1894 } |
| 2103 } | 1895 } |
| 2104 } | 1896 } |
| 2105 | 1897 |
| 2106 | 1898 |
| 2107 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1899 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2108 // Assignment to a property, using a named store IC. | 1900 // Assignment to a property, using a named store IC. |
| 2109 Property* prop = expr->target()->AsProperty(); | 1901 Property* prop = expr->target()->AsProperty(); |
| 2110 ASSERT(prop != NULL); | 1902 ASSERT(prop != NULL); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2122 | 1914 |
| 2123 // Record source code position before IC call. | 1915 // Record source code position before IC call. |
| 2124 SetSourcePosition(expr->position()); | 1916 SetSourcePosition(expr->position()); |
| 2125 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1917 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 2126 if (expr->ends_initialization_block()) { | 1918 if (expr->ends_initialization_block()) { |
| 2127 __ mov(edx, Operand(esp, 0)); | 1919 __ mov(edx, Operand(esp, 0)); |
| 2128 } else { | 1920 } else { |
| 2129 __ pop(edx); | 1921 __ pop(edx); |
| 2130 } | 1922 } |
| 2131 Handle<Code> ic(isolate()->builtins()->builtin( | 1923 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2132 Builtins::StoreIC_Initialize)); | 1924 is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 1925 : Builtins::StoreIC_Initialize)); |
| 2133 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1926 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2134 | 1927 |
| 2135 // If the assignment ends an initialization block, revert to fast case. | 1928 // If the assignment ends an initialization block, revert to fast case. |
| 2136 if (expr->ends_initialization_block()) { | 1929 if (expr->ends_initialization_block()) { |
| 2137 __ push(eax); // Result of assignment, saved even if not needed. | 1930 __ push(eax); // Result of assignment, saved even if not needed. |
| 2138 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 1931 __ push(Operand(esp, kPointerSize)); // Receiver is under value. |
| 2139 __ CallRuntime(Runtime::kToFastProperties, 1); | 1932 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2140 __ pop(eax); | 1933 __ pop(eax); |
| 2141 __ Drop(1); | 1934 __ Drop(1); |
| 2142 } | 1935 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2161 | 1954 |
| 2162 __ pop(ecx); | 1955 __ pop(ecx); |
| 2163 if (expr->ends_initialization_block()) { | 1956 if (expr->ends_initialization_block()) { |
| 2164 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. | 1957 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. |
| 2165 } else { | 1958 } else { |
| 2166 __ pop(edx); | 1959 __ pop(edx); |
| 2167 } | 1960 } |
| 2168 // Record source code position before IC call. | 1961 // Record source code position before IC call. |
| 2169 SetSourcePosition(expr->position()); | 1962 SetSourcePosition(expr->position()); |
| 2170 Handle<Code> ic(isolate()->builtins()->builtin( | 1963 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2171 Builtins::KeyedStoreIC_Initialize)); | 1964 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1965 : Builtins::KeyedStoreIC_Initialize)); |
| 2172 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1966 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2173 | 1967 |
| 2174 // If the assignment ends an initialization block, revert to fast case. | 1968 // If the assignment ends an initialization block, revert to fast case. |
| 2175 if (expr->ends_initialization_block()) { | 1969 if (expr->ends_initialization_block()) { |
| 2176 __ pop(edx); | 1970 __ pop(edx); |
| 2177 __ push(eax); // Result of assignment, saved even if not needed. | 1971 __ push(eax); // Result of assignment, saved even if not needed. |
| 2178 __ push(edx); | 1972 __ push(edx); |
| 2179 __ CallRuntime(Runtime::kToFastProperties, 1); | 1973 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2180 __ pop(eax); | 1974 __ pop(eax); |
| 2181 } | 1975 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2276 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2070 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2277 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2071 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 2278 __ CallStub(&stub); | 2072 __ CallStub(&stub); |
| 2279 RecordJSReturnSite(expr); | 2073 RecordJSReturnSite(expr); |
| 2280 // Restore context register. | 2074 // Restore context register. |
| 2281 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2075 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2282 context()->DropAndPlug(1, eax); | 2076 context()->DropAndPlug(1, eax); |
| 2283 } | 2077 } |
| 2284 | 2078 |
| 2285 | 2079 |
| 2080 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
| 2081 int arg_count) { |
| 2082 // Push copy of the first argument or undefined if it doesn't exist. |
| 2083 if (arg_count > 0) { |
| 2084 __ push(Operand(esp, arg_count * kPointerSize)); |
| 2085 } else { |
| 2086 __ push(Immediate(FACTORY->undefined_value())); |
| 2087 } |
| 2088 |
| 2089 // Push the receiver of the enclosing function. |
| 2090 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 2091 |
| 2092 // Push the strict mode flag. |
| 2093 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 2094 |
| 2095 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2096 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| 2097 : Runtime::kResolvePossiblyDirectEval, 4); |
| 2098 } |
| 2099 |
| 2100 |
| 2286 void FullCodeGenerator::VisitCall(Call* expr) { | 2101 void FullCodeGenerator::VisitCall(Call* expr) { |
| 2287 #ifdef DEBUG | 2102 #ifdef DEBUG |
| 2288 // We want to verify that RecordJSReturnSite gets called on all paths | 2103 // We want to verify that RecordJSReturnSite gets called on all paths |
| 2289 // through this function. Avoid early returns. | 2104 // through this function. Avoid early returns. |
| 2290 expr->return_is_recorded_ = false; | 2105 expr->return_is_recorded_ = false; |
| 2291 #endif | 2106 #endif |
| 2292 | 2107 |
| 2293 Comment cmnt(masm_, "[ Call"); | 2108 Comment cmnt(masm_, "[ Call"); |
| 2294 Expression* fun = expr->expression(); | 2109 Expression* fun = expr->expression(); |
| 2295 Variable* var = fun->AsVariableProxy()->AsVariable(); | 2110 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 2296 | 2111 |
| 2297 if (var != NULL && var->is_possibly_eval()) { | 2112 if (var != NULL && var->is_possibly_eval()) { |
| 2298 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 2113 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 2299 // resolve the function we need to call and the receiver of the | 2114 // resolve the function we need to call and the receiver of the |
| 2300 // call. Then we call the resolved function using the given | 2115 // call. Then we call the resolved function using the given |
| 2301 // arguments. | 2116 // arguments. |
| 2302 ZoneList<Expression*>* args = expr->arguments(); | 2117 ZoneList<Expression*>* args = expr->arguments(); |
| 2303 int arg_count = args->length(); | 2118 int arg_count = args->length(); |
| 2304 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 2119 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
| 2305 VisitForStackValue(fun); | 2120 VisitForStackValue(fun); |
| 2306 // Reserved receiver slot. | 2121 // Reserved receiver slot. |
| 2307 __ push(Immediate(isolate()->factory()->undefined_value())); | 2122 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2308 | 2123 |
| 2309 // Push the arguments. | 2124 // Push the arguments. |
| 2310 for (int i = 0; i < arg_count; i++) { | 2125 for (int i = 0; i < arg_count; i++) { |
| 2311 VisitForStackValue(args->at(i)); | 2126 VisitForStackValue(args->at(i)); |
| 2312 } | 2127 } |
| 2313 | 2128 |
| 2314 // Push copy of the function - found below the arguments. | 2129 // If we know that eval can only be shadowed by eval-introduced |
| 2315 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); | 2130 // variables we attempt to load the global eval function directly |
| 2316 | 2131 // in generated code. If we succeed, there is no need to perform a |
| 2317 // Push copy of the first argument or undefined if it doesn't exist. | 2132 // context lookup in the runtime system. |
| 2318 if (arg_count > 0) { | 2133 Label done; |
| 2319 __ push(Operand(esp, arg_count * kPointerSize)); | 2134 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2320 } else { | 2135 Label slow; |
| 2321 __ push(Immediate(isolate()->factory()->undefined_value())); | 2136 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), |
| 2137 NOT_INSIDE_TYPEOF, |
| 2138 &slow); |
| 2139 // Push the function and resolve eval. |
| 2140 __ push(eax); |
| 2141 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
| 2142 __ jmp(&done); |
| 2143 __ bind(&slow); |
| 2322 } | 2144 } |
| 2323 | 2145 |
| 2324 // Push the receiver of the enclosing function and do runtime call. | 2146 // Push copy of the function (found below the arguments) and |
| 2325 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2147 // resolve eval. |
| 2326 // Push the strict mode flag. | 2148 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2327 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 2149 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); |
| 2328 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); | 2150 if (done.is_linked()) { |
| 2151 __ bind(&done); |
| 2152 } |
| 2329 | 2153 |
| 2330 // The runtime call returns a pair of values in eax (function) and | 2154 // The runtime call returns a pair of values in eax (function) and |
| 2331 // edx (receiver). Touch up the stack with the right values. | 2155 // edx (receiver). Touch up the stack with the right values. |
| 2332 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); | 2156 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
| 2333 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | 2157 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
| 2334 } | 2158 } |
| 2335 // Record source position for debugger. | 2159 // Record source position for debugger. |
| 2336 SetSourcePosition(expr->position()); | 2160 SetSourcePosition(expr->position()); |
| 2337 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2161 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2338 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2162 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2383 __ bind(&call); | 2207 __ bind(&call); |
| 2384 } | 2208 } |
| 2385 | 2209 |
| 2386 EmitCallWithStub(expr); | 2210 EmitCallWithStub(expr); |
| 2387 } else if (fun->AsProperty() != NULL) { | 2211 } else if (fun->AsProperty() != NULL) { |
| 2388 // Call to an object property. | 2212 // Call to an object property. |
| 2389 Property* prop = fun->AsProperty(); | 2213 Property* prop = fun->AsProperty(); |
| 2390 Literal* key = prop->key()->AsLiteral(); | 2214 Literal* key = prop->key()->AsLiteral(); |
| 2391 if (key != NULL && key->handle()->IsSymbol()) { | 2215 if (key != NULL && key->handle()->IsSymbol()) { |
| 2392 // Call to a named property, use call IC. | 2216 // Call to a named property, use call IC. |
| 2393 VisitForStackValue(prop->obj()); | 2217 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2218 VisitForStackValue(prop->obj()); |
| 2219 } |
| 2394 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2220 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2395 } else { | 2221 } else { |
| 2396 // Call to a keyed property. | 2222 // Call to a keyed property. |
| 2397 // For a synthetic property use keyed load IC followed by function call, | 2223 // For a synthetic property use keyed load IC followed by function call, |
| 2398 // for a regular property use keyed EmitCallIC. | 2224 // for a regular property use keyed EmitCallIC. |
| 2399 if (prop->is_synthetic()) { | 2225 if (prop->is_synthetic()) { |
| 2400 // Do not visit the object and key subexpressions (they are shared | 2226 // Do not visit the object and key subexpressions (they are shared |
| 2401 // by all occurrences of the same rewritten parameter). | 2227 // by all occurrences of the same rewritten parameter). |
| 2402 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 2228 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2403 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | 2229 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); |
| (...skipping 993 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3397 Immediate(String::kContainsCachedArrayIndexMask)); | 3223 Immediate(String::kContainsCachedArrayIndexMask)); |
| 3398 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3224 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3399 Split(zero, if_true, if_false, fall_through); | 3225 Split(zero, if_true, if_false, fall_through); |
| 3400 | 3226 |
| 3401 context()->Plug(if_true, if_false); | 3227 context()->Plug(if_true, if_false); |
| 3402 } | 3228 } |
| 3403 | 3229 |
| 3404 | 3230 |
| 3405 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 3231 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 3406 ASSERT(args->length() == 1); | 3232 ASSERT(args->length() == 1); |
| 3407 | |
| 3408 VisitForAccumulatorValue(args->at(0)); | 3233 VisitForAccumulatorValue(args->at(0)); |
| 3409 | 3234 |
| 3410 if (FLAG_debug_code) { | 3235 if (FLAG_debug_code) { |
| 3411 __ AbortIfNotString(eax); | 3236 __ AbortIfNotString(eax); |
| 3412 } | 3237 } |
| 3413 | 3238 |
| 3414 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); | 3239 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); |
| 3415 __ IndexFromHash(eax, eax); | 3240 __ IndexFromHash(eax, eax); |
| 3416 | 3241 |
| 3417 context()->Plug(eax); | 3242 context()->Plug(eax); |
| 3418 } | 3243 } |
| 3419 | 3244 |
| 3420 | 3245 |
| 3421 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 3246 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| 3422 Label bailout, done, one_char_separator, long_separator, | 3247 Label bailout, done, one_char_separator, long_separator, |
| 3423 non_trivial_array, not_size_one_array, loop, loop_condition, | 3248 non_trivial_array, not_size_one_array, loop, |
| 3424 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; | 3249 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; |
| 3425 | 3250 |
| 3426 ASSERT(args->length() == 2); | 3251 ASSERT(args->length() == 2); |
| 3427 // We will leave the separator on the stack until the end of the function. | 3252 // We will leave the separator on the stack until the end of the function. |
| 3428 VisitForStackValue(args->at(1)); | 3253 VisitForStackValue(args->at(1)); |
| 3429 // Load this to eax (= array) | 3254 // Load this to eax (= array) |
| 3430 VisitForAccumulatorValue(args->at(0)); | 3255 VisitForAccumulatorValue(args->at(0)); |
| 3431 // All aliases of the same register have disjoint lifetimes. | 3256 // All aliases of the same register have disjoint lifetimes. |
| 3432 Register array = eax; | 3257 Register array = eax; |
| 3433 Register elements = no_reg; // Will be eax. | 3258 Register elements = no_reg; // Will be eax. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3455 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 3280 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 3456 __ j(not_equal, &bailout); | 3281 __ j(not_equal, &bailout); |
| 3457 | 3282 |
| 3458 // Check that the array has fast elements. | 3283 // Check that the array has fast elements. |
| 3459 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 3284 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 3460 1 << Map::kHasFastElements); | 3285 1 << Map::kHasFastElements); |
| 3461 __ j(zero, &bailout); | 3286 __ j(zero, &bailout); |
| 3462 | 3287 |
| 3463 // If the array has length zero, return the empty string. | 3288 // If the array has length zero, return the empty string. |
| 3464 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); | 3289 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3465 __ sar(array_length, 1); | 3290 __ SmiUntag(array_length); |
| 3466 __ j(not_zero, &non_trivial_array); | 3291 __ j(not_zero, &non_trivial_array); |
| 3467 __ mov(result_operand, FACTORY->empty_string()); | 3292 __ mov(result_operand, FACTORY->empty_string()); |
| 3468 __ jmp(&done); | 3293 __ jmp(&done); |
| 3469 | 3294 |
| 3470 // Save the array length. | 3295 // Save the array length. |
| 3471 __ bind(&non_trivial_array); | 3296 __ bind(&non_trivial_array); |
| 3472 __ mov(array_length_operand, array_length); | 3297 __ mov(array_length_operand, array_length); |
| 3473 | 3298 |
| 3474 // Save the FixedArray containing array's elements. | 3299 // Save the FixedArray containing array's elements. |
| 3475 // End of array's live range. | 3300 // End of array's live range. |
| 3476 elements = array; | 3301 elements = array; |
| 3477 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); | 3302 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| 3478 array = no_reg; | 3303 array = no_reg; |
| 3479 | 3304 |
| 3480 | 3305 |
| 3481 // Check that all array elements are sequential ASCII strings, and | 3306 // Check that all array elements are sequential ASCII strings, and |
| 3482 // accumulate the sum of their lengths, as a smi-encoded value. | 3307 // accumulate the sum of their lengths, as a smi-encoded value. |
| 3483 __ Set(index, Immediate(0)); | 3308 __ Set(index, Immediate(0)); |
| 3484 __ Set(string_length, Immediate(0)); | 3309 __ Set(string_length, Immediate(0)); |
| 3485 // Loop condition: while (index < length). | 3310 // Loop condition: while (index < length). |
| 3486 // Live loop registers: index, array_length, string, | 3311 // Live loop registers: index, array_length, string, |
| 3487 // scratch, string_length, elements. | 3312 // scratch, string_length, elements. |
| 3488 __ jmp(&loop_condition); | 3313 if (FLAG_debug_code) { |
| 3314 __ cmp(index, Operand(array_length)); |
| 3315 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); |
| 3316 } |
| 3489 __ bind(&loop); | 3317 __ bind(&loop); |
| 3490 __ cmp(index, Operand(array_length)); | 3318 __ mov(string, FieldOperand(elements, |
| 3491 __ j(greater_equal, &done); | 3319 index, |
| 3492 | 3320 times_pointer_size, |
| 3493 __ mov(string, FieldOperand(elements, index, | 3321 FixedArray::kHeaderSize)); |
| 3494 times_pointer_size, | |
| 3495 FixedArray::kHeaderSize)); | |
| 3496 __ test(string, Immediate(kSmiTagMask)); | 3322 __ test(string, Immediate(kSmiTagMask)); |
| 3497 __ j(zero, &bailout); | 3323 __ j(zero, &bailout); |
| 3498 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3324 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3499 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3325 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3500 __ and_(scratch, Immediate( | 3326 __ and_(scratch, Immediate( |
| 3501 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3327 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3502 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3328 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 3503 __ j(not_equal, &bailout); | 3329 __ j(not_equal, &bailout); |
| 3504 __ add(string_length, | 3330 __ add(string_length, |
| 3505 FieldOperand(string, SeqAsciiString::kLengthOffset)); | 3331 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
| 3506 __ j(overflow, &bailout); | 3332 __ j(overflow, &bailout); |
| 3507 __ add(Operand(index), Immediate(1)); | 3333 __ add(Operand(index), Immediate(1)); |
| 3508 __ bind(&loop_condition); | |
| 3509 __ cmp(index, Operand(array_length)); | 3334 __ cmp(index, Operand(array_length)); |
| 3510 __ j(less, &loop); | 3335 __ j(less, &loop); |
| 3511 | 3336 |
| 3512 // If array_length is 1, return elements[0], a string. | 3337 // If array_length is 1, return elements[0], a string. |
| 3513 __ cmp(array_length, 1); | 3338 __ cmp(array_length, 1); |
| 3514 __ j(not_equal, ¬_size_one_array); | 3339 __ j(not_equal, ¬_size_one_array); |
| 3515 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); | 3340 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); |
| 3516 __ mov(result_operand, scratch); | 3341 __ mov(result_operand, scratch); |
| 3517 __ jmp(&done); | 3342 __ jmp(&done); |
| 3518 | 3343 |
| 3519 __ bind(¬_size_one_array); | 3344 __ bind(¬_size_one_array); |
| 3520 | 3345 |
| 3521 // End of array_length live range. | 3346 // End of array_length live range. |
| 3522 result_pos = array_length; | 3347 result_pos = array_length; |
| 3523 array_length = no_reg; | 3348 array_length = no_reg; |
| 3524 | 3349 |
| 3525 // Live registers: | 3350 // Live registers: |
| 3526 // string_length: Sum of string lengths, as a smi. | 3351 // string_length: Sum of string lengths, as a smi. |
| 3527 // elements: FixedArray of strings. | 3352 // elements: FixedArray of strings. |
| 3528 | 3353 |
| 3529 // Check that the separator is a flat ASCII string. | 3354 // Check that the separator is a flat ASCII string. |
| 3530 __ mov(string, separator_operand); | 3355 __ mov(string, separator_operand); |
| 3531 __ test(string, Immediate(kSmiTagMask)); | 3356 __ test(string, Immediate(kSmiTagMask)); |
| 3532 __ j(zero, &bailout); | 3357 __ j(zero, &bailout); |
| 3533 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3358 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3534 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3359 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3535 __ and_(scratch, Immediate( | 3360 __ and_(scratch, Immediate( |
| 3536 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3361 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3537 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3362 __ cmp(scratch, ASCII_STRING_TYPE); |
| 3538 __ j(not_equal, &bailout); | 3363 __ j(not_equal, &bailout); |
| 3539 | 3364 |
| 3540 // Add (separator length times array_length) - separator length | 3365 // Add (separator length times array_length) - separator length |
| 3541 // to string_length. | 3366 // to string_length. |
| 3542 __ mov(scratch, separator_operand); | 3367 __ mov(scratch, separator_operand); |
| 3543 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); | 3368 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
| 3544 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. | 3369 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. |
| 3545 __ imul(scratch, array_length_operand); | 3370 __ imul(scratch, array_length_operand); |
| 3546 __ j(overflow, &bailout); | 3371 __ j(overflow, &bailout); |
| 3547 __ add(string_length, Operand(scratch)); | 3372 __ add(string_length, Operand(scratch)); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3725 context()->Plug(eax); | 3550 context()->Plug(eax); |
| 3726 } | 3551 } |
| 3727 | 3552 |
| 3728 | 3553 |
| 3729 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3554 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 3730 switch (expr->op()) { | 3555 switch (expr->op()) { |
| 3731 case Token::DELETE: { | 3556 case Token::DELETE: { |
| 3732 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3557 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 3733 Property* prop = expr->expression()->AsProperty(); | 3558 Property* prop = expr->expression()->AsProperty(); |
| 3734 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3559 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 3735 if (prop == NULL && var == NULL) { | 3560 |
| 3561 if (prop != NULL) { |
| 3562 if (prop->is_synthetic()) { |
| 3563 // Result of deleting parameters is false, even when they rewrite |
| 3564 // to accesses on the arguments object. |
| 3565 context()->Plug(false); |
| 3566 } else { |
| 3567 VisitForStackValue(prop->obj()); |
| 3568 VisitForStackValue(prop->key()); |
| 3569 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 3570 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3571 context()->Plug(eax); |
| 3572 } |
| 3573 } else if (var != NULL) { |
| 3574 // Delete of an unqualified identifier is disallowed in strict mode |
| 3575 // but "delete this" is. |
| 3576 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3577 if (var->is_global()) { |
| 3578 __ push(GlobalObjectOperand()); |
| 3579 __ push(Immediate(var->name())); |
| 3580 __ push(Immediate(Smi::FromInt(kNonStrictMode))); |
| 3581 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3582 context()->Plug(eax); |
| 3583 } else if (var->AsSlot() != NULL && |
| 3584 var->AsSlot()->type() != Slot::LOOKUP) { |
| 3585 // Result of deleting non-global, non-dynamic variables is false. |
| 3586 // The subexpression does not have side effects. |
| 3587 context()->Plug(false); |
| 3588 } else { |
| 3589 // Non-global variable. Call the runtime to try to delete from the |
| 3590 // context where the variable was introduced. |
| 3591 __ push(context_register()); |
| 3592 __ push(Immediate(var->name())); |
| 3593 __ CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 3594 context()->Plug(eax); |
| 3595 } |
| 3596 } else { |
| 3736 // Result of deleting non-property, non-variable reference is true. | 3597 // Result of deleting non-property, non-variable reference is true. |
| 3737 // The subexpression may have side effects. | 3598 // The subexpression may have side effects. |
| 3738 VisitForEffect(expr->expression()); | 3599 VisitForEffect(expr->expression()); |
| 3739 context()->Plug(true); | 3600 context()->Plug(true); |
| 3740 } else if (var != NULL && | |
| 3741 !var->is_global() && | |
| 3742 var->AsSlot() != NULL && | |
| 3743 var->AsSlot()->type() != Slot::LOOKUP) { | |
| 3744 // Result of deleting non-global, non-dynamic variables is false. | |
| 3745 // The subexpression does not have side effects. | |
| 3746 context()->Plug(false); | |
| 3747 } else { | |
| 3748 // Property or variable reference. Call the delete builtin with | |
| 3749 // object and property name as arguments. | |
| 3750 if (prop != NULL) { | |
| 3751 VisitForStackValue(prop->obj()); | |
| 3752 VisitForStackValue(prop->key()); | |
| 3753 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
| 3754 } else if (var->is_global()) { | |
| 3755 __ push(GlobalObjectOperand()); | |
| 3756 __ push(Immediate(var->name())); | |
| 3757 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
| 3758 } else { | |
| 3759 // Non-global variable. Call the runtime to delete from the | |
| 3760 // context where the variable was introduced. | |
| 3761 __ push(context_register()); | |
| 3762 __ push(Immediate(var->name())); | |
| 3763 __ CallRuntime(Runtime::kDeleteContextSlot, 2); | |
| 3764 } | |
| 3765 context()->Plug(eax); | |
| 3766 } | 3601 } |
| 3767 break; | 3602 break; |
| 3768 } | 3603 } |
| 3769 | 3604 |
| 3770 case Token::VOID: { | 3605 case Token::VOID: { |
| 3771 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 3606 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 3772 VisitForEffect(expr->expression()); | 3607 VisitForEffect(expr->expression()); |
| 3773 context()->Plug(isolate()->factory()->undefined_value()); | 3608 context()->Plug(isolate()->factory()->undefined_value()); |
| 3774 break; | 3609 break; |
| 3775 } | 3610 } |
| 3776 | 3611 |
| 3777 case Token::NOT: { | 3612 case Token::NOT: { |
| 3778 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3613 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 3614 if (context()->IsEffect()) { |
| 3615 // Unary NOT has no side effects so it's only necessary to visit the |
| 3616 // subexpression. Match the optimizing compiler by not branching. |
| 3617 VisitForEffect(expr->expression()); |
| 3618 } else { |
| 3619 Label materialize_true, materialize_false; |
| 3620 Label* if_true = NULL; |
| 3621 Label* if_false = NULL; |
| 3622 Label* fall_through = NULL; |
| 3779 | 3623 |
| 3780 Label materialize_true, materialize_false; | 3624 // Notice that the labels are swapped. |
| 3781 Label* if_true = NULL; | 3625 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3782 Label* if_false = NULL; | 3626 &if_false, &if_true, &fall_through); |
| 3783 Label* fall_through = NULL; | 3627 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 3784 // Notice that the labels are swapped. | 3628 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 3785 context()->PrepareTest(&materialize_true, &materialize_false, | 3629 context()->Plug(if_false, if_true); // Labels swapped. |
| 3786 &if_false, &if_true, &fall_through); | 3630 } |
| 3787 if (context()->IsTest()) ForwardBailoutToChild(expr); | |
| 3788 VisitForControl(expr->expression(), if_true, if_false, fall_through); | |
| 3789 context()->Plug(if_false, if_true); // Labels swapped. | |
| 3790 break; | 3631 break; |
| 3791 } | 3632 } |
| 3792 | 3633 |
| 3793 case Token::TYPEOF: { | 3634 case Token::TYPEOF: { |
| 3794 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3635 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 3795 { StackValueContext context(this); | 3636 { StackValueContext context(this); |
| 3796 VisitForTypeofValue(expr->expression()); | 3637 VisitForTypeofValue(expr->expression()); |
| 3797 } | 3638 } |
| 3798 __ CallRuntime(Runtime::kTypeof, 1); | 3639 __ CallRuntime(Runtime::kTypeof, 1); |
| 3799 context()->Plug(eax); | 3640 context()->Plug(eax); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4006 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3847 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4007 Token::ASSIGN); | 3848 Token::ASSIGN); |
| 4008 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3849 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4009 context()->Plug(eax); | 3850 context()->Plug(eax); |
| 4010 } | 3851 } |
| 4011 break; | 3852 break; |
| 4012 case NAMED_PROPERTY: { | 3853 case NAMED_PROPERTY: { |
| 4013 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 3854 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 4014 __ pop(edx); | 3855 __ pop(edx); |
| 4015 Handle<Code> ic(isolate()->builtins()->builtin( | 3856 Handle<Code> ic(isolate()->builtins()->builtin( |
| 4016 Builtins::StoreIC_Initialize)); | 3857 is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 3858 : Builtins::StoreIC_Initialize)); |
| 4017 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3859 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 4018 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3860 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4019 if (expr->is_postfix()) { | 3861 if (expr->is_postfix()) { |
| 4020 if (!context()->IsEffect()) { | 3862 if (!context()->IsEffect()) { |
| 4021 context()->PlugTOS(); | 3863 context()->PlugTOS(); |
| 4022 } | 3864 } |
| 4023 } else { | 3865 } else { |
| 4024 context()->Plug(eax); | 3866 context()->Plug(eax); |
| 4025 } | 3867 } |
| 4026 break; | 3868 break; |
| 4027 } | 3869 } |
| 4028 case KEYED_PROPERTY: { | 3870 case KEYED_PROPERTY: { |
| 4029 __ pop(ecx); | 3871 __ pop(ecx); |
| 4030 __ pop(edx); | 3872 __ pop(edx); |
| 4031 Handle<Code> ic(isolate()->builtins()->builtin( | 3873 Handle<Code> ic(isolate()->builtins()->builtin( |
| 4032 Builtins::KeyedStoreIC_Initialize)); | 3874 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 3875 : Builtins::KeyedStoreIC_Initialize)); |
| 4033 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3876 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 4034 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3877 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4035 if (expr->is_postfix()) { | 3878 if (expr->is_postfix()) { |
| 4036 // Result is on the stack | 3879 // Result is on the stack |
| 4037 if (!context()->IsEffect()) { | 3880 if (!context()->IsEffect()) { |
| 4038 context()->PlugTOS(); | 3881 context()->PlugTOS(); |
| 4039 } | 3882 } |
| 4040 } else { | 3883 } else { |
| 4041 context()->Plug(eax); | 3884 context()->Plug(eax); |
| 4042 } | 3885 } |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4371 __ nop(); // Signals no inlined code. | 4214 __ nop(); // Signals no inlined code. |
| 4372 break; | 4215 break; |
| 4373 default: | 4216 default: |
| 4374 // Do nothing. | 4217 // Do nothing. |
| 4375 break; | 4218 break; |
| 4376 } | 4219 } |
| 4377 } | 4220 } |
| 4378 | 4221 |
| 4379 | 4222 |
| 4380 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { | 4223 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { |
| 4224 switch (ic->kind()) { |
| 4225 case Code::LOAD_IC: |
| 4226 __ IncrementCounter(COUNTERS->named_load_full(), 1); |
| 4227 break; |
| 4228 case Code::KEYED_LOAD_IC: |
| 4229 __ IncrementCounter(COUNTERS->keyed_load_full(), 1); |
| 4230 break; |
| 4231 case Code::STORE_IC: |
| 4232 __ IncrementCounter(COUNTERS->named_store_full(), 1); |
| 4233 break; |
| 4234 case Code::KEYED_STORE_IC: |
| 4235 __ IncrementCounter(COUNTERS->keyed_store_full(), 1); |
| 4236 default: |
| 4237 break; |
| 4238 } |
| 4239 |
| 4381 __ call(ic, RelocInfo::CODE_TARGET); | 4240 __ call(ic, RelocInfo::CODE_TARGET); |
| 4382 if (patch_site != NULL && patch_site->is_bound()) { | 4241 if (patch_site != NULL && patch_site->is_bound()) { |
| 4383 patch_site->EmitPatchInfo(); | 4242 patch_site->EmitPatchInfo(); |
| 4384 } else { | 4243 } else { |
| 4385 __ nop(); // Signals no inlined code. | 4244 __ nop(); // Signals no inlined code. |
| 4386 } | 4245 } |
| 4387 } | 4246 } |
| 4388 | 4247 |
| 4389 | 4248 |
| 4390 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 4249 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4427 // And return. | 4286 // And return. |
| 4428 __ ret(0); | 4287 __ ret(0); |
| 4429 } | 4288 } |
| 4430 | 4289 |
| 4431 | 4290 |
| 4432 #undef __ | 4291 #undef __ |
| 4433 | 4292 |
| 4434 } } // namespace v8::internal | 4293 } } // namespace v8::internal |
| 4435 | 4294 |
| 4436 #endif // V8_TARGET_ARCH_IA32 | 4295 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |