Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 11 matching lines...) Expand all Loading... | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 | 28 |
| 29 #include "v8.h" | 29 #include "v8.h" |
| 30 | 30 |
| 31 #include "bootstrapper.h" | 31 #include "bootstrapper.h" |
| 32 // #include "macro-assembler.h" | |
| 33 #include "codegen-inl.h" | 32 #include "codegen-inl.h" |
| 33 #include "debug.h" | |
| 34 #include "ic-inl.h" | |
| 35 #include "parser.h" | |
| 34 #include "register-allocator-inl.h" | 36 #include "register-allocator-inl.h" |
| 37 #include "scopes.h" | |
| 35 | 38 |
| 36 // TEST | 39 // TEST |
| 37 #include "compiler.h" | 40 #include "compiler.h" |
| 38 | 41 |
| 39 namespace v8 { | 42 namespace v8 { |
| 40 namespace internal { | 43 namespace internal { |
| 41 | 44 |
| 42 #define __ ACCESS_MASM(masm_) | 45 #define __ ACCESS_MASM(masm_) |
| 43 | 46 |
| 44 // ------------------------------------------------------------------------- | 47 // ------------------------------------------------------------------------- |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 160 " var w; y = x; x = w; w = y; y = x; return w;" | 163 " var w; y = x; x = w; w = y; y = x; return w;" |
| 161 " };" | 164 " };" |
| 162 " test_local_variables(2,3);" | 165 " test_local_variables(2,3);" |
| 163 " function test_nesting_calls(x, y, zee){return zee;};" | 166 " function test_nesting_calls(x, y, zee){return zee;};" |
| 164 " test_local_variables(" | 167 " test_local_variables(" |
| 165 " test_nesting_calls(test_local_variables(1,3), 42, 47)," | 168 " test_nesting_calls(test_local_variables(1,3), 42, 47)," |
| 166 " test_local_variables(-25.3, 2));" | 169 " test_local_variables(-25.3, 2));" |
| 167 " // return test_recursion_with_base(0, 0, 0, 47);\n" | 170 " // return test_recursion_with_base(0, 0, 0, 47);\n" |
| 168 " var x_value = 42;" | 171 " var x_value = 42;" |
| 169 " var o = { x: x_value };" | 172 " var o = { x: x_value };" |
| 173 " o.x = 43;" | |
| 174 " o.x;" | |
| 175 " var x_string = 'x';" | |
| 176 " o[x_string] = 44;" | |
| 177 " o[x_string];" | |
| 178 " o.f = function() { return 45; };" | |
| 179 " o.f();" | |
| 180 " var f_string = 'f';" | |
| 181 " o[f_string]();" | |
|
William Hesse
2009/06/22 21:31:29
Now that if ... then is working, we can check all
| |
| 170 " var a = [ 1, 2, 3 ];" | 182 " var a = [ 1, 2, 3 ];" |
| 171 " var x = true ? 42 : 32;" | 183 " var x = true ? 42 : 32;" |
| 172 " return test_if_then_else(0, 46, 47);" | 184 " return test_if_then_else(0, 46, 47);" |
| 173 "})()")), | 185 "})()")), |
| 174 Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")), | 186 Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")), |
| 175 0, | 187 0, |
| 176 0, | 188 0, |
| 177 NULL, | 189 NULL, |
| 178 NULL); | 190 NULL); |
| 179 | 191 |
| (...skipping 969 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1149 // first value pushed as part of the reference, which is below | 1161 // first value pushed as part of the reference, which is below |
| 1150 // the lhs value. | 1162 // the lhs value. |
| 1151 frame_->PushElementAt(target.size()); | 1163 frame_->PushElementAt(target.size()); |
| 1152 // Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 1164 // Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
| 1153 } | 1165 } |
| 1154 } | 1166 } |
| 1155 } | 1167 } |
| 1156 } | 1168 } |
| 1157 | 1169 |
| 1158 | 1170 |
| 1159 void CodeGenerator::VisitThrow(Throw* a) { | 1171 void CodeGenerator::VisitThrow(Throw* node) { |
| 1160 // UNIMPLEMENTED(); | 1172 Comment cmnt(masm_, "[ Throw"); |
| 1161 } | 1173 CodeForStatementPosition(node); |
| 1162 | 1174 |
| 1163 void CodeGenerator::VisitProperty(Property* a) { | 1175 Load(node->exception()); |
| 1164 UNIMPLEMENTED(); | 1176 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
| 1177 frame_->Push(&result); | |
| 1165 } | 1178 } |
| 1166 | 1179 |
| 1167 | 1180 |
| 1181 void CodeGenerator::VisitProperty(Property* node) { | |
| 1182 Comment cmnt(masm_, "[ Property"); | |
| 1183 Reference property(this, node); | |
| 1184 property.GetValue(typeof_state()); | |
| 1185 } | |
| 1186 | |
| 1187 | |
| 1168 void CodeGenerator::VisitCall(Call* node) { | 1188 void CodeGenerator::VisitCall(Call* node) { |
| 1169 Comment cmnt(masm_, "[ Call"); | 1189 Comment cmnt(masm_, "[ Call"); |
| 1170 | 1190 |
| 1171 ZoneList<Expression*>* args = node->arguments(); | 1191 ZoneList<Expression*>* args = node->arguments(); |
| 1172 | 1192 |
| 1173 CodeForStatementPosition(node); | 1193 CodeForStatementPosition(node); |
| 1174 | 1194 |
| 1175 // Check if the function is a variable or a property. | 1195 // Check if the function is a variable or a property. |
| 1176 Expression* function = node->expression(); | 1196 Expression* function = node->expression(); |
| 1177 Variable* var = function->AsVariableProxy()->AsVariable(); | 1197 Variable* var = function->AsVariableProxy()->AsVariable(); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1237 frame_->EmitPush(eax); | 1257 frame_->EmitPush(eax); |
| 1238 | 1258 |
| 1239 // Load the receiver. | 1259 // Load the receiver. |
| 1240 ASSERT(!allocator()->is_used(edx)); | 1260 ASSERT(!allocator()->is_used(edx)); |
| 1241 frame_->EmitPush(edx); | 1261 frame_->EmitPush(edx); |
| 1242 | 1262 |
| 1243 // Call the function. | 1263 // Call the function. |
| 1244 CallWithArguments(args, node->position()); | 1264 CallWithArguments(args, node->position()); |
| 1245 */ | 1265 */ |
| 1246 } else if (property != NULL) { | 1266 } else if (property != NULL) { |
| 1247 UNIMPLEMENTED(); | |
| 1248 /* | |
| 1249 // Check if the key is a literal string. | 1267 // Check if the key is a literal string. |
| 1250 Literal* literal = property->key()->AsLiteral(); | 1268 Literal* literal = property->key()->AsLiteral(); |
| 1251 | 1269 |
| 1252 if (literal != NULL && literal->handle()->IsSymbol()) { | 1270 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 1253 // ------------------------------------------------------------------ | 1271 // ------------------------------------------------------------------ |
| 1254 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 1272 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 1255 // ------------------------------------------------------------------ | 1273 // ------------------------------------------------------------------ |
| 1256 | 1274 |
| 1257 // Push the name of the function and the receiver onto the stack. | 1275 // Push the name of the function and the receiver onto the stack. |
| 1258 frame_->Push(literal->handle()); | 1276 frame_->Push(literal->handle()); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1286 // Use global object as receiver. | 1304 // Use global object as receiver. |
| 1287 LoadGlobalReceiver(); | 1305 LoadGlobalReceiver(); |
| 1288 } else { | 1306 } else { |
| 1289 // The reference's size is non-negative. | 1307 // The reference's size is non-negative. |
| 1290 frame_->PushElementAt(ref.size()); | 1308 frame_->PushElementAt(ref.size()); |
| 1291 } | 1309 } |
| 1292 | 1310 |
| 1293 // Call the function. | 1311 // Call the function. |
| 1294 CallWithArguments(args, node->position()); | 1312 CallWithArguments(args, node->position()); |
| 1295 } | 1313 } |
| 1296 */ | 1314 |
| 1297 } else { | 1315 } else { |
| 1298 // ---------------------------------- | 1316 // ---------------------------------- |
| 1299 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 1317 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 1300 // ---------------------------------- | 1318 // ---------------------------------- |
| 1301 | 1319 |
| 1302 // Load the function. | 1320 // Load the function. |
| 1303 Load(function); | 1321 Load(function); |
| 1304 | 1322 |
| 1305 // Pass the global proxy as the receiver. | 1323 // Pass the global proxy as the receiver. |
| 1306 LoadGlobalReceiver(); | 1324 LoadGlobalReceiver(); |
| 1307 | 1325 |
| 1308 // Call the function. | 1326 // Call the function. |
| 1309 CallWithArguments(args, node->position()); | 1327 CallWithArguments(args, node->position()); |
| 1310 } | 1328 } |
| 1311 } | 1329 } |
| 1312 | 1330 |
| 1313 | 1331 |
| 1314 void CodeGenerator::VisitCallEval(CallEval* a) { | 1332 void CodeGenerator::VisitCallEval(CallEval* a) { |
| 1315 UNIMPLEMENTED(); | 1333 UNIMPLEMENTED(); |
| 1316 } | 1334 } |
| 1317 | 1335 |
| 1336 | |
| 1318 void CodeGenerator::VisitCallNew(CallNew* a) { | 1337 void CodeGenerator::VisitCallNew(CallNew* a) { |
| 1319 UNIMPLEMENTED(); | 1338 UNIMPLEMENTED(); |
| 1320 } | 1339 } |
| 1321 | 1340 |
| 1341 | |
| 1322 void CodeGenerator::VisitCallRuntime(CallRuntime* a) { | 1342 void CodeGenerator::VisitCallRuntime(CallRuntime* a) { |
| 1323 UNIMPLEMENTED(); | 1343 UNIMPLEMENTED(); |
| 1324 } | 1344 } |
| 1325 | 1345 |
| 1326 | 1346 |
| 1327 void CodeGenerator::VisitUnaryOperation(UnaryOperation* a) { | 1347 void CodeGenerator::VisitUnaryOperation(UnaryOperation* a) { |
| 1328 UNIMPLEMENTED(); | 1348 UNIMPLEMENTED(); |
| 1329 } | 1349 } |
| 1330 | 1350 |
| 1331 void CodeGenerator::VisitCountOperation(CountOperation* a) { | 1351 void CodeGenerator::VisitCountOperation(CountOperation* a) { |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1625 } | 1645 } |
| 1626 | 1646 |
| 1627 | 1647 |
| 1628 void CodeGenerator::UnloadReference(Reference* ref) { | 1648 void CodeGenerator::UnloadReference(Reference* ref) { |
| 1629 // Pop a reference from the stack while preserving TOS. | 1649 // Pop a reference from the stack while preserving TOS. |
| 1630 Comment cmnt(masm_, "[ UnloadReference"); | 1650 Comment cmnt(masm_, "[ UnloadReference"); |
| 1631 frame_->Nip(ref->size()); | 1651 frame_->Nip(ref->size()); |
| 1632 } | 1652 } |
| 1633 | 1653 |
| 1634 | 1654 |
| 1635 void Reference::SetValue(InitState init_state) { | |
| 1636 ASSERT(cgen_->HasValidEntryRegisters()); | |
| 1637 ASSERT(!is_illegal()); | |
| 1638 MacroAssembler* masm = cgen_->masm(); | |
| 1639 switch (type_) { | |
| 1640 case SLOT: { | |
| 1641 Comment cmnt(masm, "[ Store to Slot"); | |
| 1642 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | |
| 1643 ASSERT(slot != NULL); | |
| 1644 cgen_->StoreToSlot(slot, init_state); | |
| 1645 break; | |
| 1646 } | |
| 1647 // TODO(X64): Make cases other than SLOT work. | |
| 1648 /* | |
| 1649 case NAMED: { | |
| 1650 Comment cmnt(masm, "[ Store to named Property"); | |
| 1651 cgen_->frame()->Push(GetName()); | |
| 1652 Result answer = cgen_->frame()->CallStoreIC(); | |
| 1653 cgen_->frame()->Push(&answer); | |
| 1654 break; | |
| 1655 } | |
| 1656 | |
| 1657 case KEYED: { | |
| 1658 Comment cmnt(masm, "[ Store to keyed Property"); | |
| 1659 | |
| 1660 // Generate inlined version of the keyed store if the code is in | |
| 1661 // a loop and the key is likely to be a smi. | |
| 1662 Property* property = expression()->AsProperty(); | |
| 1663 ASSERT(property != NULL); | |
| 1664 SmiAnalysis* key_smi_analysis = property->key()->type(); | |
| 1665 | |
| 1666 if (cgen_->loop_nesting() > 0 && key_smi_analysis->IsLikelySmi()) { | |
| 1667 Comment cmnt(masm, "[ Inlined store to keyed Property"); | |
| 1668 | |
| 1669 // Get the receiver, key and value into registers. | |
| 1670 Result value = cgen_->frame()->Pop(); | |
| 1671 Result key = cgen_->frame()->Pop(); | |
| 1672 Result receiver = cgen_->frame()->Pop(); | |
| 1673 | |
| 1674 Result tmp = cgen_->allocator_->Allocate(); | |
| 1675 ASSERT(tmp.is_valid()); | |
| 1676 | |
| 1677 // Determine whether the value is a constant before putting it | |
| 1678 // in a register. | |
| 1679 bool value_is_constant = value.is_constant(); | |
| 1680 | |
| 1681 // Make sure that value, key and receiver are in registers. | |
| 1682 value.ToRegister(); | |
| 1683 key.ToRegister(); | |
| 1684 receiver.ToRegister(); | |
| 1685 | |
| 1686 DeferredReferenceSetKeyedValue* deferred = | |
| 1687 new DeferredReferenceSetKeyedValue(value.reg(), | |
| 1688 key.reg(), | |
| 1689 receiver.reg()); | |
| 1690 | |
| 1691 // Check that the value is a smi if it is not a constant. We | |
| 1692 // can skip the write barrier for smis and constants. | |
| 1693 if (!value_is_constant) { | |
| 1694 __ test(value.reg(), Immediate(kSmiTagMask)); | |
| 1695 deferred->Branch(not_zero); | |
| 1696 } | |
| 1697 | |
| 1698 // Check that the key is a non-negative smi. | |
| 1699 __ test(key.reg(), Immediate(kSmiTagMask | 0x80000000)); | |
| 1700 deferred->Branch(not_zero); | |
| 1701 | |
| 1702 // Check that the receiver is not a smi. | |
| 1703 __ test(receiver.reg(), Immediate(kSmiTagMask)); | |
| 1704 deferred->Branch(zero); | |
| 1705 | |
| 1706 // Check that the receiver is a JSArray. | |
| 1707 __ mov(tmp.reg(), | |
| 1708 FieldOperand(receiver.reg(), HeapObject::kMapOffset)); | |
| 1709 __ movzx_b(tmp.reg(), | |
| 1710 FieldOperand(tmp.reg(), Map::kInstanceTypeOffset)); | |
| 1711 __ cmp(tmp.reg(), JS_ARRAY_TYPE); | |
| 1712 deferred->Branch(not_equal); | |
| 1713 | |
| 1714 // Check that the key is within bounds. Both the key and the | |
| 1715 // length of the JSArray are smis. | |
| 1716 __ cmp(key.reg(), | |
| 1717 FieldOperand(receiver.reg(), JSArray::kLengthOffset)); | |
| 1718 deferred->Branch(greater_equal); | |
| 1719 | |
| 1720 // Get the elements array from the receiver and check that it | |
| 1721 // is not a dictionary. | |
| 1722 __ mov(tmp.reg(), | |
| 1723 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | |
| 1724 // Bind the deferred code patch site to be able to locate the | |
| 1725 // fixed array map comparison. When debugging, we patch this | |
| 1726 // comparison to always fail so that we will hit the IC call | |
| 1727 // in the deferred code which will allow the debugger to | |
| 1728 // break for fast case stores. | |
| 1729 __ bind(deferred->patch_site()); | |
| 1730 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | |
| 1731 Immediate(Factory::fixed_array_map())); | |
| 1732 deferred->Branch(not_equal); | |
| 1733 | |
| 1734 // Store the value. | |
| 1735 __ mov(Operand(tmp.reg(), | |
| 1736 key.reg(), | |
| 1737 times_2, | |
| 1738 Array::kHeaderSize - kHeapObjectTag), | |
| 1739 value.reg()); | |
| 1740 __ IncrementCounter(&Counters::keyed_store_inline, 1); | |
| 1741 | |
| 1742 deferred->BindExit(); | |
| 1743 | |
| 1744 cgen_->frame()->Push(&receiver); | |
| 1745 cgen_->frame()->Push(&key); | |
| 1746 cgen_->frame()->Push(&value); | |
| 1747 } else { | |
| 1748 Result answer = cgen_->frame()->CallKeyedStoreIC(); | |
| 1749 // Make sure that we do not have a test instruction after the | |
| 1750 // call. A test instruction after the call is used to | |
| 1751 // indicate that we have generated an inline version of the | |
| 1752 // keyed store. | |
| 1753 __ nop(); | |
| 1754 cgen_->frame()->Push(&answer); | |
| 1755 } | |
| 1756 break; | |
| 1757 } | |
| 1758 */ | |
| 1759 default: | |
| 1760 UNREACHABLE(); | |
| 1761 } | |
| 1762 } | |
| 1763 | |
| 1764 | |
| 1765 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 1655 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 1766 // Currently, this assertion will fail if we try to assign to | 1656 // Currently, this assertion will fail if we try to assign to |
| 1767 // a constant variable that is constant because it is read-only | 1657 // a constant variable that is constant because it is read-only |
| 1768 // (such as the variable referring to a named function expression). | 1658 // (such as the variable referring to a named function expression). |
| 1769 // We need to implement assignments to read-only variables. | 1659 // We need to implement assignments to read-only variables. |
| 1770 // Ideally, we should do this during AST generation (by converting | 1660 // Ideally, we should do this during AST generation (by converting |
| 1771 // such assignments into expression statements); however, in general | 1661 // such assignments into expression statements); however, in general |
| 1772 // we may not be able to make the decision until past AST generation, | 1662 // we may not be able to make the decision until past AST generation, |
| 1773 // that is when the entire program is known. | 1663 // that is when the entire program is known. |
| 1774 ASSERT(slot != NULL); | 1664 ASSERT(slot != NULL); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2050 | 1940 |
| 2051 | 1941 |
| 2052 void CodeGenerator::LoadGlobalReceiver() { | 1942 void CodeGenerator::LoadGlobalReceiver() { |
| 2053 Result temp = allocator_->Allocate(); | 1943 Result temp = allocator_->Allocate(); |
| 2054 Register reg = temp.reg(); | 1944 Register reg = temp.reg(); |
| 2055 __ movq(reg, GlobalObject()); | 1945 __ movq(reg, GlobalObject()); |
| 2056 __ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset)); | 1946 __ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset)); |
| 2057 frame_->Push(&temp); | 1947 frame_->Push(&temp); |
| 2058 } | 1948 } |
| 2059 | 1949 |
| 1950 // Emit a LoadIC call to get the value from receiver and leave it in | |
| 1951 // dst. The receiver register is restored after the call. | |
| 1952 class DeferredReferenceGetNamedValue: public DeferredCode { | |
| 1953 public: | |
| 1954 DeferredReferenceGetNamedValue(Register dst, | |
| 1955 Register receiver, | |
| 1956 Handle<String> name) | |
| 1957 : dst_(dst), receiver_(receiver), name_(name) { | |
| 1958 set_comment("[ DeferredReferenceGetNamedValue"); | |
| 1959 } | |
| 1960 | |
| 1961 virtual void Generate(); | |
| 1962 | |
| 1963 Label* patch_site() { return &patch_site_; } | |
| 1964 | |
| 1965 private: | |
| 1966 Label patch_site_; | |
| 1967 Register dst_; | |
| 1968 Register receiver_; | |
| 1969 Handle<String> name_; | |
| 1970 }; | |
| 1971 | |
| 1972 | |
| 1973 void DeferredReferenceGetNamedValue::Generate() { | |
| 1974 __ push(receiver_); | |
| 1975 __ Move(rcx, name_); | |
| 1976 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
| 1977 __ Call(ic, RelocInfo::CODE_TARGET); | |
| 1978 // The call must be followed by a test eax instruction to indicate | |
| 1979 // that the inobject property case was inlined. | |
| 1980 // | |
| 1981 // Store the delta to the map check instruction here in the test | |
| 1982 // instruction. Use masm_-> instead of the __ macro since the | |
| 1983 // latter can't return a value. | |
| 1984 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | |
| 1985 // Here we use masm_-> instead of the __ macro because this is the | |
| 1986 // instruction that gets patched and coverage code gets in the way. | |
| 1987 masm_->testq(rax, Immediate(-delta_to_patch_site)); | |
| 1988 __ IncrementCounter(&Counters::named_load_inline_miss, 1); | |
| 1989 | |
| 1990 if (!dst_.is(rax)) __ movq(dst_, rax); | |
| 1991 __ pop(receiver_); | |
| 1992 } | |
| 1993 | |
| 2060 | 1994 |
| 2061 #undef __ | 1995 #undef __ |
| 2062 | |
| 2063 // End of CodeGenerator implementation. | |
| 2064 | |
| 2065 // ----------------------------------------------------------------------------- | |
| 2066 // Implementation of stubs. | |
| 2067 | |
| 2068 // Stub classes have public member named masm, not masm_. | |
| 2069 #define __ ACCESS_MASM(masm) | 1996 #define __ ACCESS_MASM(masm) |
| 2070 | 1997 |
| 2071 | 1998 |
| 1999 Handle<String> Reference::GetName() { | |
| 2000 ASSERT(type_ == NAMED); | |
| 2001 Property* property = expression_->AsProperty(); | |
| 2002 if (property == NULL) { | |
| 2003 // Global variable reference treated as a named property reference. | |
| 2004 VariableProxy* proxy = expression_->AsVariableProxy(); | |
| 2005 ASSERT(proxy->AsVariable() != NULL); | |
| 2006 ASSERT(proxy->AsVariable()->is_global()); | |
| 2007 return proxy->name(); | |
| 2008 } else { | |
| 2009 Literal* raw_name = property->key()->AsLiteral(); | |
| 2010 ASSERT(raw_name != NULL); | |
| 2011 return Handle<String>(String::cast(*raw_name->handle())); | |
| 2012 } | |
| 2013 } | |
| 2014 | |
| 2015 | |
| 2072 void Reference::GetValue(TypeofState typeof_state) { | 2016 void Reference::GetValue(TypeofState typeof_state) { |
| 2073 UNIMPLEMENTED(); | 2017 ASSERT(!cgen_->in_spilled_code()); |
| 2018 ASSERT(cgen_->HasValidEntryRegisters()); | |
| 2019 ASSERT(!is_illegal()); | |
| 2020 MacroAssembler* masm = cgen_->masm(); | |
| 2021 switch (type_) { | |
| 2022 case SLOT: { | |
| 2023 Comment cmnt(masm, "[ Load from Slot"); | |
| 2024 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | |
| 2025 ASSERT(slot != NULL); | |
| 2026 cgen_->LoadFromSlot(slot, typeof_state); | |
| 2027 break; | |
| 2028 } | |
| 2029 | |
| 2030 case NAMED: { | |
| 2031 // TODO(1241834): Make sure that it is safe to ignore the | |
| 2032 // distinction between expressions in a typeof and not in a | |
| 2033 // typeof. If there is a chance that reference errors can be | |
| 2034 // thrown below, we must distinguish between the two kinds of | |
| 2035 // loads (typeof expression loads must not throw a reference | |
| 2036 // error). | |
| 2037 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
| 2038 bool is_global = var != NULL; | |
| 2039 ASSERT(!is_global || var->is_global()); | |
| 2040 | |
| 2041 // Do not inline the inobject property case for loads from the global | |
| 2042 // object. Also do not inline for unoptimized code. This saves time | |
| 2043 // in the code generator. Unoptimized code is toplevel code or code | |
| 2044 // that is not in a loop. | |
| 2045 if (is_global || | |
| 2046 cgen_->scope()->is_global_scope() || | |
| 2047 cgen_->loop_nesting() == 0) { | |
| 2048 Comment cmnt(masm, "[ Load from named Property"); | |
| 2049 cgen_->frame()->Push(GetName()); | |
| 2050 | |
| 2051 RelocInfo::Mode mode = is_global | |
| 2052 ? RelocInfo::CODE_TARGET_CONTEXT | |
| 2053 : RelocInfo::CODE_TARGET; | |
| 2054 Result answer = cgen_->frame()->CallLoadIC(mode); | |
| 2055 // A test eax instruction following the call signals that the | |
| 2056 // inobject property case was inlined. Ensure that there is not | |
| 2057 // a test eax instruction here. | |
| 2058 __ nop(); | |
| 2059 cgen_->frame()->Push(&answer); | |
| 2060 } else { | |
| 2061 // Inline the inobject property case. | |
| 2062 Comment cmnt(masm, "[ Inlined named property load"); | |
| 2063 Result receiver = cgen_->frame()->Pop(); | |
| 2064 receiver.ToRegister(); | |
| 2065 | |
| 2066 Result value = cgen_->allocator()->Allocate(); | |
| 2067 ASSERT(value.is_valid()); | |
| 2068 DeferredReferenceGetNamedValue* deferred = | |
| 2069 new DeferredReferenceGetNamedValue(value.reg(), | |
| 2070 receiver.reg(), | |
| 2071 GetName()); | |
| 2072 | |
| 2073 // Check that the receiver is a heap object. | |
| 2074 __ testq(receiver.reg(), Immediate(kSmiTagMask)); | |
| 2075 deferred->Branch(zero); | |
| 2076 | |
| 2077 __ bind(deferred->patch_site()); | |
| 2078 // This is the map check instruction that will be patched (so we can't | |
| 2079 // use the double underscore macro that may insert instructions). | |
| 2080 // Initially use an invalid map to force a failure. | |
| 2081 masm->Move(kScratchRegister, Factory::null_value()); | |
| 2082 masm->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | |
| 2083 kScratchRegister); | |
| 2084 // This branch is always a forwards branch so it's always a fixed | |
| 2085 // size which allows the assert below to succeed and patching to work. | |
| 2086 deferred->Branch(not_equal); | |
| 2087 | |
| 2088 // The delta from the patch label to the load offset must be | |
| 2089 // statically known. | |
| 2090 ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == | |
| 2091 LoadIC::kOffsetToLoadInstruction); | |
| 2092 // The initial (invalid) offset has to be large enough to force | |
| 2093 // a 32-bit instruction encoding to allow patching with an | |
| 2094 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). | |
| 2095 int offset = kMaxInt; | |
| 2096 masm->movq(value.reg(), FieldOperand(receiver.reg(), offset)); | |
| 2097 | |
| 2098 __ IncrementCounter(&Counters::named_load_inline, 1); | |
| 2099 deferred->BindExit(); | |
| 2100 cgen_->frame()->Push(&receiver); | |
| 2101 cgen_->frame()->Push(&value); | |
| 2102 } | |
| 2103 break; | |
| 2104 } | |
| 2105 | |
| 2106 case KEYED: { | |
| 2107 // TODO(1241834): Make sure that this it is safe to ignore the | |
| 2108 // distinction between expressions in a typeof and not in a typeof. | |
| 2109 Comment cmnt(masm, "[ Load from keyed Property"); | |
| 2110 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
| 2111 bool is_global = var != NULL; | |
| 2112 ASSERT(!is_global || var->is_global()); | |
| 2113 // Inline array load code if inside of a loop. We do not know | |
| 2114 // the receiver map yet, so we initially generate the code with | |
| 2115 // a check against an invalid map. In the inline cache code, we | |
| 2116 // patch the map check if appropriate. | |
| 2117 | |
| 2118 // TODO(x64): Implement inlined loads for keyed properties. | |
| 2119 // Comment cmnt(masm, "[ Load from keyed Property"); | |
| 2120 | |
| 2121 RelocInfo::Mode mode = is_global | |
| 2122 ? RelocInfo::CODE_TARGET_CONTEXT | |
| 2123 : RelocInfo::CODE_TARGET; | |
| 2124 Result answer = cgen_->frame()->CallKeyedLoadIC(mode); | |
| 2125 // Make sure that we do not have a test instruction after the | |
| 2126 // call. A test instruction after the call is used to | |
| 2127 // indicate that we have generated an inline version of the | |
| 2128 // keyed load. The explicit nop instruction is here because | |
| 2129 // the push that follows might be peep-hole optimized away. | |
| 2130 __ nop(); | |
| 2131 cgen_->frame()->Push(&answer); | |
| 2132 break; | |
| 2133 } | |
| 2134 | |
| 2135 default: | |
| 2136 UNREACHABLE(); | |
| 2137 } | |
| 2138 } | |
| 2139 | |
| 2140 | |
| 2141 void Reference::SetValue(InitState init_state) { | |
| 2142 ASSERT(cgen_->HasValidEntryRegisters()); | |
| 2143 ASSERT(!is_illegal()); | |
| 2144 MacroAssembler* masm = cgen_->masm(); | |
| 2145 switch (type_) { | |
| 2146 case SLOT: { | |
| 2147 Comment cmnt(masm, "[ Store to Slot"); | |
| 2148 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | |
| 2149 ASSERT(slot != NULL); | |
| 2150 cgen_->StoreToSlot(slot, init_state); | |
| 2151 break; | |
| 2152 } | |
| 2153 | |
| 2154 case NAMED: { | |
| 2155 Comment cmnt(masm, "[ Store to named Property"); | |
| 2156 cgen_->frame()->Push(GetName()); | |
| 2157 Result answer = cgen_->frame()->CallStoreIC(); | |
| 2158 cgen_->frame()->Push(&answer); | |
| 2159 break; | |
| 2160 } | |
| 2161 | |
| 2162 case KEYED: { | |
| 2163 Comment cmnt(masm, "[ Store to keyed Property"); | |
| 2164 | |
| 2165 // Generate inlined version of the keyed store if the code is in | |
| 2166 // a loop and the key is likely to be a smi. | |
| 2167 Property* property = expression()->AsProperty(); | |
| 2168 ASSERT(property != NULL); | |
| 2169 | |
| 2170 // TODO(x64): Implement inlined version of keyed stores. | |
| 2171 | |
| 2172 Result answer = cgen_->frame()->CallKeyedStoreIC(); | |
| 2173 // Make sure that we do not have a test instruction after the | |
| 2174 // call. A test instruction after the call is used to | |
| 2175 // indicate that we have generated an inline version of the | |
| 2176 // keyed store. | |
| 2177 __ nop(); | |
| 2178 cgen_->frame()->Push(&answer); | |
| 2179 break; | |
| 2180 } | |
| 2181 | |
| 2182 default: | |
| 2183 UNREACHABLE(); | |
| 2184 } | |
| 2074 } | 2185 } |
| 2075 | 2186 |
| 2076 | 2187 |
| 2077 void ToBooleanStub::Generate(MacroAssembler* masm) { | 2188 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 2078 Label false_result, true_result, not_string; | 2189 Label false_result, true_result, not_string; |
| 2079 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 2190 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 2080 | 2191 |
| 2081 // 'null' => false. | 2192 // 'null' => false. |
| 2082 __ Cmp(rax, Factory::null_value()); | 2193 __ Cmp(rax, Factory::null_value()); |
| 2083 __ j(equal, &false_result); | 2194 __ j(equal, &false_result); |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2923 __ addq(rsp, Immediate(2 * kPointerSize)); // remove markers | 3034 __ addq(rsp, Immediate(2 * kPointerSize)); // remove markers |
| 2924 | 3035 |
| 2925 // Restore frame pointer and return. | 3036 // Restore frame pointer and return. |
| 2926 __ pop(rbp); | 3037 __ pop(rbp); |
| 2927 __ ret(0); | 3038 __ ret(0); |
| 2928 } | 3039 } |
| 2929 | 3040 |
| 2930 #undef __ | 3041 #undef __ |
| 2931 | 3042 |
| 2932 } } // namespace v8::internal | 3043 } } // namespace v8::internal |
| OLD | NEW |