| 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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 __ lea(edx, | 192 __ lea(edx, |
| 193 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); | 193 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); |
| 194 __ push(edx); | 194 __ push(edx); |
| 195 __ push(Immediate(Smi::FromInt(scope()->num_parameters()))); | 195 __ push(Immediate(Smi::FromInt(scope()->num_parameters()))); |
| 196 // Arguments to ArgumentsAccessStub: | 196 // Arguments to ArgumentsAccessStub: |
| 197 // function, receiver address, parameter count. | 197 // function, receiver address, parameter count. |
| 198 // The stub will rewrite receiver and parameter count if the previous | 198 // The stub will rewrite receiver and parameter count if the previous |
| 199 // stack frame was an arguments adapter frame. | 199 // stack frame was an arguments adapter frame. |
| 200 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 200 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 201 __ CallStub(&stub); | 201 __ CallStub(&stub); |
| 202 __ mov(ecx, eax); // Duplicate result. | 202 |
| 203 Variable* arguments_shadow = scope()->arguments_shadow(); |
| 204 if (arguments_shadow != NULL) { |
| 205 __ mov(ecx, eax); // Duplicate result. |
| 206 Move(arguments_shadow->AsSlot(), ecx, ebx, edx); |
| 207 } |
| 203 Move(arguments->AsSlot(), eax, ebx, edx); | 208 Move(arguments->AsSlot(), eax, ebx, edx); |
| 204 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); | |
| 205 Move(dot_arguments_slot, ecx, ebx, edx); | |
| 206 } | 209 } |
| 207 | 210 |
| 208 if (FLAG_trace) { | 211 if (FLAG_trace) { |
| 209 __ CallRuntime(Runtime::kTraceEnter, 0); | 212 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 210 } | 213 } |
| 211 | 214 |
| 212 // Visit the declarations and body unless there is an illegal | 215 // Visit the declarations and body unless there is an illegal |
| 213 // redeclaration. | 216 // redeclaration. |
| 214 if (scope()->HasIllegalRedeclaration()) { | 217 if (scope()->HasIllegalRedeclaration()) { |
| 215 Comment cmnt(masm_, "[ Declarations"); | 218 Comment cmnt(masm_, "[ Declarations"); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 #ifdef ENABLE_DEBUGGER_SUPPORT | 318 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 316 // Check that the size of the code used for returning is large enough | 319 // Check that the size of the code used for returning is large enough |
| 317 // for the debugger's requirements. | 320 // for the debugger's requirements. |
| 318 ASSERT(Assembler::kJSReturnSequenceLength <= | 321 ASSERT(Assembler::kJSReturnSequenceLength <= |
| 319 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 322 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 320 #endif | 323 #endif |
| 321 } | 324 } |
| 322 } | 325 } |
| 323 | 326 |
| 324 | 327 |
| 325 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | |
| 326 Token::Value op, Expression* left, Expression* right) { | |
| 327 ASSERT(ShouldInlineSmiCase(op)); | |
| 328 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) { | |
| 329 // We never generate inlined constant smi operations for these. | |
| 330 return kNoConstants; | |
| 331 } else if (right->IsSmiLiteral()) { | |
| 332 return kRightConstant; | |
| 333 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) { | |
| 334 return kLeftConstant; | |
| 335 } else { | |
| 336 return kNoConstants; | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 | |
| 341 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { | 328 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { |
| 342 } | 329 } |
| 343 | 330 |
| 344 | 331 |
| 345 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { | 332 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { |
| 346 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 333 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 347 __ mov(result_register(), slot_operand); | 334 __ mov(result_register(), slot_operand); |
| 348 } | 335 } |
| 349 | 336 |
| 350 | 337 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 void FullCodeGenerator::DoTest(Label* if_true, | 527 void FullCodeGenerator::DoTest(Label* if_true, |
| 541 Label* if_false, | 528 Label* if_false, |
| 542 Label* fall_through) { | 529 Label* fall_through) { |
| 543 // Emit the inlined tests assumed by the stub. | 530 // Emit the inlined tests assumed by the stub. |
| 544 __ cmp(result_register(), Factory::undefined_value()); | 531 __ cmp(result_register(), Factory::undefined_value()); |
| 545 __ j(equal, if_false); | 532 __ j(equal, if_false); |
| 546 __ cmp(result_register(), Factory::true_value()); | 533 __ cmp(result_register(), Factory::true_value()); |
| 547 __ j(equal, if_true); | 534 __ j(equal, if_true); |
| 548 __ cmp(result_register(), Factory::false_value()); | 535 __ cmp(result_register(), Factory::false_value()); |
| 549 __ j(equal, if_false); | 536 __ j(equal, if_false); |
| 550 ASSERT_EQ(0, kSmiTag); | 537 STATIC_ASSERT(kSmiTag == 0); |
| 551 __ test(result_register(), Operand(result_register())); | 538 __ test(result_register(), Operand(result_register())); |
| 552 __ j(zero, if_false); | 539 __ j(zero, if_false); |
| 553 __ test(result_register(), Immediate(kSmiTagMask)); | 540 __ test(result_register(), Immediate(kSmiTagMask)); |
| 554 __ j(zero, if_true); | 541 __ j(zero, if_true); |
| 555 | 542 |
| 556 // Call the ToBoolean stub for all other cases. | 543 // Call the ToBoolean stub for all other cases. |
| 557 ToBooleanStub stub; | 544 ToBooleanStub stub; |
| 558 __ push(result_register()); | 545 __ push(result_register()); |
| 559 __ CallStub(&stub); | 546 __ CallStub(&stub); |
| 560 __ test(eax, Operand(eax)); | 547 __ test(eax, Operand(eax)); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 } | 635 } |
| 649 | 636 |
| 650 | 637 |
| 651 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 638 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 652 Variable::Mode mode, | 639 Variable::Mode mode, |
| 653 FunctionLiteral* function) { | 640 FunctionLiteral* function) { |
| 654 Comment cmnt(masm_, "[ Declaration"); | 641 Comment cmnt(masm_, "[ Declaration"); |
| 655 ASSERT(variable != NULL); // Must have been resolved. | 642 ASSERT(variable != NULL); // Must have been resolved. |
| 656 Slot* slot = variable->AsSlot(); | 643 Slot* slot = variable->AsSlot(); |
| 657 Property* prop = variable->AsProperty(); | 644 Property* prop = variable->AsProperty(); |
| 645 |
| 658 if (slot != NULL) { | 646 if (slot != NULL) { |
| 659 switch (slot->type()) { | 647 switch (slot->type()) { |
| 660 case Slot::PARAMETER: | 648 case Slot::PARAMETER: |
| 661 case Slot::LOCAL: | 649 case Slot::LOCAL: |
| 662 if (mode == Variable::CONST) { | 650 if (mode == Variable::CONST) { |
| 663 __ mov(Operand(ebp, SlotOffset(slot)), | 651 __ mov(Operand(ebp, SlotOffset(slot)), |
| 664 Immediate(Factory::the_hole_value())); | 652 Immediate(Factory::the_hole_value())); |
| 665 } else if (function != NULL) { | 653 } else if (function != NULL) { |
| 666 VisitForAccumulatorValue(function); | 654 VisitForAccumulatorValue(function); |
| 667 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 655 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 VisitForAccumulatorValue(function); | 721 VisitForAccumulatorValue(function); |
| 734 __ pop(edx); | 722 __ pop(edx); |
| 735 } else { | 723 } else { |
| 736 __ mov(edx, eax); | 724 __ mov(edx, eax); |
| 737 __ mov(eax, Factory::the_hole_value()); | 725 __ mov(eax, Factory::the_hole_value()); |
| 738 } | 726 } |
| 739 ASSERT(prop->key()->AsLiteral() != NULL && | 727 ASSERT(prop->key()->AsLiteral() != NULL && |
| 740 prop->key()->AsLiteral()->handle()->IsSmi()); | 728 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 741 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 729 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 742 | 730 |
| 743 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 731 Handle<Code> ic(Builtins::builtin( |
| 732 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 733 : Builtins::KeyedStoreIC_Initialize)); |
| 744 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 734 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 745 } | 735 } |
| 746 } | 736 } |
| 747 } | 737 } |
| 748 | 738 |
| 749 | 739 |
| 750 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 740 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 751 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 741 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 752 } | 742 } |
| 753 | 743 |
| 754 | 744 |
| 755 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 745 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 756 // Call the runtime to declare the globals. | 746 // Call the runtime to declare the globals. |
| 757 __ push(esi); // The context is the first argument. | 747 __ push(esi); // The context is the first argument. |
| 758 __ push(Immediate(pairs)); | 748 __ push(Immediate(pairs)); |
| 759 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 749 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 760 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 750 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 751 __ CallRuntime(Runtime::kDeclareGlobals, 4); |
| 761 // Return value is ignored. | 752 // Return value is ignored. |
| 762 } | 753 } |
| 763 | 754 |
| 764 | 755 |
| 765 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 756 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 766 Comment cmnt(masm_, "[ SwitchStatement"); | 757 Comment cmnt(masm_, "[ SwitchStatement"); |
| 767 Breakable nested_statement(this, stmt); | 758 Breakable nested_statement(this, stmt); |
| 768 SetStatementPosition(stmt); | 759 SetStatementPosition(stmt); |
| 769 | 760 |
| 770 // Keep the switch value on the stack until a case matches. | 761 // Keep the switch value on the stack until a case matches. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 __ j(not_equal, &next_test); | 798 __ j(not_equal, &next_test); |
| 808 __ Drop(1); // Switch value is no longer needed. | 799 __ Drop(1); // Switch value is no longer needed. |
| 809 __ jmp(clause->body_target()->entry_label()); | 800 __ jmp(clause->body_target()->entry_label()); |
| 810 __ bind(&slow_case); | 801 __ bind(&slow_case); |
| 811 } | 802 } |
| 812 | 803 |
| 813 // Record position before stub call for type feedback. | 804 // Record position before stub call for type feedback. |
| 814 SetSourcePosition(clause->position()); | 805 SetSourcePosition(clause->position()); |
| 815 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 806 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
| 816 EmitCallIC(ic, &patch_site); | 807 EmitCallIC(ic, &patch_site); |
| 817 | |
| 818 __ test(eax, Operand(eax)); | 808 __ test(eax, Operand(eax)); |
| 819 __ j(not_equal, &next_test); | 809 __ j(not_equal, &next_test); |
| 820 __ Drop(1); // Switch value is no longer needed. | 810 __ Drop(1); // Switch value is no longer needed. |
| 821 __ jmp(clause->body_target()->entry_label()); | 811 __ jmp(clause->body_target()->entry_label()); |
| 822 } | 812 } |
| 823 | 813 |
| 824 // Discard the test value and jump to the default if present, otherwise to | 814 // Discard the test value and jump to the default if present, otherwise to |
| 825 // the end of the statement. | 815 // the end of the statement. |
| 826 __ bind(&next_test); | 816 __ bind(&next_test); |
| 827 __ Drop(1); // Switch value is no longer needed. | 817 __ Drop(1); // Switch value is no longer needed. |
| 828 if (default_clause == NULL) { | 818 if (default_clause == NULL) { |
| 829 __ jmp(nested_statement.break_target()); | 819 __ jmp(nested_statement.break_target()); |
| 830 } else { | 820 } else { |
| 831 __ jmp(default_clause->body_target()->entry_label()); | 821 __ jmp(default_clause->body_target()->entry_label()); |
| 832 } | 822 } |
| 833 | 823 |
| 834 // Compile all the case bodies. | 824 // Compile all the case bodies. |
| 835 for (int i = 0; i < clauses->length(); i++) { | 825 for (int i = 0; i < clauses->length(); i++) { |
| 836 Comment cmnt(masm_, "[ Case body"); | 826 Comment cmnt(masm_, "[ Case body"); |
| 837 CaseClause* clause = clauses->at(i); | 827 CaseClause* clause = clauses->at(i); |
| 838 __ bind(clause->body_target()->entry_label()); | 828 __ bind(clause->body_target()->entry_label()); |
| 829 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); |
| 839 VisitStatements(clause->statements()); | 830 VisitStatements(clause->statements()); |
| 840 } | 831 } |
| 841 | 832 |
| 842 __ bind(nested_statement.break_target()); | 833 __ bind(nested_statement.break_target()); |
| 843 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 834 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 844 } | 835 } |
| 845 | 836 |
| 846 | 837 |
| 847 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 838 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 848 Comment cmnt(masm_, "[ ForInStatement"); | 839 Comment cmnt(masm_, "[ ForInStatement"); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 __ j(not_equal, &call_runtime); | 879 __ j(not_equal, &call_runtime); |
| 889 | 880 |
| 890 // Check that instance descriptors are not empty so that we can | 881 // Check that instance descriptors are not empty so that we can |
| 891 // check for an enum cache. Leave the map in ebx for the subsequent | 882 // check for an enum cache. Leave the map in ebx for the subsequent |
| 892 // prototype load. | 883 // prototype load. |
| 893 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | 884 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 894 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); | 885 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); |
| 895 __ cmp(edx, Factory::empty_descriptor_array()); | 886 __ cmp(edx, Factory::empty_descriptor_array()); |
| 896 __ j(equal, &call_runtime); | 887 __ j(equal, &call_runtime); |
| 897 | 888 |
| 898 // Check that there in an enum cache in the non-empty instance | 889 // Check that there is an enum cache in the non-empty instance |
| 899 // descriptors (edx). This is the case if the next enumeration | 890 // descriptors (edx). This is the case if the next enumeration |
| 900 // index field does not contain a smi. | 891 // index field does not contain a smi. |
| 901 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 892 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 902 __ test(edx, Immediate(kSmiTagMask)); | 893 __ test(edx, Immediate(kSmiTagMask)); |
| 903 __ j(zero, &call_runtime); | 894 __ j(zero, &call_runtime); |
| 904 | 895 |
| 905 // For all objects but the receiver, check that the cache is empty. | 896 // For all objects but the receiver, check that the cache is empty. |
| 906 NearLabel check_prototype; | 897 NearLabel check_prototype; |
| 907 __ cmp(ecx, Operand(eax)); | 898 __ cmp(ecx, Operand(eax)); |
| 908 __ j(equal, &check_prototype); | 899 __ j(equal, &check_prototype); |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 switch (property->kind()) { | 1364 switch (property->kind()) { |
| 1374 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1365 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1375 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1366 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1376 // Fall through. | 1367 // Fall through. |
| 1377 case ObjectLiteral::Property::COMPUTED: | 1368 case ObjectLiteral::Property::COMPUTED: |
| 1378 if (key->handle()->IsSymbol()) { | 1369 if (key->handle()->IsSymbol()) { |
| 1379 if (property->emit_store()) { | 1370 if (property->emit_store()) { |
| 1380 VisitForAccumulatorValue(value); | 1371 VisitForAccumulatorValue(value); |
| 1381 __ mov(ecx, Immediate(key->handle())); | 1372 __ mov(ecx, Immediate(key->handle())); |
| 1382 __ mov(edx, Operand(esp, 0)); | 1373 __ mov(edx, Operand(esp, 0)); |
| 1383 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1374 Handle<Code> ic(Builtins::builtin( |
| 1375 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1376 : Builtins::StoreIC_Initialize)); |
| 1384 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1377 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1385 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1378 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1386 } else { | 1379 } else { |
| 1387 VisitForEffect(value); | 1380 VisitForEffect(value); |
| 1388 } | 1381 } |
| 1389 break; | 1382 break; |
| 1390 } | 1383 } |
| 1391 // Fall through. | 1384 // Fall through. |
| 1392 case ObjectLiteral::Property::PROTOTYPE: | 1385 case ObjectLiteral::Property::PROTOTYPE: |
| 1393 __ push(Operand(esp, 0)); // Duplicate receiver. | 1386 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1394 VisitForStackValue(key); | 1387 VisitForStackValue(key); |
| 1395 VisitForStackValue(value); | 1388 VisitForStackValue(value); |
| 1396 if (property->emit_store()) { | 1389 if (property->emit_store()) { |
| 1397 __ CallRuntime(Runtime::kSetProperty, 3); | 1390 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes |
| 1391 __ CallRuntime(Runtime::kSetProperty, 4); |
| 1398 } else { | 1392 } else { |
| 1399 __ Drop(3); | 1393 __ Drop(3); |
| 1400 } | 1394 } |
| 1401 break; | 1395 break; |
| 1402 case ObjectLiteral::Property::SETTER: | 1396 case ObjectLiteral::Property::SETTER: |
| 1403 case ObjectLiteral::Property::GETTER: | 1397 case ObjectLiteral::Property::GETTER: |
| 1404 __ push(Operand(esp, 0)); // Duplicate receiver. | 1398 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1405 VisitForStackValue(key); | 1399 VisitForStackValue(key); |
| 1406 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 1400 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
| 1407 Smi::FromInt(1) : | 1401 Smi::FromInt(1) : |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1565 } | 1559 } |
| 1566 } | 1560 } |
| 1567 | 1561 |
| 1568 // For property compound assignments we need another deoptimization | 1562 // For property compound assignments we need another deoptimization |
| 1569 // point after the property load. | 1563 // point after the property load. |
| 1570 if (property != NULL) { | 1564 if (property != NULL) { |
| 1571 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); | 1565 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1572 } | 1566 } |
| 1573 | 1567 |
| 1574 Token::Value op = expr->binary_op(); | 1568 Token::Value op = expr->binary_op(); |
| 1575 ConstantOperand constant = ShouldInlineSmiCase(op) | 1569 __ push(eax); // Left operand goes on the stack. |
| 1576 ? GetConstantOperand(op, expr->target(), expr->value()) | 1570 VisitForAccumulatorValue(expr->value()); |
| 1577 : kNoConstants; | |
| 1578 ASSERT(constant == kRightConstant || constant == kNoConstants); | |
| 1579 if (constant == kNoConstants) { | |
| 1580 __ push(eax); // Left operand goes on the stack. | |
| 1581 VisitForAccumulatorValue(expr->value()); | |
| 1582 } | |
| 1583 | 1571 |
| 1584 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1572 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1585 ? OVERWRITE_RIGHT | 1573 ? OVERWRITE_RIGHT |
| 1586 : NO_OVERWRITE; | 1574 : NO_OVERWRITE; |
| 1587 SetSourcePosition(expr->position() + 1); | 1575 SetSourcePosition(expr->position() + 1); |
| 1588 AccumulatorValueContext context(this); | 1576 AccumulatorValueContext context(this); |
| 1589 if (ShouldInlineSmiCase(op)) { | 1577 if (ShouldInlineSmiCase(op)) { |
| 1590 EmitInlineSmiBinaryOp(expr, | 1578 EmitInlineSmiBinaryOp(expr, |
| 1591 op, | 1579 op, |
| 1592 mode, | 1580 mode, |
| 1593 expr->target(), | 1581 expr->target(), |
| 1594 expr->value(), | 1582 expr->value()); |
| 1595 constant); | |
| 1596 } else { | 1583 } else { |
| 1597 EmitBinaryOp(op, mode); | 1584 EmitBinaryOp(op, mode); |
| 1598 } | 1585 } |
| 1599 | 1586 |
| 1600 // Deoptimization point in case the binary operation may have side effects. | 1587 // Deoptimization point in case the binary operation may have side effects. |
| 1601 PrepareForBailout(expr->binary_operation(), TOS_REG); | 1588 PrepareForBailout(expr->binary_operation(), TOS_REG); |
| 1602 } else { | 1589 } else { |
| 1603 VisitForAccumulatorValue(expr->value()); | 1590 VisitForAccumulatorValue(expr->value()); |
| 1604 } | 1591 } |
| 1605 | 1592 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1633 } | 1620 } |
| 1634 | 1621 |
| 1635 | 1622 |
| 1636 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1623 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1637 SetSourcePosition(prop->position()); | 1624 SetSourcePosition(prop->position()); |
| 1638 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1625 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1639 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1626 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1640 } | 1627 } |
| 1641 | 1628 |
| 1642 | 1629 |
| 1643 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, | |
| 1644 OverwriteMode mode, | |
| 1645 bool left_is_constant_smi, | |
| 1646 Smi* value) { | |
| 1647 NearLabel call_stub, done; | |
| 1648 __ add(Operand(eax), Immediate(value)); | |
| 1649 __ j(overflow, &call_stub); | |
| 1650 JumpPatchSite patch_site(masm_); | |
| 1651 patch_site.EmitJumpIfSmi(eax, &done); | |
| 1652 | |
| 1653 // Undo the optimistic add operation and call the shared stub. | |
| 1654 __ bind(&call_stub); | |
| 1655 __ sub(Operand(eax), Immediate(value)); | |
| 1656 Token::Value op = Token::ADD; | |
| 1657 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1658 if (left_is_constant_smi) { | |
| 1659 __ mov(edx, Immediate(value)); | |
| 1660 } else { | |
| 1661 __ mov(edx, eax); | |
| 1662 __ mov(eax, Immediate(value)); | |
| 1663 } | |
| 1664 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1665 | |
| 1666 __ bind(&done); | |
| 1667 context()->Plug(eax); | |
| 1668 } | |
| 1669 | |
| 1670 | |
| 1671 void FullCodeGenerator::EmitConstantSmiSub(Expression* expr, | |
| 1672 OverwriteMode mode, | |
| 1673 bool left_is_constant_smi, | |
| 1674 Smi* value) { | |
| 1675 NearLabel call_stub, done; | |
| 1676 if (left_is_constant_smi) { | |
| 1677 __ mov(ecx, eax); | |
| 1678 __ mov(eax, Immediate(value)); | |
| 1679 __ sub(Operand(eax), ecx); | |
| 1680 } else { | |
| 1681 __ sub(Operand(eax), Immediate(value)); | |
| 1682 } | |
| 1683 __ j(overflow, &call_stub); | |
| 1684 JumpPatchSite patch_site(masm_); | |
| 1685 patch_site.EmitJumpIfSmi(eax, &done); | |
| 1686 | |
| 1687 __ bind(&call_stub); | |
| 1688 if (left_is_constant_smi) { | |
| 1689 __ mov(edx, Immediate(value)); | |
| 1690 __ mov(eax, ecx); | |
| 1691 } else { | |
| 1692 __ add(Operand(eax), Immediate(value)); // Undo the subtraction. | |
| 1693 __ mov(edx, eax); | |
| 1694 __ mov(eax, Immediate(value)); | |
| 1695 } | |
| 1696 Token::Value op = Token::SUB; | |
| 1697 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1698 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1699 | |
| 1700 __ bind(&done); | |
| 1701 context()->Plug(eax); | |
| 1702 } | |
| 1703 | |
| 1704 | |
| 1705 void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr, | |
| 1706 Token::Value op, | |
| 1707 OverwriteMode mode, | |
| 1708 Smi* value) { | |
| 1709 NearLabel call_stub, smi_case, done; | |
| 1710 int shift_value = value->value() & 0x1f; | |
| 1711 | |
| 1712 JumpPatchSite patch_site(masm_); | |
| 1713 patch_site.EmitJumpIfSmi(eax, &smi_case); | |
| 1714 | |
| 1715 // Call stub. | |
| 1716 __ bind(&call_stub); | |
| 1717 __ mov(edx, eax); | |
| 1718 __ mov(eax, Immediate(value)); | |
| 1719 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1720 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1721 __ jmp(&done); | |
| 1722 | |
| 1723 // Smi case. | |
| 1724 __ bind(&smi_case); | |
| 1725 switch (op) { | |
| 1726 case Token::SHL: | |
| 1727 if (shift_value != 0) { | |
| 1728 __ mov(edx, eax); | |
| 1729 if (shift_value > 1) { | |
| 1730 __ shl(edx, shift_value - 1); | |
| 1731 } | |
| 1732 // Convert int result to smi, checking that it is in int range. | |
| 1733 ASSERT(kSmiTagSize == 1); // Adjust code if not the case. | |
| 1734 __ add(edx, Operand(edx)); | |
| 1735 __ j(overflow, &call_stub); | |
| 1736 __ mov(eax, edx); // Put result back into eax. | |
| 1737 } | |
| 1738 break; | |
| 1739 case Token::SAR: | |
| 1740 if (shift_value != 0) { | |
| 1741 __ sar(eax, shift_value); | |
| 1742 __ and_(eax, ~kSmiTagMask); | |
| 1743 } | |
| 1744 break; | |
| 1745 case Token::SHR: | |
| 1746 if (shift_value < 2) { | |
| 1747 __ mov(edx, eax); | |
| 1748 __ SmiUntag(edx); | |
| 1749 __ shr(edx, shift_value); | |
| 1750 __ test(edx, Immediate(0xc0000000)); | |
| 1751 __ j(not_zero, &call_stub); | |
| 1752 __ SmiTag(edx); | |
| 1753 __ mov(eax, edx); // Put result back into eax. | |
| 1754 } else { | |
| 1755 __ SmiUntag(eax); | |
| 1756 __ shr(eax, shift_value); | |
| 1757 __ SmiTag(eax); | |
| 1758 } | |
| 1759 break; | |
| 1760 default: | |
| 1761 UNREACHABLE(); | |
| 1762 } | |
| 1763 | |
| 1764 __ bind(&done); | |
| 1765 context()->Plug(eax); | |
| 1766 } | |
| 1767 | |
| 1768 | |
| 1769 void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr, | |
| 1770 Token::Value op, | |
| 1771 OverwriteMode mode, | |
| 1772 Smi* value) { | |
| 1773 NearLabel smi_case, done; | |
| 1774 | |
| 1775 JumpPatchSite patch_site(masm_); | |
| 1776 patch_site.EmitJumpIfSmi(eax, &smi_case); | |
| 1777 | |
| 1778 // The order of the arguments does not matter for bit-ops with a | |
| 1779 // constant operand. | |
| 1780 __ mov(edx, Immediate(value)); | |
| 1781 TypeRecordingBinaryOpStub stub(op, mode); | |
| 1782 EmitCallIC(stub.GetCode(), &patch_site); | |
| 1783 __ jmp(&done); | |
| 1784 | |
| 1785 // Smi case. | |
| 1786 __ bind(&smi_case); | |
| 1787 switch (op) { | |
| 1788 case Token::BIT_OR: | |
| 1789 __ or_(Operand(eax), Immediate(value)); | |
| 1790 break; | |
| 1791 case Token::BIT_XOR: | |
| 1792 __ xor_(Operand(eax), Immediate(value)); | |
| 1793 break; | |
| 1794 case Token::BIT_AND: | |
| 1795 __ and_(Operand(eax), Immediate(value)); | |
| 1796 break; | |
| 1797 default: | |
| 1798 UNREACHABLE(); | |
| 1799 } | |
| 1800 | |
| 1801 __ bind(&done); | |
| 1802 context()->Plug(eax); | |
| 1803 } | |
| 1804 | |
| 1805 | |
| 1806 void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr, | |
| 1807 Token::Value op, | |
| 1808 OverwriteMode mode, | |
| 1809 bool left_is_constant_smi, | |
| 1810 Smi* value) { | |
| 1811 switch (op) { | |
| 1812 case Token::BIT_OR: | |
| 1813 case Token::BIT_XOR: | |
| 1814 case Token::BIT_AND: | |
| 1815 EmitConstantSmiBitOp(expr, op, mode, value); | |
| 1816 break; | |
| 1817 case Token::SHL: | |
| 1818 case Token::SAR: | |
| 1819 case Token::SHR: | |
| 1820 ASSERT(!left_is_constant_smi); | |
| 1821 EmitConstantSmiShiftOp(expr, op, mode, value); | |
| 1822 break; | |
| 1823 case Token::ADD: | |
| 1824 EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value); | |
| 1825 break; | |
| 1826 case Token::SUB: | |
| 1827 EmitConstantSmiSub(expr, mode, left_is_constant_smi, value); | |
| 1828 break; | |
| 1829 default: | |
| 1830 UNREACHABLE(); | |
| 1831 } | |
| 1832 } | |
| 1833 | |
| 1834 | |
| 1835 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1630 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
| 1836 Token::Value op, | 1631 Token::Value op, |
| 1837 OverwriteMode mode, | 1632 OverwriteMode mode, |
| 1838 Expression* left, | 1633 Expression* left, |
| 1839 Expression* right, | 1634 Expression* right) { |
| 1840 ConstantOperand constant) { | |
| 1841 if (constant == kRightConstant) { | |
| 1842 Smi* value = Smi::cast(*right->AsLiteral()->handle()); | |
| 1843 EmitConstantSmiBinaryOp(expr, op, mode, false, value); | |
| 1844 return; | |
| 1845 } else if (constant == kLeftConstant) { | |
| 1846 Smi* value = Smi::cast(*left->AsLiteral()->handle()); | |
| 1847 EmitConstantSmiBinaryOp(expr, op, mode, true, value); | |
| 1848 return; | |
| 1849 } | |
| 1850 | |
| 1851 // Do combined smi check of the operands. Left operand is on the | 1635 // Do combined smi check of the operands. Left operand is on the |
| 1852 // stack. Right operand is in eax. | 1636 // stack. Right operand is in eax. |
| 1853 NearLabel done, smi_case, stub_call; | 1637 NearLabel done, smi_case, stub_call; |
| 1854 __ pop(edx); | 1638 __ pop(edx); |
| 1855 __ mov(ecx, eax); | 1639 __ mov(ecx, eax); |
| 1856 __ or_(eax, Operand(edx)); | 1640 __ or_(eax, Operand(edx)); |
| 1857 JumpPatchSite patch_site(masm_); | 1641 JumpPatchSite patch_site(masm_); |
| 1858 patch_site.EmitJumpIfSmi(eax, &smi_case); | 1642 patch_site.EmitJumpIfSmi(eax, &smi_case); |
| 1859 | 1643 |
| 1860 __ bind(&stub_call); | 1644 __ bind(&stub_call); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1972 EffectContext context(this); | 1756 EffectContext context(this); |
| 1973 EmitVariableAssignment(var, Token::ASSIGN); | 1757 EmitVariableAssignment(var, Token::ASSIGN); |
| 1974 break; | 1758 break; |
| 1975 } | 1759 } |
| 1976 case NAMED_PROPERTY: { | 1760 case NAMED_PROPERTY: { |
| 1977 __ push(eax); // Preserve value. | 1761 __ push(eax); // Preserve value. |
| 1978 VisitForAccumulatorValue(prop->obj()); | 1762 VisitForAccumulatorValue(prop->obj()); |
| 1979 __ mov(edx, eax); | 1763 __ mov(edx, eax); |
| 1980 __ pop(eax); // Restore value. | 1764 __ pop(eax); // Restore value. |
| 1981 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1765 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1982 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1766 Handle<Code> ic(Builtins::builtin( |
| 1767 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1768 : Builtins::StoreIC_Initialize)); |
| 1983 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1769 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1984 break; | 1770 break; |
| 1985 } | 1771 } |
| 1986 case KEYED_PROPERTY: { | 1772 case KEYED_PROPERTY: { |
| 1987 __ push(eax); // Preserve value. | 1773 __ push(eax); // Preserve value. |
| 1988 if (prop->is_synthetic()) { | 1774 if (prop->is_synthetic()) { |
| 1989 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1775 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 1990 ASSERT(prop->key()->AsLiteral() != NULL); | 1776 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1991 { AccumulatorValueContext for_object(this); | 1777 { AccumulatorValueContext for_object(this); |
| 1992 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | 1778 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1993 } | 1779 } |
| 1994 __ mov(edx, eax); | 1780 __ mov(edx, eax); |
| 1995 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 1781 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 1996 } else { | 1782 } else { |
| 1997 VisitForStackValue(prop->obj()); | 1783 VisitForStackValue(prop->obj()); |
| 1998 VisitForAccumulatorValue(prop->key()); | 1784 VisitForAccumulatorValue(prop->key()); |
| 1999 __ mov(ecx, eax); | 1785 __ mov(ecx, eax); |
| 2000 __ pop(edx); | 1786 __ pop(edx); |
| 2001 } | 1787 } |
| 2002 __ pop(eax); // Restore value. | 1788 __ pop(eax); // Restore value. |
| 2003 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1789 Handle<Code> ic(Builtins::builtin( |
| 1790 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1791 : Builtins::KeyedStoreIC_Initialize)); |
| 2004 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1792 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2005 break; | 1793 break; |
| 2006 } | 1794 } |
| 2007 } | 1795 } |
| 2008 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1796 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 2009 context()->Plug(eax); | 1797 context()->Plug(eax); |
| 2010 } | 1798 } |
| 2011 | 1799 |
| 2012 | 1800 |
| 2013 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1801 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2014 Token::Value op) { | 1802 Token::Value op) { |
| 2015 // Left-hand sides that rewrite to explicit property accesses do not reach | 1803 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 2016 // here. | 1804 // here. |
| 2017 ASSERT(var != NULL); | 1805 ASSERT(var != NULL); |
| 2018 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1806 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 2019 | 1807 |
| 2020 if (var->is_global()) { | 1808 if (var->is_global()) { |
| 2021 ASSERT(!var->is_this()); | 1809 ASSERT(!var->is_this()); |
| 2022 // Assignment to a global variable. Use inline caching for the | 1810 // Assignment to a global variable. Use inline caching for the |
| 2023 // assignment. Right-hand-side value is passed in eax, variable name in | 1811 // assignment. Right-hand-side value is passed in eax, variable name in |
| 2024 // ecx, and the global object on the stack. | 1812 // ecx, and the global object on the stack. |
| 2025 __ mov(ecx, var->name()); | 1813 __ mov(ecx, var->name()); |
| 2026 __ mov(edx, GlobalObjectOperand()); | 1814 __ mov(edx, GlobalObjectOperand()); |
| 2027 Handle<Code> ic(Builtins::builtin( | 1815 Handle<Code> ic(Builtins::builtin( |
| 2028 is_strict() ? Builtins::StoreIC_Initialize_Strict | 1816 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 2029 : Builtins::StoreIC_Initialize)); | 1817 : Builtins::StoreIC_Initialize)); |
| 2030 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1818 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 2031 | 1819 |
| 2032 } else if (op == Token::INIT_CONST) { | 1820 } else if (op == Token::INIT_CONST) { |
| 2033 // Like var declarations, const declarations are hoisted to function | 1821 // Like var declarations, const declarations are hoisted to function |
| 2034 // scope. However, unlike var initializers, const initializers are able | 1822 // scope. However, unlike var initializers, const initializers are able |
| 2035 // to drill a hole to that function context, even from inside a 'with' | 1823 // to drill a hole to that function context, even from inside a 'with' |
| 2036 // context. We thus bypass the normal static scope lookup. | 1824 // context. We thus bypass the normal static scope lookup. |
| 2037 Slot* slot = var->AsSlot(); | 1825 Slot* slot = var->AsSlot(); |
| 2038 Label skip; | 1826 Label skip; |
| 2039 switch (slot->type()) { | 1827 switch (slot->type()) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2089 int offset = Context::SlotOffset(slot->index()); | 1877 int offset = Context::SlotOffset(slot->index()); |
| 2090 __ RecordWrite(ecx, offset, edx, ebx, kDontSaveFPRegs); | 1878 __ RecordWrite(ecx, offset, edx, ebx, kDontSaveFPRegs); |
| 2091 break; | 1879 break; |
| 2092 } | 1880 } |
| 2093 | 1881 |
| 2094 case Slot::LOOKUP: | 1882 case Slot::LOOKUP: |
| 2095 // Call the runtime for the assignment. | 1883 // Call the runtime for the assignment. |
| 2096 __ push(eax); // Value. | 1884 __ push(eax); // Value. |
| 2097 __ push(esi); // Context. | 1885 __ push(esi); // Context. |
| 2098 __ push(Immediate(var->name())); | 1886 __ push(Immediate(var->name())); |
| 2099 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 1887 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 1888 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2100 break; | 1889 break; |
| 2101 } | 1890 } |
| 2102 } | 1891 } |
| 2103 } | 1892 } |
| 2104 | 1893 |
| 2105 | 1894 |
| 2106 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1895 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2107 // Assignment to a property, using a named store IC. | 1896 // Assignment to a property, using a named store IC. |
| 2108 Property* prop = expr->target()->AsProperty(); | 1897 Property* prop = expr->target()->AsProperty(); |
| 2109 ASSERT(prop != NULL); | 1898 ASSERT(prop != NULL); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2120 } | 1909 } |
| 2121 | 1910 |
| 2122 // Record source code position before IC call. | 1911 // Record source code position before IC call. |
| 2123 SetSourcePosition(expr->position()); | 1912 SetSourcePosition(expr->position()); |
| 2124 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1913 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 2125 if (expr->ends_initialization_block()) { | 1914 if (expr->ends_initialization_block()) { |
| 2126 __ mov(edx, Operand(esp, 0)); | 1915 __ mov(edx, Operand(esp, 0)); |
| 2127 } else { | 1916 } else { |
| 2128 __ pop(edx); | 1917 __ pop(edx); |
| 2129 } | 1918 } |
| 2130 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1919 Handle<Code> ic(Builtins::builtin( |
| 1920 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1921 : Builtins::StoreIC_Initialize)); |
| 2131 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1922 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2132 | 1923 |
| 2133 // If the assignment ends an initialization block, revert to fast case. | 1924 // If the assignment ends an initialization block, revert to fast case. |
| 2134 if (expr->ends_initialization_block()) { | 1925 if (expr->ends_initialization_block()) { |
| 2135 __ push(eax); // Result of assignment, saved even if not needed. | 1926 __ push(eax); // Result of assignment, saved even if not needed. |
| 2136 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 1927 __ push(Operand(esp, kPointerSize)); // Receiver is under value. |
| 2137 __ CallRuntime(Runtime::kToFastProperties, 1); | 1928 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2138 __ pop(eax); | 1929 __ pop(eax); |
| 2139 __ Drop(1); | 1930 __ Drop(1); |
| 2140 } | 1931 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2158 } | 1949 } |
| 2159 | 1950 |
| 2160 __ pop(ecx); | 1951 __ pop(ecx); |
| 2161 if (expr->ends_initialization_block()) { | 1952 if (expr->ends_initialization_block()) { |
| 2162 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. | 1953 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. |
| 2163 } else { | 1954 } else { |
| 2164 __ pop(edx); | 1955 __ pop(edx); |
| 2165 } | 1956 } |
| 2166 // Record source code position before IC call. | 1957 // Record source code position before IC call. |
| 2167 SetSourcePosition(expr->position()); | 1958 SetSourcePosition(expr->position()); |
| 2168 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1959 Handle<Code> ic(Builtins::builtin( |
| 1960 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1961 : Builtins::KeyedStoreIC_Initialize)); |
| 2169 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1962 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2170 | 1963 |
| 2171 // If the assignment ends an initialization block, revert to fast case. | 1964 // If the assignment ends an initialization block, revert to fast case. |
| 2172 if (expr->ends_initialization_block()) { | 1965 if (expr->ends_initialization_block()) { |
| 2173 __ pop(edx); | 1966 __ pop(edx); |
| 2174 __ push(eax); // Result of assignment, saved even if not needed. | 1967 __ push(eax); // Result of assignment, saved even if not needed. |
| 2175 __ push(edx); | 1968 __ push(edx); |
| 2176 __ CallRuntime(Runtime::kToFastProperties, 1); | 1969 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2177 __ pop(eax); | 1970 __ pop(eax); |
| 2178 } | 1971 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2271 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2064 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2272 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2065 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 2273 __ CallStub(&stub); | 2066 __ CallStub(&stub); |
| 2274 RecordJSReturnSite(expr); | 2067 RecordJSReturnSite(expr); |
| 2275 // Restore context register. | 2068 // Restore context register. |
| 2276 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2069 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2277 context()->DropAndPlug(1, eax); | 2070 context()->DropAndPlug(1, eax); |
| 2278 } | 2071 } |
| 2279 | 2072 |
| 2280 | 2073 |
| 2074 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
| 2075 int arg_count) { |
| 2076 // Push copy of the first argument or undefined if it doesn't exist. |
| 2077 if (arg_count > 0) { |
| 2078 __ push(Operand(esp, arg_count * kPointerSize)); |
| 2079 } else { |
| 2080 __ push(Immediate(Factory::undefined_value())); |
| 2081 } |
| 2082 |
| 2083 // Push the receiver of the enclosing function. |
| 2084 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 2085 |
| 2086 // Push the strict mode flag. |
| 2087 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 2088 |
| 2089 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2090 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| 2091 : Runtime::kResolvePossiblyDirectEval, 4); |
| 2092 } |
| 2093 |
| 2094 |
| 2281 void FullCodeGenerator::VisitCall(Call* expr) { | 2095 void FullCodeGenerator::VisitCall(Call* expr) { |
| 2282 #ifdef DEBUG | 2096 #ifdef DEBUG |
| 2283 // We want to verify that RecordJSReturnSite gets called on all paths | 2097 // We want to verify that RecordJSReturnSite gets called on all paths |
| 2284 // through this function. Avoid early returns. | 2098 // through this function. Avoid early returns. |
| 2285 expr->return_is_recorded_ = false; | 2099 expr->return_is_recorded_ = false; |
| 2286 #endif | 2100 #endif |
| 2287 | 2101 |
| 2288 Comment cmnt(masm_, "[ Call"); | 2102 Comment cmnt(masm_, "[ Call"); |
| 2289 Expression* fun = expr->expression(); | 2103 Expression* fun = expr->expression(); |
| 2290 Variable* var = fun->AsVariableProxy()->AsVariable(); | 2104 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 2291 | 2105 |
| 2292 if (var != NULL && var->is_possibly_eval()) { | 2106 if (var != NULL && var->is_possibly_eval()) { |
| 2293 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 2107 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 2294 // resolve the function we need to call and the receiver of the | 2108 // resolve the function we need to call and the receiver of the |
| 2295 // call. Then we call the resolved function using the given | 2109 // call. Then we call the resolved function using the given |
| 2296 // arguments. | 2110 // arguments. |
| 2297 ZoneList<Expression*>* args = expr->arguments(); | 2111 ZoneList<Expression*>* args = expr->arguments(); |
| 2298 int arg_count = args->length(); | 2112 int arg_count = args->length(); |
| 2299 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 2113 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
| 2300 VisitForStackValue(fun); | 2114 VisitForStackValue(fun); |
| 2301 // Reserved receiver slot. | 2115 // Reserved receiver slot. |
| 2302 __ push(Immediate(Factory::undefined_value())); | 2116 __ push(Immediate(Factory::undefined_value())); |
| 2303 | 2117 |
| 2304 // Push the arguments. | 2118 // Push the arguments. |
| 2305 for (int i = 0; i < arg_count; i++) { | 2119 for (int i = 0; i < arg_count; i++) { |
| 2306 VisitForStackValue(args->at(i)); | 2120 VisitForStackValue(args->at(i)); |
| 2307 } | 2121 } |
| 2308 | 2122 |
| 2309 // Push copy of the function - found below the arguments. | 2123 // If we know that eval can only be shadowed by eval-introduced |
| 2310 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); | 2124 // variables we attempt to load the global eval function directly |
| 2311 | 2125 // in generated code. If we succeed, there is no need to perform a |
| 2312 // Push copy of the first argument or undefined if it doesn't exist. | 2126 // context lookup in the runtime system. |
| 2313 if (arg_count > 0) { | 2127 Label done; |
| 2314 __ push(Operand(esp, arg_count * kPointerSize)); | 2128 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2315 } else { | 2129 Label slow; |
| 2316 __ push(Immediate(Factory::undefined_value())); | 2130 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), |
| 2131 NOT_INSIDE_TYPEOF, |
| 2132 &slow); |
| 2133 // Push the function and resolve eval. |
| 2134 __ push(eax); |
| 2135 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
| 2136 __ jmp(&done); |
| 2137 __ bind(&slow); |
| 2317 } | 2138 } |
| 2318 | 2139 |
| 2319 // Push the receiver of the enclosing function and do runtime call. | 2140 // Push copy of the function (found below the arguments) and |
| 2320 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2141 // resolve eval. |
| 2321 // Push the strict mode flag. | 2142 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2322 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 2143 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); |
| 2323 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); | 2144 if (done.is_linked()) { |
| 2145 __ bind(&done); |
| 2146 } |
| 2324 | 2147 |
| 2325 // The runtime call returns a pair of values in eax (function) and | 2148 // The runtime call returns a pair of values in eax (function) and |
| 2326 // edx (receiver). Touch up the stack with the right values. | 2149 // edx (receiver). Touch up the stack with the right values. |
| 2327 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); | 2150 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
| 2328 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | 2151 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
| 2329 } | 2152 } |
| 2330 // Record source position for debugger. | 2153 // Record source position for debugger. |
| 2331 SetSourcePosition(expr->position()); | 2154 SetSourcePosition(expr->position()); |
| 2332 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2155 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2333 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2156 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2378 __ bind(&call); | 2201 __ bind(&call); |
| 2379 } | 2202 } |
| 2380 | 2203 |
| 2381 EmitCallWithStub(expr); | 2204 EmitCallWithStub(expr); |
| 2382 } else if (fun->AsProperty() != NULL) { | 2205 } else if (fun->AsProperty() != NULL) { |
| 2383 // Call to an object property. | 2206 // Call to an object property. |
| 2384 Property* prop = fun->AsProperty(); | 2207 Property* prop = fun->AsProperty(); |
| 2385 Literal* key = prop->key()->AsLiteral(); | 2208 Literal* key = prop->key()->AsLiteral(); |
| 2386 if (key != NULL && key->handle()->IsSymbol()) { | 2209 if (key != NULL && key->handle()->IsSymbol()) { |
| 2387 // Call to a named property, use call IC. | 2210 // Call to a named property, use call IC. |
| 2388 VisitForStackValue(prop->obj()); | 2211 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2212 VisitForStackValue(prop->obj()); |
| 2213 } |
| 2389 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2214 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2390 } else { | 2215 } else { |
| 2391 // Call to a keyed property. | 2216 // Call to a keyed property. |
| 2392 // For a synthetic property use keyed load IC followed by function call, | 2217 // For a synthetic property use keyed load IC followed by function call, |
| 2393 // for a regular property use keyed EmitCallIC. | 2218 // for a regular property use keyed EmitCallIC. |
| 2394 if (prop->is_synthetic()) { | 2219 if (prop->is_synthetic()) { |
| 2395 // Do not visit the object and key subexpressions (they are shared | 2220 // Do not visit the object and key subexpressions (they are shared |
| 2396 // by all occurrences of the same rewritten parameter). | 2221 // by all occurrences of the same rewritten parameter). |
| 2397 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 2222 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2398 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | 2223 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); |
| (...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3220 Label slow_case; | 3045 Label slow_case; |
| 3221 Register object = eax; | 3046 Register object = eax; |
| 3222 Register index_1 = ebx; | 3047 Register index_1 = ebx; |
| 3223 Register index_2 = ecx; | 3048 Register index_2 = ecx; |
| 3224 Register elements = edi; | 3049 Register elements = edi; |
| 3225 Register temp = edx; | 3050 Register temp = edx; |
| 3226 __ mov(object, Operand(esp, 2 * kPointerSize)); | 3051 __ mov(object, Operand(esp, 2 * kPointerSize)); |
| 3227 // Fetch the map and check if array is in fast case. | 3052 // Fetch the map and check if array is in fast case. |
| 3228 // Check that object doesn't require security checks and | 3053 // Check that object doesn't require security checks and |
| 3229 // has no indexed interceptor. | 3054 // has no indexed interceptor. |
| 3230 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp); | 3055 __ CmpObjectType(object, JS_ARRAY_TYPE, temp); |
| 3231 __ j(below, &slow_case); | 3056 __ j(not_equal, &slow_case); |
| 3232 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), | 3057 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), |
| 3233 KeyedLoadIC::kSlowCaseBitFieldMask); | 3058 KeyedLoadIC::kSlowCaseBitFieldMask); |
| 3234 __ j(not_zero, &slow_case); | 3059 __ j(not_zero, &slow_case); |
| 3235 | 3060 |
| 3236 // Check the object's elements are in fast case and writable. | 3061 // Check the object's elements are in fast case and writable. |
| 3237 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); | 3062 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); |
| 3238 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), | 3063 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), |
| 3239 Immediate(Factory::fixed_array_map())); | 3064 Immediate(Factory::fixed_array_map())); |
| 3240 __ j(not_equal, &slow_case); | 3065 __ j(not_equal, &slow_case); |
| 3241 | 3066 |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3391 Immediate(String::kContainsCachedArrayIndexMask)); | 3216 Immediate(String::kContainsCachedArrayIndexMask)); |
| 3392 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3217 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3393 Split(zero, if_true, if_false, fall_through); | 3218 Split(zero, if_true, if_false, fall_through); |
| 3394 | 3219 |
| 3395 context()->Plug(if_true, if_false); | 3220 context()->Plug(if_true, if_false); |
| 3396 } | 3221 } |
| 3397 | 3222 |
| 3398 | 3223 |
| 3399 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 3224 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 3400 ASSERT(args->length() == 1); | 3225 ASSERT(args->length() == 1); |
| 3401 | |
| 3402 VisitForAccumulatorValue(args->at(0)); | 3226 VisitForAccumulatorValue(args->at(0)); |
| 3403 | 3227 |
| 3404 if (FLAG_debug_code) { | 3228 if (FLAG_debug_code) { |
| 3405 __ AbortIfNotString(eax); | 3229 __ AbortIfNotString(eax); |
| 3406 } | 3230 } |
| 3407 | 3231 |
| 3408 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); | 3232 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); |
| 3409 __ IndexFromHash(eax, eax); | 3233 __ IndexFromHash(eax, eax); |
| 3410 | 3234 |
| 3411 context()->Plug(eax); | 3235 context()->Plug(eax); |
| 3412 } | 3236 } |
| 3413 | 3237 |
| 3414 | 3238 |
| 3415 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 3239 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| 3416 Label bailout, done, one_char_separator, long_separator, | 3240 Label bailout, done, one_char_separator, long_separator, |
| 3417 non_trivial_array, not_size_one_array, loop, loop_condition, | 3241 non_trivial_array, not_size_one_array, loop, |
| 3418 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; | 3242 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; |
| 3419 | 3243 |
| 3420 ASSERT(args->length() == 2); | 3244 ASSERT(args->length() == 2); |
| 3421 // We will leave the separator on the stack until the end of the function. | 3245 // We will leave the separator on the stack until the end of the function. |
| 3422 VisitForStackValue(args->at(1)); | 3246 VisitForStackValue(args->at(1)); |
| 3423 // Load this to eax (= array) | 3247 // Load this to eax (= array) |
| 3424 VisitForAccumulatorValue(args->at(0)); | 3248 VisitForAccumulatorValue(args->at(0)); |
| 3425 // All aliases of the same register have disjoint lifetimes. | 3249 // All aliases of the same register have disjoint lifetimes. |
| 3426 Register array = eax; | 3250 Register array = eax; |
| 3427 Register elements = no_reg; // Will be eax. | 3251 Register elements = no_reg; // Will be eax. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3449 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 3273 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 3450 __ j(not_equal, &bailout); | 3274 __ j(not_equal, &bailout); |
| 3451 | 3275 |
| 3452 // Check that the array has fast elements. | 3276 // Check that the array has fast elements. |
| 3453 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 3277 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 3454 1 << Map::kHasFastElements); | 3278 1 << Map::kHasFastElements); |
| 3455 __ j(zero, &bailout); | 3279 __ j(zero, &bailout); |
| 3456 | 3280 |
| 3457 // If the array has length zero, return the empty string. | 3281 // If the array has length zero, return the empty string. |
| 3458 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); | 3282 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3459 __ sar(array_length, 1); | 3283 __ SmiUntag(array_length); |
| 3460 __ j(not_zero, &non_trivial_array); | 3284 __ j(not_zero, &non_trivial_array); |
| 3461 __ mov(result_operand, Factory::empty_string()); | 3285 __ mov(result_operand, Factory::empty_string()); |
| 3462 __ jmp(&done); | 3286 __ jmp(&done); |
| 3463 | 3287 |
| 3464 // Save the array length. | 3288 // Save the array length. |
| 3465 __ bind(&non_trivial_array); | 3289 __ bind(&non_trivial_array); |
| 3466 __ mov(array_length_operand, array_length); | 3290 __ mov(array_length_operand, array_length); |
| 3467 | 3291 |
| 3468 // Save the FixedArray containing array's elements. | 3292 // Save the FixedArray containing array's elements. |
| 3469 // End of array's live range. | 3293 // End of array's live range. |
| 3470 elements = array; | 3294 elements = array; |
| 3471 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); | 3295 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| 3472 array = no_reg; | 3296 array = no_reg; |
| 3473 | 3297 |
| 3474 | 3298 |
| 3475 // Check that all array elements are sequential ASCII strings, and | 3299 // Check that all array elements are sequential ASCII strings, and |
| 3476 // accumulate the sum of their lengths, as a smi-encoded value. | 3300 // accumulate the sum of their lengths, as a smi-encoded value. |
| 3477 __ Set(index, Immediate(0)); | 3301 __ Set(index, Immediate(0)); |
| 3478 __ Set(string_length, Immediate(0)); | 3302 __ Set(string_length, Immediate(0)); |
| 3479 // Loop condition: while (index < length). | 3303 // Loop condition: while (index < length). |
| 3480 // Live loop registers: index, array_length, string, | 3304 // Live loop registers: index, array_length, string, |
| 3481 // scratch, string_length, elements. | 3305 // scratch, string_length, elements. |
| 3482 __ jmp(&loop_condition); | 3306 if (FLAG_debug_code) { |
| 3307 __ cmp(index, Operand(array_length)); |
| 3308 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); |
| 3309 } |
| 3483 __ bind(&loop); | 3310 __ bind(&loop); |
| 3484 __ cmp(index, Operand(array_length)); | 3311 __ mov(string, FieldOperand(elements, |
| 3485 __ j(greater_equal, &done); | 3312 index, |
| 3486 | 3313 times_pointer_size, |
| 3487 __ mov(string, FieldOperand(elements, index, | 3314 FixedArray::kHeaderSize)); |
| 3488 times_pointer_size, | |
| 3489 FixedArray::kHeaderSize)); | |
| 3490 __ test(string, Immediate(kSmiTagMask)); | 3315 __ test(string, Immediate(kSmiTagMask)); |
| 3491 __ j(zero, &bailout); | 3316 __ j(zero, &bailout); |
| 3492 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3317 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3493 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3318 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3494 __ and_(scratch, Immediate( | 3319 __ and_(scratch, Immediate( |
| 3495 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3320 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3496 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3321 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 3497 __ j(not_equal, &bailout); | 3322 __ j(not_equal, &bailout); |
| 3498 __ add(string_length, | 3323 __ add(string_length, |
| 3499 FieldOperand(string, SeqAsciiString::kLengthOffset)); | 3324 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
| 3500 __ j(overflow, &bailout); | 3325 __ j(overflow, &bailout); |
| 3501 __ add(Operand(index), Immediate(1)); | 3326 __ add(Operand(index), Immediate(1)); |
| 3502 __ bind(&loop_condition); | |
| 3503 __ cmp(index, Operand(array_length)); | 3327 __ cmp(index, Operand(array_length)); |
| 3504 __ j(less, &loop); | 3328 __ j(less, &loop); |
| 3505 | 3329 |
| 3506 // If array_length is 1, return elements[0], a string. | 3330 // If array_length is 1, return elements[0], a string. |
| 3507 __ cmp(array_length, 1); | 3331 __ cmp(array_length, 1); |
| 3508 __ j(not_equal, ¬_size_one_array); | 3332 __ j(not_equal, ¬_size_one_array); |
| 3509 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); | 3333 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); |
| 3510 __ mov(result_operand, scratch); | 3334 __ mov(result_operand, scratch); |
| 3511 __ jmp(&done); | 3335 __ jmp(&done); |
| 3512 | 3336 |
| 3513 __ bind(¬_size_one_array); | 3337 __ bind(¬_size_one_array); |
| 3514 | 3338 |
| 3515 // End of array_length live range. | 3339 // End of array_length live range. |
| 3516 result_pos = array_length; | 3340 result_pos = array_length; |
| 3517 array_length = no_reg; | 3341 array_length = no_reg; |
| 3518 | 3342 |
| 3519 // Live registers: | 3343 // Live registers: |
| 3520 // string_length: Sum of string lengths, as a smi. | 3344 // string_length: Sum of string lengths, as a smi. |
| 3521 // elements: FixedArray of strings. | 3345 // elements: FixedArray of strings. |
| 3522 | 3346 |
| 3523 // Check that the separator is a flat ASCII string. | 3347 // Check that the separator is a flat ASCII string. |
| 3524 __ mov(string, separator_operand); | 3348 __ mov(string, separator_operand); |
| 3525 __ test(string, Immediate(kSmiTagMask)); | 3349 __ test(string, Immediate(kSmiTagMask)); |
| 3526 __ j(zero, &bailout); | 3350 __ j(zero, &bailout); |
| 3527 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3351 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3528 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3352 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3529 __ and_(scratch, Immediate( | 3353 __ and_(scratch, Immediate( |
| 3530 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3354 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3531 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3355 __ cmp(scratch, ASCII_STRING_TYPE); |
| 3532 __ j(not_equal, &bailout); | 3356 __ j(not_equal, &bailout); |
| 3533 | 3357 |
| 3534 // Add (separator length times array_length) - separator length | 3358 // Add (separator length times array_length) - separator length |
| 3535 // to string_length. | 3359 // to string_length. |
| 3536 __ mov(scratch, separator_operand); | 3360 __ mov(scratch, separator_operand); |
| 3537 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); | 3361 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
| 3538 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. | 3362 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. |
| 3539 __ imul(scratch, array_length_operand); | 3363 __ imul(scratch, array_length_operand); |
| 3540 __ j(overflow, &bailout); | 3364 __ j(overflow, &bailout); |
| 3541 __ add(string_length, Operand(scratch)); | 3365 __ add(string_length, Operand(scratch)); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3733 context()->Plug(false); | 3557 context()->Plug(false); |
| 3734 } else { | 3558 } else { |
| 3735 VisitForStackValue(prop->obj()); | 3559 VisitForStackValue(prop->obj()); |
| 3736 VisitForStackValue(prop->key()); | 3560 VisitForStackValue(prop->key()); |
| 3737 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 3561 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 3738 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3562 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3739 context()->Plug(eax); | 3563 context()->Plug(eax); |
| 3740 } | 3564 } |
| 3741 } else if (var != NULL) { | 3565 } else if (var != NULL) { |
| 3742 // Delete of an unqualified identifier is disallowed in strict mode | 3566 // Delete of an unqualified identifier is disallowed in strict mode |
| 3743 // so this code can only be reached in non-strict mode. | 3567 // but "delete this" is. |
| 3744 ASSERT(strict_mode_flag() == kNonStrictMode); | 3568 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3745 if (var->is_global()) { | 3569 if (var->is_global()) { |
| 3746 __ push(GlobalObjectOperand()); | 3570 __ push(GlobalObjectOperand()); |
| 3747 __ push(Immediate(var->name())); | 3571 __ push(Immediate(var->name())); |
| 3748 __ push(Immediate(Smi::FromInt(kNonStrictMode))); | 3572 __ push(Immediate(Smi::FromInt(kNonStrictMode))); |
| 3749 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3573 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3750 context()->Plug(eax); | 3574 context()->Plug(eax); |
| 3751 } else if (var->AsSlot() != NULL && | 3575 } else if (var->AsSlot() != NULL && |
| 3752 var->AsSlot()->type() != Slot::LOOKUP) { | 3576 var->AsSlot()->type() != Slot::LOOKUP) { |
| 3753 // Result of deleting non-global, non-dynamic variables is false. | 3577 // Result of deleting non-global, non-dynamic variables is false. |
| 3754 // The subexpression does not have side effects. | 3578 // The subexpression does not have side effects. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3772 | 3596 |
| 3773 case Token::VOID: { | 3597 case Token::VOID: { |
| 3774 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 3598 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 3775 VisitForEffect(expr->expression()); | 3599 VisitForEffect(expr->expression()); |
| 3776 context()->Plug(Factory::undefined_value()); | 3600 context()->Plug(Factory::undefined_value()); |
| 3777 break; | 3601 break; |
| 3778 } | 3602 } |
| 3779 | 3603 |
| 3780 case Token::NOT: { | 3604 case Token::NOT: { |
| 3781 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3605 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 3606 if (context()->IsEffect()) { |
| 3607 // Unary NOT has no side effects so it's only necessary to visit the |
| 3608 // subexpression. Match the optimizing compiler by not branching. |
| 3609 VisitForEffect(expr->expression()); |
| 3610 } else { |
| 3611 Label materialize_true, materialize_false; |
| 3612 Label* if_true = NULL; |
| 3613 Label* if_false = NULL; |
| 3614 Label* fall_through = NULL; |
| 3782 | 3615 |
| 3783 Label materialize_true, materialize_false; | 3616 // Notice that the labels are swapped. |
| 3784 Label* if_true = NULL; | 3617 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3785 Label* if_false = NULL; | 3618 &if_false, &if_true, &fall_through); |
| 3786 Label* fall_through = NULL; | 3619 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 3787 // Notice that the labels are swapped. | 3620 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 3788 context()->PrepareTest(&materialize_true, &materialize_false, | 3621 context()->Plug(if_false, if_true); // Labels swapped. |
| 3789 &if_false, &if_true, &fall_through); | 3622 } |
| 3790 if (context()->IsTest()) ForwardBailoutToChild(expr); | |
| 3791 VisitForControl(expr->expression(), if_true, if_false, fall_through); | |
| 3792 context()->Plug(if_false, if_true); // Labels swapped. | |
| 3793 break; | 3623 break; |
| 3794 } | 3624 } |
| 3795 | 3625 |
| 3796 case Token::TYPEOF: { | 3626 case Token::TYPEOF: { |
| 3797 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3627 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 3798 { StackValueContext context(this); | 3628 { StackValueContext context(this); |
| 3799 VisitForTypeofValue(expr->expression()); | 3629 VisitForTypeofValue(expr->expression()); |
| 3800 } | 3630 } |
| 3801 __ CallRuntime(Runtime::kTypeof, 1); | 3631 __ CallRuntime(Runtime::kTypeof, 1); |
| 3802 context()->Plug(eax); | 3632 context()->Plug(eax); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4008 // Perform the assignment as if via '='. | 3838 // Perform the assignment as if via '='. |
| 4009 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3839 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4010 Token::ASSIGN); | 3840 Token::ASSIGN); |
| 4011 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3841 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4012 context()->Plug(eax); | 3842 context()->Plug(eax); |
| 4013 } | 3843 } |
| 4014 break; | 3844 break; |
| 4015 case NAMED_PROPERTY: { | 3845 case NAMED_PROPERTY: { |
| 4016 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 3846 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 4017 __ pop(edx); | 3847 __ pop(edx); |
| 4018 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3848 Handle<Code> ic(Builtins::builtin( |
| 3849 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 3850 : Builtins::StoreIC_Initialize)); |
| 4019 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3851 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 4020 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3852 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4021 if (expr->is_postfix()) { | 3853 if (expr->is_postfix()) { |
| 4022 if (!context()->IsEffect()) { | 3854 if (!context()->IsEffect()) { |
| 4023 context()->PlugTOS(); | 3855 context()->PlugTOS(); |
| 4024 } | 3856 } |
| 4025 } else { | 3857 } else { |
| 4026 context()->Plug(eax); | 3858 context()->Plug(eax); |
| 4027 } | 3859 } |
| 4028 break; | 3860 break; |
| 4029 } | 3861 } |
| 4030 case KEYED_PROPERTY: { | 3862 case KEYED_PROPERTY: { |
| 4031 __ pop(ecx); | 3863 __ pop(ecx); |
| 4032 __ pop(edx); | 3864 __ pop(edx); |
| 4033 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3865 Handle<Code> ic(Builtins::builtin( |
| 3866 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 3867 : Builtins::KeyedStoreIC_Initialize)); |
| 4034 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3868 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 4035 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3869 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4036 if (expr->is_postfix()) { | 3870 if (expr->is_postfix()) { |
| 4037 // Result is on the stack | 3871 // Result is on the stack |
| 4038 if (!context()->IsEffect()) { | 3872 if (!context()->IsEffect()) { |
| 4039 context()->PlugTOS(); | 3873 context()->PlugTOS(); |
| 4040 } | 3874 } |
| 4041 } else { | 3875 } else { |
| 4042 context()->Plug(eax); | 3876 context()->Plug(eax); |
| 4043 } | 3877 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4103 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3937 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 4104 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3938 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 4105 Handle<String> check = Handle<String>::cast(right_literal_value); | 3939 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 4106 | 3940 |
| 4107 { AccumulatorValueContext context(this); | 3941 { AccumulatorValueContext context(this); |
| 4108 VisitForTypeofValue(left_unary->expression()); | 3942 VisitForTypeofValue(left_unary->expression()); |
| 4109 } | 3943 } |
| 4110 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3944 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4111 | 3945 |
| 4112 if (check->Equals(Heap::number_symbol())) { | 3946 if (check->Equals(Heap::number_symbol())) { |
| 4113 __ test(eax, Immediate(kSmiTagMask)); | 3947 __ JumpIfSmi(eax, if_true); |
| 4114 __ j(zero, if_true); | |
| 4115 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3948 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 4116 Factory::heap_number_map()); | 3949 Factory::heap_number_map()); |
| 4117 Split(equal, if_true, if_false, fall_through); | 3950 Split(equal, if_true, if_false, fall_through); |
| 4118 } else if (check->Equals(Heap::string_symbol())) { | 3951 } else if (check->Equals(Heap::string_symbol())) { |
| 4119 __ test(eax, Immediate(kSmiTagMask)); | 3952 __ JumpIfSmi(eax, if_false); |
| 4120 __ j(zero, if_false); | 3953 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); |
| 3954 __ j(above_equal, if_false); |
| 4121 // Check for undetectable objects => false. | 3955 // Check for undetectable objects => false. |
| 4122 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3956 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 4123 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3957 1 << Map::kIsUndetectable); |
| 4124 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3958 Split(zero, if_true, if_false, fall_through); |
| 4125 __ j(not_zero, if_false); | |
| 4126 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); | |
| 4127 Split(below, if_true, if_false, fall_through); | |
| 4128 } else if (check->Equals(Heap::boolean_symbol())) { | 3959 } else if (check->Equals(Heap::boolean_symbol())) { |
| 4129 __ cmp(eax, Factory::true_value()); | 3960 __ cmp(eax, Factory::true_value()); |
| 4130 __ j(equal, if_true); | 3961 __ j(equal, if_true); |
| 4131 __ cmp(eax, Factory::false_value()); | 3962 __ cmp(eax, Factory::false_value()); |
| 4132 Split(equal, if_true, if_false, fall_through); | 3963 Split(equal, if_true, if_false, fall_through); |
| 4133 } else if (check->Equals(Heap::undefined_symbol())) { | 3964 } else if (check->Equals(Heap::undefined_symbol())) { |
| 4134 __ cmp(eax, Factory::undefined_value()); | 3965 __ cmp(eax, Factory::undefined_value()); |
| 4135 __ j(equal, if_true); | 3966 __ j(equal, if_true); |
| 4136 __ test(eax, Immediate(kSmiTagMask)); | 3967 __ JumpIfSmi(eax, if_false); |
| 4137 __ j(zero, if_false); | |
| 4138 // Check for undetectable objects => true. | 3968 // Check for undetectable objects => true. |
| 4139 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3969 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4140 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3970 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4141 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3971 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 4142 Split(not_zero, if_true, if_false, fall_through); | 3972 Split(not_zero, if_true, if_false, fall_through); |
| 4143 } else if (check->Equals(Heap::function_symbol())) { | 3973 } else if (check->Equals(Heap::function_symbol())) { |
| 4144 __ test(eax, Immediate(kSmiTagMask)); | 3974 __ JumpIfSmi(eax, if_false); |
| 4145 __ j(zero, if_false); | 3975 __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx); |
| 4146 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); | 3976 Split(above_equal, if_true, if_false, fall_through); |
| 4147 __ j(equal, if_true); | |
| 4148 // Regular expressions => 'function' (they are callable). | |
| 4149 __ CmpInstanceType(edx, JS_REGEXP_TYPE); | |
| 4150 Split(equal, if_true, if_false, fall_through); | |
| 4151 } else if (check->Equals(Heap::object_symbol())) { | 3977 } else if (check->Equals(Heap::object_symbol())) { |
| 4152 __ test(eax, Immediate(kSmiTagMask)); | 3978 __ JumpIfSmi(eax, if_false); |
| 4153 __ j(zero, if_false); | |
| 4154 __ cmp(eax, Factory::null_value()); | 3979 __ cmp(eax, Factory::null_value()); |
| 4155 __ j(equal, if_true); | 3980 __ j(equal, if_true); |
| 4156 // Regular expressions => 'function', not 'object'. | 3981 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx); |
| 4157 __ CmpObjectType(eax, JS_REGEXP_TYPE, edx); | 3982 __ j(below, if_false); |
| 4158 __ j(equal, if_false); | 3983 __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE); |
| 3984 __ j(above_equal, if_false); |
| 4159 // Check for undetectable objects => false. | 3985 // Check for undetectable objects => false. |
| 4160 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3986 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 4161 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 3987 1 << Map::kIsUndetectable); |
| 4162 __ j(not_zero, if_false); | 3988 Split(zero, if_true, if_false, fall_through); |
| 4163 // Check for JS objects => true. | |
| 4164 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | |
| 4165 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
| 4166 __ j(less, if_false); | |
| 4167 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | |
| 4168 Split(less_equal, if_true, if_false, fall_through); | |
| 4169 } else { | 3989 } else { |
| 4170 if (if_false != fall_through) __ jmp(if_false); | 3990 if (if_false != fall_through) __ jmp(if_false); |
| 4171 } | 3991 } |
| 4172 | 3992 |
| 4173 return true; | 3993 return true; |
| 4174 } | 3994 } |
| 4175 | 3995 |
| 4176 | 3996 |
| 4177 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 3997 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 4178 Comment cmnt(masm_, "[ CompareOperation"); | 3998 Comment cmnt(masm_, "[ CompareOperation"); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4371 __ nop(); // Signals no inlined code. | 4191 __ nop(); // Signals no inlined code. |
| 4372 break; | 4192 break; |
| 4373 default: | 4193 default: |
| 4374 // Do nothing. | 4194 // Do nothing. |
| 4375 break; | 4195 break; |
| 4376 } | 4196 } |
| 4377 } | 4197 } |
| 4378 | 4198 |
| 4379 | 4199 |
| 4380 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { | 4200 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { |
| 4201 switch (ic->kind()) { |
| 4202 case Code::LOAD_IC: |
| 4203 __ IncrementCounter(&Counters::named_load_full, 1); |
| 4204 break; |
| 4205 case Code::KEYED_LOAD_IC: |
| 4206 __ IncrementCounter(&Counters::keyed_load_full, 1); |
| 4207 break; |
| 4208 case Code::STORE_IC: |
| 4209 __ IncrementCounter(&Counters::named_store_full, 1); |
| 4210 break; |
| 4211 case Code::KEYED_STORE_IC: |
| 4212 __ IncrementCounter(&Counters::keyed_store_full, 1); |
| 4213 default: |
| 4214 break; |
| 4215 } |
| 4216 |
| 4381 __ call(ic, RelocInfo::CODE_TARGET); | 4217 __ call(ic, RelocInfo::CODE_TARGET); |
| 4382 if (patch_site != NULL && patch_site->is_bound()) { | 4218 if (patch_site != NULL && patch_site->is_bound()) { |
| 4383 patch_site->EmitPatchInfo(); | 4219 patch_site->EmitPatchInfo(); |
| 4384 } else { | 4220 } else { |
| 4385 __ nop(); // Signals no inlined code. | 4221 __ nop(); // Signals no inlined code. |
| 4386 } | 4222 } |
| 4387 } | 4223 } |
| 4388 | 4224 |
| 4389 | 4225 |
| 4390 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 4226 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4427 // And return. | 4263 // And return. |
| 4428 __ ret(0); | 4264 __ ret(0); |
| 4429 } | 4265 } |
| 4430 | 4266 |
| 4431 | 4267 |
| 4432 #undef __ | 4268 #undef __ |
| 4433 | 4269 |
| 4434 } } // namespace v8::internal | 4270 } } // namespace v8::internal |
| 4435 | 4271 |
| 4436 #endif // V8_TARGET_ARCH_IA32 | 4272 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |