| 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 // o fp: our caller's frame pointer | 131 // o fp: our caller's frame pointer |
| 132 // o sp: stack pointer | 132 // o sp: stack pointer |
| 133 // o ra: return address | 133 // o ra: return address |
| 134 // | 134 // |
| 135 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 135 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 136 // frames-mips.h for its layout. | 136 // frames-mips.h for its layout. |
| 137 void FullCodeGenerator::Generate() { | 137 void FullCodeGenerator::Generate() { |
| 138 CompilationInfo* info = info_; | 138 CompilationInfo* info = info_; |
| 139 handler_table_ = | 139 handler_table_ = |
| 140 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); | 140 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); |
| 141 | |
| 142 InitializeFeedbackVector(); | |
| 143 | |
| 144 profiling_counter_ = isolate()->factory()->NewCell( | 141 profiling_counter_ = isolate()->factory()->NewCell( |
| 145 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 142 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
| 146 SetFunctionPosition(function()); | 143 SetFunctionPosition(function()); |
| 147 Comment cmnt(masm_, "[ function compiled by full code generator"); | 144 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 148 | 145 |
| 149 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 146 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 150 | 147 |
| 151 #ifdef DEBUG | 148 #ifdef DEBUG |
| 152 if (strlen(FLAG_stop_at) > 0 && | 149 if (strlen(FLAG_stop_at) > 0 && |
| 153 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 150 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| (...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 } | 672 } |
| 676 } | 673 } |
| 677 | 674 |
| 678 | 675 |
| 679 void FullCodeGenerator::DoTest(Expression* condition, | 676 void FullCodeGenerator::DoTest(Expression* condition, |
| 680 Label* if_true, | 677 Label* if_true, |
| 681 Label* if_false, | 678 Label* if_false, |
| 682 Label* fall_through) { | 679 Label* fall_through) { |
| 683 __ mov(a0, result_register()); | 680 __ mov(a0, result_register()); |
| 684 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); | 681 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
| 685 CallIC(ic, condition->test_id()); | 682 CallIC(ic, NOT_CONTEXTUAL, condition->test_id()); |
| 686 __ mov(at, zero_reg); | 683 __ mov(at, zero_reg); |
| 687 Split(ne, v0, Operand(at), if_true, if_false, fall_through); | 684 Split(ne, v0, Operand(at), if_true, if_false, fall_through); |
| 688 } | 685 } |
| 689 | 686 |
| 690 | 687 |
| 691 void FullCodeGenerator::Split(Condition cc, | 688 void FullCodeGenerator::Split(Condition cc, |
| 692 Register lhs, | 689 Register lhs, |
| 693 const Operand& rhs, | 690 const Operand& rhs, |
| 694 Label* if_true, | 691 Label* if_true, |
| 695 Label* if_false, | 692 Label* if_false, |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1040 __ Branch(&next_test, ne, a1, Operand(a0)); | 1037 __ Branch(&next_test, ne, a1, Operand(a0)); |
| 1041 __ Drop(1); // Switch value is no longer needed. | 1038 __ Drop(1); // Switch value is no longer needed. |
| 1042 __ Branch(clause->body_target()); | 1039 __ Branch(clause->body_target()); |
| 1043 | 1040 |
| 1044 __ bind(&slow_case); | 1041 __ bind(&slow_case); |
| 1045 } | 1042 } |
| 1046 | 1043 |
| 1047 // Record position before stub call for type feedback. | 1044 // Record position before stub call for type feedback. |
| 1048 SetSourcePosition(clause->position()); | 1045 SetSourcePosition(clause->position()); |
| 1049 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 1046 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 1050 CallIC(ic, clause->CompareId()); | 1047 CallIC(ic, NOT_CONTEXTUAL, clause->CompareId()); |
| 1051 patch_site.EmitPatchInfo(); | 1048 patch_site.EmitPatchInfo(); |
| 1052 | 1049 |
| 1053 Label skip; | 1050 Label skip; |
| 1054 __ Branch(&skip); | 1051 __ Branch(&skip); |
| 1055 PrepareForBailout(clause, TOS_REG); | 1052 PrepareForBailout(clause, TOS_REG); |
| 1056 __ LoadRoot(at, Heap::kTrueValueRootIndex); | 1053 __ LoadRoot(at, Heap::kTrueValueRootIndex); |
| 1057 __ Branch(&next_test, ne, v0, Operand(at)); | 1054 __ Branch(&next_test, ne, v0, Operand(at)); |
| 1058 __ Drop(1); | 1055 __ Drop(1); |
| 1059 __ Branch(clause->body_target()); | 1056 __ Branch(clause->body_target()); |
| 1060 __ bind(&skip); | 1057 __ bind(&skip); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1083 VisitStatements(clause->statements()); | 1080 VisitStatements(clause->statements()); |
| 1084 } | 1081 } |
| 1085 | 1082 |
| 1086 __ bind(nested_statement.break_label()); | 1083 __ bind(nested_statement.break_label()); |
| 1087 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 1084 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1088 } | 1085 } |
| 1089 | 1086 |
| 1090 | 1087 |
| 1091 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 1088 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 1092 Comment cmnt(masm_, "[ ForInStatement"); | 1089 Comment cmnt(masm_, "[ ForInStatement"); |
| 1093 int slot = stmt->ForInFeedbackSlot(); | |
| 1094 SetStatementPosition(stmt); | 1090 SetStatementPosition(stmt); |
| 1095 | 1091 |
| 1096 Label loop, exit; | 1092 Label loop, exit; |
| 1097 ForIn loop_statement(this, stmt); | 1093 ForIn loop_statement(this, stmt); |
| 1098 increment_loop_depth(); | 1094 increment_loop_depth(); |
| 1099 | 1095 |
| 1100 // Get the object to enumerate over. If the object is null or undefined, skip | 1096 // Get the object to enumerate over. If the object is null or undefined, skip |
| 1101 // over the loop. See ECMA-262 version 5, section 12.6.4. | 1097 // over the loop. See ECMA-262 version 5, section 12.6.4. |
| 1102 VisitForAccumulatorValue(stmt->enumerable()); | 1098 VisitForAccumulatorValue(stmt->enumerable()); |
| 1103 __ mov(a0, result_register()); // Result as param to InvokeBuiltin below. | 1099 __ mov(a0, result_register()); // Result as param to InvokeBuiltin below. |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1169 __ jmp(&loop); | 1165 __ jmp(&loop); |
| 1170 | 1166 |
| 1171 __ bind(&no_descriptors); | 1167 __ bind(&no_descriptors); |
| 1172 __ Drop(1); | 1168 __ Drop(1); |
| 1173 __ jmp(&exit); | 1169 __ jmp(&exit); |
| 1174 | 1170 |
| 1175 // We got a fixed array in register v0. Iterate through that. | 1171 // We got a fixed array in register v0. Iterate through that. |
| 1176 Label non_proxy; | 1172 Label non_proxy; |
| 1177 __ bind(&fixed_array); | 1173 __ bind(&fixed_array); |
| 1178 | 1174 |
| 1179 Handle<Object> feedback = Handle<Object>( | 1175 Handle<Cell> cell = isolate()->factory()->NewCell( |
| 1180 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), | 1176 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), |
| 1181 isolate()); | 1177 isolate())); |
| 1182 StoreFeedbackVectorSlot(slot, feedback); | 1178 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); |
| 1183 __ li(a1, FeedbackVector()); | 1179 __ li(a1, cell); |
| 1184 __ li(a2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); | 1180 __ li(a2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); |
| 1185 __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot))); | 1181 __ sw(a2, FieldMemOperand(a1, Cell::kValueOffset)); |
| 1186 | 1182 |
| 1187 __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check | 1183 __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check |
| 1188 __ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object | 1184 __ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object |
| 1189 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1185 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1190 __ GetObjectType(a2, a3, a3); | 1186 __ GetObjectType(a2, a3, a3); |
| 1191 __ Branch(&non_proxy, gt, a3, Operand(LAST_JS_PROXY_TYPE)); | 1187 __ Branch(&non_proxy, gt, a3, Operand(LAST_JS_PROXY_TYPE)); |
| 1192 __ li(a1, Operand(Smi::FromInt(0))); // Zero indicates proxy | 1188 __ li(a1, Operand(Smi::FromInt(0))); // Zero indicates proxy |
| 1193 __ bind(&non_proxy); | 1189 __ bind(&non_proxy); |
| 1194 __ Push(a1, v0); // Smi and array | 1190 __ Push(a1, v0); // Smi and array |
| 1195 __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset)); | 1191 __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset)); |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1483 | 1479 |
| 1484 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1480 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| 1485 // Record position before possible IC call. | 1481 // Record position before possible IC call. |
| 1486 SetSourcePosition(proxy->position()); | 1482 SetSourcePosition(proxy->position()); |
| 1487 Variable* var = proxy->var(); | 1483 Variable* var = proxy->var(); |
| 1488 | 1484 |
| 1489 // Three cases: global variables, lookup variables, and all other types of | 1485 // Three cases: global variables, lookup variables, and all other types of |
| 1490 // variables. | 1486 // variables. |
| 1491 switch (var->location()) { | 1487 switch (var->location()) { |
| 1492 case Variable::UNALLOCATED: { | 1488 case Variable::UNALLOCATED: { |
| 1493 Comment cmnt(masm_, "[ Global variable"); | 1489 Comment cmnt(masm_, "Global variable"); |
| 1494 // Use inline caching. Variable name is passed in a2 and the global | 1490 // Use inline caching. Variable name is passed in a2 and the global |
| 1495 // object (receiver) in a0. | 1491 // object (receiver) in a0. |
| 1496 __ lw(a0, GlobalObjectOperand()); | 1492 __ lw(a0, GlobalObjectOperand()); |
| 1497 __ li(a2, Operand(var->name())); | 1493 __ li(a2, Operand(var->name())); |
| 1498 CallLoadIC(CONTEXTUAL); | 1494 CallLoadIC(CONTEXTUAL); |
| 1499 context()->Plug(v0); | 1495 context()->Plug(v0); |
| 1500 break; | 1496 break; |
| 1501 } | 1497 } |
| 1502 | 1498 |
| 1503 case Variable::PARAMETER: | 1499 case Variable::PARAMETER: |
| 1504 case Variable::LOCAL: | 1500 case Variable::LOCAL: |
| 1505 case Variable::CONTEXT: { | 1501 case Variable::CONTEXT: { |
| 1506 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" | 1502 Comment cmnt(masm_, var->IsContextSlot() |
| 1507 : "[ Stack variable"); | 1503 ? "Context variable" |
| 1504 : "Stack variable"); |
| 1508 if (var->binding_needs_init()) { | 1505 if (var->binding_needs_init()) { |
| 1509 // var->scope() may be NULL when the proxy is located in eval code and | 1506 // var->scope() may be NULL when the proxy is located in eval code and |
| 1510 // refers to a potential outside binding. Currently those bindings are | 1507 // refers to a potential outside binding. Currently those bindings are |
| 1511 // always looked up dynamically, i.e. in that case | 1508 // always looked up dynamically, i.e. in that case |
| 1512 // var->location() == LOOKUP. | 1509 // var->location() == LOOKUP. |
| 1513 // always holds. | 1510 // always holds. |
| 1514 ASSERT(var->scope() != NULL); | 1511 ASSERT(var->scope() != NULL); |
| 1515 | 1512 |
| 1516 // Check if the binding really needs an initialization check. The check | 1513 // Check if the binding really needs an initialization check. The check |
| 1517 // can be skipped in the following situation: we have a LET or CONST | 1514 // can be skipped in the following situation: we have a LET or CONST |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 } | 1559 } |
| 1563 context()->Plug(v0); | 1560 context()->Plug(v0); |
| 1564 break; | 1561 break; |
| 1565 } | 1562 } |
| 1566 } | 1563 } |
| 1567 context()->Plug(var); | 1564 context()->Plug(var); |
| 1568 break; | 1565 break; |
| 1569 } | 1566 } |
| 1570 | 1567 |
| 1571 case Variable::LOOKUP: { | 1568 case Variable::LOOKUP: { |
| 1572 Comment cmnt(masm_, "[ Lookup variable"); | |
| 1573 Label done, slow; | 1569 Label done, slow; |
| 1574 // Generate code for loading from variables potentially shadowed | 1570 // Generate code for loading from variables potentially shadowed |
| 1575 // by eval-introduced variables. | 1571 // by eval-introduced variables. |
| 1576 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); | 1572 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1577 __ bind(&slow); | 1573 __ bind(&slow); |
| 1574 Comment cmnt(masm_, "Lookup variable"); |
| 1578 __ li(a1, Operand(var->name())); | 1575 __ li(a1, Operand(var->name())); |
| 1579 __ Push(cp, a1); // Context and name. | 1576 __ Push(cp, a1); // Context and name. |
| 1580 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1577 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1581 __ bind(&done); | 1578 __ bind(&done); |
| 1582 context()->Plug(v0); | 1579 context()->Plug(v0); |
| 1583 } | 1580 } |
| 1584 } | 1581 } |
| 1585 } | 1582 } |
| 1586 | 1583 |
| 1587 | 1584 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1699 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1696 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1700 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); | 1697 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); |
| 1701 // Fall through. | 1698 // Fall through. |
| 1702 case ObjectLiteral::Property::COMPUTED: | 1699 case ObjectLiteral::Property::COMPUTED: |
| 1703 if (key->value()->IsInternalizedString()) { | 1700 if (key->value()->IsInternalizedString()) { |
| 1704 if (property->emit_store()) { | 1701 if (property->emit_store()) { |
| 1705 VisitForAccumulatorValue(value); | 1702 VisitForAccumulatorValue(value); |
| 1706 __ mov(a0, result_register()); | 1703 __ mov(a0, result_register()); |
| 1707 __ li(a2, Operand(key->value())); | 1704 __ li(a2, Operand(key->value())); |
| 1708 __ lw(a1, MemOperand(sp)); | 1705 __ lw(a1, MemOperand(sp)); |
| 1709 CallStoreIC(key->LiteralFeedbackId()); | 1706 CallStoreIC(NOT_CONTEXTUAL, key->LiteralFeedbackId()); |
| 1710 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1707 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1711 } else { | 1708 } else { |
| 1712 VisitForEffect(value); | 1709 VisitForEffect(value); |
| 1713 } | 1710 } |
| 1714 break; | 1711 break; |
| 1715 } | 1712 } |
| 1716 // Duplicate receiver on stack. | 1713 // Duplicate receiver on stack. |
| 1717 __ lw(a0, MemOperand(sp)); | 1714 __ lw(a0, MemOperand(sp)); |
| 1718 __ push(a0); | 1715 __ push(a0); |
| 1719 VisitForStackValue(key); | 1716 VisitForStackValue(key); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2107 __ bind(&l_next); | 2104 __ bind(&l_next); |
| 2108 __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next" | 2105 __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next" |
| 2109 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter | 2106 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2110 __ Push(a2, a3, a0); // "next", iter, received | 2107 __ Push(a2, a3, a0); // "next", iter, received |
| 2111 | 2108 |
| 2112 // result = receiver[f](arg); | 2109 // result = receiver[f](arg); |
| 2113 __ bind(&l_call); | 2110 __ bind(&l_call); |
| 2114 __ lw(a1, MemOperand(sp, kPointerSize)); | 2111 __ lw(a1, MemOperand(sp, kPointerSize)); |
| 2115 __ lw(a0, MemOperand(sp, 2 * kPointerSize)); | 2112 __ lw(a0, MemOperand(sp, 2 * kPointerSize)); |
| 2116 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2113 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2117 CallIC(ic, TypeFeedbackId::None()); | 2114 CallIC(ic, NOT_CONTEXTUAL, TypeFeedbackId::None()); |
| 2118 __ mov(a0, v0); | 2115 __ mov(a0, v0); |
| 2119 __ mov(a1, a0); | 2116 __ mov(a1, a0); |
| 2120 __ sw(a1, MemOperand(sp, 2 * kPointerSize)); | 2117 __ sw(a1, MemOperand(sp, 2 * kPointerSize)); |
| 2121 CallFunctionStub stub(1, CALL_AS_METHOD); | 2118 CallFunctionStub stub(1, CALL_AS_METHOD); |
| 2122 __ CallStub(&stub); | 2119 __ CallStub(&stub); |
| 2123 | 2120 |
| 2124 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2121 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2125 __ Drop(1); // The function is still on the stack; drop it. | 2122 __ Drop(1); // The function is still on the stack; drop it. |
| 2126 | 2123 |
| 2127 // if (!result.done) goto l_try; | 2124 // if (!result.done) goto l_try; |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2305 // Call load IC. It has arguments receiver and property name a0 and a2. | 2302 // Call load IC. It has arguments receiver and property name a0 and a2. |
| 2306 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2303 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2307 } | 2304 } |
| 2308 | 2305 |
| 2309 | 2306 |
| 2310 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 2307 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 2311 SetSourcePosition(prop->position()); | 2308 SetSourcePosition(prop->position()); |
| 2312 __ mov(a0, result_register()); | 2309 __ mov(a0, result_register()); |
| 2313 // Call keyed load IC. It has arguments key and receiver in a0 and a1. | 2310 // Call keyed load IC. It has arguments key and receiver in a0 and a1. |
| 2314 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2311 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2315 CallIC(ic, prop->PropertyFeedbackId()); | 2312 CallIC(ic, NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2316 } | 2313 } |
| 2317 | 2314 |
| 2318 | 2315 |
| 2319 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2316 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 2320 Token::Value op, | 2317 Token::Value op, |
| 2321 OverwriteMode mode, | 2318 OverwriteMode mode, |
| 2322 Expression* left_expr, | 2319 Expression* left_expr, |
| 2323 Expression* right_expr) { | 2320 Expression* right_expr) { |
| 2324 Label done, smi_case, stub_call; | 2321 Label done, smi_case, stub_call; |
| 2325 | 2322 |
| 2326 Register scratch1 = a2; | 2323 Register scratch1 = a2; |
| 2327 Register scratch2 = a3; | 2324 Register scratch2 = a3; |
| 2328 | 2325 |
| 2329 // Get the arguments. | 2326 // Get the arguments. |
| 2330 Register left = a1; | 2327 Register left = a1; |
| 2331 Register right = a0; | 2328 Register right = a0; |
| 2332 __ pop(left); | 2329 __ pop(left); |
| 2333 __ mov(a0, result_register()); | 2330 __ mov(a0, result_register()); |
| 2334 | 2331 |
| 2335 // Perform combined smi check on both operands. | 2332 // Perform combined smi check on both operands. |
| 2336 __ Or(scratch1, left, Operand(right)); | 2333 __ Or(scratch1, left, Operand(right)); |
| 2337 STATIC_ASSERT(kSmiTag == 0); | 2334 STATIC_ASSERT(kSmiTag == 0); |
| 2338 JumpPatchSite patch_site(masm_); | 2335 JumpPatchSite patch_site(masm_); |
| 2339 patch_site.EmitJumpIfSmi(scratch1, &smi_case); | 2336 patch_site.EmitJumpIfSmi(scratch1, &smi_case); |
| 2340 | 2337 |
| 2341 __ bind(&stub_call); | 2338 __ bind(&stub_call); |
| 2342 BinaryOpICStub stub(op, mode); | 2339 BinaryOpICStub stub(op, mode); |
| 2343 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); | 2340 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, |
| 2341 expr->BinaryOperationFeedbackId()); |
| 2344 patch_site.EmitPatchInfo(); | 2342 patch_site.EmitPatchInfo(); |
| 2345 __ jmp(&done); | 2343 __ jmp(&done); |
| 2346 | 2344 |
| 2347 __ bind(&smi_case); | 2345 __ bind(&smi_case); |
| 2348 // Smi case. This code works the same way as the smi-smi case in the type | 2346 // Smi case. This code works the same way as the smi-smi case in the type |
| 2349 // recording binary operation stub, see | 2347 // recording binary operation stub, see |
| 2350 switch (op) { | 2348 switch (op) { |
| 2351 case Token::SAR: | 2349 case Token::SAR: |
| 2352 __ GetLeastBitsFromSmi(scratch1, right, 5); | 2350 __ GetLeastBitsFromSmi(scratch1, right, 5); |
| 2353 __ srav(right, left, scratch1); | 2351 __ srav(right, left, scratch1); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2412 } | 2410 } |
| 2413 | 2411 |
| 2414 | 2412 |
| 2415 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 2413 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 2416 Token::Value op, | 2414 Token::Value op, |
| 2417 OverwriteMode mode) { | 2415 OverwriteMode mode) { |
| 2418 __ mov(a0, result_register()); | 2416 __ mov(a0, result_register()); |
| 2419 __ pop(a1); | 2417 __ pop(a1); |
| 2420 BinaryOpICStub stub(op, mode); | 2418 BinaryOpICStub stub(op, mode); |
| 2421 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2419 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 2422 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); | 2420 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, |
| 2421 expr->BinaryOperationFeedbackId()); |
| 2423 patch_site.EmitPatchInfo(); | 2422 patch_site.EmitPatchInfo(); |
| 2424 context()->Plug(v0); | 2423 context()->Plug(v0); |
| 2425 } | 2424 } |
| 2426 | 2425 |
| 2427 | 2426 |
| 2428 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 2427 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 2429 // Invalid left-hand sides are rewritten by the parser to have a 'throw | 2428 // Invalid left-hand sides are rewritten by the parser to have a 'throw |
| 2430 // ReferenceError' on the left-hand side. | 2429 // ReferenceError' on the left-hand side. |
| 2431 if (!expr->IsValidLeftHandSide()) { | 2430 if (!expr->IsValidLeftHandSide()) { |
| 2432 VisitForEffect(expr); | 2431 VisitForEffect(expr); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2450 EffectContext context(this); | 2449 EffectContext context(this); |
| 2451 EmitVariableAssignment(var, Token::ASSIGN); | 2450 EmitVariableAssignment(var, Token::ASSIGN); |
| 2452 break; | 2451 break; |
| 2453 } | 2452 } |
| 2454 case NAMED_PROPERTY: { | 2453 case NAMED_PROPERTY: { |
| 2455 __ push(result_register()); // Preserve value. | 2454 __ push(result_register()); // Preserve value. |
| 2456 VisitForAccumulatorValue(prop->obj()); | 2455 VisitForAccumulatorValue(prop->obj()); |
| 2457 __ mov(a1, result_register()); | 2456 __ mov(a1, result_register()); |
| 2458 __ pop(a0); // Restore value. | 2457 __ pop(a0); // Restore value. |
| 2459 __ li(a2, Operand(prop->key()->AsLiteral()->value())); | 2458 __ li(a2, Operand(prop->key()->AsLiteral()->value())); |
| 2460 CallStoreIC(); | 2459 CallStoreIC(NOT_CONTEXTUAL); |
| 2461 break; | 2460 break; |
| 2462 } | 2461 } |
| 2463 case KEYED_PROPERTY: { | 2462 case KEYED_PROPERTY: { |
| 2464 __ push(result_register()); // Preserve value. | 2463 __ push(result_register()); // Preserve value. |
| 2465 VisitForStackValue(prop->obj()); | 2464 VisitForStackValue(prop->obj()); |
| 2466 VisitForAccumulatorValue(prop->key()); | 2465 VisitForAccumulatorValue(prop->key()); |
| 2467 __ mov(a1, result_register()); | 2466 __ mov(a1, result_register()); |
| 2468 __ Pop(a0, a2); // a0 = restored value. | 2467 __ Pop(a0, a2); // a0 = restored value. |
| 2469 Handle<Code> ic = is_classic_mode() | 2468 Handle<Code> ic = is_classic_mode() |
| 2470 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2469 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2471 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2470 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2472 CallIC(ic); | 2471 CallIC(ic); |
| 2473 break; | 2472 break; |
| 2474 } | 2473 } |
| 2475 } | 2474 } |
| 2476 context()->Plug(v0); | 2475 context()->Plug(v0); |
| 2477 } | 2476 } |
| 2478 | 2477 |
| 2479 | 2478 |
| 2480 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | |
| 2481 Variable* var, MemOperand location) { | |
| 2482 __ sw(result_register(), location); | |
| 2483 if (var->IsContextSlot()) { | |
| 2484 // RecordWrite may destroy all its register arguments. | |
| 2485 __ Move(a3, result_register()); | |
| 2486 int offset = Context::SlotOffset(var->index()); | |
| 2487 __ RecordWriteContextSlot( | |
| 2488 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | |
| 2489 } | |
| 2490 } | |
| 2491 | |
| 2492 | |
| 2493 void FullCodeGenerator::EmitCallStoreContextSlot( | |
| 2494 Handle<String> name, LanguageMode mode) { | |
| 2495 __ li(a1, Operand(name)); | |
| 2496 __ li(a0, Operand(Smi::FromInt(mode))); | |
| 2497 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode. | |
| 2498 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2499 } | |
| 2500 | |
| 2501 | |
| 2502 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2479 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2503 Token::Value op) { | 2480 Token::Value op) { |
| 2504 if (var->IsUnallocated()) { | 2481 if (var->IsUnallocated()) { |
| 2505 // Global var, const, or let. | 2482 // Global var, const, or let. |
| 2506 __ mov(a0, result_register()); | 2483 __ mov(a0, result_register()); |
| 2507 __ li(a2, Operand(var->name())); | 2484 __ li(a2, Operand(var->name())); |
| 2508 __ lw(a1, GlobalObjectOperand()); | 2485 __ lw(a1, GlobalObjectOperand()); |
| 2509 CallStoreIC(); | 2486 CallStoreIC(CONTEXTUAL); |
| 2510 | |
| 2511 } else if (op == Token::INIT_CONST) { | 2487 } else if (op == Token::INIT_CONST) { |
| 2512 // Const initializers need a write barrier. | 2488 // Const initializers need a write barrier. |
| 2513 ASSERT(!var->IsParameter()); // No const parameters. | 2489 ASSERT(!var->IsParameter()); // No const parameters. |
| 2514 if (var->IsLookupSlot()) { | 2490 if (var->IsStackLocal()) { |
| 2491 Label skip; |
| 2492 __ lw(a1, StackOperand(var)); |
| 2493 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 2494 __ Branch(&skip, ne, a1, Operand(t0)); |
| 2495 __ sw(result_register(), StackOperand(var)); |
| 2496 __ bind(&skip); |
| 2497 } else { |
| 2498 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); |
| 2499 // Like var declarations, const declarations are hoisted to function |
| 2500 // scope. However, unlike var initializers, const initializers are |
| 2501 // able to drill a hole to that function context, even from inside a |
| 2502 // 'with' context. We thus bypass the normal static scope lookup for |
| 2503 // var->IsContextSlot(). |
| 2515 __ li(a0, Operand(var->name())); | 2504 __ li(a0, Operand(var->name())); |
| 2516 __ Push(v0, cp, a0); // Context and name. | 2505 __ Push(v0, cp, a0); // Context and name. |
| 2517 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2506 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2518 } else { | |
| 2519 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | |
| 2520 Label skip; | |
| 2521 MemOperand location = VarOperand(var, a1); | |
| 2522 __ lw(a2, location); | |
| 2523 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | |
| 2524 __ Branch(&skip, ne, a2, Operand(at)); | |
| 2525 EmitStoreToStackLocalOrContextSlot(var, location); | |
| 2526 __ bind(&skip); | |
| 2527 } | 2507 } |
| 2528 | 2508 |
| 2529 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2509 } else if (var->mode() == LET && op != Token::INIT_LET) { |
| 2530 // Non-initializing assignment to let variable needs a write barrier. | 2510 // Non-initializing assignment to let variable needs a write barrier. |
| 2531 if (var->IsLookupSlot()) { | 2511 if (var->IsLookupSlot()) { |
| 2532 EmitCallStoreContextSlot(var->name(), language_mode()); | 2512 __ li(a1, Operand(var->name())); |
| 2513 __ li(a0, Operand(Smi::FromInt(language_mode()))); |
| 2514 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode. |
| 2515 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2533 } else { | 2516 } else { |
| 2534 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2517 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2535 Label assign; | 2518 Label assign; |
| 2536 MemOperand location = VarOperand(var, a1); | 2519 MemOperand location = VarOperand(var, a1); |
| 2537 __ lw(a3, location); | 2520 __ lw(a3, location); |
| 2538 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2521 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 2539 __ Branch(&assign, ne, a3, Operand(t0)); | 2522 __ Branch(&assign, ne, a3, Operand(t0)); |
| 2540 __ li(a3, Operand(var->name())); | 2523 __ li(a3, Operand(var->name())); |
| 2541 __ push(a3); | 2524 __ push(a3); |
| 2542 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2525 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 2543 // Perform the assignment. | 2526 // Perform the assignment. |
| 2544 __ bind(&assign); | 2527 __ bind(&assign); |
| 2545 EmitStoreToStackLocalOrContextSlot(var, location); | 2528 __ sw(result_register(), location); |
| 2529 if (var->IsContextSlot()) { |
| 2530 // RecordWrite may destroy all its register arguments. |
| 2531 __ mov(a3, result_register()); |
| 2532 int offset = Context::SlotOffset(var->index()); |
| 2533 __ RecordWriteContextSlot( |
| 2534 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
| 2535 } |
| 2546 } | 2536 } |
| 2547 | 2537 |
| 2548 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2538 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 2549 // Assignment to var or initializing assignment to let/const | 2539 // Assignment to var or initializing assignment to let/const |
| 2550 // in harmony mode. | 2540 // in harmony mode. |
| 2551 if (var->IsLookupSlot()) { | 2541 if (var->IsStackAllocated() || var->IsContextSlot()) { |
| 2552 EmitCallStoreContextSlot(var->name(), language_mode()); | |
| 2553 } else { | |
| 2554 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); | |
| 2555 MemOperand location = VarOperand(var, a1); | 2542 MemOperand location = VarOperand(var, a1); |
| 2556 if (generate_debug_code_ && op == Token::INIT_LET) { | 2543 if (generate_debug_code_ && op == Token::INIT_LET) { |
| 2557 // Check for an uninitialized let binding. | 2544 // Check for an uninitialized let binding. |
| 2558 __ lw(a2, location); | 2545 __ lw(a2, location); |
| 2559 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2546 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 2560 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); | 2547 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); |
| 2561 } | 2548 } |
| 2562 EmitStoreToStackLocalOrContextSlot(var, location); | 2549 // Perform the assignment. |
| 2550 __ sw(v0, location); |
| 2551 if (var->IsContextSlot()) { |
| 2552 __ mov(a3, v0); |
| 2553 int offset = Context::SlotOffset(var->index()); |
| 2554 __ RecordWriteContextSlot( |
| 2555 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
| 2556 } |
| 2557 } else { |
| 2558 ASSERT(var->IsLookupSlot()); |
| 2559 __ li(a1, Operand(var->name())); |
| 2560 __ li(a0, Operand(Smi::FromInt(language_mode()))); |
| 2561 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode. |
| 2562 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2563 } | 2563 } |
| 2564 } | 2564 } |
| 2565 // Non-initializing assignments to consts are ignored. | 2565 // Non-initializing assignments to consts are ignored. |
| 2566 } | 2566 } |
| 2567 | 2567 |
| 2568 | 2568 |
| 2569 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2569 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2570 // Assignment to a property, using a named store IC. | 2570 // Assignment to a property, using a named store IC. |
| 2571 Property* prop = expr->target()->AsProperty(); | 2571 Property* prop = expr->target()->AsProperty(); |
| 2572 ASSERT(prop != NULL); | 2572 ASSERT(prop != NULL); |
| 2573 ASSERT(prop->key()->AsLiteral() != NULL); | 2573 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2574 | 2574 |
| 2575 // Record source code position before IC call. | 2575 // Record source code position before IC call. |
| 2576 SetSourcePosition(expr->position()); | 2576 SetSourcePosition(expr->position()); |
| 2577 __ mov(a0, result_register()); // Load the value. | 2577 __ mov(a0, result_register()); // Load the value. |
| 2578 __ li(a2, Operand(prop->key()->AsLiteral()->value())); | 2578 __ li(a2, Operand(prop->key()->AsLiteral()->value())); |
| 2579 __ pop(a1); | 2579 __ pop(a1); |
| 2580 | 2580 |
| 2581 CallStoreIC(expr->AssignmentFeedbackId()); | 2581 CallStoreIC(NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); |
| 2582 | 2582 |
| 2583 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2583 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2584 context()->Plug(v0); | 2584 context()->Plug(v0); |
| 2585 } | 2585 } |
| 2586 | 2586 |
| 2587 | 2587 |
| 2588 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2588 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2589 // Assignment to a property, using a keyed store IC. | 2589 // Assignment to a property, using a keyed store IC. |
| 2590 | 2590 |
| 2591 // Record source code position before IC call. | 2591 // Record source code position before IC call. |
| 2592 SetSourcePosition(expr->position()); | 2592 SetSourcePosition(expr->position()); |
| 2593 // Call keyed store IC. | 2593 // Call keyed store IC. |
| 2594 // The arguments are: | 2594 // The arguments are: |
| 2595 // - a0 is the value, | 2595 // - a0 is the value, |
| 2596 // - a1 is the key, | 2596 // - a1 is the key, |
| 2597 // - a2 is the receiver. | 2597 // - a2 is the receiver. |
| 2598 __ mov(a0, result_register()); | 2598 __ mov(a0, result_register()); |
| 2599 __ Pop(a2, a1); // a1 = key. | 2599 __ Pop(a2, a1); // a1 = key. |
| 2600 | 2600 |
| 2601 Handle<Code> ic = is_classic_mode() | 2601 Handle<Code> ic = is_classic_mode() |
| 2602 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2602 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2603 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2603 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2604 CallIC(ic, expr->AssignmentFeedbackId()); | 2604 CallIC(ic, NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); |
| 2605 | 2605 |
| 2606 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2606 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2607 context()->Plug(v0); | 2607 context()->Plug(v0); |
| 2608 } | 2608 } |
| 2609 | 2609 |
| 2610 | 2610 |
| 2611 void FullCodeGenerator::VisitProperty(Property* expr) { | 2611 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 2612 Comment cmnt(masm_, "[ Property"); | 2612 Comment cmnt(masm_, "[ Property"); |
| 2613 Expression* key = expr->key(); | 2613 Expression* key = expr->key(); |
| 2614 | 2614 |
| 2615 if (key->IsPropertyName()) { | 2615 if (key->IsPropertyName()) { |
| 2616 VisitForAccumulatorValue(expr->obj()); | 2616 VisitForAccumulatorValue(expr->obj()); |
| 2617 EmitNamedPropertyLoad(expr); | 2617 EmitNamedPropertyLoad(expr); |
| 2618 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2618 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
| 2619 context()->Plug(v0); | 2619 context()->Plug(v0); |
| 2620 } else { | 2620 } else { |
| 2621 VisitForStackValue(expr->obj()); | 2621 VisitForStackValue(expr->obj()); |
| 2622 VisitForAccumulatorValue(expr->key()); | 2622 VisitForAccumulatorValue(expr->key()); |
| 2623 __ pop(a1); | 2623 __ pop(a1); |
| 2624 EmitKeyedPropertyLoad(expr); | 2624 EmitKeyedPropertyLoad(expr); |
| 2625 context()->Plug(v0); | 2625 context()->Plug(v0); |
| 2626 } | 2626 } |
| 2627 } | 2627 } |
| 2628 | 2628 |
| 2629 | 2629 |
| 2630 void FullCodeGenerator::CallIC(Handle<Code> code, | 2630 void FullCodeGenerator::CallIC(Handle<Code> code, |
| 2631 ContextualMode mode, |
| 2631 TypeFeedbackId id) { | 2632 TypeFeedbackId id) { |
| 2632 ic_total_count_++; | 2633 ic_total_count_++; |
| 2634 ASSERT(mode != CONTEXTUAL || id.IsNone()); |
| 2633 __ Call(code, RelocInfo::CODE_TARGET, id); | 2635 __ Call(code, RelocInfo::CODE_TARGET, id); |
| 2634 } | 2636 } |
| 2635 | 2637 |
| 2636 | 2638 |
| 2637 // Code common for calls using the IC. | 2639 // Code common for calls using the IC. |
| 2638 void FullCodeGenerator::EmitCallWithIC(Call* expr) { | 2640 void FullCodeGenerator::EmitCallWithIC(Call* expr) { |
| 2639 Expression* callee = expr->expression(); | 2641 Expression* callee = expr->expression(); |
| 2640 ZoneList<Expression*>* args = expr->arguments(); | 2642 ZoneList<Expression*>* args = expr->arguments(); |
| 2641 int arg_count = args->length(); | 2643 int arg_count = args->length(); |
| 2642 | 2644 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2732 int arg_count = args->length(); | 2734 int arg_count = args->length(); |
| 2733 { PreservePositionScope scope(masm()->positions_recorder()); | 2735 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2734 for (int i = 0; i < arg_count; i++) { | 2736 for (int i = 0; i < arg_count; i++) { |
| 2735 VisitForStackValue(args->at(i)); | 2737 VisitForStackValue(args->at(i)); |
| 2736 } | 2738 } |
| 2737 } | 2739 } |
| 2738 // Record source position for debugger. | 2740 // Record source position for debugger. |
| 2739 SetSourcePosition(expr->position()); | 2741 SetSourcePosition(expr->position()); |
| 2740 | 2742 |
| 2741 Handle<Object> uninitialized = | 2743 Handle<Object> uninitialized = |
| 2742 TypeFeedbackInfo::UninitializedSentinel(isolate()); | 2744 TypeFeedbackCells::UninitializedSentinel(isolate()); |
| 2743 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); | 2745 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); |
| 2744 __ li(a2, FeedbackVector()); | 2746 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); |
| 2745 __ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot()))); | 2747 __ li(a2, Operand(cell)); |
| 2746 | 2748 |
| 2747 // Record call targets in unoptimized code. | 2749 // Record call targets in unoptimized code. |
| 2748 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); | 2750 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); |
| 2749 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 2751 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2750 __ CallStub(&stub); | 2752 __ CallStub(&stub, expr->CallFeedbackId()); |
| 2751 RecordJSReturnSite(expr); | 2753 RecordJSReturnSite(expr); |
| 2752 // Restore context register. | 2754 // Restore context register. |
| 2753 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2755 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2754 context()->DropAndPlug(1, v0); | 2756 context()->DropAndPlug(1, v0); |
| 2755 } | 2757 } |
| 2756 | 2758 |
| 2757 | 2759 |
| 2758 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2760 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
| 2759 // t2: copy of the first argument or undefined if it doesn't exist. | 2761 // t2: copy of the first argument or undefined if it doesn't exist. |
| 2760 if (arg_count > 0) { | 2762 if (arg_count > 0) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2919 // Call the construct call builtin that handles allocation and | 2921 // Call the construct call builtin that handles allocation and |
| 2920 // constructor invocation. | 2922 // constructor invocation. |
| 2921 SetSourcePosition(expr->position()); | 2923 SetSourcePosition(expr->position()); |
| 2922 | 2924 |
| 2923 // Load function and argument count into a1 and a0. | 2925 // Load function and argument count into a1 and a0. |
| 2924 __ li(a0, Operand(arg_count)); | 2926 __ li(a0, Operand(arg_count)); |
| 2925 __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); | 2927 __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); |
| 2926 | 2928 |
| 2927 // Record call targets in unoptimized code. | 2929 // Record call targets in unoptimized code. |
| 2928 Handle<Object> uninitialized = | 2930 Handle<Object> uninitialized = |
| 2929 TypeFeedbackInfo::UninitializedSentinel(isolate()); | 2931 TypeFeedbackCells::UninitializedSentinel(isolate()); |
| 2930 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); | 2932 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); |
| 2931 __ li(a2, FeedbackVector()); | 2933 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); |
| 2932 __ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot()))); | 2934 __ li(a2, Operand(cell)); |
| 2933 | 2935 |
| 2934 CallConstructStub stub(RECORD_CALL_TARGET); | 2936 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2935 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2937 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2936 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2938 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2937 context()->Plug(v0); | 2939 context()->Plug(v0); |
| 2938 } | 2940 } |
| 2939 | 2941 |
| 2940 | 2942 |
| 2941 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2943 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
| 2942 ZoneList<Expression*>* args = expr->arguments(); | 2944 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 1519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4462 } | 4464 } |
| 4463 | 4465 |
| 4464 __ bind(&stub_call); | 4466 __ bind(&stub_call); |
| 4465 __ mov(a1, v0); | 4467 __ mov(a1, v0); |
| 4466 __ li(a0, Operand(Smi::FromInt(count_value))); | 4468 __ li(a0, Operand(Smi::FromInt(count_value))); |
| 4467 | 4469 |
| 4468 // Record position before stub call. | 4470 // Record position before stub call. |
| 4469 SetSourcePosition(expr->position()); | 4471 SetSourcePosition(expr->position()); |
| 4470 | 4472 |
| 4471 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE); | 4473 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE); |
| 4472 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId()); | 4474 CallIC(stub.GetCode(isolate()), |
| 4475 NOT_CONTEXTUAL, |
| 4476 expr->CountBinOpFeedbackId()); |
| 4473 patch_site.EmitPatchInfo(); | 4477 patch_site.EmitPatchInfo(); |
| 4474 __ bind(&done); | 4478 __ bind(&done); |
| 4475 | 4479 |
| 4476 // Store the value returned in v0. | 4480 // Store the value returned in v0. |
| 4477 switch (assign_type) { | 4481 switch (assign_type) { |
| 4478 case VARIABLE: | 4482 case VARIABLE: |
| 4479 if (expr->is_postfix()) { | 4483 if (expr->is_postfix()) { |
| 4480 { EffectContext context(this); | 4484 { EffectContext context(this); |
| 4481 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4485 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4482 Token::ASSIGN); | 4486 Token::ASSIGN); |
| 4483 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4487 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4484 context.Plug(v0); | 4488 context.Plug(v0); |
| 4485 } | 4489 } |
| 4486 // For all contexts except EffectConstant we have the result on | 4490 // For all contexts except EffectConstant we have the result on |
| 4487 // top of the stack. | 4491 // top of the stack. |
| 4488 if (!context()->IsEffect()) { | 4492 if (!context()->IsEffect()) { |
| 4489 context()->PlugTOS(); | 4493 context()->PlugTOS(); |
| 4490 } | 4494 } |
| 4491 } else { | 4495 } else { |
| 4492 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4496 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4493 Token::ASSIGN); | 4497 Token::ASSIGN); |
| 4494 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4498 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4495 context()->Plug(v0); | 4499 context()->Plug(v0); |
| 4496 } | 4500 } |
| 4497 break; | 4501 break; |
| 4498 case NAMED_PROPERTY: { | 4502 case NAMED_PROPERTY: { |
| 4499 __ mov(a0, result_register()); // Value. | 4503 __ mov(a0, result_register()); // Value. |
| 4500 __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name. | 4504 __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name. |
| 4501 __ pop(a1); // Receiver. | 4505 __ pop(a1); // Receiver. |
| 4502 CallStoreIC(expr->CountStoreFeedbackId()); | 4506 CallStoreIC(NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); |
| 4503 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4507 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4504 if (expr->is_postfix()) { | 4508 if (expr->is_postfix()) { |
| 4505 if (!context()->IsEffect()) { | 4509 if (!context()->IsEffect()) { |
| 4506 context()->PlugTOS(); | 4510 context()->PlugTOS(); |
| 4507 } | 4511 } |
| 4508 } else { | 4512 } else { |
| 4509 context()->Plug(v0); | 4513 context()->Plug(v0); |
| 4510 } | 4514 } |
| 4511 break; | 4515 break; |
| 4512 } | 4516 } |
| 4513 case KEYED_PROPERTY: { | 4517 case KEYED_PROPERTY: { |
| 4514 __ mov(a0, result_register()); // Value. | 4518 __ mov(a0, result_register()); // Value. |
| 4515 __ Pop(a2, a1); // a1 = key, a2 = receiver. | 4519 __ Pop(a2, a1); // a1 = key, a2 = receiver. |
| 4516 Handle<Code> ic = is_classic_mode() | 4520 Handle<Code> ic = is_classic_mode() |
| 4517 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4521 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4518 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4522 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4519 CallIC(ic, expr->CountStoreFeedbackId()); | 4523 CallIC(ic, NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); |
| 4520 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4524 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4521 if (expr->is_postfix()) { | 4525 if (expr->is_postfix()) { |
| 4522 if (!context()->IsEffect()) { | 4526 if (!context()->IsEffect()) { |
| 4523 context()->PlugTOS(); | 4527 context()->PlugTOS(); |
| 4524 } | 4528 } |
| 4525 } else { | 4529 } else { |
| 4526 context()->Plug(v0); | 4530 context()->Plug(v0); |
| 4527 } | 4531 } |
| 4528 break; | 4532 break; |
| 4529 } | 4533 } |
| 4530 } | 4534 } |
| 4531 } | 4535 } |
| 4532 | 4536 |
| 4533 | 4537 |
| 4534 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 4538 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4535 ASSERT(!context()->IsEffect()); | 4539 ASSERT(!context()->IsEffect()); |
| 4536 ASSERT(!context()->IsTest()); | 4540 ASSERT(!context()->IsTest()); |
| 4537 VariableProxy* proxy = expr->AsVariableProxy(); | 4541 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4538 if (proxy != NULL && proxy->var()->IsUnallocated()) { | 4542 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 4539 Comment cmnt(masm_, "[ Global variable"); | 4543 Comment cmnt(masm_, "Global variable"); |
| 4540 __ lw(a0, GlobalObjectOperand()); | 4544 __ lw(a0, GlobalObjectOperand()); |
| 4541 __ li(a2, Operand(proxy->name())); | 4545 __ li(a2, Operand(proxy->name())); |
| 4542 // Use a regular load, not a contextual load, to avoid a reference | 4546 // Use a regular load, not a contextual load, to avoid a reference |
| 4543 // error. | 4547 // error. |
| 4544 CallLoadIC(NOT_CONTEXTUAL); | 4548 CallLoadIC(NOT_CONTEXTUAL); |
| 4545 PrepareForBailout(expr, TOS_REG); | 4549 PrepareForBailout(expr, TOS_REG); |
| 4546 context()->Plug(v0); | 4550 context()->Plug(v0); |
| 4547 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 4551 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 4548 Comment cmnt(masm_, "[ Lookup slot"); | |
| 4549 Label done, slow; | 4552 Label done, slow; |
| 4550 | 4553 |
| 4551 // Generate code for loading from variables potentially shadowed | 4554 // Generate code for loading from variables potentially shadowed |
| 4552 // by eval-introduced variables. | 4555 // by eval-introduced variables. |
| 4553 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); | 4556 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
| 4554 | 4557 |
| 4555 __ bind(&slow); | 4558 __ bind(&slow); |
| 4556 __ li(a0, Operand(proxy->name())); | 4559 __ li(a0, Operand(proxy->name())); |
| 4557 __ Push(cp, a0); | 4560 __ Push(cp, a0); |
| 4558 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 4561 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4695 if (inline_smi_code) { | 4698 if (inline_smi_code) { |
| 4696 Label slow_case; | 4699 Label slow_case; |
| 4697 __ Or(a2, a0, Operand(a1)); | 4700 __ Or(a2, a0, Operand(a1)); |
| 4698 patch_site.EmitJumpIfNotSmi(a2, &slow_case); | 4701 patch_site.EmitJumpIfNotSmi(a2, &slow_case); |
| 4699 Split(cc, a1, Operand(a0), if_true, if_false, NULL); | 4702 Split(cc, a1, Operand(a0), if_true, if_false, NULL); |
| 4700 __ bind(&slow_case); | 4703 __ bind(&slow_case); |
| 4701 } | 4704 } |
| 4702 // Record position and call the compare IC. | 4705 // Record position and call the compare IC. |
| 4703 SetSourcePosition(expr->position()); | 4706 SetSourcePosition(expr->position()); |
| 4704 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 4707 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 4705 CallIC(ic, expr->CompareOperationFeedbackId()); | 4708 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); |
| 4706 patch_site.EmitPatchInfo(); | 4709 patch_site.EmitPatchInfo(); |
| 4707 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4710 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4708 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); | 4711 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); |
| 4709 } | 4712 } |
| 4710 } | 4713 } |
| 4711 | 4714 |
| 4712 // Convert the result of the comparison into one expected for this | 4715 // Convert the result of the comparison into one expected for this |
| 4713 // expression's context. | 4716 // expression's context. |
| 4714 context()->Plug(if_true, if_false); | 4717 context()->Plug(if_true, if_false); |
| 4715 } | 4718 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4729 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4732 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4730 __ mov(a0, result_register()); | 4733 __ mov(a0, result_register()); |
| 4731 if (expr->op() == Token::EQ_STRICT) { | 4734 if (expr->op() == Token::EQ_STRICT) { |
| 4732 Heap::RootListIndex nil_value = nil == kNullValue ? | 4735 Heap::RootListIndex nil_value = nil == kNullValue ? |
| 4733 Heap::kNullValueRootIndex : | 4736 Heap::kNullValueRootIndex : |
| 4734 Heap::kUndefinedValueRootIndex; | 4737 Heap::kUndefinedValueRootIndex; |
| 4735 __ LoadRoot(a1, nil_value); | 4738 __ LoadRoot(a1, nil_value); |
| 4736 Split(eq, a0, Operand(a1), if_true, if_false, fall_through); | 4739 Split(eq, a0, Operand(a1), if_true, if_false, fall_through); |
| 4737 } else { | 4740 } else { |
| 4738 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); | 4741 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
| 4739 CallIC(ic, expr->CompareOperationFeedbackId()); | 4742 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); |
| 4740 Split(ne, v0, Operand(zero_reg), if_true, if_false, fall_through); | 4743 Split(ne, v0, Operand(zero_reg), if_true, if_false, fall_through); |
| 4741 } | 4744 } |
| 4742 context()->Plug(if_true, if_false); | 4745 context()->Plug(if_true, if_false); |
| 4743 } | 4746 } |
| 4744 | 4747 |
| 4745 | 4748 |
| 4746 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4749 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4747 __ lw(v0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 4750 __ lw(v0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4748 context()->Plug(v0); | 4751 context()->Plug(v0); |
| 4749 } | 4752 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4967 Assembler::target_address_at(pc_immediate_load_address)) == | 4970 Assembler::target_address_at(pc_immediate_load_address)) == |
| 4968 reinterpret_cast<uint32_t>( | 4971 reinterpret_cast<uint32_t>( |
| 4969 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4972 isolate->builtins()->OsrAfterStackCheck()->entry())); |
| 4970 return OSR_AFTER_STACK_CHECK; | 4973 return OSR_AFTER_STACK_CHECK; |
| 4971 } | 4974 } |
| 4972 | 4975 |
| 4973 | 4976 |
| 4974 } } // namespace v8::internal | 4977 } } // namespace v8::internal |
| 4975 | 4978 |
| 4976 #endif // V8_TARGET_ARCH_MIPS | 4979 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |