| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 | 126 |
| 127 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 127 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 128 | 128 |
| 129 #ifdef DEBUG | 129 #ifdef DEBUG |
| 130 if (strlen(FLAG_stop_at) > 0 && | 130 if (strlen(FLAG_stop_at) > 0 && |
| 131 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 131 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 132 __ int3(); | 132 __ int3(); |
| 133 } | 133 } |
| 134 #endif | 134 #endif |
| 135 | 135 |
| 136 // Strict mode functions and builtins need to replace the receiver | 136 // Classic mode functions and builtins need to replace the receiver with the |
| 137 // with undefined when called as functions (without an explicit | 137 // global proxy when called as functions (without an explicit receiver |
| 138 // receiver object). ecx is zero for method calls and non-zero for | 138 // object). |
| 139 // function calls. | 139 if (info->is_classic_mode() && !info->is_native()) { |
| 140 if (!info->is_classic_mode() || info->is_native()) { | |
| 141 Label ok; | 140 Label ok; |
| 142 __ test(ecx, ecx); | 141 __ test(ecx, ecx); |
| 143 __ j(zero, &ok, Label::kNear); | 142 __ j(zero, &ok, Label::kNear); |
| 143 |
| 144 // +1 for return address. | 144 // +1 for return address. |
| 145 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; | 145 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
| 146 __ mov(ecx, Operand(esp, receiver_offset)); | 146 __ mov(ecx, Operand(esp, receiver_offset)); |
| 147 __ JumpIfSmi(ecx, &ok); | 147 |
| 148 __ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx); | 148 __ cmp(ecx, isolate()->factory()->undefined_value()); |
| 149 __ j(not_equal, &ok, Label::kNear); | 149 __ j(not_equal, &ok, Label::kNear); |
| 150 __ mov(Operand(esp, receiver_offset), | 150 |
| 151 Immediate(isolate()->factory()->undefined_value())); | 151 __ mov(ecx, GlobalObjectOperand()); |
| 152 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); |
| 153 |
| 154 __ mov(Operand(esp, receiver_offset), ecx); |
| 155 |
| 152 __ bind(&ok); | 156 __ bind(&ok); |
| 153 } | 157 } |
| 154 | 158 |
| 155 // Open a frame scope to indicate that there is a frame on the stack. The | 159 // Open a frame scope to indicate that there is a frame on the stack. The |
| 156 // MANUAL indicates that the scope shouldn't actually generate code to set up | 160 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 157 // the frame (that is done below). | 161 // the frame (that is done below). |
| 158 FrameScope frame_scope(masm_, StackFrame::MANUAL); | 162 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 159 | 163 |
| 160 info->set_prologue_offset(masm_->pc_offset()); | 164 info->set_prologue_offset(masm_->pc_offset()); |
| 161 __ Prologue(BUILD_FUNCTION_FRAME); | 165 __ Prologue(BUILD_FUNCTION_FRAME); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 if (false_label_ != fall_through_) __ jmp(false_label_); | 621 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 618 } | 622 } |
| 619 } | 623 } |
| 620 | 624 |
| 621 | 625 |
| 622 void FullCodeGenerator::DoTest(Expression* condition, | 626 void FullCodeGenerator::DoTest(Expression* condition, |
| 623 Label* if_true, | 627 Label* if_true, |
| 624 Label* if_false, | 628 Label* if_false, |
| 625 Label* fall_through) { | 629 Label* fall_through) { |
| 626 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); | 630 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
| 627 CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id()); | 631 CallIC(ic, NOT_CONTEXTUAL, condition->test_id()); |
| 628 __ test(result_register(), result_register()); | 632 __ test(result_register(), result_register()); |
| 629 // The stub returns nonzero for true. | 633 // The stub returns nonzero for true. |
| 630 Split(not_zero, if_true, if_false, fall_through); | 634 Split(not_zero, if_true, if_false, fall_through); |
| 631 } | 635 } |
| 632 | 636 |
| 633 | 637 |
| 634 void FullCodeGenerator::Split(Condition cc, | 638 void FullCodeGenerator::Split(Condition cc, |
| 635 Label* if_true, | 639 Label* if_true, |
| 636 Label* if_false, | 640 Label* if_false, |
| 637 Label* fall_through) { | 641 Label* fall_through) { |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 __ cmp(edx, eax); | 972 __ cmp(edx, eax); |
| 969 __ j(not_equal, &next_test); | 973 __ j(not_equal, &next_test); |
| 970 __ Drop(1); // Switch value is no longer needed. | 974 __ Drop(1); // Switch value is no longer needed. |
| 971 __ jmp(clause->body_target()); | 975 __ jmp(clause->body_target()); |
| 972 __ bind(&slow_case); | 976 __ bind(&slow_case); |
| 973 } | 977 } |
| 974 | 978 |
| 975 // Record position before stub call for type feedback. | 979 // Record position before stub call for type feedback. |
| 976 SetSourcePosition(clause->position()); | 980 SetSourcePosition(clause->position()); |
| 977 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 981 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 978 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); | 982 CallIC(ic, NOT_CONTEXTUAL, clause->CompareId()); |
| 979 patch_site.EmitPatchInfo(); | 983 patch_site.EmitPatchInfo(); |
| 980 | 984 |
| 981 Label skip; | 985 Label skip; |
| 982 __ jmp(&skip, Label::kNear); | 986 __ jmp(&skip, Label::kNear); |
| 983 PrepareForBailout(clause, TOS_REG); | 987 PrepareForBailout(clause, TOS_REG); |
| 984 __ cmp(eax, isolate()->factory()->true_value()); | 988 __ cmp(eax, isolate()->factory()->true_value()); |
| 985 __ j(not_equal, &next_test); | 989 __ j(not_equal, &next_test); |
| 986 __ Drop(1); | 990 __ Drop(1); |
| 987 __ jmp(clause->body_target()); | 991 __ jmp(clause->body_target()); |
| 988 __ bind(&skip); | 992 __ bind(&skip); |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1324 // Load next context in chain. | 1328 // Load next context in chain. |
| 1325 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX)); | 1329 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX)); |
| 1326 __ jmp(&next); | 1330 __ jmp(&next); |
| 1327 __ bind(&fast); | 1331 __ bind(&fast); |
| 1328 } | 1332 } |
| 1329 | 1333 |
| 1330 // All extension objects were empty and it is safe to use a global | 1334 // All extension objects were empty and it is safe to use a global |
| 1331 // load IC call. | 1335 // load IC call. |
| 1332 __ mov(edx, GlobalObjectOperand()); | 1336 __ mov(edx, GlobalObjectOperand()); |
| 1333 __ mov(ecx, var->name()); | 1337 __ mov(ecx, var->name()); |
| 1334 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1338 ContextualMode mode = (typeof_state == INSIDE_TYPEOF) |
| 1335 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1339 ? NOT_CONTEXTUAL |
| 1336 ? RelocInfo::CODE_TARGET | 1340 : CONTEXTUAL; |
| 1337 : RelocInfo::CODE_TARGET_CONTEXT; | 1341 |
| 1338 CallIC(ic, mode); | 1342 CallLoadIC(mode); |
| 1339 } | 1343 } |
| 1340 | 1344 |
| 1341 | 1345 |
| 1342 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, | 1346 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, |
| 1343 Label* slow) { | 1347 Label* slow) { |
| 1344 ASSERT(var->IsContextSlot()); | 1348 ASSERT(var->IsContextSlot()); |
| 1345 Register context = esi; | 1349 Register context = esi; |
| 1346 Register temp = ebx; | 1350 Register temp = ebx; |
| 1347 | 1351 |
| 1348 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { | 1352 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 | 1412 |
| 1409 // Three cases: global variables, lookup variables, and all other types of | 1413 // Three cases: global variables, lookup variables, and all other types of |
| 1410 // variables. | 1414 // variables. |
| 1411 switch (var->location()) { | 1415 switch (var->location()) { |
| 1412 case Variable::UNALLOCATED: { | 1416 case Variable::UNALLOCATED: { |
| 1413 Comment cmnt(masm_, "Global variable"); | 1417 Comment cmnt(masm_, "Global variable"); |
| 1414 // Use inline caching. Variable name is passed in ecx and the global | 1418 // Use inline caching. Variable name is passed in ecx and the global |
| 1415 // object in eax. | 1419 // object in eax. |
| 1416 __ mov(edx, GlobalObjectOperand()); | 1420 __ mov(edx, GlobalObjectOperand()); |
| 1417 __ mov(ecx, var->name()); | 1421 __ mov(ecx, var->name()); |
| 1418 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1422 CallLoadIC(CONTEXTUAL); |
| 1419 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
| 1420 context()->Plug(eax); | 1423 context()->Plug(eax); |
| 1421 break; | 1424 break; |
| 1422 } | 1425 } |
| 1423 | 1426 |
| 1424 case Variable::PARAMETER: | 1427 case Variable::PARAMETER: |
| 1425 case Variable::LOCAL: | 1428 case Variable::LOCAL: |
| 1426 case Variable::CONTEXT: { | 1429 case Variable::CONTEXT: { |
| 1427 Comment cmnt(masm_, var->IsContextSlot() | 1430 Comment cmnt(masm_, var->IsContextSlot() |
| 1428 ? "Context variable" | 1431 ? "Context variable" |
| 1429 : "Stack variable"); | 1432 : "Stack variable"); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 UNREACHABLE(); | 1628 UNREACHABLE(); |
| 1626 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1629 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1627 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1630 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1628 // Fall through. | 1631 // Fall through. |
| 1629 case ObjectLiteral::Property::COMPUTED: | 1632 case ObjectLiteral::Property::COMPUTED: |
| 1630 if (key->value()->IsInternalizedString()) { | 1633 if (key->value()->IsInternalizedString()) { |
| 1631 if (property->emit_store()) { | 1634 if (property->emit_store()) { |
| 1632 VisitForAccumulatorValue(value); | 1635 VisitForAccumulatorValue(value); |
| 1633 __ mov(ecx, Immediate(key->value())); | 1636 __ mov(ecx, Immediate(key->value())); |
| 1634 __ mov(edx, Operand(esp, 0)); | 1637 __ mov(edx, Operand(esp, 0)); |
| 1635 Handle<Code> ic = is_classic_mode() | 1638 CallStoreIC(NOT_CONTEXTUAL, key->LiteralFeedbackId()); |
| 1636 ? isolate()->builtins()->StoreIC_Initialize() | |
| 1637 : isolate()->builtins()->StoreIC_Initialize_Strict(); | |
| 1638 CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId()); | |
| 1639 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1639 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1640 } else { | 1640 } else { |
| 1641 VisitForEffect(value); | 1641 VisitForEffect(value); |
| 1642 } | 1642 } |
| 1643 break; | 1643 break; |
| 1644 } | 1644 } |
| 1645 __ push(Operand(esp, 0)); // Duplicate receiver. | 1645 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1646 VisitForStackValue(key); | 1646 VisitForStackValue(key); |
| 1647 VisitForStackValue(value); | 1647 VisitForStackValue(value); |
| 1648 if (property->emit_store()) { | 1648 if (property->emit_store()) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1709 int length = subexprs->length(); | 1709 int length = subexprs->length(); |
| 1710 Handle<FixedArray> constant_elements = expr->constant_elements(); | 1710 Handle<FixedArray> constant_elements = expr->constant_elements(); |
| 1711 ASSERT_EQ(2, constant_elements->length()); | 1711 ASSERT_EQ(2, constant_elements->length()); |
| 1712 ElementsKind constant_elements_kind = | 1712 ElementsKind constant_elements_kind = |
| 1713 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); | 1713 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); |
| 1714 bool has_constant_fast_elements = | 1714 bool has_constant_fast_elements = |
| 1715 IsFastObjectElementsKind(constant_elements_kind); | 1715 IsFastObjectElementsKind(constant_elements_kind); |
| 1716 Handle<FixedArrayBase> constant_elements_values( | 1716 Handle<FixedArrayBase> constant_elements_values( |
| 1717 FixedArrayBase::cast(constant_elements->get(1))); | 1717 FixedArrayBase::cast(constant_elements->get(1))); |
| 1718 | 1718 |
| 1719 AllocationSiteMode allocation_site_mode = FLAG_track_allocation_sites | 1719 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; |
| 1720 ? TRACK_ALLOCATION_SITE : DONT_TRACK_ALLOCATION_SITE; | |
| 1721 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { | 1720 if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { |
| 1722 // If the only customer of allocation sites is transitioning, then | 1721 // If the only customer of allocation sites is transitioning, then |
| 1723 // we can turn it off if we don't have anywhere else to transition to. | 1722 // we can turn it off if we don't have anywhere else to transition to. |
| 1724 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; | 1723 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; |
| 1725 } | 1724 } |
| 1726 | 1725 |
| 1727 Heap* heap = isolate()->heap(); | 1726 Heap* heap = isolate()->heap(); |
| 1728 if (has_constant_fast_elements && | 1727 if (has_constant_fast_elements && |
| 1729 constant_elements_values->map() == heap->fixed_cow_array_map()) { | 1728 constant_elements_values->map() == heap->fixed_cow_array_map()) { |
| 1730 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot | 1729 // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 2050 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); |
| 2052 CallIC(ic); | 2051 CallIC(ic); |
| 2053 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2052 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2054 __ Drop(1); // The key is still on the stack; drop it. | 2053 __ Drop(1); // The key is still on the stack; drop it. |
| 2055 | 2054 |
| 2056 // if (!result.done) goto l_try; | 2055 // if (!result.done) goto l_try; |
| 2057 __ bind(&l_loop); | 2056 __ bind(&l_loop); |
| 2058 __ push(eax); // save result | 2057 __ push(eax); // save result |
| 2059 __ mov(edx, eax); // result | 2058 __ mov(edx, eax); // result |
| 2060 __ mov(ecx, isolate()->factory()->done_string()); // "done" | 2059 __ mov(ecx, isolate()->factory()->done_string()); // "done" |
| 2061 Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize(); | 2060 CallLoadIC(NOT_CONTEXTUAL); // result.done in eax |
| 2062 CallIC(done_ic); // result.done in eax | |
| 2063 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 2061 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 2064 CallIC(bool_ic); | 2062 CallIC(bool_ic); |
| 2065 __ test(eax, eax); | 2063 __ test(eax, eax); |
| 2066 __ j(zero, &l_try); | 2064 __ j(zero, &l_try); |
| 2067 | 2065 |
| 2068 // result.value | 2066 // result.value |
| 2069 __ pop(edx); // result | 2067 __ pop(edx); // result |
| 2070 __ mov(ecx, isolate()->factory()->value_string()); // "value" | 2068 __ mov(ecx, isolate()->factory()->value_string()); // "value" |
| 2071 Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize(); | 2069 CallLoadIC(NOT_CONTEXTUAL); // result.value in eax |
| 2072 CallIC(value_ic); // result.value in eax | 2070 context()->DropAndPlug(2, eax); // drop iter and g |
| 2073 context()->DropAndPlug(2, eax); // drop iter and g | |
| 2074 break; | 2071 break; |
| 2075 } | 2072 } |
| 2076 } | 2073 } |
| 2077 } | 2074 } |
| 2078 | 2075 |
| 2079 | 2076 |
| 2080 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, | 2077 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
| 2081 Expression *value, | 2078 Expression *value, |
| 2082 JSGeneratorObject::ResumeMode resume_mode) { | 2079 JSGeneratorObject::ResumeMode resume_mode) { |
| 2083 // The value stays in eax, and is ultimately read by the resumed generator, as | 2080 // The value stays in eax, and is ultimately read by the resumed generator, as |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2206 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, | 2203 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, |
| 2207 ecx, edx, kDontSaveFPRegs); | 2204 ecx, edx, kDontSaveFPRegs); |
| 2208 } | 2205 } |
| 2209 | 2206 |
| 2210 | 2207 |
| 2211 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 2208 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 2212 SetSourcePosition(prop->position()); | 2209 SetSourcePosition(prop->position()); |
| 2213 Literal* key = prop->key()->AsLiteral(); | 2210 Literal* key = prop->key()->AsLiteral(); |
| 2214 ASSERT(!key->value()->IsSmi()); | 2211 ASSERT(!key->value()->IsSmi()); |
| 2215 __ mov(ecx, Immediate(key->value())); | 2212 __ mov(ecx, Immediate(key->value())); |
| 2216 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2213 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2217 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); | |
| 2218 } | 2214 } |
| 2219 | 2215 |
| 2220 | 2216 |
| 2221 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 2217 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 2222 SetSourcePosition(prop->position()); | 2218 SetSourcePosition(prop->position()); |
| 2223 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2219 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2224 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); | 2220 CallIC(ic, NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2225 } | 2221 } |
| 2226 | 2222 |
| 2227 | 2223 |
| 2228 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2224 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 2229 Token::Value op, | 2225 Token::Value op, |
| 2230 OverwriteMode mode, | 2226 OverwriteMode mode, |
| 2231 Expression* left, | 2227 Expression* left, |
| 2232 Expression* right) { | 2228 Expression* right) { |
| 2233 // Do combined smi check of the operands. Left operand is on the | 2229 // Do combined smi check of the operands. Left operand is on the |
| 2234 // stack. Right operand is in eax. | 2230 // stack. Right operand is in eax. |
| 2235 Label smi_case, done, stub_call; | 2231 Label smi_case, done, stub_call; |
| 2236 __ pop(edx); | 2232 __ pop(edx); |
| 2237 __ mov(ecx, eax); | 2233 __ mov(ecx, eax); |
| 2238 __ or_(eax, edx); | 2234 __ or_(eax, edx); |
| 2239 JumpPatchSite patch_site(masm_); | 2235 JumpPatchSite patch_site(masm_); |
| 2240 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); | 2236 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); |
| 2241 | 2237 |
| 2242 __ bind(&stub_call); | 2238 __ bind(&stub_call); |
| 2243 __ mov(eax, ecx); | 2239 __ mov(eax, ecx); |
| 2244 BinaryOpICStub stub(op, mode); | 2240 BinaryOpICStub stub(op, mode); |
| 2245 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, | 2241 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, |
| 2246 expr->BinaryOperationFeedbackId()); | 2242 expr->BinaryOperationFeedbackId()); |
| 2247 patch_site.EmitPatchInfo(); | 2243 patch_site.EmitPatchInfo(); |
| 2248 __ jmp(&done, Label::kNear); | 2244 __ jmp(&done, Label::kNear); |
| 2249 | 2245 |
| 2250 // Smi case. | 2246 // Smi case. |
| 2251 __ bind(&smi_case); | 2247 __ bind(&smi_case); |
| 2252 __ mov(eax, edx); // Copy left operand in case of a stub call. | 2248 __ mov(eax, edx); // Copy left operand in case of a stub call. |
| 2253 | 2249 |
| 2254 switch (op) { | 2250 switch (op) { |
| 2255 case Token::SAR: | 2251 case Token::SAR: |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2321 context()->Plug(eax); | 2317 context()->Plug(eax); |
| 2322 } | 2318 } |
| 2323 | 2319 |
| 2324 | 2320 |
| 2325 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 2321 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 2326 Token::Value op, | 2322 Token::Value op, |
| 2327 OverwriteMode mode) { | 2323 OverwriteMode mode) { |
| 2328 __ pop(edx); | 2324 __ pop(edx); |
| 2329 BinaryOpICStub stub(op, mode); | 2325 BinaryOpICStub stub(op, mode); |
| 2330 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2326 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 2331 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, | 2327 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, |
| 2332 expr->BinaryOperationFeedbackId()); | 2328 expr->BinaryOperationFeedbackId()); |
| 2333 patch_site.EmitPatchInfo(); | 2329 patch_site.EmitPatchInfo(); |
| 2334 context()->Plug(eax); | 2330 context()->Plug(eax); |
| 2335 } | 2331 } |
| 2336 | 2332 |
| 2337 | 2333 |
| 2338 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 2334 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 2339 // Invalid left-hand sides are rewritten by the parser to have a 'throw | 2335 // Invalid left-hand sides are rewritten by the parser to have a 'throw |
| 2340 // ReferenceError' on the left-hand side. | 2336 // ReferenceError' on the left-hand side. |
| 2341 if (!expr->IsValidLeftHandSide()) { | 2337 if (!expr->IsValidLeftHandSide()) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2360 EffectContext context(this); | 2356 EffectContext context(this); |
| 2361 EmitVariableAssignment(var, Token::ASSIGN); | 2357 EmitVariableAssignment(var, Token::ASSIGN); |
| 2362 break; | 2358 break; |
| 2363 } | 2359 } |
| 2364 case NAMED_PROPERTY: { | 2360 case NAMED_PROPERTY: { |
| 2365 __ push(eax); // Preserve value. | 2361 __ push(eax); // Preserve value. |
| 2366 VisitForAccumulatorValue(prop->obj()); | 2362 VisitForAccumulatorValue(prop->obj()); |
| 2367 __ mov(edx, eax); | 2363 __ mov(edx, eax); |
| 2368 __ pop(eax); // Restore value. | 2364 __ pop(eax); // Restore value. |
| 2369 __ mov(ecx, prop->key()->AsLiteral()->value()); | 2365 __ mov(ecx, prop->key()->AsLiteral()->value()); |
| 2370 Handle<Code> ic = is_classic_mode() | 2366 CallStoreIC(NOT_CONTEXTUAL); |
| 2371 ? isolate()->builtins()->StoreIC_Initialize() | |
| 2372 : isolate()->builtins()->StoreIC_Initialize_Strict(); | |
| 2373 CallIC(ic); | |
| 2374 break; | 2367 break; |
| 2375 } | 2368 } |
| 2376 case KEYED_PROPERTY: { | 2369 case KEYED_PROPERTY: { |
| 2377 __ push(eax); // Preserve value. | 2370 __ push(eax); // Preserve value. |
| 2378 VisitForStackValue(prop->obj()); | 2371 VisitForStackValue(prop->obj()); |
| 2379 VisitForAccumulatorValue(prop->key()); | 2372 VisitForAccumulatorValue(prop->key()); |
| 2380 __ mov(ecx, eax); | 2373 __ mov(ecx, eax); |
| 2381 __ pop(edx); // Receiver. | 2374 __ pop(edx); // Receiver. |
| 2382 __ pop(eax); // Restore value. | 2375 __ pop(eax); // Restore value. |
| 2383 Handle<Code> ic = is_classic_mode() | 2376 Handle<Code> ic = is_classic_mode() |
| 2384 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2377 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2385 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2378 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2386 CallIC(ic); | 2379 CallIC(ic); |
| 2387 break; | 2380 break; |
| 2388 } | 2381 } |
| 2389 } | 2382 } |
| 2390 context()->Plug(eax); | 2383 context()->Plug(eax); |
| 2391 } | 2384 } |
| 2392 | 2385 |
| 2393 | 2386 |
| 2394 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2387 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2395 Token::Value op) { | 2388 Token::Value op) { |
| 2396 if (var->IsUnallocated()) { | 2389 if (var->IsUnallocated()) { |
| 2397 // Global var, const, or let. | 2390 // Global var, const, or let. |
| 2398 __ mov(ecx, var->name()); | 2391 __ mov(ecx, var->name()); |
| 2399 __ mov(edx, GlobalObjectOperand()); | 2392 __ mov(edx, GlobalObjectOperand()); |
| 2400 Handle<Code> ic = is_classic_mode() | 2393 CallStoreIC(CONTEXTUAL); |
| 2401 ? isolate()->builtins()->StoreIC_Initialize() | |
| 2402 : isolate()->builtins()->StoreIC_Initialize_Strict(); | |
| 2403 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
| 2404 | |
| 2405 } else if (op == Token::INIT_CONST) { | 2394 } else if (op == Token::INIT_CONST) { |
| 2406 // Const initializers need a write barrier. | 2395 // Const initializers need a write barrier. |
| 2407 ASSERT(!var->IsParameter()); // No const parameters. | 2396 ASSERT(!var->IsParameter()); // No const parameters. |
| 2408 if (var->IsStackLocal()) { | 2397 if (var->IsStackLocal()) { |
| 2409 Label skip; | 2398 Label skip; |
| 2410 __ mov(edx, StackOperand(var)); | 2399 __ mov(edx, StackOperand(var)); |
| 2411 __ cmp(edx, isolate()->factory()->the_hole_value()); | 2400 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2412 __ j(not_equal, &skip); | 2401 __ j(not_equal, &skip); |
| 2413 __ mov(StackOperand(var), eax); | 2402 __ mov(StackOperand(var), eax); |
| 2414 __ bind(&skip); | 2403 __ bind(&skip); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2488 // esp[0] : receiver | 2477 // esp[0] : receiver |
| 2489 | 2478 |
| 2490 Property* prop = expr->target()->AsProperty(); | 2479 Property* prop = expr->target()->AsProperty(); |
| 2491 ASSERT(prop != NULL); | 2480 ASSERT(prop != NULL); |
| 2492 ASSERT(prop->key()->AsLiteral() != NULL); | 2481 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2493 | 2482 |
| 2494 // Record source code position before IC call. | 2483 // Record source code position before IC call. |
| 2495 SetSourcePosition(expr->position()); | 2484 SetSourcePosition(expr->position()); |
| 2496 __ mov(ecx, prop->key()->AsLiteral()->value()); | 2485 __ mov(ecx, prop->key()->AsLiteral()->value()); |
| 2497 __ pop(edx); | 2486 __ pop(edx); |
| 2498 Handle<Code> ic = is_classic_mode() | 2487 CallStoreIC(NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); |
| 2499 ? isolate()->builtins()->StoreIC_Initialize() | |
| 2500 : isolate()->builtins()->StoreIC_Initialize_Strict(); | |
| 2501 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); | |
| 2502 | |
| 2503 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2488 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2504 context()->Plug(eax); | 2489 context()->Plug(eax); |
| 2505 } | 2490 } |
| 2506 | 2491 |
| 2507 | 2492 |
| 2508 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2493 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2509 // Assignment to a property, using a keyed store IC. | 2494 // Assignment to a property, using a keyed store IC. |
| 2510 // eax : value | 2495 // eax : value |
| 2511 // esp[0] : key | 2496 // esp[0] : key |
| 2512 // esp[kPointerSize] : receiver | 2497 // esp[kPointerSize] : receiver |
| 2513 | 2498 |
| 2514 __ pop(ecx); // Key. | 2499 __ pop(ecx); // Key. |
| 2515 __ pop(edx); | 2500 __ pop(edx); |
| 2516 // Record source code position before IC call. | 2501 // Record source code position before IC call. |
| 2517 SetSourcePosition(expr->position()); | 2502 SetSourcePosition(expr->position()); |
| 2518 Handle<Code> ic = is_classic_mode() | 2503 Handle<Code> ic = is_classic_mode() |
| 2519 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2504 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2520 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2505 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2521 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); | 2506 CallIC(ic, NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); |
| 2522 | 2507 |
| 2523 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2508 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2524 context()->Plug(eax); | 2509 context()->Plug(eax); |
| 2525 } | 2510 } |
| 2526 | 2511 |
| 2527 | 2512 |
| 2528 void FullCodeGenerator::VisitProperty(Property* expr) { | 2513 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 2529 Comment cmnt(masm_, "[ Property"); | 2514 Comment cmnt(masm_, "[ Property"); |
| 2530 Expression* key = expr->key(); | 2515 Expression* key = expr->key(); |
| 2531 | 2516 |
| 2532 if (key->IsPropertyName()) { | 2517 if (key->IsPropertyName()) { |
| 2533 VisitForAccumulatorValue(expr->obj()); | 2518 VisitForAccumulatorValue(expr->obj()); |
| 2534 __ mov(edx, result_register()); | 2519 __ mov(edx, result_register()); |
| 2535 EmitNamedPropertyLoad(expr); | 2520 EmitNamedPropertyLoad(expr); |
| 2536 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2521 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
| 2537 context()->Plug(eax); | 2522 context()->Plug(eax); |
| 2538 } else { | 2523 } else { |
| 2539 VisitForStackValue(expr->obj()); | 2524 VisitForStackValue(expr->obj()); |
| 2540 VisitForAccumulatorValue(expr->key()); | 2525 VisitForAccumulatorValue(expr->key()); |
| 2541 __ pop(edx); // Object. | 2526 __ pop(edx); // Object. |
| 2542 __ mov(ecx, result_register()); // Key. | 2527 __ mov(ecx, result_register()); // Key. |
| 2543 EmitKeyedPropertyLoad(expr); | 2528 EmitKeyedPropertyLoad(expr); |
| 2544 context()->Plug(eax); | 2529 context()->Plug(eax); |
| 2545 } | 2530 } |
| 2546 } | 2531 } |
| 2547 | 2532 |
| 2548 | 2533 |
| 2549 void FullCodeGenerator::CallIC(Handle<Code> code, | 2534 void FullCodeGenerator::CallIC(Handle<Code> code, |
| 2550 RelocInfo::Mode rmode, | 2535 ContextualMode mode, |
| 2551 TypeFeedbackId ast_id) { | 2536 TypeFeedbackId ast_id) { |
| 2552 ic_total_count_++; | 2537 ic_total_count_++; |
| 2553 __ call(code, rmode, ast_id); | 2538 ASSERT(mode != CONTEXTUAL || ast_id.IsNone()); |
| 2539 __ call(code, RelocInfo::CODE_TARGET, ast_id); |
| 2554 } | 2540 } |
| 2555 | 2541 |
| 2556 | 2542 |
| 2557 | 2543 |
| 2558 | 2544 |
| 2559 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 2545 void FullCodeGenerator::EmitCallWithIC(Call* expr, |
| 2560 Handle<Object> name, | 2546 Handle<Object> name, |
| 2561 RelocInfo::Mode mode) { | 2547 ContextualMode mode) { |
| 2562 // Code common for calls using the IC. | 2548 // Code common for calls using the IC. |
| 2563 ZoneList<Expression*>* args = expr->arguments(); | 2549 ZoneList<Expression*>* args = expr->arguments(); |
| 2564 int arg_count = args->length(); | 2550 int arg_count = args->length(); |
| 2565 { PreservePositionScope scope(masm()->positions_recorder()); | 2551 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2566 for (int i = 0; i < arg_count; i++) { | 2552 for (int i = 0; i < arg_count; i++) { |
| 2567 VisitForStackValue(args->at(i)); | 2553 VisitForStackValue(args->at(i)); |
| 2568 } | 2554 } |
| 2569 __ Set(ecx, Immediate(name)); | 2555 __ Set(ecx, Immediate(name)); |
| 2570 } | 2556 } |
| 2571 // Record source position of the IC call. | 2557 // Record source position of the IC call. |
| 2572 SetSourcePosition(expr->position()); | 2558 SetSourcePosition(expr->position()); |
| 2573 Handle<Code> ic = | 2559 Handle<Code> ic = |
| 2574 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); | 2560 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); |
| 2575 CallIC(ic, mode, expr->CallFeedbackId()); | 2561 TypeFeedbackId ast_id = mode == CONTEXTUAL |
| 2562 ? TypeFeedbackId::None() |
| 2563 : expr->CallFeedbackId(); |
| 2564 CallIC(ic, mode, ast_id); |
| 2576 RecordJSReturnSite(expr); | 2565 RecordJSReturnSite(expr); |
| 2577 // Restore context register. | 2566 // Restore context register. |
| 2578 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2567 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2579 context()->Plug(eax); | 2568 context()->Plug(eax); |
| 2580 } | 2569 } |
| 2581 | 2570 |
| 2582 | 2571 |
| 2583 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2572 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2584 Expression* key) { | 2573 Expression* key) { |
| 2585 // Load the key. | 2574 // Load the key. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2597 { PreservePositionScope scope(masm()->positions_recorder()); | 2586 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2598 for (int i = 0; i < arg_count; i++) { | 2587 for (int i = 0; i < arg_count; i++) { |
| 2599 VisitForStackValue(args->at(i)); | 2588 VisitForStackValue(args->at(i)); |
| 2600 } | 2589 } |
| 2601 } | 2590 } |
| 2602 // Record source position of the IC call. | 2591 // Record source position of the IC call. |
| 2603 SetSourcePosition(expr->position()); | 2592 SetSourcePosition(expr->position()); |
| 2604 Handle<Code> ic = | 2593 Handle<Code> ic = |
| 2605 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); | 2594 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); |
| 2606 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. | 2595 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. |
| 2607 CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId()); | 2596 CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId()); |
| 2608 RecordJSReturnSite(expr); | 2597 RecordJSReturnSite(expr); |
| 2609 // Restore context register. | 2598 // Restore context register. |
| 2610 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2599 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2611 context()->DropAndPlug(1, eax); // Drop the key still on the stack. | 2600 context()->DropAndPlug(1, eax); // Drop the key still on the stack. |
| 2612 } | 2601 } |
| 2613 | 2602 |
| 2614 | 2603 |
| 2615 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { | 2604 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { |
| 2616 // Code common for calls using the call stub. | 2605 // Code common for calls using the call stub. |
| 2617 ZoneList<Expression*>* args = expr->arguments(); | 2606 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2696 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); | 2685 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2697 EmitResolvePossiblyDirectEval(arg_count); | 2686 EmitResolvePossiblyDirectEval(arg_count); |
| 2698 | 2687 |
| 2699 // The runtime call returns a pair of values in eax (function) and | 2688 // The runtime call returns a pair of values in eax (function) and |
| 2700 // edx (receiver). Touch up the stack with the right values. | 2689 // edx (receiver). Touch up the stack with the right values. |
| 2701 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); | 2690 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
| 2702 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | 2691 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
| 2703 } | 2692 } |
| 2704 // Record source position for debugger. | 2693 // Record source position for debugger. |
| 2705 SetSourcePosition(expr->position()); | 2694 SetSourcePosition(expr->position()); |
| 2706 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT); | 2695 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 2707 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); | 2696 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2708 __ CallStub(&stub); | 2697 __ CallStub(&stub); |
| 2709 RecordJSReturnSite(expr); | 2698 RecordJSReturnSite(expr); |
| 2710 // Restore context register. | 2699 // Restore context register. |
| 2711 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2700 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2712 context()->DropAndPlug(1, eax); | 2701 context()->DropAndPlug(1, eax); |
| 2713 | 2702 |
| 2714 } else if (proxy != NULL && proxy->var()->IsUnallocated()) { | 2703 } else if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 2715 // Push global object as receiver for the call IC. | 2704 // Push global object as receiver for the call IC. |
| 2716 __ push(GlobalObjectOperand()); | 2705 __ push(GlobalObjectOperand()); |
| 2717 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); | 2706 EmitCallWithIC(expr, proxy->name(), CONTEXTUAL); |
| 2718 | |
| 2719 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 2707 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 2720 // Call to a lookup slot (dynamically introduced variable). | 2708 // Call to a lookup slot (dynamically introduced variable). |
| 2721 Label slow, done; | 2709 Label slow, done; |
| 2722 { PreservePositionScope scope(masm()->positions_recorder()); | 2710 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2723 // Generate code for loading from variables potentially shadowed by | 2711 // Generate code for loading from variables potentially shadowed by |
| 2724 // eval-introduced variables. | 2712 // eval-introduced variables. |
| 2725 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2713 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
| 2726 } | 2714 } |
| 2727 __ bind(&slow); | 2715 __ bind(&slow); |
| 2728 // Call the runtime to find the function to call (returned in eax) and | 2716 // Call the runtime to find the function to call (returned in eax) and |
| 2729 // the object holding it (returned in edx). | 2717 // the object holding it (returned in edx). |
| 2730 __ push(context_register()); | 2718 __ push(context_register()); |
| 2731 __ push(Immediate(proxy->name())); | 2719 __ push(Immediate(proxy->name())); |
| 2732 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2720 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2733 __ push(eax); // Function. | 2721 __ push(eax); // Function. |
| 2734 __ push(edx); // Receiver. | 2722 __ push(edx); // Receiver. |
| 2735 | 2723 |
| 2736 // If fast case code has been generated, emit code to push the function | 2724 // If fast case code has been generated, emit code to push the function |
| 2737 // and receiver and have the slow path jump around this code. | 2725 // and receiver and have the slow path jump around this code. |
| 2738 if (done.is_linked()) { | 2726 if (done.is_linked()) { |
| 2739 Label call; | 2727 Label call; |
| 2740 __ jmp(&call, Label::kNear); | 2728 __ jmp(&call, Label::kNear); |
| 2741 __ bind(&done); | 2729 __ bind(&done); |
| 2742 // Push function. | 2730 // Push function. |
| 2743 __ push(eax); | 2731 __ push(eax); |
| 2744 // The receiver is implicitly the global receiver. Indicate this by | 2732 // The receiver is implicitly the global receiver. Indicate this by |
| 2745 // passing the hole to the call function stub. | 2733 // passing the hole to the call function stub. |
| 2746 __ push(Immediate(isolate()->factory()->the_hole_value())); | 2734 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2747 __ bind(&call); | 2735 __ bind(&call); |
| 2748 } | 2736 } |
| 2749 | 2737 |
| 2750 // The receiver is either the global receiver or an object found by | 2738 // The receiver is either the global receiver or an object found by |
| 2751 // LoadContextSlot. That object could be the hole if the receiver is | 2739 // LoadContextSlot. |
| 2752 // implicitly the global object. | 2740 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); |
| 2753 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); | |
| 2754 | 2741 |
| 2755 } else if (property != NULL) { | 2742 } else if (property != NULL) { |
| 2756 { PreservePositionScope scope(masm()->positions_recorder()); | 2743 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2757 VisitForStackValue(property->obj()); | 2744 VisitForStackValue(property->obj()); |
| 2758 } | 2745 } |
| 2759 if (property->key()->IsPropertyName()) { | 2746 if (property->key()->IsPropertyName()) { |
| 2760 EmitCallWithIC(expr, | 2747 EmitCallWithIC(expr, |
| 2761 property->key()->AsLiteral()->value(), | 2748 property->key()->AsLiteral()->value(), |
| 2762 RelocInfo::CODE_TARGET); | 2749 NOT_CONTEXTUAL); |
| 2763 } else { | 2750 } else { |
| 2764 EmitKeyedCallWithIC(expr, property->key()); | 2751 EmitKeyedCallWithIC(expr, property->key()); |
| 2765 } | 2752 } |
| 2766 | 2753 |
| 2767 } else { | 2754 } else { |
| 2768 // Call to an arbitrary expression not handled specially above. | 2755 // Call to an arbitrary expression not handled specially above. |
| 2769 { PreservePositionScope scope(masm()->positions_recorder()); | 2756 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2770 VisitForStackValue(callee); | 2757 VisitForStackValue(callee); |
| 2771 } | 2758 } |
| 2772 // Load global receiver object. | 2759 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2773 __ mov(ebx, GlobalObjectOperand()); | |
| 2774 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | |
| 2775 // Emit function call. | 2760 // Emit function call. |
| 2776 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | 2761 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); |
| 2777 } | 2762 } |
| 2778 | 2763 |
| 2779 #ifdef DEBUG | 2764 #ifdef DEBUG |
| 2780 // RecordJSReturnSite should have been called. | 2765 // RecordJSReturnSite should have been called. |
| 2781 ASSERT(expr->return_is_recorded_); | 2766 ASSERT(expr->return_is_recorded_); |
| 2782 #endif | 2767 #endif |
| 2783 } | 2768 } |
| 2784 | 2769 |
| (...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3702 Label runtime, done; | 3687 Label runtime, done; |
| 3703 // Check for non-function argument (including proxy). | 3688 // Check for non-function argument (including proxy). |
| 3704 __ JumpIfSmi(eax, &runtime); | 3689 __ JumpIfSmi(eax, &runtime); |
| 3705 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 3690 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 3706 __ j(not_equal, &runtime); | 3691 __ j(not_equal, &runtime); |
| 3707 | 3692 |
| 3708 // InvokeFunction requires the function in edi. Move it in there. | 3693 // InvokeFunction requires the function in edi. Move it in there. |
| 3709 __ mov(edi, result_register()); | 3694 __ mov(edi, result_register()); |
| 3710 ParameterCount count(arg_count); | 3695 ParameterCount count(arg_count); |
| 3711 __ InvokeFunction(edi, count, CALL_FUNCTION, | 3696 __ InvokeFunction(edi, count, CALL_FUNCTION, |
| 3712 NullCallWrapper(), CALL_AS_METHOD); | 3697 NullCallWrapper(), CALL_AS_FUNCTION); |
| 3713 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3698 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3714 __ jmp(&done); | 3699 __ jmp(&done); |
| 3715 | 3700 |
| 3716 __ bind(&runtime); | 3701 __ bind(&runtime); |
| 3717 __ push(eax); | 3702 __ push(eax); |
| 3718 __ CallRuntime(Runtime::kCall, args->length()); | 3703 __ CallRuntime(Runtime::kCall, args->length()); |
| 3719 __ bind(&done); | 3704 __ bind(&done); |
| 3720 | 3705 |
| 3721 context()->Plug(eax); | 3706 context()->Plug(eax); |
| 3722 } | 3707 } |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4143 | 4128 |
| 4144 // Push the arguments ("left-to-right"). | 4129 // Push the arguments ("left-to-right"). |
| 4145 int arg_count = args->length(); | 4130 int arg_count = args->length(); |
| 4146 for (int i = 0; i < arg_count; i++) { | 4131 for (int i = 0; i < arg_count; i++) { |
| 4147 VisitForStackValue(args->at(i)); | 4132 VisitForStackValue(args->at(i)); |
| 4148 } | 4133 } |
| 4149 | 4134 |
| 4150 if (expr->is_jsruntime()) { | 4135 if (expr->is_jsruntime()) { |
| 4151 // Call the JS runtime function via a call IC. | 4136 // Call the JS runtime function via a call IC. |
| 4152 __ Set(ecx, Immediate(expr->name())); | 4137 __ Set(ecx, Immediate(expr->name())); |
| 4153 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; | 4138 ContextualMode mode = NOT_CONTEXTUAL; |
| 4154 Handle<Code> ic = | 4139 Handle<Code> ic = |
| 4155 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); | 4140 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); |
| 4156 CallIC(ic, mode, expr->CallRuntimeFeedbackId()); | 4141 CallIC(ic, mode, expr->CallRuntimeFeedbackId()); |
| 4157 // Restore context register. | 4142 // Restore context register. |
| 4158 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 4143 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 4159 } else { | 4144 } else { |
| 4160 // Call the C runtime function. | 4145 // Call the C runtime function. |
| 4161 __ CallRuntime(expr->function(), arg_count); | 4146 __ CallRuntime(expr->function(), arg_count); |
| 4162 } | 4147 } |
| 4163 context()->Plug(eax); | 4148 context()->Plug(eax); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4403 | 4388 |
| 4404 // Record position before stub call. | 4389 // Record position before stub call. |
| 4405 SetSourcePosition(expr->position()); | 4390 SetSourcePosition(expr->position()); |
| 4406 | 4391 |
| 4407 // Call stub for +1/-1. | 4392 // Call stub for +1/-1. |
| 4408 __ bind(&stub_call); | 4393 __ bind(&stub_call); |
| 4409 __ mov(edx, eax); | 4394 __ mov(edx, eax); |
| 4410 __ mov(eax, Immediate(Smi::FromInt(1))); | 4395 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 4411 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); | 4396 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); |
| 4412 CallIC(stub.GetCode(isolate()), | 4397 CallIC(stub.GetCode(isolate()), |
| 4413 RelocInfo::CODE_TARGET, | 4398 NOT_CONTEXTUAL, |
| 4414 expr->CountBinOpFeedbackId()); | 4399 expr->CountBinOpFeedbackId()); |
| 4415 patch_site.EmitPatchInfo(); | 4400 patch_site.EmitPatchInfo(); |
| 4416 __ bind(&done); | 4401 __ bind(&done); |
| 4417 | 4402 |
| 4418 // Store the value returned in eax. | 4403 // Store the value returned in eax. |
| 4419 switch (assign_type) { | 4404 switch (assign_type) { |
| 4420 case VARIABLE: | 4405 case VARIABLE: |
| 4421 if (expr->is_postfix()) { | 4406 if (expr->is_postfix()) { |
| 4422 // Perform the assignment as if via '='. | 4407 // Perform the assignment as if via '='. |
| 4423 { EffectContext context(this); | 4408 { EffectContext context(this); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4435 // Perform the assignment as if via '='. | 4420 // Perform the assignment as if via '='. |
| 4436 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4421 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4437 Token::ASSIGN); | 4422 Token::ASSIGN); |
| 4438 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4423 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4439 context()->Plug(eax); | 4424 context()->Plug(eax); |
| 4440 } | 4425 } |
| 4441 break; | 4426 break; |
| 4442 case NAMED_PROPERTY: { | 4427 case NAMED_PROPERTY: { |
| 4443 __ mov(ecx, prop->key()->AsLiteral()->value()); | 4428 __ mov(ecx, prop->key()->AsLiteral()->value()); |
| 4444 __ pop(edx); | 4429 __ pop(edx); |
| 4445 Handle<Code> ic = is_classic_mode() | 4430 CallStoreIC(NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); |
| 4446 ? isolate()->builtins()->StoreIC_Initialize() | |
| 4447 : isolate()->builtins()->StoreIC_Initialize_Strict(); | |
| 4448 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); | |
| 4449 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4431 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4450 if (expr->is_postfix()) { | 4432 if (expr->is_postfix()) { |
| 4451 if (!context()->IsEffect()) { | 4433 if (!context()->IsEffect()) { |
| 4452 context()->PlugTOS(); | 4434 context()->PlugTOS(); |
| 4453 } | 4435 } |
| 4454 } else { | 4436 } else { |
| 4455 context()->Plug(eax); | 4437 context()->Plug(eax); |
| 4456 } | 4438 } |
| 4457 break; | 4439 break; |
| 4458 } | 4440 } |
| 4459 case KEYED_PROPERTY: { | 4441 case KEYED_PROPERTY: { |
| 4460 __ pop(ecx); | 4442 __ pop(ecx); |
| 4461 __ pop(edx); | 4443 __ pop(edx); |
| 4462 Handle<Code> ic = is_classic_mode() | 4444 Handle<Code> ic = is_classic_mode() |
| 4463 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4445 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4464 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4446 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4465 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId()); | 4447 CallIC(ic, NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); |
| 4466 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4448 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4467 if (expr->is_postfix()) { | 4449 if (expr->is_postfix()) { |
| 4468 // Result is on the stack | 4450 // Result is on the stack |
| 4469 if (!context()->IsEffect()) { | 4451 if (!context()->IsEffect()) { |
| 4470 context()->PlugTOS(); | 4452 context()->PlugTOS(); |
| 4471 } | 4453 } |
| 4472 } else { | 4454 } else { |
| 4473 context()->Plug(eax); | 4455 context()->Plug(eax); |
| 4474 } | 4456 } |
| 4475 break; | 4457 break; |
| 4476 } | 4458 } |
| 4477 } | 4459 } |
| 4478 } | 4460 } |
| 4479 | 4461 |
| 4480 | 4462 |
| 4481 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 4463 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4482 VariableProxy* proxy = expr->AsVariableProxy(); | 4464 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4483 ASSERT(!context()->IsEffect()); | 4465 ASSERT(!context()->IsEffect()); |
| 4484 ASSERT(!context()->IsTest()); | 4466 ASSERT(!context()->IsTest()); |
| 4485 | 4467 |
| 4486 if (proxy != NULL && proxy->var()->IsUnallocated()) { | 4468 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 4487 Comment cmnt(masm_, "Global variable"); | 4469 Comment cmnt(masm_, "Global variable"); |
| 4488 __ mov(edx, GlobalObjectOperand()); | 4470 __ mov(edx, GlobalObjectOperand()); |
| 4489 __ mov(ecx, Immediate(proxy->name())); | 4471 __ mov(ecx, Immediate(proxy->name())); |
| 4490 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 4491 // Use a regular load, not a contextual load, to avoid a reference | 4472 // Use a regular load, not a contextual load, to avoid a reference |
| 4492 // error. | 4473 // error. |
| 4493 CallIC(ic); | 4474 CallLoadIC(NOT_CONTEXTUAL); |
| 4494 PrepareForBailout(expr, TOS_REG); | 4475 PrepareForBailout(expr, TOS_REG); |
| 4495 context()->Plug(eax); | 4476 context()->Plug(eax); |
| 4496 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 4477 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 4497 Label done, slow; | 4478 Label done, slow; |
| 4498 | 4479 |
| 4499 // Generate code for loading from variables potentially shadowed | 4480 // Generate code for loading from variables potentially shadowed |
| 4500 // by eval-introduced variables. | 4481 // by eval-introduced variables. |
| 4501 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); | 4482 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
| 4502 | 4483 |
| 4503 __ bind(&slow); | 4484 __ bind(&slow); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4645 __ or_(ecx, eax); | 4626 __ or_(ecx, eax); |
| 4646 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); | 4627 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
| 4647 __ cmp(edx, eax); | 4628 __ cmp(edx, eax); |
| 4648 Split(cc, if_true, if_false, NULL); | 4629 Split(cc, if_true, if_false, NULL); |
| 4649 __ bind(&slow_case); | 4630 __ bind(&slow_case); |
| 4650 } | 4631 } |
| 4651 | 4632 |
| 4652 // Record position and call the compare IC. | 4633 // Record position and call the compare IC. |
| 4653 SetSourcePosition(expr->position()); | 4634 SetSourcePosition(expr->position()); |
| 4654 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 4635 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 4655 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); | 4636 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); |
| 4656 patch_site.EmitPatchInfo(); | 4637 patch_site.EmitPatchInfo(); |
| 4657 | 4638 |
| 4658 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4639 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4659 __ test(eax, eax); | 4640 __ test(eax, eax); |
| 4660 Split(cc, if_true, if_false, fall_through); | 4641 Split(cc, if_true, if_false, fall_through); |
| 4661 } | 4642 } |
| 4662 } | 4643 } |
| 4663 | 4644 |
| 4664 // Convert the result of the comparison into one expected for this | 4645 // Convert the result of the comparison into one expected for this |
| 4665 // expression's context. | 4646 // expression's context. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4681 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4662 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4682 | 4663 |
| 4683 Handle<Object> nil_value = nil == kNullValue | 4664 Handle<Object> nil_value = nil == kNullValue |
| 4684 ? isolate()->factory()->null_value() | 4665 ? isolate()->factory()->null_value() |
| 4685 : isolate()->factory()->undefined_value(); | 4666 : isolate()->factory()->undefined_value(); |
| 4686 if (expr->op() == Token::EQ_STRICT) { | 4667 if (expr->op() == Token::EQ_STRICT) { |
| 4687 __ cmp(eax, nil_value); | 4668 __ cmp(eax, nil_value); |
| 4688 Split(equal, if_true, if_false, fall_through); | 4669 Split(equal, if_true, if_false, fall_through); |
| 4689 } else { | 4670 } else { |
| 4690 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); | 4671 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
| 4691 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); | 4672 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); |
| 4692 __ test(eax, eax); | 4673 __ test(eax, eax); |
| 4693 Split(not_zero, if_true, if_false, fall_through); | 4674 Split(not_zero, if_true, if_false, fall_through); |
| 4694 } | 4675 } |
| 4695 context()->Plug(if_true, if_false); | 4676 context()->Plug(if_true, if_false); |
| 4696 } | 4677 } |
| 4697 | 4678 |
| 4698 | 4679 |
| 4699 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4680 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4700 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 4681 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4701 context()->Plug(eax); | 4682 context()->Plug(eax); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4909 | 4890 |
| 4910 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), | 4891 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), |
| 4911 Assembler::target_address_at(call_target_address)); | 4892 Assembler::target_address_at(call_target_address)); |
| 4912 return OSR_AFTER_STACK_CHECK; | 4893 return OSR_AFTER_STACK_CHECK; |
| 4913 } | 4894 } |
| 4914 | 4895 |
| 4915 | 4896 |
| 4916 } } // namespace v8::internal | 4897 } } // namespace v8::internal |
| 4917 | 4898 |
| 4918 #endif // V8_TARGET_ARCH_IA32 | 4899 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |