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 |