| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 if (first_ == NULL) { | 108 if (first_ == NULL) { |
| 109 HBlockEntry* entry = new(zone()) HBlockEntry(); | 109 HBlockEntry* entry = new(zone()) HBlockEntry(); |
| 110 entry->InitializeAsFirst(this); | 110 entry->InitializeAsFirst(this); |
| 111 first_ = last_ = entry; | 111 first_ = last_ = entry; |
| 112 } | 112 } |
| 113 instr->InsertAfter(last_); | 113 instr->InsertAfter(last_); |
| 114 last_ = instr; | 114 last_ = instr; |
| 115 } | 115 } |
| 116 | 116 |
| 117 | 117 |
| 118 HDeoptimize* HBasicBlock::CreateDeoptimize() { | 118 HDeoptimize* HBasicBlock::CreateDeoptimize( |
| 119 HDeoptimize::UseEnvironment has_uses) { |
| 119 ASSERT(HasEnvironment()); | 120 ASSERT(HasEnvironment()); |
| 121 if (has_uses == HDeoptimize::kNoUses) return new(zone()) HDeoptimize(0); |
| 122 |
| 120 HEnvironment* environment = last_environment(); | 123 HEnvironment* environment = last_environment(); |
| 121 | |
| 122 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); | 124 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); |
| 123 | |
| 124 for (int i = 0; i < environment->length(); i++) { | 125 for (int i = 0; i < environment->length(); i++) { |
| 125 HValue* val = environment->values()->at(i); | 126 HValue* val = environment->values()->at(i); |
| 126 instr->AddEnvironmentValue(val); | 127 instr->AddEnvironmentValue(val); |
| 127 } | 128 } |
| 128 | 129 |
| 129 return instr; | 130 return instr; |
| 130 } | 131 } |
| 131 | 132 |
| 132 | 133 |
| 133 HSimulate* HBasicBlock::CreateSimulate(int id) { | 134 HSimulate* HBasicBlock::CreateSimulate(int id) { |
| (...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1013 void TraceGVN(const char* msg, ...) { | 1014 void TraceGVN(const char* msg, ...) { |
| 1014 if (FLAG_trace_gvn) { | 1015 if (FLAG_trace_gvn) { |
| 1015 va_list arguments; | 1016 va_list arguments; |
| 1016 va_start(arguments, msg); | 1017 va_start(arguments, msg); |
| 1017 OS::VPrint(msg, arguments); | 1018 OS::VPrint(msg, arguments); |
| 1018 va_end(arguments); | 1019 va_end(arguments); |
| 1019 } | 1020 } |
| 1020 } | 1021 } |
| 1021 | 1022 |
| 1022 | 1023 |
| 1023 HValueMap::HValueMap(const HValueMap* other) | 1024 HValueMap::HValueMap(Zone* zone, const HValueMap* other) |
| 1024 : array_size_(other->array_size_), | 1025 : array_size_(other->array_size_), |
| 1025 lists_size_(other->lists_size_), | 1026 lists_size_(other->lists_size_), |
| 1026 count_(other->count_), | 1027 count_(other->count_), |
| 1027 present_flags_(other->present_flags_), | 1028 present_flags_(other->present_flags_), |
| 1028 array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)), | 1029 array_(zone->NewArray<HValueMapListElement>(other->array_size_)), |
| 1029 lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)), | 1030 lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)), |
| 1030 free_list_head_(other->free_list_head_) { | 1031 free_list_head_(other->free_list_head_) { |
| 1031 memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement)); | 1032 memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement)); |
| 1032 memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement)); | 1033 memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement)); |
| 1033 } | 1034 } |
| 1034 | 1035 |
| 1035 | 1036 |
| 1036 void HValueMap::Kill(int flags) { | 1037 void HValueMap::Kill(int flags) { |
| 1037 int depends_flags = HValue::ConvertChangesToDependsFlags(flags); | 1038 int depends_flags = HValue::ConvertChangesToDependsFlags(flags); |
| 1038 if ((present_flags_ & depends_flags) == 0) return; | 1039 if ((present_flags_ & depends_flags) == 0) return; |
| 1039 present_flags_ = 0; | 1040 present_flags_ = 0; |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1232 while (instr != NULL) { | 1233 while (instr != NULL) { |
| 1233 if (instr->IsGoto()) { | 1234 if (instr->IsGoto()) { |
| 1234 HGoto::cast(instr)->set_include_stack_check(false); | 1235 HGoto::cast(instr)->set_include_stack_check(false); |
| 1235 return; | 1236 return; |
| 1236 } | 1237 } |
| 1237 instr = instr->next(); | 1238 instr = instr->next(); |
| 1238 } | 1239 } |
| 1239 } | 1240 } |
| 1240 | 1241 |
| 1241 | 1242 |
| 1243 // Simple sparse set with O(1) add, contains, and clear. |
| 1244 class SparseSet { |
| 1245 public: |
| 1246 SparseSet(Zone* zone, int capacity) |
| 1247 : capacity_(capacity), |
| 1248 length_(0), |
| 1249 dense_(zone->NewArray<int>(capacity)), |
| 1250 sparse_(zone->NewArray<int>(capacity)) {} |
| 1251 |
| 1252 bool Contains(int n) const { |
| 1253 ASSERT(0 <= n && n < capacity_); |
| 1254 int d = sparse_[n]; |
| 1255 return 0 <= d && d < length_ && dense_[d] == n; |
| 1256 } |
| 1257 |
| 1258 bool Add(int n) { |
| 1259 if (Contains(n)) return false; |
| 1260 dense_[length_] = n; |
| 1261 sparse_[n] = length_; |
| 1262 ++length_; |
| 1263 return true; |
| 1264 } |
| 1265 |
| 1266 void Clear() { length_ = 0; } |
| 1267 |
| 1268 private: |
| 1269 int capacity_; |
| 1270 int length_; |
| 1271 int* dense_; |
| 1272 int* sparse_; |
| 1273 |
| 1274 DISALLOW_COPY_AND_ASSIGN(SparseSet); |
| 1275 }; |
| 1276 |
| 1277 |
| 1242 class HGlobalValueNumberer BASE_EMBEDDED { | 1278 class HGlobalValueNumberer BASE_EMBEDDED { |
| 1243 public: | 1279 public: |
| 1244 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) | 1280 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) |
| 1245 : graph_(graph), | 1281 : graph_(graph), |
| 1246 info_(info), | 1282 info_(info), |
| 1247 block_side_effects_(graph_->blocks()->length()), | 1283 block_side_effects_(graph->blocks()->length()), |
| 1248 loop_side_effects_(graph_->blocks()->length()) { | 1284 loop_side_effects_(graph->blocks()->length()), |
| 1285 visited_on_paths_(graph->zone(), graph->blocks()->length()) { |
| 1249 ASSERT(info->isolate()->heap()->allow_allocation(false)); | 1286 ASSERT(info->isolate()->heap()->allow_allocation(false)); |
| 1250 block_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1287 block_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1251 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1288 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1252 } | 1289 } |
| 1253 ~HGlobalValueNumberer() { | 1290 ~HGlobalValueNumberer() { |
| 1254 ASSERT(!info_->isolate()->heap()->allow_allocation(true)); | 1291 ASSERT(!info_->isolate()->heap()->allow_allocation(true)); |
| 1255 } | 1292 } |
| 1256 | 1293 |
| 1257 void Analyze(); | 1294 void Analyze(); |
| 1258 | 1295 |
| 1259 private: | 1296 private: |
| 1297 int CollectSideEffectsOnPathsToDominatedBlock(HBasicBlock* dominator, |
| 1298 HBasicBlock* dominated); |
| 1260 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); | 1299 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); |
| 1261 void ComputeBlockSideEffects(); | 1300 void ComputeBlockSideEffects(); |
| 1262 void LoopInvariantCodeMotion(); | 1301 void LoopInvariantCodeMotion(); |
| 1263 void ProcessLoopBlock(HBasicBlock* block, | 1302 void ProcessLoopBlock(HBasicBlock* block, |
| 1264 HBasicBlock* before_loop, | 1303 HBasicBlock* before_loop, |
| 1265 int loop_kills); | 1304 int loop_kills); |
| 1266 bool AllowCodeMotion(); | 1305 bool AllowCodeMotion(); |
| 1267 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | 1306 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
| 1268 | 1307 |
| 1269 HGraph* graph() { return graph_; } | 1308 HGraph* graph() { return graph_; } |
| 1270 CompilationInfo* info() { return info_; } | 1309 CompilationInfo* info() { return info_; } |
| 1271 Zone* zone() { return graph_->zone(); } | 1310 Zone* zone() { return graph_->zone(); } |
| 1272 | 1311 |
| 1273 HGraph* graph_; | 1312 HGraph* graph_; |
| 1274 CompilationInfo* info_; | 1313 CompilationInfo* info_; |
| 1275 | 1314 |
| 1276 // A map of block IDs to their side effects. | 1315 // A map of block IDs to their side effects. |
| 1277 ZoneList<int> block_side_effects_; | 1316 ZoneList<int> block_side_effects_; |
| 1278 | 1317 |
| 1279 // A map of loop header block IDs to their loop's side effects. | 1318 // A map of loop header block IDs to their loop's side effects. |
| 1280 ZoneList<int> loop_side_effects_; | 1319 ZoneList<int> loop_side_effects_; |
| 1320 |
| 1321 // Used when collecting side effects on paths from dominator to |
| 1322 // dominated. |
| 1323 SparseSet visited_on_paths_; |
| 1281 }; | 1324 }; |
| 1282 | 1325 |
| 1283 | 1326 |
| 1284 void HGlobalValueNumberer::Analyze() { | 1327 void HGlobalValueNumberer::Analyze() { |
| 1285 ComputeBlockSideEffects(); | 1328 ComputeBlockSideEffects(); |
| 1286 if (FLAG_loop_invariant_code_motion) { | 1329 if (FLAG_loop_invariant_code_motion) { |
| 1287 LoopInvariantCodeMotion(); | 1330 LoopInvariantCodeMotion(); |
| 1288 } | 1331 } |
| 1289 HValueMap* map = new(zone()) HValueMap(); | 1332 HValueMap* map = new(zone()) HValueMap(); |
| 1290 AnalyzeBlock(graph_->blocks()->at(0), map); | 1333 AnalyzeBlock(graph_->blocks()->at(0), map); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1406 if (!found) { | 1449 if (!found) { |
| 1407 result = false; | 1450 result = false; |
| 1408 break; | 1451 break; |
| 1409 } | 1452 } |
| 1410 } | 1453 } |
| 1411 } | 1454 } |
| 1412 return result; | 1455 return result; |
| 1413 } | 1456 } |
| 1414 | 1457 |
| 1415 | 1458 |
| 1459 int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( |
| 1460 HBasicBlock* dominator, HBasicBlock* dominated) { |
| 1461 int side_effects = 0; |
| 1462 for (int i = 0; i < dominated->predecessors()->length(); ++i) { |
| 1463 HBasicBlock* block = dominated->predecessors()->at(i); |
| 1464 if (dominator->block_id() < block->block_id() && |
| 1465 block->block_id() < dominated->block_id() && |
| 1466 visited_on_paths_.Add(block->block_id())) { |
| 1467 side_effects |= block_side_effects_[block->block_id()]; |
| 1468 side_effects |= CollectSideEffectsOnPathsToDominatedBlock( |
| 1469 dominator, block); |
| 1470 } |
| 1471 } |
| 1472 return side_effects; |
| 1473 } |
| 1474 |
| 1475 |
| 1416 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { | 1476 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { |
| 1417 TraceGVN("Analyzing block B%d\n", block->block_id()); | 1477 TraceGVN("Analyzing block B%d%s\n", |
| 1478 block->block_id(), |
| 1479 block->IsLoopHeader() ? " (loop header)" : ""); |
| 1418 | 1480 |
| 1419 // If this is a loop header kill everything killed by the loop. | 1481 // If this is a loop header kill everything killed by the loop. |
| 1420 if (block->IsLoopHeader()) { | 1482 if (block->IsLoopHeader()) { |
| 1421 map->Kill(loop_side_effects_[block->block_id()]); | 1483 map->Kill(loop_side_effects_[block->block_id()]); |
| 1422 } | 1484 } |
| 1423 | 1485 |
| 1424 // Go through all instructions of the current block. | 1486 // Go through all instructions of the current block. |
| 1425 HInstruction* instr = block->first(); | 1487 HInstruction* instr = block->first(); |
| 1426 while (instr != NULL) { | 1488 while (instr != NULL) { |
| 1427 HInstruction* next = instr->next(); | 1489 HInstruction* next = instr->next(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1448 instr = next; | 1510 instr = next; |
| 1449 } | 1511 } |
| 1450 | 1512 |
| 1451 // Recursively continue analysis for all immediately dominated blocks. | 1513 // Recursively continue analysis for all immediately dominated blocks. |
| 1452 int length = block->dominated_blocks()->length(); | 1514 int length = block->dominated_blocks()->length(); |
| 1453 for (int i = 0; i < length; ++i) { | 1515 for (int i = 0; i < length; ++i) { |
| 1454 HBasicBlock* dominated = block->dominated_blocks()->at(i); | 1516 HBasicBlock* dominated = block->dominated_blocks()->at(i); |
| 1455 // No need to copy the map for the last child in the dominator tree. | 1517 // No need to copy the map for the last child in the dominator tree. |
| 1456 HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone()); | 1518 HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone()); |
| 1457 | 1519 |
| 1458 // If the dominated block is not a successor to this block we have to | 1520 // Kill everything killed on any path between this block and the |
| 1459 // kill everything killed on any path between this block and the | 1521 // dominated block. |
| 1460 // dominated block. Note we rely on the block ordering. | 1522 // We don't have to traverse these paths if the value map is |
| 1461 bool is_successor = false; | 1523 // already empty. |
| 1462 int predecessor_count = dominated->predecessors()->length(); | 1524 // If the range of block ids (block_id, dominated_id) is empty |
| 1463 for (int j = 0; !is_successor && j < predecessor_count; ++j) { | 1525 // there are no such paths. |
| 1464 is_successor = (dominated->predecessors()->at(j) == block); | 1526 if (!successor_map->IsEmpty() && |
| 1527 block->block_id() + 1 < dominated->block_id()) { |
| 1528 visited_on_paths_.Clear(); |
| 1529 successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block, |
| 1530 dominated)); |
| 1465 } | 1531 } |
| 1466 | |
| 1467 if (!is_successor) { | |
| 1468 int side_effects = 0; | |
| 1469 for (int j = block->block_id() + 1; j < dominated->block_id(); ++j) { | |
| 1470 side_effects |= block_side_effects_[j]; | |
| 1471 } | |
| 1472 successor_map->Kill(side_effects); | |
| 1473 } | |
| 1474 | |
| 1475 AnalyzeBlock(dominated, successor_map); | 1532 AnalyzeBlock(dominated, successor_map); |
| 1476 } | 1533 } |
| 1477 } | 1534 } |
| 1478 | 1535 |
| 1479 | 1536 |
| 1480 class HInferRepresentation BASE_EMBEDDED { | 1537 class HInferRepresentation BASE_EMBEDDED { |
| 1481 public: | 1538 public: |
| 1482 explicit HInferRepresentation(HGraph* graph) | 1539 explicit HInferRepresentation(HGraph* graph) |
| 1483 : graph_(graph), worklist_(8), in_worklist_(graph->GetMaximumValueID()) {} | 1540 : graph_(graph), worklist_(8), in_worklist_(graph->GetMaximumValueID()) {} |
| 1484 | 1541 |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1795 HValue* use_value = it.value(); | 1852 HValue* use_value = it.value(); |
| 1796 int use_index = it.index(); | 1853 int use_index = it.index(); |
| 1797 Representation req = use_value->RequiredInputRepresentation(use_index); | 1854 Representation req = use_value->RequiredInputRepresentation(use_index); |
| 1798 if (req.IsNone() || req.Equals(r)) continue; | 1855 if (req.IsNone() || req.Equals(r)) continue; |
| 1799 InsertRepresentationChangeForUse(value, use_value, use_index, req); | 1856 InsertRepresentationChangeForUse(value, use_value, use_index, req); |
| 1800 } | 1857 } |
| 1801 if (value->HasNoUses()) { | 1858 if (value->HasNoUses()) { |
| 1802 ASSERT(value->IsConstant()); | 1859 ASSERT(value->IsConstant()); |
| 1803 value->DeleteAndReplaceWith(NULL); | 1860 value->DeleteAndReplaceWith(NULL); |
| 1804 } | 1861 } |
| 1862 |
| 1863 // The only purpose of a HForceRepresentation is to represent the value |
| 1864 // after the (possible) HChange instruction. We make it disappear. |
| 1865 if (value->IsForceRepresentation()) { |
| 1866 value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value()); |
| 1867 } |
| 1805 } | 1868 } |
| 1806 | 1869 |
| 1807 | 1870 |
| 1808 void HGraph::InsertRepresentationChanges() { | 1871 void HGraph::InsertRepresentationChanges() { |
| 1809 HPhase phase("Insert representation changes", this); | 1872 HPhase phase("Insert representation changes", this); |
| 1810 | 1873 |
| 1811 | 1874 |
| 1812 // Compute truncation flag for phis: Initially assume that all | 1875 // Compute truncation flag for phis: Initially assume that all |
| 1813 // int32-phis allow truncation and iteratively remove the ones that | 1876 // int32-phis allow truncation and iteratively remove the ones that |
| 1814 // are used in an operation that does not allow a truncating | 1877 // are used in an operation that does not allow a truncating |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 // We don't yet handle the function name for named function expressions. | 2285 // We don't yet handle the function name for named function expressions. |
| 2223 if (scope->function() != NULL) return Bailout("named function expression"); | 2286 if (scope->function() != NULL) return Bailout("named function expression"); |
| 2224 | 2287 |
| 2225 HConstant* undefined_constant = new(zone()) HConstant( | 2288 HConstant* undefined_constant = new(zone()) HConstant( |
| 2226 isolate()->factory()->undefined_value(), Representation::Tagged()); | 2289 isolate()->factory()->undefined_value(), Representation::Tagged()); |
| 2227 AddInstruction(undefined_constant); | 2290 AddInstruction(undefined_constant); |
| 2228 graph_->set_undefined_constant(undefined_constant); | 2291 graph_->set_undefined_constant(undefined_constant); |
| 2229 | 2292 |
| 2230 // Set the initial values of parameters including "this". "This" has | 2293 // Set the initial values of parameters including "this". "This" has |
| 2231 // parameter index 0. | 2294 // parameter index 0. |
| 2232 int count = scope->num_parameters() + 1; | 2295 ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count()); |
| 2233 for (int i = 0; i < count; ++i) { | 2296 |
| 2297 for (int i = 0; i < environment()->parameter_count(); ++i) { |
| 2234 HInstruction* parameter = AddInstruction(new(zone()) HParameter(i)); | 2298 HInstruction* parameter = AddInstruction(new(zone()) HParameter(i)); |
| 2235 environment()->Bind(i, parameter); | 2299 environment()->Bind(i, parameter); |
| 2236 } | 2300 } |
| 2237 | 2301 |
| 2238 // Set the initial values of stack-allocated locals. | 2302 // First special is HContext. |
| 2239 for (int i = count; i < environment()->length(); ++i) { | 2303 HInstruction* context = AddInstruction(new(zone()) HContext); |
| 2304 environment()->BindContext(context); |
| 2305 |
| 2306 // Initialize specials and locals to undefined. |
| 2307 for (int i = environment()->parameter_count() + 1; |
| 2308 i < environment()->length(); |
| 2309 ++i) { |
| 2240 environment()->Bind(i, undefined_constant); | 2310 environment()->Bind(i, undefined_constant); |
| 2241 } | 2311 } |
| 2242 | 2312 |
| 2243 // Handle the arguments and arguments shadow variables specially (they do | 2313 // Handle the arguments and arguments shadow variables specially (they do |
| 2244 // not have declarations). | 2314 // not have declarations). |
| 2245 if (scope->arguments() != NULL) { | 2315 if (scope->arguments() != NULL) { |
| 2246 if (!scope->arguments()->IsStackAllocated() || | 2316 if (!scope->arguments()->IsStackAllocated() || |
| 2247 (scope->arguments_shadow() != NULL && | 2317 (scope->arguments_shadow() != NULL && |
| 2248 !scope->arguments_shadow()->IsStackAllocated())) { | 2318 !scope->arguments_shadow()->IsStackAllocated())) { |
| 2249 return Bailout("context-allocated arguments"); | 2319 return Bailout("context-allocated arguments"); |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2476 for (int i = 0; i < clause_count; ++i) { | 2546 for (int i = 0; i < clause_count; ++i) { |
| 2477 CaseClause* clause = clauses->at(i); | 2547 CaseClause* clause = clauses->at(i); |
| 2478 if (clause->is_default()) continue; | 2548 if (clause->is_default()) continue; |
| 2479 if (!clause->label()->IsSmiLiteral()) { | 2549 if (!clause->label()->IsSmiLiteral()) { |
| 2480 return Bailout("SwitchStatement: non-literal switch label"); | 2550 return Bailout("SwitchStatement: non-literal switch label"); |
| 2481 } | 2551 } |
| 2482 | 2552 |
| 2483 // Unconditionally deoptimize on the first non-smi compare. | 2553 // Unconditionally deoptimize on the first non-smi compare. |
| 2484 clause->RecordTypeFeedback(oracle()); | 2554 clause->RecordTypeFeedback(oracle()); |
| 2485 if (!clause->IsSmiCompare()) { | 2555 if (!clause->IsSmiCompare()) { |
| 2486 current_block()->FinishExitWithDeoptimization(); | 2556 // Finish with deoptimize and add uses of enviroment values to |
| 2557 // account for invisible uses. |
| 2558 current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll); |
| 2487 set_current_block(NULL); | 2559 set_current_block(NULL); |
| 2488 break; | 2560 break; |
| 2489 } | 2561 } |
| 2490 | 2562 |
| 2491 // Otherwise generate a compare and branch. | 2563 // Otherwise generate a compare and branch. |
| 2492 CHECK_ALIVE(VisitForValue(clause->label())); | 2564 CHECK_ALIVE(VisitForValue(clause->label())); |
| 2493 HValue* label_value = Pop(); | 2565 HValue* label_value = Pop(); |
| 2494 HCompare* compare = | 2566 HCompare* compare = |
| 2495 new(zone()) HCompare(tag_value, label_value, Token::EQ_STRICT); | 2567 new(zone()) HCompare(tag_value, label_value, Token::EQ_STRICT); |
| 2496 compare->SetInputRepresentation(Representation::Integer32()); | 2568 compare->SetInputRepresentation(Representation::Integer32()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2512 HBasicBlock* curr_test_block = first_test_block; | 2584 HBasicBlock* curr_test_block = first_test_block; |
| 2513 HBasicBlock* fall_through_block = NULL; | 2585 HBasicBlock* fall_through_block = NULL; |
| 2514 BreakAndContinueInfo break_info(stmt); | 2586 BreakAndContinueInfo break_info(stmt); |
| 2515 { BreakAndContinueScope push(&break_info, this); | 2587 { BreakAndContinueScope push(&break_info, this); |
| 2516 for (int i = 0; i < clause_count; ++i) { | 2588 for (int i = 0; i < clause_count; ++i) { |
| 2517 CaseClause* clause = clauses->at(i); | 2589 CaseClause* clause = clauses->at(i); |
| 2518 | 2590 |
| 2519 // Identify the block where normal (non-fall-through) control flow | 2591 // Identify the block where normal (non-fall-through) control flow |
| 2520 // goes to. | 2592 // goes to. |
| 2521 HBasicBlock* normal_block = NULL; | 2593 HBasicBlock* normal_block = NULL; |
| 2522 if (clause->is_default() && last_block != NULL) { | 2594 if (clause->is_default()) { |
| 2523 normal_block = last_block; | 2595 if (last_block != NULL) { |
| 2524 last_block = NULL; // Cleared to indicate we've handled it. | 2596 normal_block = last_block; |
| 2597 last_block = NULL; // Cleared to indicate we've handled it. |
| 2598 } |
| 2525 } else if (!curr_test_block->end()->IsDeoptimize()) { | 2599 } else if (!curr_test_block->end()->IsDeoptimize()) { |
| 2526 normal_block = curr_test_block->end()->FirstSuccessor(); | 2600 normal_block = curr_test_block->end()->FirstSuccessor(); |
| 2527 curr_test_block = curr_test_block->end()->SecondSuccessor(); | 2601 curr_test_block = curr_test_block->end()->SecondSuccessor(); |
| 2528 } | 2602 } |
| 2529 | 2603 |
| 2530 // Identify a block to emit the body into. | 2604 // Identify a block to emit the body into. |
| 2531 if (normal_block == NULL) { | 2605 if (normal_block == NULL) { |
| 2532 if (fall_through_block == NULL) { | 2606 if (fall_through_block == NULL) { |
| 2533 // (a) Unreachable. | 2607 // (a) Unreachable. |
| 2534 if (clause->is_default()) { | 2608 if (clause->is_default()) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2586 HTest* test = new(zone()) HTest(true_value, non_osr_entry, osr_entry); | 2660 HTest* test = new(zone()) HTest(true_value, non_osr_entry, osr_entry); |
| 2587 current_block()->Finish(test); | 2661 current_block()->Finish(test); |
| 2588 | 2662 |
| 2589 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2663 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2590 non_osr_entry->Goto(loop_predecessor); | 2664 non_osr_entry->Goto(loop_predecessor); |
| 2591 | 2665 |
| 2592 set_current_block(osr_entry); | 2666 set_current_block(osr_entry); |
| 2593 int osr_entry_id = statement->OsrEntryId(); | 2667 int osr_entry_id = statement->OsrEntryId(); |
| 2594 // We want the correct environment at the OsrEntry instruction. Build | 2668 // We want the correct environment at the OsrEntry instruction. Build |
| 2595 // it explicitly. The expression stack should be empty. | 2669 // it explicitly. The expression stack should be empty. |
| 2596 int count = environment()->length(); | 2670 ASSERT(environment()->ExpressionStackIsEmpty()); |
| 2597 ASSERT(count == | 2671 for (int i = 0; i < environment()->length(); ++i) { |
| 2598 (environment()->parameter_count() + environment()->local_count())); | 2672 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; |
| 2599 for (int i = 0; i < count; ++i) { | 2673 AddInstruction(osr_value); |
| 2600 HUnknownOSRValue* unknown = new(zone()) HUnknownOSRValue; | 2674 environment()->Bind(i, osr_value); |
| 2601 AddInstruction(unknown); | |
| 2602 environment()->Bind(i, unknown); | |
| 2603 } | 2675 } |
| 2604 | 2676 |
| 2605 AddSimulate(osr_entry_id); | 2677 AddSimulate(osr_entry_id); |
| 2606 AddInstruction(new(zone()) HOsrEntry(osr_entry_id)); | 2678 AddInstruction(new(zone()) HOsrEntry(osr_entry_id)); |
| 2679 HContext* context = new(zone()) HContext; |
| 2680 AddInstruction(context); |
| 2681 environment()->BindContext(context); |
| 2607 current_block()->Goto(loop_predecessor); | 2682 current_block()->Goto(loop_predecessor); |
| 2608 loop_predecessor->SetJoinId(statement->EntryId()); | 2683 loop_predecessor->SetJoinId(statement->EntryId()); |
| 2609 set_current_block(loop_predecessor); | 2684 set_current_block(loop_predecessor); |
| 2610 } | 2685 } |
| 2611 | 2686 |
| 2612 | 2687 |
| 2613 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { | 2688 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 2614 ASSERT(!HasStackOverflow()); | 2689 ASSERT(!HasStackOverflow()); |
| 2615 ASSERT(current_block() != NULL); | 2690 ASSERT(current_block() != NULL); |
| 2616 ASSERT(current_block()->HasPredecessor()); | 2691 ASSERT(current_block()->HasPredecessor()); |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2879 lookup->holder() != *global) { | 2954 lookup->holder() != *global) { |
| 2880 return kUseGeneric; | 2955 return kUseGeneric; |
| 2881 } | 2956 } |
| 2882 | 2957 |
| 2883 return kUseCell; | 2958 return kUseCell; |
| 2884 } | 2959 } |
| 2885 | 2960 |
| 2886 | 2961 |
| 2887 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { | 2962 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 2888 ASSERT(var->IsContextSlot()); | 2963 ASSERT(var->IsContextSlot()); |
| 2889 HInstruction* context = new(zone()) HContext; | 2964 HValue* context = environment()->LookupContext(); |
| 2890 AddInstruction(context); | |
| 2891 int length = info()->scope()->ContextChainLength(var->scope()); | 2965 int length = info()->scope()->ContextChainLength(var->scope()); |
| 2892 while (length-- > 0) { | 2966 while (length-- > 0) { |
| 2893 context = new(zone()) HOuterContext(context); | 2967 HInstruction* context_instruction = new(zone()) HOuterContext(context); |
| 2894 AddInstruction(context); | 2968 AddInstruction(context_instruction); |
| 2969 context = context_instruction; |
| 2895 } | 2970 } |
| 2896 return context; | 2971 return context; |
| 2897 } | 2972 } |
| 2898 | 2973 |
| 2899 | 2974 |
| 2900 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2975 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2901 ASSERT(!HasStackOverflow()); | 2976 ASSERT(!HasStackOverflow()); |
| 2902 ASSERT(current_block() != NULL); | 2977 ASSERT(current_block() != NULL); |
| 2903 ASSERT(current_block()->HasPredecessor()); | 2978 ASSERT(current_block()->HasPredecessor()); |
| 2904 Variable* variable = expr->AsVariable(); | 2979 Variable* variable = expr->AsVariable(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2923 type = kUseGeneric; | 2998 type = kUseGeneric; |
| 2924 } | 2999 } |
| 2925 | 3000 |
| 2926 if (type == kUseCell) { | 3001 if (type == kUseCell) { |
| 2927 Handle<GlobalObject> global(info()->global_object()); | 3002 Handle<GlobalObject> global(info()->global_object()); |
| 2928 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3003 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2929 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3004 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2930 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); | 3005 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); |
| 2931 ast_context()->ReturnInstruction(instr, expr->id()); | 3006 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2932 } else { | 3007 } else { |
| 2933 HContext* context = new(zone()) HContext; | 3008 HValue* context = environment()->LookupContext(); |
| 2934 AddInstruction(context); | |
| 2935 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3009 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 2936 AddInstruction(global_object); | 3010 AddInstruction(global_object); |
| 2937 HLoadGlobalGeneric* instr = | 3011 HLoadGlobalGeneric* instr = |
| 2938 new(zone()) HLoadGlobalGeneric(context, | 3012 new(zone()) HLoadGlobalGeneric(context, |
| 2939 global_object, | 3013 global_object, |
| 2940 variable->name(), | 3014 variable->name(), |
| 2941 ast_context()->is_for_typeof()); | 3015 ast_context()->is_for_typeof()); |
| 2942 instr->set_position(expr->position()); | 3016 instr->set_position(expr->position()); |
| 2943 ASSERT(instr->HasSideEffects()); | 3017 ASSERT(instr->HasSideEffects()); |
| 2944 ast_context()->ReturnInstruction(instr, expr->id()); | 3018 ast_context()->ReturnInstruction(instr, expr->id()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2967 expr->flags(), | 3041 expr->flags(), |
| 2968 expr->literal_index()); | 3042 expr->literal_index()); |
| 2969 ast_context()->ReturnInstruction(instr, expr->id()); | 3043 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2970 } | 3044 } |
| 2971 | 3045 |
| 2972 | 3046 |
| 2973 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 3047 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 2974 ASSERT(!HasStackOverflow()); | 3048 ASSERT(!HasStackOverflow()); |
| 2975 ASSERT(current_block() != NULL); | 3049 ASSERT(current_block() != NULL); |
| 2976 ASSERT(current_block()->HasPredecessor()); | 3050 ASSERT(current_block()->HasPredecessor()); |
| 2977 HContext* context = new(zone()) HContext; | 3051 HValue* context = environment()->LookupContext(); |
| 2978 AddInstruction(context); | |
| 2979 HObjectLiteral* literal = | 3052 HObjectLiteral* literal = |
| 2980 new(zone()) HObjectLiteral(context, | 3053 new(zone()) HObjectLiteral(context, |
| 2981 expr->constant_properties(), | 3054 expr->constant_properties(), |
| 2982 expr->fast_elements(), | 3055 expr->fast_elements(), |
| 2983 expr->literal_index(), | 3056 expr->literal_index(), |
| 2984 expr->depth(), | 3057 expr->depth(), |
| 2985 expr->has_function()); | 3058 expr->has_function()); |
| 2986 // The object is expected in the bailout environment during computation | 3059 // The object is expected in the bailout environment during computation |
| 2987 // of the property values and is the value of the entire expression. | 3060 // of the property values and is the value of the entire expression. |
| 2988 PushAndAdd(literal); | 3061 PushAndAdd(literal); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3150 // enable elimination of redundant checks after the transition store. | 3223 // enable elimination of redundant checks after the transition store. |
| 3151 instr->SetFlag(HValue::kChangesMaps); | 3224 instr->SetFlag(HValue::kChangesMaps); |
| 3152 } | 3225 } |
| 3153 return instr; | 3226 return instr; |
| 3154 } | 3227 } |
| 3155 | 3228 |
| 3156 | 3229 |
| 3157 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, | 3230 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, |
| 3158 Handle<String> name, | 3231 Handle<String> name, |
| 3159 HValue* value) { | 3232 HValue* value) { |
| 3160 HContext* context = new(zone()) HContext; | 3233 HValue* context = environment()->LookupContext(); |
| 3161 AddInstruction(context); | |
| 3162 return new(zone()) HStoreNamedGeneric( | 3234 return new(zone()) HStoreNamedGeneric( |
| 3163 context, | 3235 context, |
| 3164 object, | 3236 object, |
| 3165 name, | 3237 name, |
| 3166 value, | 3238 value, |
| 3167 function_strict_mode()); | 3239 function_strict_mode()); |
| 3168 } | 3240 } |
| 3169 | 3241 |
| 3170 | 3242 |
| 3171 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, | 3243 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3225 current_block()->Goto(join); | 3297 current_block()->Goto(join); |
| 3226 | 3298 |
| 3227 set_current_block(if_false); | 3299 set_current_block(if_false); |
| 3228 } | 3300 } |
| 3229 } | 3301 } |
| 3230 | 3302 |
| 3231 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 3303 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3232 // know about and do not want to handle ones we've never seen. Otherwise | 3304 // know about and do not want to handle ones we've never seen. Otherwise |
| 3233 // use a generic IC. | 3305 // use a generic IC. |
| 3234 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 3306 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3235 current_block()->FinishExitWithDeoptimization(); | 3307 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
| 3236 } else { | 3308 } else { |
| 3237 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3309 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3238 instr->set_position(expr->position()); | 3310 instr->set_position(expr->position()); |
| 3239 AddInstruction(instr); | 3311 AddInstruction(instr); |
| 3240 | 3312 |
| 3241 if (join != NULL) { | 3313 if (join != NULL) { |
| 3242 if (!ast_context()->IsEffect()) Push(value); | 3314 if (!ast_context()->IsEffect()) Push(value); |
| 3243 current_block()->Goto(join); | 3315 current_block()->Goto(join); |
| 3244 } else { | 3316 } else { |
| 3245 // The HSimulate for the store should not see the stored value in | 3317 // The HSimulate for the store should not see the stored value in |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3327 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); | 3399 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); |
| 3328 if (type == kUseCell) { | 3400 if (type == kUseCell) { |
| 3329 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3401 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3330 Handle<GlobalObject> global(info()->global_object()); | 3402 Handle<GlobalObject> global(info()->global_object()); |
| 3331 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3403 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3332 HInstruction* instr = new(zone()) HStoreGlobalCell(value, cell, check_hole); | 3404 HInstruction* instr = new(zone()) HStoreGlobalCell(value, cell, check_hole); |
| 3333 instr->set_position(position); | 3405 instr->set_position(position); |
| 3334 AddInstruction(instr); | 3406 AddInstruction(instr); |
| 3335 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3407 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3336 } else { | 3408 } else { |
| 3337 HContext* context = new(zone()) HContext; | 3409 HValue* context = environment()->LookupContext(); |
| 3338 AddInstruction(context); | |
| 3339 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3410 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 3340 AddInstruction(global_object); | 3411 AddInstruction(global_object); |
| 3341 HStoreGlobalGeneric* instr = | 3412 HStoreGlobalGeneric* instr = |
| 3342 new(zone()) HStoreGlobalGeneric(context, | 3413 new(zone()) HStoreGlobalGeneric(context, |
| 3343 global_object, | 3414 global_object, |
| 3344 var->name(), | 3415 var->name(), |
| 3345 value, | 3416 value, |
| 3346 function_strict_mode()); | 3417 function_strict_mode()); |
| 3347 instr->set_position(position); | 3418 instr->set_position(position); |
| 3348 AddInstruction(instr); | 3419 AddInstruction(instr); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3553 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; | 3624 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; |
| 3554 return new(zone()) HLoadNamedField(object, false, offset); | 3625 return new(zone()) HLoadNamedField(object, false, offset); |
| 3555 } | 3626 } |
| 3556 } | 3627 } |
| 3557 | 3628 |
| 3558 | 3629 |
| 3559 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, | 3630 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, |
| 3560 Property* expr) { | 3631 Property* expr) { |
| 3561 ASSERT(expr->key()->IsPropertyName()); | 3632 ASSERT(expr->key()->IsPropertyName()); |
| 3562 Handle<Object> name = expr->key()->AsLiteral()->handle(); | 3633 Handle<Object> name = expr->key()->AsLiteral()->handle(); |
| 3563 HContext* context = new(zone()) HContext; | 3634 HValue* context = environment()->LookupContext(); |
| 3564 AddInstruction(context); | |
| 3565 return new(zone()) HLoadNamedGeneric(context, obj, name); | 3635 return new(zone()) HLoadNamedGeneric(context, obj, name); |
| 3566 } | 3636 } |
| 3567 | 3637 |
| 3568 | 3638 |
| 3569 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, | 3639 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, |
| 3570 Property* expr, | 3640 Property* expr, |
| 3571 Handle<Map> map, | 3641 Handle<Map> map, |
| 3572 Handle<String> name) { | 3642 Handle<String> name) { |
| 3573 LookupResult lookup; | 3643 LookupResult lookup; |
| 3574 map->LookupInDescriptors(NULL, *name, &lookup); | 3644 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3575 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3645 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3576 return BuildLoadNamedField(obj, | 3646 return BuildLoadNamedField(obj, |
| 3577 expr, | 3647 expr, |
| 3578 map, | 3648 map, |
| 3579 &lookup, | 3649 &lookup, |
| 3580 true); | 3650 true); |
| 3581 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { | 3651 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { |
| 3582 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 3652 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 3583 AddInstruction(new(zone()) HCheckMap(obj, map)); | 3653 AddInstruction(new(zone()) HCheckMap(obj, map)); |
| 3584 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); | 3654 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); |
| 3585 return new(zone()) HConstant(function, Representation::Tagged()); | 3655 return new(zone()) HConstant(function, Representation::Tagged()); |
| 3586 } else { | 3656 } else { |
| 3587 return BuildLoadNamedGeneric(obj, expr); | 3657 return BuildLoadNamedGeneric(obj, expr); |
| 3588 } | 3658 } |
| 3589 } | 3659 } |
| 3590 | 3660 |
| 3591 | 3661 |
| 3592 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3662 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 3593 HValue* key) { | 3663 HValue* key) { |
| 3594 HContext* context = new(zone()) HContext; | 3664 HValue* context = environment()->LookupContext(); |
| 3595 AddInstruction(context); | |
| 3596 return new(zone()) HLoadKeyedGeneric(context, object, key); | 3665 return new(zone()) HLoadKeyedGeneric(context, object, key); |
| 3597 } | 3666 } |
| 3598 | 3667 |
| 3599 | 3668 |
| 3600 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, | 3669 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, |
| 3601 HValue* key, | 3670 HValue* key, |
| 3602 Property* expr) { | 3671 Property* expr) { |
| 3603 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); | 3672 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); |
| 3604 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3673 AddInstruction(new(zone()) HCheckNonSmi(object)); |
| 3605 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3674 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3660 return BuildLoadKeyedFastElement(obj, key, prop); | 3729 return BuildLoadKeyedFastElement(obj, key, prop); |
| 3661 } | 3730 } |
| 3662 } | 3731 } |
| 3663 return BuildLoadKeyedGeneric(obj, key); | 3732 return BuildLoadKeyedGeneric(obj, key); |
| 3664 } | 3733 } |
| 3665 | 3734 |
| 3666 | 3735 |
| 3667 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 3736 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
| 3668 HValue* key, | 3737 HValue* key, |
| 3669 HValue* value) { | 3738 HValue* value) { |
| 3670 HContext* context = new(zone()) HContext; | 3739 HValue* context = environment()->LookupContext(); |
| 3671 AddInstruction(context); | |
| 3672 return new(zone()) HStoreKeyedGeneric( | 3740 return new(zone()) HStoreKeyedGeneric( |
| 3673 context, | 3741 context, |
| 3674 object, | 3742 object, |
| 3675 key, | 3743 key, |
| 3676 value, | 3744 value, |
| 3677 function_strict_mode()); | 3745 function_strict_mode()); |
| 3678 } | 3746 } |
| 3679 | 3747 |
| 3680 | 3748 |
| 3681 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, | 3749 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3714 ASSERT(map->has_external_array_elements()); | 3782 ASSERT(map->has_external_array_elements()); |
| 3715 AddInstruction(new(zone()) HCheckMap(object, map)); | 3783 AddInstruction(new(zone()) HCheckMap(object, map)); |
| 3716 HLoadElements* elements = new(zone()) HLoadElements(object); | 3784 HLoadElements* elements = new(zone()) HLoadElements(object); |
| 3717 AddInstruction(elements); | 3785 AddInstruction(elements); |
| 3718 HInstruction* length = AddInstruction( | 3786 HInstruction* length = AddInstruction( |
| 3719 new(zone()) HExternalArrayLength(elements)); | 3787 new(zone()) HExternalArrayLength(elements)); |
| 3720 AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3788 AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 3721 HLoadExternalArrayPointer* external_elements = | 3789 HLoadExternalArrayPointer* external_elements = |
| 3722 new(zone()) HLoadExternalArrayPointer(elements); | 3790 new(zone()) HLoadExternalArrayPointer(elements); |
| 3723 AddInstruction(external_elements); | 3791 AddInstruction(external_elements); |
| 3792 if (expr->external_array_type() == kExternalPixelArray) { |
| 3793 HClampToUint8* clamp = new(zone()) HClampToUint8(val); |
| 3794 AddInstruction(clamp); |
| 3795 val = clamp; |
| 3796 } |
| 3724 return new(zone()) HStoreKeyedSpecializedArrayElement( | 3797 return new(zone()) HStoreKeyedSpecializedArrayElement( |
| 3725 external_elements, | 3798 external_elements, |
| 3726 key, | 3799 key, |
| 3727 val, | 3800 val, |
| 3728 expr->external_array_type()); | 3801 expr->external_array_type()); |
| 3729 } | 3802 } |
| 3730 | 3803 |
| 3731 | 3804 |
| 3732 HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object, | 3805 HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object, |
| 3733 HValue* key, | 3806 HValue* key, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3789 expr->RecordTypeFeedback(oracle()); | 3862 expr->RecordTypeFeedback(oracle()); |
| 3790 | 3863 |
| 3791 if (TryArgumentsAccess(expr)) return; | 3864 if (TryArgumentsAccess(expr)) return; |
| 3792 | 3865 |
| 3793 CHECK_ALIVE(VisitForValue(expr->obj())); | 3866 CHECK_ALIVE(VisitForValue(expr->obj())); |
| 3794 | 3867 |
| 3795 HInstruction* instr = NULL; | 3868 HInstruction* instr = NULL; |
| 3796 if (expr->IsArrayLength()) { | 3869 if (expr->IsArrayLength()) { |
| 3797 HValue* array = Pop(); | 3870 HValue* array = Pop(); |
| 3798 AddInstruction(new(zone()) HCheckNonSmi(array)); | 3871 AddInstruction(new(zone()) HCheckNonSmi(array)); |
| 3799 AddInstruction(new(zone()) HCheckInstanceType(array, | 3872 AddInstruction(HCheckInstanceType::NewIsJSArray(array)); |
| 3800 JS_ARRAY_TYPE, | |
| 3801 JS_ARRAY_TYPE)); | |
| 3802 instr = new(zone()) HJSArrayLength(array); | 3873 instr = new(zone()) HJSArrayLength(array); |
| 3803 | 3874 |
| 3804 } else if (expr->IsStringLength()) { | 3875 } else if (expr->IsStringLength()) { |
| 3805 HValue* string = Pop(); | 3876 HValue* string = Pop(); |
| 3806 AddInstruction(new(zone()) HCheckNonSmi(string)); | 3877 AddInstruction(new(zone()) HCheckNonSmi(string)); |
| 3807 AddInstruction(new(zone()) HCheckInstanceType(string, | 3878 AddInstruction(HCheckInstanceType::NewIsString(string)); |
| 3808 FIRST_STRING_TYPE, | |
| 3809 LAST_STRING_TYPE)); | |
| 3810 instr = new(zone()) HStringLength(string); | 3879 instr = new(zone()) HStringLength(string); |
| 3811 } else if (expr->IsStringAccess()) { | 3880 } else if (expr->IsStringAccess()) { |
| 3812 CHECK_ALIVE(VisitForValue(expr->key())); | 3881 CHECK_ALIVE(VisitForValue(expr->key())); |
| 3813 HValue* index = Pop(); | 3882 HValue* index = Pop(); |
| 3814 HValue* string = Pop(); | 3883 HValue* string = Pop(); |
| 3815 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); | 3884 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); |
| 3816 AddInstruction(char_code); | 3885 AddInstruction(char_code); |
| 3817 instr = new(zone()) HStringCharFromCode(char_code); | 3886 instr = new(zone()) HStringCharFromCode(char_code); |
| 3818 | 3887 |
| 3819 } else if (expr->IsFunctionPrototype()) { | 3888 } else if (expr->IsFunctionPrototype()) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3912 | 3981 |
| 3913 if (current_block() != NULL) current_block()->Goto(join); | 3982 if (current_block() != NULL) current_block()->Goto(join); |
| 3914 set_current_block(if_false); | 3983 set_current_block(if_false); |
| 3915 } | 3984 } |
| 3916 } | 3985 } |
| 3917 | 3986 |
| 3918 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 3987 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3919 // know about and do not want to handle ones we've never seen. Otherwise | 3988 // know about and do not want to handle ones we've never seen. Otherwise |
| 3920 // use a generic IC. | 3989 // use a generic IC. |
| 3921 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 3990 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3922 current_block()->FinishExitWithDeoptimization(); | 3991 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
| 3923 } else { | 3992 } else { |
| 3924 HContext* context = new(zone()) HContext; | 3993 HValue* context = environment()->LookupContext(); |
| 3925 AddInstruction(context); | |
| 3926 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); | 3994 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); |
| 3927 call->set_position(expr->position()); | 3995 call->set_position(expr->position()); |
| 3928 PreProcessCall(call); | 3996 PreProcessCall(call); |
| 3929 | 3997 |
| 3930 if (join != NULL) { | 3998 if (join != NULL) { |
| 3931 AddInstruction(call); | 3999 AddInstruction(call); |
| 3932 if (!ast_context()->IsEffect()) Push(call); | 4000 if (!ast_context()->IsEffect()) Push(call); |
| 3933 current_block()->Goto(join); | 4001 current_block()->Goto(join); |
| 3934 } else { | 4002 } else { |
| 3935 ast_context()->ReturnInstruction(call, expr->id()); | 4003 ast_context()->ReturnInstruction(call, expr->id()); |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4342 | 4410 |
| 4343 CHECK_ALIVE(VisitForValue(prop->key())); | 4411 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4344 // Push receiver and key like the non-optimized code generator expects it. | 4412 // Push receiver and key like the non-optimized code generator expects it. |
| 4345 HValue* key = Pop(); | 4413 HValue* key = Pop(); |
| 4346 HValue* receiver = Pop(); | 4414 HValue* receiver = Pop(); |
| 4347 Push(key); | 4415 Push(key); |
| 4348 Push(receiver); | 4416 Push(receiver); |
| 4349 | 4417 |
| 4350 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4418 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 4351 | 4419 |
| 4352 HContext* context = new(zone()) HContext; | 4420 HValue* context = environment()->LookupContext(); |
| 4353 AddInstruction(context); | |
| 4354 call = PreProcessCall( | 4421 call = PreProcessCall( |
| 4355 new(zone()) HCallKeyed(context, key, argument_count)); | 4422 new(zone()) HCallKeyed(context, key, argument_count)); |
| 4356 call->set_position(expr->position()); | 4423 call->set_position(expr->position()); |
| 4357 Drop(1); // Key. | 4424 Drop(1); // Key. |
| 4358 ast_context()->ReturnInstruction(call, expr->id()); | 4425 ast_context()->ReturnInstruction(call, expr->id()); |
| 4359 return; | 4426 return; |
| 4360 } | 4427 } |
| 4361 | 4428 |
| 4362 // Named function call. | 4429 // Named function call. |
| 4363 expr->RecordTypeFeedback(oracle()); | 4430 expr->RecordTypeFeedback(oracle()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4382 receiver_map, | 4449 receiver_map, |
| 4383 expr->check_type())) { | 4450 expr->check_type())) { |
| 4384 return; | 4451 return; |
| 4385 } | 4452 } |
| 4386 | 4453 |
| 4387 if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) || | 4454 if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) || |
| 4388 expr->check_type() != RECEIVER_MAP_CHECK) { | 4455 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 4389 // When the target has a custom call IC generator, use the IC, | 4456 // When the target has a custom call IC generator, use the IC, |
| 4390 // because it is likely to generate better code. Also use the IC | 4457 // because it is likely to generate better code. Also use the IC |
| 4391 // when a primitive receiver check is required. | 4458 // when a primitive receiver check is required. |
| 4392 HContext* context = new(zone()) HContext; | 4459 HValue* context = environment()->LookupContext(); |
| 4393 AddInstruction(context); | |
| 4394 call = PreProcessCall( | 4460 call = PreProcessCall( |
| 4395 new(zone()) HCallNamed(context, name, argument_count)); | 4461 new(zone()) HCallNamed(context, name, argument_count)); |
| 4396 } else { | 4462 } else { |
| 4397 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4463 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4398 | 4464 |
| 4399 if (TryInline(expr)) return; | 4465 if (TryInline(expr)) return; |
| 4400 call = PreProcessCall( | 4466 call = PreProcessCall( |
| 4401 new(zone()) HCallConstantFunction(expr->target(), | 4467 new(zone()) HCallConstantFunction(expr->target(), |
| 4402 argument_count)); | 4468 argument_count)); |
| 4403 } | 4469 } |
| 4404 } else if (types != NULL && types->length() > 1) { | 4470 } else if (types != NULL && types->length() > 1) { |
| 4405 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 4471 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 4406 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4472 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4407 return; | 4473 return; |
| 4408 | 4474 |
| 4409 } else { | 4475 } else { |
| 4410 HContext* context = new(zone()) HContext; | 4476 HValue* context = environment()->LookupContext(); |
| 4411 AddInstruction(context); | |
| 4412 call = PreProcessCall( | 4477 call = PreProcessCall( |
| 4413 new(zone()) HCallNamed(context, name, argument_count)); | 4478 new(zone()) HCallNamed(context, name, argument_count)); |
| 4414 } | 4479 } |
| 4415 | 4480 |
| 4416 } else { | 4481 } else { |
| 4417 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4482 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4418 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4483 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4419 | 4484 |
| 4420 if (!global_call) { | 4485 if (!global_call) { |
| 4421 ++argument_count; | 4486 ++argument_count; |
| 4422 CHECK_ALIVE(VisitForValue(expr->expression())); | 4487 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4423 } | 4488 } |
| 4424 | 4489 |
| 4425 if (global_call) { | 4490 if (global_call) { |
| 4426 bool known_global_function = false; | 4491 bool known_global_function = false; |
| 4427 // If there is a global property cell for the name at compile time and | 4492 // If there is a global property cell for the name at compile time and |
| 4428 // access check is not enabled we assume that the function will not change | 4493 // access check is not enabled we assume that the function will not change |
| 4429 // and generate optimized code for calling the function. | 4494 // and generate optimized code for calling the function. |
| 4430 LookupResult lookup; | 4495 LookupResult lookup; |
| 4431 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 4496 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
| 4432 if (type == kUseCell && | 4497 if (type == kUseCell && |
| 4433 !info()->global_object()->IsAccessCheckNeeded()) { | 4498 !info()->global_object()->IsAccessCheckNeeded()) { |
| 4434 Handle<GlobalObject> global(info()->global_object()); | 4499 Handle<GlobalObject> global(info()->global_object()); |
| 4435 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 4500 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
| 4436 } | 4501 } |
| 4437 if (known_global_function) { | 4502 if (known_global_function) { |
| 4438 // Push the global object instead of the global receiver because | 4503 // Push the global object instead of the global receiver because |
| 4439 // code generated by the full code generator expects it. | 4504 // code generated by the full code generator expects it. |
| 4440 HContext* context = new(zone()) HContext; | 4505 HValue* context = environment()->LookupContext(); |
| 4441 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 4506 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 4442 AddInstruction(context); | |
| 4443 PushAndAdd(global_object); | 4507 PushAndAdd(global_object); |
| 4444 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4508 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 4445 | 4509 |
| 4446 CHECK_ALIVE(VisitForValue(expr->expression())); | 4510 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4447 HValue* function = Pop(); | 4511 HValue* function = Pop(); |
| 4448 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); | 4512 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
| 4449 | 4513 |
| 4450 // Replace the global object with the global receiver. | 4514 // Replace the global object with the global receiver. |
| 4451 HGlobalReceiver* global_receiver = | 4515 HGlobalReceiver* global_receiver = |
| 4452 new(zone()) HGlobalReceiver(global_object); | 4516 new(zone()) HGlobalReceiver(global_object); |
| 4453 // Index of the receiver from the top of the expression stack. | 4517 // Index of the receiver from the top of the expression stack. |
| 4454 const int receiver_index = argument_count - 1; | 4518 const int receiver_index = argument_count - 1; |
| 4455 AddInstruction(global_receiver); | 4519 AddInstruction(global_receiver); |
| 4456 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4520 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4457 IsGlobalObject()); | 4521 IsGlobalObject()); |
| 4458 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4522 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4459 | 4523 |
| 4460 if (TryInline(expr)) return; | 4524 if (TryInline(expr)) return; |
| 4461 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), | 4525 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), |
| 4462 argument_count)); | 4526 argument_count)); |
| 4463 } else { | 4527 } else { |
| 4464 HContext* context = new(zone()) HContext; | 4528 HValue* context = environment()->LookupContext(); |
| 4465 AddInstruction(context); | |
| 4466 PushAndAdd(new(zone()) HGlobalObject(context)); | 4529 PushAndAdd(new(zone()) HGlobalObject(context)); |
| 4467 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4530 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 4468 | 4531 |
| 4469 call = PreProcessCall(new(zone()) HCallGlobal(context, | 4532 call = PreProcessCall(new(zone()) HCallGlobal(context, |
| 4470 var->name(), | 4533 var->name(), |
| 4471 argument_count)); | 4534 argument_count)); |
| 4472 } | 4535 } |
| 4473 | 4536 |
| 4474 } else { | 4537 } else { |
| 4475 HContext* context = new(zone()) HContext; | 4538 HValue* context = environment()->LookupContext(); |
| 4476 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 4539 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
| 4477 AddInstruction(context); | |
| 4478 AddInstruction(global_object); | 4540 AddInstruction(global_object); |
| 4479 PushAndAdd(new(zone()) HGlobalReceiver(global_object)); | 4541 PushAndAdd(new(zone()) HGlobalReceiver(global_object)); |
| 4480 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4542 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 4481 | 4543 |
| 4482 call = PreProcessCall(new(zone()) HCallFunction(context, argument_count)); | 4544 call = PreProcessCall(new(zone()) HCallFunction(context, argument_count)); |
| 4483 } | 4545 } |
| 4484 } | 4546 } |
| 4485 | 4547 |
| 4486 call->set_position(expr->position()); | 4548 call->set_position(expr->position()); |
| 4487 ast_context()->ReturnInstruction(call, expr->id()); | 4549 ast_context()->ReturnInstruction(call, expr->id()); |
| 4488 } | 4550 } |
| 4489 | 4551 |
| 4490 | 4552 |
| 4491 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4553 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4492 ASSERT(!HasStackOverflow()); | 4554 ASSERT(!HasStackOverflow()); |
| 4493 ASSERT(current_block() != NULL); | 4555 ASSERT(current_block() != NULL); |
| 4494 ASSERT(current_block()->HasPredecessor()); | 4556 ASSERT(current_block()->HasPredecessor()); |
| 4495 // The constructor function is also used as the receiver argument to the | 4557 // The constructor function is also used as the receiver argument to the |
| 4496 // JS construct call builtin. | 4558 // JS construct call builtin. |
| 4497 CHECK_ALIVE(VisitForValue(expr->expression())); | 4559 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4498 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 4560 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 4499 | 4561 |
| 4500 HContext* context = new(zone()) HContext; | 4562 HValue* context = environment()->LookupContext(); |
| 4501 AddInstruction(context); | |
| 4502 | 4563 |
| 4503 // The constructor is both an operand to the instruction and an argument | 4564 // The constructor is both an operand to the instruction and an argument |
| 4504 // to the construct call. | 4565 // to the construct call. |
| 4505 int arg_count = expr->arguments()->length() + 1; // Plus constructor. | 4566 int arg_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4506 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); | 4567 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); |
| 4507 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); | 4568 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); |
| 4508 call->set_position(expr->position()); | 4569 call->set_position(expr->position()); |
| 4509 PreProcessCall(call); | 4570 PreProcessCall(call); |
| 4510 ast_context()->ReturnInstruction(call, expr->id()); | 4571 ast_context()->ReturnInstruction(call, expr->id()); |
| 4511 } | 4572 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4561 Drop(argument_count); | 4622 Drop(argument_count); |
| 4562 ast_context()->ReturnInstruction(call, expr->id()); | 4623 ast_context()->ReturnInstruction(call, expr->id()); |
| 4563 } | 4624 } |
| 4564 } | 4625 } |
| 4565 | 4626 |
| 4566 | 4627 |
| 4567 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4628 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4568 ASSERT(!HasStackOverflow()); | 4629 ASSERT(!HasStackOverflow()); |
| 4569 ASSERT(current_block() != NULL); | 4630 ASSERT(current_block() != NULL); |
| 4570 ASSERT(current_block()->HasPredecessor()); | 4631 ASSERT(current_block()->HasPredecessor()); |
| 4571 Token::Value op = expr->op(); | 4632 switch (expr->op()) { |
| 4572 if (op == Token::VOID) { | 4633 case Token::DELETE: return VisitDelete(expr); |
| 4634 case Token::VOID: return VisitVoid(expr); |
| 4635 case Token::TYPEOF: return VisitTypeof(expr); |
| 4636 case Token::ADD: return VisitAdd(expr); |
| 4637 case Token::SUB: return VisitSub(expr); |
| 4638 case Token::BIT_NOT: return VisitBitNot(expr); |
| 4639 case Token::NOT: return VisitNot(expr); |
| 4640 default: UNREACHABLE(); |
| 4641 } |
| 4642 } |
| 4643 |
| 4644 void HGraphBuilder::VisitDelete(UnaryOperation* expr) { |
| 4645 Property* prop = expr->expression()->AsProperty(); |
| 4646 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4647 if (prop == NULL && var == NULL) { |
| 4648 // Result of deleting non-property, non-variable reference is true. |
| 4649 // Evaluate the subexpression for side effects. |
| 4573 CHECK_ALIVE(VisitForEffect(expr->expression())); | 4650 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 4574 ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 4651 ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4575 } else if (op == Token::DELETE) { | 4652 } else if (var != NULL && |
| 4576 Property* prop = expr->expression()->AsProperty(); | 4653 !var->is_global() && |
| 4577 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4654 var->AsSlot() != NULL && |
| 4578 if (prop == NULL && var == NULL) { | 4655 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4579 // Result of deleting non-property, non-variable reference is true. | 4656 // Result of deleting non-global, non-dynamic variables is false. |
| 4580 // Evaluate the subexpression for side effects. | 4657 // The subexpression does not have side effects. |
| 4581 CHECK_ALIVE(VisitForEffect(expr->expression())); | 4658 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4582 ast_context()->ReturnValue(graph()->GetConstantTrue()); | 4659 } else if (prop != NULL) { |
| 4583 } else if (var != NULL && | 4660 if (prop->is_synthetic()) { |
| 4584 !var->is_global() && | 4661 // Result of deleting parameters is false, even when they rewrite |
| 4585 var->AsSlot() != NULL && | 4662 // to accesses on the arguments object. |
| 4586 var->AsSlot()->type() != Slot::LOOKUP) { | |
| 4587 // Result of deleting non-global, non-dynamic variables is false. | |
| 4588 // The subexpression does not have side effects. | |
| 4589 ast_context()->ReturnValue(graph()->GetConstantFalse()); | 4663 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4590 } else if (prop != NULL) { | |
| 4591 if (prop->is_synthetic()) { | |
| 4592 // Result of deleting parameters is false, even when they rewrite | |
| 4593 // to accesses on the arguments object. | |
| 4594 ast_context()->ReturnValue(graph()->GetConstantFalse()); | |
| 4595 } else { | |
| 4596 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 4597 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 4598 HValue* key = Pop(); | |
| 4599 HValue* obj = Pop(); | |
| 4600 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key); | |
| 4601 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4602 } | |
| 4603 } else if (var->is_global()) { | |
| 4604 return Bailout("delete with global variable"); | |
| 4605 } else { | 4664 } else { |
| 4606 return Bailout("delete with non-global variable"); | 4665 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4666 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4667 HValue* key = Pop(); |
| 4668 HValue* obj = Pop(); |
| 4669 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key); |
| 4670 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4607 } | 4671 } |
| 4608 } else if (op == Token::NOT) { | 4672 } else if (var->is_global()) { |
| 4609 if (ast_context()->IsTest()) { | 4673 Bailout("delete with global variable"); |
| 4610 TestContext* context = TestContext::cast(ast_context()); | |
| 4611 VisitForControl(expr->expression(), | |
| 4612 context->if_false(), | |
| 4613 context->if_true()); | |
| 4614 } else if (ast_context()->IsValue()) { | |
| 4615 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); | |
| 4616 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); | |
| 4617 CHECK_BAILOUT(VisitForControl(expr->expression(), | |
| 4618 materialize_false, | |
| 4619 materialize_true)); | |
| 4620 | |
| 4621 if (materialize_false->HasPredecessor()) { | |
| 4622 materialize_false->SetJoinId(expr->expression()->id()); | |
| 4623 set_current_block(materialize_false); | |
| 4624 Push(graph()->GetConstantFalse()); | |
| 4625 } else { | |
| 4626 materialize_false = NULL; | |
| 4627 } | |
| 4628 | |
| 4629 if (materialize_true->HasPredecessor()) { | |
| 4630 materialize_true->SetJoinId(expr->expression()->id()); | |
| 4631 set_current_block(materialize_true); | |
| 4632 Push(graph()->GetConstantTrue()); | |
| 4633 } else { | |
| 4634 materialize_true = NULL; | |
| 4635 } | |
| 4636 | |
| 4637 HBasicBlock* join = | |
| 4638 CreateJoin(materialize_false, materialize_true, expr->id()); | |
| 4639 set_current_block(join); | |
| 4640 if (join != NULL) ast_context()->ReturnValue(Pop()); | |
| 4641 } else { | |
| 4642 ASSERT(ast_context()->IsEffect()); | |
| 4643 VisitForEffect(expr->expression()); | |
| 4644 } | |
| 4645 | |
| 4646 } else if (op == Token::TYPEOF) { | |
| 4647 CHECK_ALIVE(VisitForTypeOf(expr->expression())); | |
| 4648 HValue* value = Pop(); | |
| 4649 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id()); | |
| 4650 | |
| 4651 } else { | 4674 } else { |
| 4652 CHECK_ALIVE(VisitForValue(expr->expression())); | 4675 Bailout("delete with non-global variable"); |
| 4653 HValue* value = Pop(); | |
| 4654 HInstruction* instr = NULL; | |
| 4655 switch (op) { | |
| 4656 case Token::BIT_NOT: | |
| 4657 instr = new(zone()) HBitNot(value); | |
| 4658 break; | |
| 4659 case Token::SUB: | |
| 4660 instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); | |
| 4661 break; | |
| 4662 case Token::ADD: | |
| 4663 instr = new(zone()) HMul(value, graph_->GetConstant1()); | |
| 4664 break; | |
| 4665 default: | |
| 4666 return Bailout("Value: unsupported unary operation"); | |
| 4667 break; | |
| 4668 } | |
| 4669 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4670 } | 4676 } |
| 4671 } | 4677 } |
| 4672 | 4678 |
| 4673 | 4679 |
| 4674 HInstruction* HGraphBuilder::BuildIncrement(HValue* value, | 4680 void HGraphBuilder::VisitVoid(UnaryOperation* expr) { |
| 4675 bool increment, | 4681 CHECK_ALIVE(VisitForEffect(expr->expression())); |
| 4682 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4683 } |
| 4684 |
| 4685 |
| 4686 void HGraphBuilder::VisitTypeof(UnaryOperation* expr) { |
| 4687 CHECK_ALIVE(VisitForTypeOf(expr->expression())); |
| 4688 HValue* value = Pop(); |
| 4689 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id()); |
| 4690 } |
| 4691 |
| 4692 |
| 4693 void HGraphBuilder::VisitAdd(UnaryOperation* expr) { |
| 4694 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4695 HValue* value = Pop(); |
| 4696 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstant1()); |
| 4697 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4698 } |
| 4699 |
| 4700 |
| 4701 void HGraphBuilder::VisitSub(UnaryOperation* expr) { |
| 4702 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4703 HValue* value = Pop(); |
| 4704 HInstruction* instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); |
| 4705 TypeInfo info = oracle()->UnaryType(expr); |
| 4706 Representation rep = ToRepresentation(info); |
| 4707 TraceRepresentation(expr->op(), info, instr, rep); |
| 4708 instr->AssumeRepresentation(rep); |
| 4709 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4710 } |
| 4711 |
| 4712 |
| 4713 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) { |
| 4714 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 4715 HValue* value = Pop(); |
| 4716 HInstruction* instr = new(zone()) HBitNot(value); |
| 4717 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4718 } |
| 4719 |
| 4720 |
| 4721 void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
| 4722 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. |
| 4723 if (ast_context()->IsTest()) { |
| 4724 TestContext* context = TestContext::cast(ast_context()); |
| 4725 VisitForControl(expr->expression(), |
| 4726 context->if_false(), |
| 4727 context->if_true()); |
| 4728 return; |
| 4729 } |
| 4730 |
| 4731 if (ast_context()->IsEffect()) { |
| 4732 VisitForEffect(expr->expression()); |
| 4733 return; |
| 4734 } |
| 4735 |
| 4736 ASSERT(ast_context()->IsValue()); |
| 4737 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); |
| 4738 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); |
| 4739 CHECK_BAILOUT(VisitForControl(expr->expression(), |
| 4740 materialize_false, |
| 4741 materialize_true)); |
| 4742 |
| 4743 if (materialize_false->HasPredecessor()) { |
| 4744 materialize_false->SetJoinId(expr->expression()->id()); |
| 4745 set_current_block(materialize_false); |
| 4746 Push(graph()->GetConstantFalse()); |
| 4747 } else { |
| 4748 materialize_false = NULL; |
| 4749 } |
| 4750 |
| 4751 if (materialize_true->HasPredecessor()) { |
| 4752 materialize_true->SetJoinId(expr->expression()->id()); |
| 4753 set_current_block(materialize_true); |
| 4754 Push(graph()->GetConstantTrue()); |
| 4755 } else { |
| 4756 materialize_true = NULL; |
| 4757 } |
| 4758 |
| 4759 HBasicBlock* join = |
| 4760 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 4761 set_current_block(join); |
| 4762 if (join != NULL) ast_context()->ReturnValue(Pop()); |
| 4763 } |
| 4764 |
| 4765 |
| 4766 HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input, |
| 4676 CountOperation* expr) { | 4767 CountOperation* expr) { |
| 4677 HConstant* delta = increment | 4768 // The input to the count operation is on top of the expression stack. |
| 4678 ? graph_->GetConstant1() | 4769 TypeInfo info = oracle()->IncrementType(expr); |
| 4679 : graph_->GetConstantMinus1(); | 4770 Representation rep = ToRepresentation(info); |
| 4680 HInstruction* instr = new(zone()) HAdd(value, delta); | |
| 4681 Representation rep = ToRepresentation(oracle()->IncrementType(expr)); | |
| 4682 if (rep.IsTagged()) { | 4771 if (rep.IsTagged()) { |
| 4683 rep = Representation::Integer32(); | 4772 rep = Representation::Integer32(); |
| 4684 } | 4773 } |
| 4685 AssumeRepresentation(instr, rep); | 4774 |
| 4775 if (returns_original_input) { |
| 4776 // We need an explicit HValue representing ToNumber(input). The |
| 4777 // actual HChange instruction we need is (sometimes) added in a later |
| 4778 // phase, so it is not available now to be used as an input to HAdd and |
| 4779 // as the return value. |
| 4780 HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep); |
| 4781 AddInstruction(number_input); |
| 4782 Push(number_input); |
| 4783 } |
| 4784 |
| 4785 // The addition has no side effects, so we do not need |
| 4786 // to simulate the expression stack after this instruction. |
| 4787 // Any later failures deopt to the load of the input or earlier. |
| 4788 HConstant* delta = (expr->op() == Token::INC) |
| 4789 ? graph_->GetConstant1() |
| 4790 : graph_->GetConstantMinus1(); |
| 4791 HInstruction* instr = new(zone()) HAdd(Top(), delta); |
| 4792 TraceRepresentation(expr->op(), info, instr, rep); |
| 4793 instr->AssumeRepresentation(rep); |
| 4794 AddInstruction(instr); |
| 4686 return instr; | 4795 return instr; |
| 4687 } | 4796 } |
| 4688 | 4797 |
| 4689 | 4798 |
| 4690 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { | 4799 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 4691 ASSERT(!HasStackOverflow()); | 4800 ASSERT(!HasStackOverflow()); |
| 4692 ASSERT(current_block() != NULL); | 4801 ASSERT(current_block() != NULL); |
| 4693 ASSERT(current_block()->HasPredecessor()); | 4802 ASSERT(current_block()->HasPredecessor()); |
| 4694 Expression* target = expr->expression(); | 4803 Expression* target = expr->expression(); |
| 4695 VariableProxy* proxy = target->AsVariableProxy(); | 4804 VariableProxy* proxy = target->AsVariableProxy(); |
| 4696 Variable* var = proxy->AsVariable(); | 4805 Variable* var = proxy->AsVariable(); |
| 4697 Property* prop = target->AsProperty(); | 4806 Property* prop = target->AsProperty(); |
| 4698 ASSERT(var == NULL || prop == NULL); | 4807 if (var == NULL && prop == NULL) { |
| 4699 bool inc = expr->op() == Token::INC; | 4808 return Bailout("invalid lhs in count operation"); |
| 4809 } |
| 4810 |
| 4811 // Match the full code generator stack by simulating an extra stack |
| 4812 // element for postfix operations in a non-effect context. The return |
| 4813 // value is ToNumber(input). |
| 4814 bool returns_original_input = |
| 4815 expr->is_postfix() && !ast_context()->IsEffect(); |
| 4816 HValue* input = NULL; // ToNumber(original_input). |
| 4817 HValue* after = NULL; // The result after incrementing or decrementing. |
| 4700 | 4818 |
| 4701 if (var != NULL) { | 4819 if (var != NULL) { |
| 4820 // Argument of the count operation is a variable, not a property. |
| 4821 ASSERT(prop == NULL); |
| 4702 CHECK_ALIVE(VisitForValue(target)); | 4822 CHECK_ALIVE(VisitForValue(target)); |
| 4703 | 4823 |
| 4704 // Match the full code generator stack by simulating an extra stack | 4824 after = BuildIncrement(returns_original_input, expr); |
| 4705 // element for postfix operations in a non-effect context. | 4825 input = returns_original_input ? Top() : Pop(); |
| 4706 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | |
| 4707 HValue* before = has_extra ? Top() : Pop(); | |
| 4708 HInstruction* after = BuildIncrement(before, inc, expr); | |
| 4709 AddInstruction(after); | |
| 4710 Push(after); | 4826 Push(after); |
| 4711 | 4827 |
| 4712 if (var->is_global()) { | 4828 if (var->is_global()) { |
| 4713 HandleGlobalVariableAssignment(var, | 4829 HandleGlobalVariableAssignment(var, |
| 4714 after, | 4830 after, |
| 4715 expr->position(), | 4831 expr->position(), |
| 4716 expr->AssignmentId()); | 4832 expr->AssignmentId()); |
| 4717 } else if (var->IsStackAllocated()) { | 4833 } else if (var->IsStackAllocated()) { |
| 4718 Bind(var, after); | 4834 Bind(var, after); |
| 4719 } else if (var->IsContextSlot()) { | 4835 } else if (var->IsContextSlot()) { |
| 4720 HValue* context = BuildContextChainWalk(var); | 4836 HValue* context = BuildContextChainWalk(var); |
| 4721 int index = var->AsSlot()->index(); | 4837 int index = var->AsSlot()->index(); |
| 4722 HStoreContextSlot* instr = | 4838 HStoreContextSlot* instr = |
| 4723 new(zone()) HStoreContextSlot(context, index, after); | 4839 new(zone()) HStoreContextSlot(context, index, after); |
| 4724 AddInstruction(instr); | 4840 AddInstruction(instr); |
| 4725 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4841 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4726 } else { | 4842 } else { |
| 4727 return Bailout("lookup variable in count operation"); | 4843 return Bailout("lookup variable in count operation"); |
| 4728 } | 4844 } |
| 4729 Drop(has_extra ? 2 : 1); | |
| 4730 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | |
| 4731 | 4845 |
| 4732 } else if (prop != NULL) { | 4846 } else { |
| 4847 // Argument of the count operation is a property. |
| 4848 ASSERT(prop != NULL); |
| 4733 prop->RecordTypeFeedback(oracle()); | 4849 prop->RecordTypeFeedback(oracle()); |
| 4734 | 4850 |
| 4735 if (prop->key()->IsPropertyName()) { | 4851 if (prop->key()->IsPropertyName()) { |
| 4736 // Named property. | 4852 // Named property. |
| 4737 | 4853 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
| 4738 // Match the full code generator stack by simulating an extra stack | |
| 4739 // element for postfix operations in a non-effect context. | |
| 4740 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | |
| 4741 if (has_extra) Push(graph_->GetConstantUndefined()); | |
| 4742 | 4854 |
| 4743 CHECK_ALIVE(VisitForValue(prop->obj())); | 4855 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4744 HValue* obj = Top(); | 4856 HValue* obj = Top(); |
| 4745 | 4857 |
| 4746 HInstruction* load = NULL; | 4858 HInstruction* load = NULL; |
| 4747 if (prop->IsMonomorphic()) { | 4859 if (prop->IsMonomorphic()) { |
| 4748 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4860 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4749 Handle<Map> map = prop->GetReceiverTypes()->first(); | 4861 Handle<Map> map = prop->GetReceiverTypes()->first(); |
| 4750 load = BuildLoadNamed(obj, prop, map, name); | 4862 load = BuildLoadNamed(obj, prop, map, name); |
| 4751 } else { | 4863 } else { |
| 4752 load = BuildLoadNamedGeneric(obj, prop); | 4864 load = BuildLoadNamedGeneric(obj, prop); |
| 4753 } | 4865 } |
| 4754 PushAndAdd(load); | 4866 PushAndAdd(load); |
| 4755 if (load->HasSideEffects()) AddSimulate(expr->CountId()); | 4867 if (load->HasSideEffects()) AddSimulate(expr->CountId()); |
| 4756 | 4868 |
| 4757 HValue* before = Pop(); | 4869 after = BuildIncrement(returns_original_input, expr); |
| 4758 // There is no deoptimization to after the increment, so we don't need | 4870 input = Pop(); |
| 4759 // to simulate the expression stack after this instruction. | |
| 4760 HInstruction* after = BuildIncrement(before, inc, expr); | |
| 4761 AddInstruction(after); | |
| 4762 | 4871 |
| 4763 HInstruction* store = BuildStoreNamed(obj, after, prop); | 4872 HInstruction* store = BuildStoreNamed(obj, after, prop); |
| 4764 AddInstruction(store); | 4873 AddInstruction(store); |
| 4765 | 4874 |
| 4766 // Overwrite the receiver in the bailout environment with the result | 4875 // Overwrite the receiver in the bailout environment with the result |
| 4767 // of the operation, and the placeholder with the original value if | 4876 // of the operation, and the placeholder with the original value if |
| 4768 // necessary. | 4877 // necessary. |
| 4769 environment()->SetExpressionStackAt(0, after); | 4878 environment()->SetExpressionStackAt(0, after); |
| 4770 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4879 if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
| 4771 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4880 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4772 Drop(has_extra ? 2 : 1); | |
| 4773 | |
| 4774 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | |
| 4775 | 4881 |
| 4776 } else { | 4882 } else { |
| 4777 // Keyed property. | 4883 // Keyed property. |
| 4778 | 4884 if (returns_original_input) Push(graph_->GetConstantUndefined()); |
| 4779 // Match the full code generator stack by simulate an extra stack element | |
| 4780 // for postfix operations in a non-effect context. | |
| 4781 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | |
| 4782 if (has_extra) Push(graph_->GetConstantUndefined()); | |
| 4783 | 4885 |
| 4784 CHECK_ALIVE(VisitForValue(prop->obj())); | 4886 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4785 CHECK_ALIVE(VisitForValue(prop->key())); | 4887 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4786 HValue* obj = environment()->ExpressionStackAt(1); | 4888 HValue* obj = environment()->ExpressionStackAt(1); |
| 4787 HValue* key = environment()->ExpressionStackAt(0); | 4889 HValue* key = environment()->ExpressionStackAt(0); |
| 4788 | 4890 |
| 4789 HInstruction* load = BuildLoadKeyed(obj, key, prop); | 4891 HInstruction* load = BuildLoadKeyed(obj, key, prop); |
| 4790 PushAndAdd(load); | 4892 PushAndAdd(load); |
| 4791 if (load->HasSideEffects()) AddSimulate(expr->CountId()); | 4893 if (load->HasSideEffects()) AddSimulate(expr->CountId()); |
| 4792 | 4894 |
| 4793 HValue* before = Pop(); | 4895 after = BuildIncrement(returns_original_input, expr); |
| 4794 // There is no deoptimization to after the increment, so we don't need | 4896 input = Pop(); |
| 4795 // to simulate the expression stack after this instruction. | |
| 4796 HInstruction* after = BuildIncrement(before, inc, expr); | |
| 4797 AddInstruction(after); | |
| 4798 | 4897 |
| 4799 expr->RecordTypeFeedback(oracle()); | 4898 expr->RecordTypeFeedback(oracle()); |
| 4800 HInstruction* store = BuildStoreKeyed(obj, key, after, expr); | 4899 HInstruction* store = BuildStoreKeyed(obj, key, after, expr); |
| 4801 AddInstruction(store); | 4900 AddInstruction(store); |
| 4802 | 4901 |
| 4803 // Drop the key from the bailout environment. Overwrite the receiver | 4902 // Drop the key from the bailout environment. Overwrite the receiver |
| 4804 // with the result of the operation, and the placeholder with the | 4903 // with the result of the operation, and the placeholder with the |
| 4805 // original value if necessary. | 4904 // original value if necessary. |
| 4806 Drop(1); | 4905 Drop(1); |
| 4807 environment()->SetExpressionStackAt(0, after); | 4906 environment()->SetExpressionStackAt(0, after); |
| 4808 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4907 if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
| 4809 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4908 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4810 Drop(has_extra ? 2 : 1); | 4909 } |
| 4910 } |
| 4811 | 4911 |
| 4812 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4912 Drop(returns_original_input ? 2 : 1); |
| 4813 } | 4913 ast_context()->ReturnValue(expr->is_postfix() ? input : after); |
| 4914 } |
| 4814 | 4915 |
| 4815 } else { | 4916 |
| 4816 return Bailout("invalid lhs in count operation"); | 4917 HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, |
| 4817 } | 4918 HValue* right, |
| 4919 Token::Value op) { |
| 4920 ASSERT(op == Token::EQ || op == Token::EQ_STRICT); |
| 4921 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 4922 AddInstruction(HCheckInstanceType::NewIsSymbol(left)); |
| 4923 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 4924 AddInstruction(HCheckInstanceType::NewIsSymbol(right)); |
| 4925 return new(zone()) HCompareSymbolEq(left, right, op); |
| 4818 } | 4926 } |
| 4819 | 4927 |
| 4820 | 4928 |
| 4821 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, | 4929 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, |
| 4822 HValue* index) { | 4930 HValue* index) { |
| 4823 AddInstruction(new(zone()) HCheckNonSmi(string)); | 4931 AddInstruction(new(zone()) HCheckNonSmi(string)); |
| 4824 AddInstruction(new(zone()) HCheckInstanceType( | 4932 AddInstruction(HCheckInstanceType::NewIsString(string)); |
| 4825 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); | |
| 4826 HStringLength* length = new(zone()) HStringLength(string); | 4933 HStringLength* length = new(zone()) HStringLength(string); |
| 4827 AddInstruction(length); | 4934 AddInstruction(length); |
| 4828 AddInstruction(new(zone()) HBoundsCheck(index, length)); | 4935 AddInstruction(new(zone()) HBoundsCheck(index, length)); |
| 4829 return new(zone()) HStringCharCodeAt(string, index); | 4936 return new(zone()) HStringCharCodeAt(string, index); |
| 4830 } | 4937 } |
| 4831 | 4938 |
| 4832 | 4939 |
| 4833 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4940 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4834 HValue* left, | 4941 HValue* left, |
| 4835 HValue* right) { | 4942 HValue* right) { |
| 4836 TypeInfo info = oracle()->BinaryType(expr); | 4943 TypeInfo info = oracle()->BinaryType(expr); |
| 4837 HInstruction* instr = NULL; | 4944 HInstruction* instr = BuildBinaryOperation(expr->op(), left, right, info); |
| 4838 switch (expr->op()) { | |
| 4839 case Token::ADD: | |
| 4840 if (info.IsString()) { | |
| 4841 AddInstruction(new(zone()) HCheckNonSmi(left)); | |
| 4842 AddInstruction(new(zone()) HCheckInstanceType( | |
| 4843 left, FIRST_STRING_TYPE, LAST_STRING_TYPE)); | |
| 4844 AddInstruction(new(zone()) HCheckNonSmi(right)); | |
| 4845 AddInstruction(new(zone()) HCheckInstanceType( | |
| 4846 right, FIRST_STRING_TYPE, LAST_STRING_TYPE)); | |
| 4847 instr = new(zone()) HStringAdd(left, right); | |
| 4848 } else { | |
| 4849 instr = new(zone()) HAdd(left, right); | |
| 4850 } | |
| 4851 break; | |
| 4852 case Token::SUB: | |
| 4853 instr = new(zone()) HSub(left, right); | |
| 4854 break; | |
| 4855 case Token::MUL: | |
| 4856 instr = new(zone()) HMul(left, right); | |
| 4857 break; | |
| 4858 case Token::MOD: | |
| 4859 instr = new(zone()) HMod(left, right); | |
| 4860 break; | |
| 4861 case Token::DIV: | |
| 4862 instr = new(zone()) HDiv(left, right); | |
| 4863 break; | |
| 4864 case Token::BIT_XOR: | |
| 4865 instr = new(zone()) HBitXor(left, right); | |
| 4866 break; | |
| 4867 case Token::BIT_AND: | |
| 4868 instr = new(zone()) HBitAnd(left, right); | |
| 4869 break; | |
| 4870 case Token::BIT_OR: | |
| 4871 instr = new(zone()) HBitOr(left, right); | |
| 4872 break; | |
| 4873 case Token::SAR: | |
| 4874 instr = new(zone()) HSar(left, right); | |
| 4875 break; | |
| 4876 case Token::SHR: | |
| 4877 instr = new(zone()) HShr(left, right); | |
| 4878 break; | |
| 4879 case Token::SHL: | |
| 4880 instr = new(zone()) HShl(left, right); | |
| 4881 break; | |
| 4882 default: | |
| 4883 UNREACHABLE(); | |
| 4884 } | |
| 4885 // If we hit an uninitialized binary op stub we will get type info | 4945 // If we hit an uninitialized binary op stub we will get type info |
| 4886 // for a smi operation. If one of the operands is a constant string | 4946 // for a smi operation. If one of the operands is a constant string |
| 4887 // do not generate code assuming it is a smi operation. | 4947 // do not generate code assuming it is a smi operation. |
| 4888 if (info.IsSmi() && | 4948 if (info.IsSmi() && |
| 4889 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || | 4949 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || |
| 4890 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { | 4950 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { |
| 4891 return instr; | 4951 return instr; |
| 4892 } | 4952 } |
| 4893 if (FLAG_trace_representation) { | |
| 4894 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); | |
| 4895 } | |
| 4896 Representation rep = ToRepresentation(info); | 4953 Representation rep = ToRepresentation(info); |
| 4897 // We only generate either int32 or generic tagged bitwise operations. | 4954 // We only generate either int32 or generic tagged bitwise operations. |
| 4898 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { | 4955 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { |
| 4899 rep = Representation::Integer32(); | 4956 rep = Representation::Integer32(); |
| 4900 } | 4957 } |
| 4901 AssumeRepresentation(instr, rep); | 4958 TraceRepresentation(expr->op(), info, instr, rep); |
| 4959 instr->AssumeRepresentation(rep); |
| 4902 return instr; | 4960 return instr; |
| 4903 } | 4961 } |
| 4904 | 4962 |
| 4905 | 4963 |
| 4964 HInstruction* HGraphBuilder::BuildBinaryOperation( |
| 4965 Token::Value op, HValue* left, HValue* right, TypeInfo info) { |
| 4966 switch (op) { |
| 4967 case Token::ADD: |
| 4968 if (info.IsString()) { |
| 4969 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 4970 AddInstruction(HCheckInstanceType::NewIsString(left)); |
| 4971 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 4972 AddInstruction(HCheckInstanceType::NewIsString(right)); |
| 4973 return new(zone()) HStringAdd(left, right); |
| 4974 } else { |
| 4975 return new(zone()) HAdd(left, right); |
| 4976 } |
| 4977 case Token::SUB: return new(zone()) HSub(left, right); |
| 4978 case Token::MUL: return new(zone()) HMul(left, right); |
| 4979 case Token::MOD: return new(zone()) HMod(left, right); |
| 4980 case Token::DIV: return new(zone()) HDiv(left, right); |
| 4981 case Token::BIT_XOR: return new(zone()) HBitXor(left, right); |
| 4982 case Token::BIT_AND: return new(zone()) HBitAnd(left, right); |
| 4983 case Token::BIT_OR: return new(zone()) HBitOr(left, right); |
| 4984 case Token::SAR: return new(zone()) HSar(left, right); |
| 4985 case Token::SHR: return new(zone()) HShr(left, right); |
| 4986 case Token::SHL: return new(zone()) HShl(left, right); |
| 4987 default: |
| 4988 UNREACHABLE(); |
| 4989 return NULL; |
| 4990 } |
| 4991 } |
| 4992 |
| 4993 |
| 4906 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 4994 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 4907 static bool IsClassOfTest(CompareOperation* expr) { | 4995 static bool IsClassOfTest(CompareOperation* expr) { |
| 4908 if (expr->op() != Token::EQ_STRICT) return false; | 4996 if (expr->op() != Token::EQ_STRICT) return false; |
| 4909 CallRuntime* call = expr->left()->AsCallRuntime(); | 4997 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4910 if (call == NULL) return false; | 4998 if (call == NULL) return false; |
| 4911 Literal* literal = expr->right()->AsLiteral(); | 4999 Literal* literal = expr->right()->AsLiteral(); |
| 4912 if (literal == NULL) return false; | 5000 if (literal == NULL) return false; |
| 4913 if (!literal->handle()->IsString()) return false; | 5001 if (!literal->handle()->IsString()) return false; |
| 4914 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; | 5002 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; |
| 4915 ASSERT(call->arguments()->length() == 1); | 5003 ASSERT(call->arguments()->length() == 1); |
| 4916 return true; | 5004 return true; |
| 4917 } | 5005 } |
| 4918 | 5006 |
| 4919 | 5007 |
| 4920 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 5008 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 4921 ASSERT(!HasStackOverflow()); | 5009 ASSERT(!HasStackOverflow()); |
| 4922 ASSERT(current_block() != NULL); | 5010 ASSERT(current_block() != NULL); |
| 4923 ASSERT(current_block()->HasPredecessor()); | 5011 ASSERT(current_block()->HasPredecessor()); |
| 4924 if (expr->op() == Token::COMMA) { | 5012 switch (expr->op()) { |
| 4925 CHECK_ALIVE(VisitForEffect(expr->left())); | 5013 case Token::COMMA: return VisitComma(expr); |
| 4926 // Visit the right subexpression in the same AST context as the entire | 5014 case Token::OR: return VisitAndOr(expr, false); |
| 4927 // expression. | 5015 case Token::AND: return VisitAndOr(expr, true); |
| 4928 Visit(expr->right()); | 5016 default: return VisitCommon(expr); |
| 4929 | |
| 4930 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { | |
| 4931 bool is_logical_and = (expr->op() == Token::AND); | |
| 4932 if (ast_context()->IsTest()) { | |
| 4933 TestContext* context = TestContext::cast(ast_context()); | |
| 4934 // Translate left subexpression. | |
| 4935 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 4936 if (is_logical_and) { | |
| 4937 CHECK_BAILOUT(VisitForControl(expr->left(), | |
| 4938 eval_right, | |
| 4939 context->if_false())); | |
| 4940 } else { | |
| 4941 CHECK_BAILOUT(VisitForControl(expr->left(), | |
| 4942 context->if_true(), | |
| 4943 eval_right)); | |
| 4944 } | |
| 4945 | |
| 4946 // Translate right subexpression by visiting it in the same AST | |
| 4947 // context as the entire expression. | |
| 4948 if (eval_right->HasPredecessor()) { | |
| 4949 eval_right->SetJoinId(expr->RightId()); | |
| 4950 set_current_block(eval_right); | |
| 4951 Visit(expr->right()); | |
| 4952 } | |
| 4953 | |
| 4954 } else if (ast_context()->IsValue()) { | |
| 4955 CHECK_ALIVE(VisitForValue(expr->left())); | |
| 4956 ASSERT(current_block() != NULL); | |
| 4957 | |
| 4958 // We need an extra block to maintain edge-split form. | |
| 4959 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | |
| 4960 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 4961 HTest* test = is_logical_and | |
| 4962 ? new(zone()) HTest(Top(), eval_right, empty_block) | |
| 4963 : new(zone()) HTest(Top(), empty_block, eval_right); | |
| 4964 current_block()->Finish(test); | |
| 4965 | |
| 4966 set_current_block(eval_right); | |
| 4967 Drop(1); // Value of the left subexpression. | |
| 4968 CHECK_BAILOUT(VisitForValue(expr->right())); | |
| 4969 | |
| 4970 HBasicBlock* join_block = | |
| 4971 CreateJoin(empty_block, current_block(), expr->id()); | |
| 4972 set_current_block(join_block); | |
| 4973 ast_context()->ReturnValue(Pop()); | |
| 4974 | |
| 4975 } else { | |
| 4976 ASSERT(ast_context()->IsEffect()); | |
| 4977 // In an effect context, we don't need the value of the left | |
| 4978 // subexpression, only its control flow and side effects. We need an | |
| 4979 // extra block to maintain edge-split form. | |
| 4980 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | |
| 4981 HBasicBlock* right_block = graph()->CreateBasicBlock(); | |
| 4982 if (is_logical_and) { | |
| 4983 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); | |
| 4984 } else { | |
| 4985 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block)); | |
| 4986 } | |
| 4987 | |
| 4988 // TODO(kmillikin): Find a way to fix this. It's ugly that there are | |
| 4989 // actually two empty blocks (one here and one inserted by | |
| 4990 // TestContext::BuildBranch, and that they both have an HSimulate | |
| 4991 // though the second one is not a merge node, and that we really have | |
| 4992 // no good AST ID to put on that first HSimulate. | |
| 4993 if (empty_block->HasPredecessor()) { | |
| 4994 empty_block->SetJoinId(expr->id()); | |
| 4995 } else { | |
| 4996 empty_block = NULL; | |
| 4997 } | |
| 4998 | |
| 4999 if (right_block->HasPredecessor()) { | |
| 5000 right_block->SetJoinId(expr->RightId()); | |
| 5001 set_current_block(right_block); | |
| 5002 CHECK_BAILOUT(VisitForEffect(expr->right())); | |
| 5003 right_block = current_block(); | |
| 5004 } else { | |
| 5005 right_block = NULL; | |
| 5006 } | |
| 5007 | |
| 5008 HBasicBlock* join_block = | |
| 5009 CreateJoin(empty_block, right_block, expr->id()); | |
| 5010 set_current_block(join_block); | |
| 5011 // We did not materialize any value in the predecessor environments, | |
| 5012 // so there is no need to handle it here. | |
| 5013 } | |
| 5014 | |
| 5015 } else { | |
| 5016 CHECK_ALIVE(VisitForValue(expr->left())); | |
| 5017 CHECK_ALIVE(VisitForValue(expr->right())); | |
| 5018 | |
| 5019 HValue* right = Pop(); | |
| 5020 HValue* left = Pop(); | |
| 5021 HInstruction* instr = BuildBinaryOperation(expr, left, right); | |
| 5022 instr->set_position(expr->position()); | |
| 5023 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 5024 } | 5017 } |
| 5025 } | 5018 } |
| 5026 | 5019 |
| 5027 | 5020 |
| 5028 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 5021 void HGraphBuilder::VisitComma(BinaryOperation* expr) { |
| 5029 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 5022 CHECK_ALIVE(VisitForEffect(expr->left())); |
| 5030 if (FLAG_trace_representation) { | 5023 // Visit the right subexpression in the same AST context as the entire |
| 5031 PrintF("Assume representation for %s to be %s (%d)\n", | 5024 // expression. |
| 5032 value->Mnemonic(), | 5025 Visit(expr->right()); |
| 5033 r.Mnemonic(), | 5026 } |
| 5034 graph_->GetMaximumValueID()); | 5027 |
| 5028 |
| 5029 void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) { |
| 5030 if (ast_context()->IsTest()) { |
| 5031 TestContext* context = TestContext::cast(ast_context()); |
| 5032 // Translate left subexpression. |
| 5033 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 5034 if (is_logical_and) { |
| 5035 CHECK_BAILOUT(VisitForControl(expr->left(), |
| 5036 eval_right, |
| 5037 context->if_false())); |
| 5038 } else { |
| 5039 CHECK_BAILOUT(VisitForControl(expr->left(), |
| 5040 context->if_true(), |
| 5041 eval_right)); |
| 5035 } | 5042 } |
| 5036 value->ChangeRepresentation(r); | 5043 |
| 5037 // The representation of the value is dictated by type feedback and | 5044 // Translate right subexpression by visiting it in the same AST |
| 5038 // will not be changed later. | 5045 // context as the entire expression. |
| 5039 value->ClearFlag(HValue::kFlexibleRepresentation); | 5046 if (eval_right->HasPredecessor()) { |
| 5040 } else if (FLAG_trace_representation) { | 5047 eval_right->SetJoinId(expr->RightId()); |
| 5041 PrintF("No representation assumed\n"); | 5048 set_current_block(eval_right); |
| 5049 Visit(expr->right()); |
| 5050 } |
| 5051 |
| 5052 } else if (ast_context()->IsValue()) { |
| 5053 CHECK_ALIVE(VisitForValue(expr->left())); |
| 5054 ASSERT(current_block() != NULL); |
| 5055 |
| 5056 // We need an extra block to maintain edge-split form. |
| 5057 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 5058 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 5059 HTest* test = is_logical_and |
| 5060 ? new(zone()) HTest(Top(), eval_right, empty_block) |
| 5061 : new(zone()) HTest(Top(), empty_block, eval_right); |
| 5062 current_block()->Finish(test); |
| 5063 |
| 5064 set_current_block(eval_right); |
| 5065 Drop(1); // Value of the left subexpression. |
| 5066 CHECK_BAILOUT(VisitForValue(expr->right())); |
| 5067 |
| 5068 HBasicBlock* join_block = |
| 5069 CreateJoin(empty_block, current_block(), expr->id()); |
| 5070 set_current_block(join_block); |
| 5071 ast_context()->ReturnValue(Pop()); |
| 5072 |
| 5073 } else { |
| 5074 ASSERT(ast_context()->IsEffect()); |
| 5075 // In an effect context, we don't need the value of the left subexpression, |
| 5076 // only its control flow and side effects. We need an extra block to |
| 5077 // maintain edge-split form. |
| 5078 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 5079 HBasicBlock* right_block = graph()->CreateBasicBlock(); |
| 5080 if (is_logical_and) { |
| 5081 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); |
| 5082 } else { |
| 5083 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block)); |
| 5084 } |
| 5085 |
| 5086 // TODO(kmillikin): Find a way to fix this. It's ugly that there are |
| 5087 // actually two empty blocks (one here and one inserted by |
| 5088 // TestContext::BuildBranch, and that they both have an HSimulate though the |
| 5089 // second one is not a merge node, and that we really have no good AST ID to |
| 5090 // put on that first HSimulate. |
| 5091 |
| 5092 if (empty_block->HasPredecessor()) { |
| 5093 empty_block->SetJoinId(expr->id()); |
| 5094 } else { |
| 5095 empty_block = NULL; |
| 5096 } |
| 5097 |
| 5098 if (right_block->HasPredecessor()) { |
| 5099 right_block->SetJoinId(expr->RightId()); |
| 5100 set_current_block(right_block); |
| 5101 CHECK_BAILOUT(VisitForEffect(expr->right())); |
| 5102 right_block = current_block(); |
| 5103 } else { |
| 5104 right_block = NULL; |
| 5105 } |
| 5106 |
| 5107 HBasicBlock* join_block = |
| 5108 CreateJoin(empty_block, right_block, expr->id()); |
| 5109 set_current_block(join_block); |
| 5110 // We did not materialize any value in the predecessor environments, |
| 5111 // so there is no need to handle it here. |
| 5042 } | 5112 } |
| 5043 } | 5113 } |
| 5044 | 5114 |
| 5045 | 5115 |
| 5116 void HGraphBuilder::VisitCommon(BinaryOperation* expr) { |
| 5117 CHECK_ALIVE(VisitForValue(expr->left())); |
| 5118 CHECK_ALIVE(VisitForValue(expr->right())); |
| 5119 HValue* right = Pop(); |
| 5120 HValue* left = Pop(); |
| 5121 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
| 5122 instr->set_position(expr->position()); |
| 5123 ast_context()->ReturnInstruction(instr, expr->id()); |
| 5124 } |
| 5125 |
| 5126 |
| 5127 void HGraphBuilder::TraceRepresentation(Token::Value op, |
| 5128 TypeInfo info, |
| 5129 HValue* value, |
| 5130 Representation rep) { |
| 5131 if (!FLAG_trace_representation) return; |
| 5132 // TODO(svenpanne) Under which circumstances are we actually not flexible? |
| 5133 // At first glance, this looks a bit weird... |
| 5134 bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation); |
| 5135 PrintF("Operation %s has type info %s, %schange representation assumption " |
| 5136 "for %s (ID %d) from %s to %s\n", |
| 5137 Token::Name(op), |
| 5138 info.ToString(), |
| 5139 flexible ? "" : " DO NOT ", |
| 5140 value->Mnemonic(), |
| 5141 graph_->GetMaximumValueID(), |
| 5142 value->representation().Mnemonic(), |
| 5143 rep.Mnemonic()); |
| 5144 } |
| 5145 |
| 5146 |
| 5046 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 5147 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
| 5047 if (info.IsSmi()) return Representation::Integer32(); | 5148 if (info.IsSmi()) return Representation::Integer32(); |
| 5048 if (info.IsInteger32()) return Representation::Integer32(); | 5149 if (info.IsInteger32()) return Representation::Integer32(); |
| 5049 if (info.IsDouble()) return Representation::Double(); | 5150 if (info.IsDouble()) return Representation::Double(); |
| 5050 if (info.IsNumber()) return Representation::Double(); | 5151 if (info.IsNumber()) return Representation::Double(); |
| 5051 return Representation::Tagged(); | 5152 return Representation::Tagged(); |
| 5052 } | 5153 } |
| 5053 | 5154 |
| 5054 | 5155 |
| 5055 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 5156 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5114 // change and thus prefer the general IC code. | 5215 // change and thus prefer the general IC code. |
| 5115 if (!isolate()->heap()->InNewSpace(*candidate)) { | 5216 if (!isolate()->heap()->InNewSpace(*candidate)) { |
| 5116 target = candidate; | 5217 target = candidate; |
| 5117 } | 5218 } |
| 5118 } | 5219 } |
| 5119 } | 5220 } |
| 5120 | 5221 |
| 5121 // If the target is not null we have found a known global function that is | 5222 // If the target is not null we have found a known global function that is |
| 5122 // assumed to stay the same for this instanceof. | 5223 // assumed to stay the same for this instanceof. |
| 5123 if (target.is_null()) { | 5224 if (target.is_null()) { |
| 5124 HContext* context = new(zone()) HContext; | 5225 HValue* context = environment()->LookupContext(); |
| 5125 AddInstruction(context); | |
| 5126 instr = new(zone()) HInstanceOf(context, left, right); | 5226 instr = new(zone()) HInstanceOf(context, left, right); |
| 5127 } else { | 5227 } else { |
| 5128 AddInstruction(new(zone()) HCheckFunction(right, target)); | 5228 AddInstruction(new(zone()) HCheckFunction(right, target)); |
| 5129 instr = new(zone()) HInstanceOfKnownGlobal(left, target); | 5229 instr = new(zone()) HInstanceOfKnownGlobal(left, target); |
| 5130 } | 5230 } |
| 5131 } else if (op == Token::IN) { | 5231 } else if (op == Token::IN) { |
| 5132 instr = new(zone()) HIn(left, right); | 5232 instr = new(zone()) HIn(left, right); |
| 5133 } else if (type_info.IsNonPrimitive()) { | 5233 } else if (type_info.IsNonPrimitive()) { |
| 5134 switch (op) { | 5234 switch (op) { |
| 5135 case Token::EQ: | 5235 case Token::EQ: |
| 5136 case Token::EQ_STRICT: { | 5236 case Token::EQ_STRICT: { |
| 5137 AddInstruction(new(zone()) HCheckNonSmi(left)); | 5237 AddInstruction(new(zone()) HCheckNonSmi(left)); |
| 5138 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 5238 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); |
| 5139 AddInstruction(new(zone()) HCheckNonSmi(right)); | 5239 AddInstruction(new(zone()) HCheckNonSmi(right)); |
| 5140 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 5240 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); |
| 5141 instr = new(zone()) HCompareJSObjectEq(left, right); | 5241 instr = new(zone()) HCompareJSObjectEq(left, right); |
| 5142 break; | 5242 break; |
| 5143 } | 5243 } |
| 5144 default: | 5244 default: |
| 5145 return Bailout("Unsupported non-primitive compare"); | 5245 return Bailout("Unsupported non-primitive compare"); |
| 5146 break; | 5246 break; |
| 5147 } | 5247 } |
| 5248 } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) && |
| 5249 (op == Token::EQ || op == Token::EQ_STRICT)) { |
| 5250 instr = BuildSymbolCompare(left, right, op); |
| 5148 } else { | 5251 } else { |
| 5149 HCompare* compare = new(zone()) HCompare(left, right, op); | 5252 HCompare* compare = new(zone()) HCompare(left, right, op); |
| 5150 Representation r = ToRepresentation(type_info); | 5253 Representation r = ToRepresentation(type_info); |
| 5151 compare->SetInputRepresentation(r); | 5254 compare->SetInputRepresentation(r); |
| 5152 instr = compare; | 5255 instr = compare; |
| 5153 } | 5256 } |
| 5154 instr->set_position(expr->position()); | 5257 instr->set_position(expr->position()); |
| 5155 ast_context()->ReturnInstruction(instr, expr->id()); | 5258 ast_context()->ReturnInstruction(instr, expr->id()); |
| 5156 } | 5259 } |
| 5157 | 5260 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5259 ast_context()->ReturnInstruction(test, call->id()); | 5362 ast_context()->ReturnInstruction(test, call->id()); |
| 5260 } | 5363 } |
| 5261 | 5364 |
| 5262 | 5365 |
| 5263 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { | 5366 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { |
| 5264 return Bailout("inlined runtime function: IsNonNegativeSmi"); | 5367 return Bailout("inlined runtime function: IsNonNegativeSmi"); |
| 5265 } | 5368 } |
| 5266 | 5369 |
| 5267 | 5370 |
| 5268 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { | 5371 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { |
| 5269 return Bailout("inlined runtime function: IsUndetectableObject"); | 5372 ASSERT(call->arguments()->length() == 1); |
| 5373 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5374 HValue* value = Pop(); |
| 5375 ast_context()->ReturnInstruction(new(zone()) HIsUndetectable(value), |
| 5376 call->id()); |
| 5270 } | 5377 } |
| 5271 | 5378 |
| 5272 | 5379 |
| 5273 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 5380 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 5274 CallRuntime* call) { | 5381 CallRuntime* call) { |
| 5275 return Bailout( | 5382 return Bailout( |
| 5276 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 5383 "inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 5277 } | 5384 } |
| 5278 | 5385 |
| 5279 | 5386 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5391 // Fast support for Math.random(). | 5498 // Fast support for Math.random(). |
| 5392 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { | 5499 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { |
| 5393 return Bailout("inlined runtime function: RandomHeapNumber"); | 5500 return Bailout("inlined runtime function: RandomHeapNumber"); |
| 5394 } | 5501 } |
| 5395 | 5502 |
| 5396 | 5503 |
| 5397 // Fast support for StringAdd. | 5504 // Fast support for StringAdd. |
| 5398 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { | 5505 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 5399 ASSERT_EQ(2, call->arguments()->length()); | 5506 ASSERT_EQ(2, call->arguments()->length()); |
| 5400 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5507 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5401 HContext* context = new(zone()) HContext; | 5508 HValue* context = environment()->LookupContext(); |
| 5402 AddInstruction(context); | |
| 5403 HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2); | 5509 HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2); |
| 5404 Drop(2); | 5510 Drop(2); |
| 5405 ast_context()->ReturnInstruction(result, call->id()); | 5511 ast_context()->ReturnInstruction(result, call->id()); |
| 5406 } | 5512 } |
| 5407 | 5513 |
| 5408 | 5514 |
| 5409 // Fast support for SubString. | 5515 // Fast support for SubString. |
| 5410 void HGraphBuilder::GenerateSubString(CallRuntime* call) { | 5516 void HGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 5411 ASSERT_EQ(3, call->arguments()->length()); | 5517 ASSERT_EQ(3, call->arguments()->length()); |
| 5412 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5518 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5413 HContext* context = new(zone()) HContext; | 5519 HValue* context = environment()->LookupContext(); |
| 5414 AddInstruction(context); | |
| 5415 HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3); | 5520 HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3); |
| 5416 Drop(3); | 5521 Drop(3); |
| 5417 ast_context()->ReturnInstruction(result, call->id()); | 5522 ast_context()->ReturnInstruction(result, call->id()); |
| 5418 } | 5523 } |
| 5419 | 5524 |
| 5420 | 5525 |
| 5421 // Fast support for StringCompare. | 5526 // Fast support for StringCompare. |
| 5422 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { | 5527 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { |
| 5423 ASSERT_EQ(2, call->arguments()->length()); | 5528 ASSERT_EQ(2, call->arguments()->length()); |
| 5424 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5529 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5425 HContext* context = new(zone()) HContext; | 5530 HValue* context = environment()->LookupContext(); |
| 5426 AddInstruction(context); | |
| 5427 HCallStub* result = | 5531 HCallStub* result = |
| 5428 new(zone()) HCallStub(context, CodeStub::StringCompare, 2); | 5532 new(zone()) HCallStub(context, CodeStub::StringCompare, 2); |
| 5429 Drop(2); | 5533 Drop(2); |
| 5430 ast_context()->ReturnInstruction(result, call->id()); | 5534 ast_context()->ReturnInstruction(result, call->id()); |
| 5431 } | 5535 } |
| 5432 | 5536 |
| 5433 | 5537 |
| 5434 // Support for direct calls from JavaScript to native RegExp code. | 5538 // Support for direct calls from JavaScript to native RegExp code. |
| 5435 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { | 5539 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { |
| 5436 ASSERT_EQ(4, call->arguments()->length()); | 5540 ASSERT_EQ(4, call->arguments()->length()); |
| 5437 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5541 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5438 HContext* context = new(zone()) HContext; | 5542 HValue* context = environment()->LookupContext(); |
| 5439 AddInstruction(context); | |
| 5440 HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4); | 5543 HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4); |
| 5441 Drop(4); | 5544 Drop(4); |
| 5442 ast_context()->ReturnInstruction(result, call->id()); | 5545 ast_context()->ReturnInstruction(result, call->id()); |
| 5443 } | 5546 } |
| 5444 | 5547 |
| 5445 | 5548 |
| 5446 // Construct a RegExp exec result with two in-object properties. | 5549 // Construct a RegExp exec result with two in-object properties. |
| 5447 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { | 5550 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { |
| 5448 ASSERT_EQ(3, call->arguments()->length()); | 5551 ASSERT_EQ(3, call->arguments()->length()); |
| 5449 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5552 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5450 HContext* context = new(zone()) HContext; | 5553 HValue* context = environment()->LookupContext(); |
| 5451 AddInstruction(context); | |
| 5452 HCallStub* result = | 5554 HCallStub* result = |
| 5453 new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3); | 5555 new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3); |
| 5454 Drop(3); | 5556 Drop(3); |
| 5455 ast_context()->ReturnInstruction(result, call->id()); | 5557 ast_context()->ReturnInstruction(result, call->id()); |
| 5456 } | 5558 } |
| 5457 | 5559 |
| 5458 | 5560 |
| 5459 // Support for fast native caches. | 5561 // Support for fast native caches. |
| 5460 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { | 5562 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 5461 return Bailout("inlined runtime function: GetFromCache"); | 5563 return Bailout("inlined runtime function: GetFromCache"); |
| 5462 } | 5564 } |
| 5463 | 5565 |
| 5464 | 5566 |
| 5465 // Fast support for number to string. | 5567 // Fast support for number to string. |
| 5466 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { | 5568 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 5467 ASSERT_EQ(1, call->arguments()->length()); | 5569 ASSERT_EQ(1, call->arguments()->length()); |
| 5468 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5570 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5469 HContext* context = new(zone()) HContext; | 5571 HValue* context = environment()->LookupContext(); |
| 5470 AddInstruction(context); | |
| 5471 HCallStub* result = | 5572 HCallStub* result = |
| 5472 new(zone()) HCallStub(context, CodeStub::NumberToString, 1); | 5573 new(zone()) HCallStub(context, CodeStub::NumberToString, 1); |
| 5473 Drop(1); | 5574 Drop(1); |
| 5474 ast_context()->ReturnInstruction(result, call->id()); | 5575 ast_context()->ReturnInstruction(result, call->id()); |
| 5475 } | 5576 } |
| 5476 | 5577 |
| 5477 | 5578 |
| 5478 // Fast swapping of elements. Takes three expressions, the object and two | 5579 // Fast swapping of elements. Takes three expressions, the object and two |
| 5479 // indices. This should only be used if the indices are known to be | 5580 // indices. This should only be used if the indices are known to be |
| 5480 // non-negative and within bounds of the elements array at the call site. | 5581 // non-negative and within bounds of the elements array at the call site. |
| 5481 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { | 5582 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { |
| 5482 return Bailout("inlined runtime function: SwapElements"); | 5583 return Bailout("inlined runtime function: SwapElements"); |
| 5483 } | 5584 } |
| 5484 | 5585 |
| 5485 | 5586 |
| 5486 // Fast call for custom callbacks. | 5587 // Fast call for custom callbacks. |
| 5487 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { | 5588 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 5488 // 1 ~ The function to call is not itself an argument to the call. | 5589 // 1 ~ The function to call is not itself an argument to the call. |
| 5489 int arg_count = call->arguments()->length() - 1; | 5590 int arg_count = call->arguments()->length() - 1; |
| 5490 ASSERT(arg_count >= 1); // There's always at least a receiver. | 5591 ASSERT(arg_count >= 1); // There's always at least a receiver. |
| 5491 | 5592 |
| 5492 for (int i = 0; i < arg_count; ++i) { | 5593 for (int i = 0; i < arg_count; ++i) { |
| 5493 CHECK_ALIVE(VisitArgument(call->arguments()->at(i))); | 5594 CHECK_ALIVE(VisitArgument(call->arguments()->at(i))); |
| 5494 } | 5595 } |
| 5495 CHECK_ALIVE(VisitForValue(call->arguments()->last())); | 5596 CHECK_ALIVE(VisitForValue(call->arguments()->last())); |
| 5496 HValue* function = Pop(); | 5597 HValue* function = Pop(); |
| 5497 HContext* context = new HContext; | 5598 HValue* context = environment()->LookupContext(); |
| 5498 AddInstruction(context); | |
| 5499 HInvokeFunction* result = | 5599 HInvokeFunction* result = |
| 5500 new(zone()) HInvokeFunction(context, function, arg_count); | 5600 new(zone()) HInvokeFunction(context, function, arg_count); |
| 5501 Drop(arg_count); | 5601 Drop(arg_count); |
| 5502 ast_context()->ReturnInstruction(result, call->id()); | 5602 ast_context()->ReturnInstruction(result, call->id()); |
| 5503 } | 5603 } |
| 5504 | 5604 |
| 5505 | 5605 |
| 5506 // Fast call to math functions. | 5606 // Fast call to math functions. |
| 5507 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { | 5607 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { |
| 5508 ASSERT_EQ(2, call->arguments()->length()); | 5608 ASSERT_EQ(2, call->arguments()->length()); |
| 5509 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5609 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 5510 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 5610 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 5511 HValue* right = Pop(); | 5611 HValue* right = Pop(); |
| 5512 HValue* left = Pop(); | 5612 HValue* left = Pop(); |
| 5513 HPower* result = new(zone()) HPower(left, right); | 5613 HPower* result = new(zone()) HPower(left, right); |
| 5514 ast_context()->ReturnInstruction(result, call->id()); | 5614 ast_context()->ReturnInstruction(result, call->id()); |
| 5515 } | 5615 } |
| 5516 | 5616 |
| 5517 | 5617 |
| 5518 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { | 5618 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { |
| 5519 ASSERT_EQ(1, call->arguments()->length()); | 5619 ASSERT_EQ(1, call->arguments()->length()); |
| 5520 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5620 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5521 HContext* context = new(zone()) HContext; | 5621 HValue* context = environment()->LookupContext(); |
| 5522 AddInstruction(context); | |
| 5523 HCallStub* result = | 5622 HCallStub* result = |
| 5524 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); | 5623 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5525 result->set_transcendental_type(TranscendentalCache::SIN); | 5624 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5526 Drop(1); | 5625 Drop(1); |
| 5527 ast_context()->ReturnInstruction(result, call->id()); | 5626 ast_context()->ReturnInstruction(result, call->id()); |
| 5528 } | 5627 } |
| 5529 | 5628 |
| 5530 | 5629 |
| 5531 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { | 5630 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { |
| 5532 ASSERT_EQ(1, call->arguments()->length()); | 5631 ASSERT_EQ(1, call->arguments()->length()); |
| 5533 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5632 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5534 HContext* context = new(zone()) HContext; | 5633 HValue* context = environment()->LookupContext(); |
| 5535 AddInstruction(context); | |
| 5536 HCallStub* result = | 5634 HCallStub* result = |
| 5537 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); | 5635 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5538 result->set_transcendental_type(TranscendentalCache::COS); | 5636 result->set_transcendental_type(TranscendentalCache::COS); |
| 5539 Drop(1); | 5637 Drop(1); |
| 5540 ast_context()->ReturnInstruction(result, call->id()); | 5638 ast_context()->ReturnInstruction(result, call->id()); |
| 5541 } | 5639 } |
| 5542 | 5640 |
| 5543 | 5641 |
| 5544 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { | 5642 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 5545 ASSERT_EQ(1, call->arguments()->length()); | 5643 ASSERT_EQ(1, call->arguments()->length()); |
| 5546 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 5644 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 5547 HContext* context = new(zone()) HContext; | 5645 HValue* context = environment()->LookupContext(); |
| 5548 AddInstruction(context); | |
| 5549 HCallStub* result = | 5646 HCallStub* result = |
| 5550 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); | 5647 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); |
| 5551 result->set_transcendental_type(TranscendentalCache::LOG); | 5648 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5552 Drop(1); | 5649 Drop(1); |
| 5553 ast_context()->ReturnInstruction(result, call->id()); | 5650 ast_context()->ReturnInstruction(result, call->id()); |
| 5554 } | 5651 } |
| 5555 | 5652 |
| 5556 | 5653 |
| 5557 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | 5654 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 5558 return Bailout("inlined runtime function: MathSqrt"); | 5655 return Bailout("inlined runtime function: MathSqrt"); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 5583 #undef CHECK_ALIVE | 5680 #undef CHECK_ALIVE |
| 5584 | 5681 |
| 5585 | 5682 |
| 5586 HEnvironment::HEnvironment(HEnvironment* outer, | 5683 HEnvironment::HEnvironment(HEnvironment* outer, |
| 5587 Scope* scope, | 5684 Scope* scope, |
| 5588 Handle<JSFunction> closure) | 5685 Handle<JSFunction> closure) |
| 5589 : closure_(closure), | 5686 : closure_(closure), |
| 5590 values_(0), | 5687 values_(0), |
| 5591 assigned_variables_(4), | 5688 assigned_variables_(4), |
| 5592 parameter_count_(0), | 5689 parameter_count_(0), |
| 5690 specials_count_(1), |
| 5593 local_count_(0), | 5691 local_count_(0), |
| 5594 outer_(outer), | 5692 outer_(outer), |
| 5595 pop_count_(0), | 5693 pop_count_(0), |
| 5596 push_count_(0), | 5694 push_count_(0), |
| 5597 ast_id_(AstNode::kNoNumber) { | 5695 ast_id_(AstNode::kNoNumber) { |
| 5598 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); | 5696 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); |
| 5599 } | 5697 } |
| 5600 | 5698 |
| 5601 | 5699 |
| 5602 HEnvironment::HEnvironment(const HEnvironment* other) | 5700 HEnvironment::HEnvironment(const HEnvironment* other) |
| 5603 : values_(0), | 5701 : values_(0), |
| 5604 assigned_variables_(0), | 5702 assigned_variables_(0), |
| 5605 parameter_count_(0), | 5703 parameter_count_(0), |
| 5704 specials_count_(1), |
| 5606 local_count_(0), | 5705 local_count_(0), |
| 5607 outer_(NULL), | 5706 outer_(NULL), |
| 5608 pop_count_(0), | 5707 pop_count_(0), |
| 5609 push_count_(0), | 5708 push_count_(0), |
| 5610 ast_id_(other->ast_id()) { | 5709 ast_id_(other->ast_id()) { |
| 5611 Initialize(other); | 5710 Initialize(other); |
| 5612 } | 5711 } |
| 5613 | 5712 |
| 5614 | 5713 |
| 5615 void HEnvironment::Initialize(int parameter_count, | 5714 void HEnvironment::Initialize(int parameter_count, |
| 5616 int local_count, | 5715 int local_count, |
| 5617 int stack_height) { | 5716 int stack_height) { |
| 5618 parameter_count_ = parameter_count; | 5717 parameter_count_ = parameter_count; |
| 5619 local_count_ = local_count; | 5718 local_count_ = local_count; |
| 5620 | 5719 |
| 5621 // Avoid reallocating the temporaries' backing store on the first Push. | 5720 // Avoid reallocating the temporaries' backing store on the first Push. |
| 5622 int total = parameter_count + local_count + stack_height; | 5721 int total = parameter_count + specials_count_ + local_count + stack_height; |
| 5623 values_.Initialize(total + 4); | 5722 values_.Initialize(total + 4); |
| 5624 for (int i = 0; i < total; ++i) values_.Add(NULL); | 5723 for (int i = 0; i < total; ++i) values_.Add(NULL); |
| 5625 } | 5724 } |
| 5626 | 5725 |
| 5627 | 5726 |
| 5628 void HEnvironment::Initialize(const HEnvironment* other) { | 5727 void HEnvironment::Initialize(const HEnvironment* other) { |
| 5629 closure_ = other->closure(); | 5728 closure_ = other->closure(); |
| 5630 values_.AddAll(other->values_); | 5729 values_.AddAll(other->values_); |
| 5631 assigned_variables_.AddAll(other->assigned_variables_); | 5730 assigned_variables_.AddAll(other->assigned_variables_); |
| 5632 parameter_count_ = other->parameter_count_; | 5731 parameter_count_ = other->parameter_count_; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5671 void HEnvironment::Bind(int index, HValue* value) { | 5770 void HEnvironment::Bind(int index, HValue* value) { |
| 5672 ASSERT(value != NULL); | 5771 ASSERT(value != NULL); |
| 5673 if (!assigned_variables_.Contains(index)) { | 5772 if (!assigned_variables_.Contains(index)) { |
| 5674 assigned_variables_.Add(index); | 5773 assigned_variables_.Add(index); |
| 5675 } | 5774 } |
| 5676 values_[index] = value; | 5775 values_[index] = value; |
| 5677 } | 5776 } |
| 5678 | 5777 |
| 5679 | 5778 |
| 5680 bool HEnvironment::HasExpressionAt(int index) const { | 5779 bool HEnvironment::HasExpressionAt(int index) const { |
| 5681 return index >= parameter_count_ + local_count_; | 5780 return index >= parameter_count_ + specials_count_ + local_count_; |
| 5682 } | 5781 } |
| 5683 | 5782 |
| 5684 | 5783 |
| 5685 bool HEnvironment::ExpressionStackIsEmpty() const { | 5784 bool HEnvironment::ExpressionStackIsEmpty() const { |
| 5686 int first_expression = parameter_count() + local_count(); | 5785 int first_expression = parameter_count() + specials_count() + local_count(); |
| 5687 ASSERT(length() >= first_expression); | 5786 ASSERT(length() >= first_expression); |
| 5688 return length() == first_expression; | 5787 return length() == first_expression; |
| 5689 } | 5788 } |
| 5690 | 5789 |
| 5691 | 5790 |
| 5692 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { | 5791 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { |
| 5693 int count = index_from_top + 1; | 5792 int count = index_from_top + 1; |
| 5694 int index = values_.length() - count; | 5793 int index = values_.length() - count; |
| 5695 ASSERT(HasExpressionAt(index)); | 5794 ASSERT(HasExpressionAt(index)); |
| 5696 // The push count must include at least the element in question or else | 5795 // The push count must include at least the element in question or else |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5754 HValue* push = ExpressionStackAt(arity - i); | 5853 HValue* push = ExpressionStackAt(arity - i); |
| 5755 inner->SetValueAt(i, push); | 5854 inner->SetValueAt(i, push); |
| 5756 } | 5855 } |
| 5757 } else { | 5856 } else { |
| 5758 ASSERT(compilation_phase == LITHIUM); | 5857 ASSERT(compilation_phase == LITHIUM); |
| 5759 for (int i = 0; i <= arity; ++i) { // Include receiver. | 5858 for (int i = 0; i <= arity; ++i) { // Include receiver. |
| 5760 HValue* push = ExpressionStackAt(arity - i); | 5859 HValue* push = ExpressionStackAt(arity - i); |
| 5761 inner->SetValueAt(i, push); | 5860 inner->SetValueAt(i, push); |
| 5762 } | 5861 } |
| 5763 } | 5862 } |
| 5764 | 5863 inner->SetValueAt(arity + 1, outer->LookupContext()); |
| 5765 // Initialize the stack-allocated locals to undefined. | 5864 for (int i = arity + 2; i < inner->length(); ++i) { |
| 5766 int local_base = arity + 1; | 5865 inner->SetValueAt(i, undefined); |
| 5767 int local_count = function->scope()->num_stack_slots(); | |
| 5768 for (int i = 0; i < local_count; ++i) { | |
| 5769 inner->SetValueAt(local_base + i, undefined); | |
| 5770 } | 5866 } |
| 5771 | 5867 |
| 5772 inner->set_ast_id(AstNode::kFunctionEntryId); | 5868 inner->set_ast_id(AstNode::kFunctionEntryId); |
| 5773 return inner; | 5869 return inner; |
| 5774 } | 5870 } |
| 5775 | 5871 |
| 5776 | 5872 |
| 5777 void HEnvironment::PrintTo(StringStream* stream) { | 5873 void HEnvironment::PrintTo(StringStream* stream) { |
| 5778 for (int i = 0; i < length(); i++) { | 5874 for (int i = 0; i < length(); i++) { |
| 5779 if (i == 0) stream->Add("parameters\n"); | 5875 if (i == 0) stream->Add("parameters\n"); |
| 5780 if (i == parameter_count()) stream->Add("locals\n"); | 5876 if (i == parameter_count()) stream->Add("specials\n"); |
| 5781 if (i == parameter_count() + local_count()) stream->Add("expressions"); | 5877 if (i == parameter_count() + specials_count()) stream->Add("locals\n"); |
| 5878 if (i == parameter_count() + specials_count() + local_count()) { |
| 5879 stream->Add("expressions"); |
| 5880 } |
| 5782 HValue* val = values_.at(i); | 5881 HValue* val = values_.at(i); |
| 5783 stream->Add("%d: ", i); | 5882 stream->Add("%d: ", i); |
| 5784 if (val != NULL) { | 5883 if (val != NULL) { |
| 5785 val->PrintNameTo(stream); | 5884 val->PrintNameTo(stream); |
| 5786 } else { | 5885 } else { |
| 5787 stream->Add("NULL"); | 5886 stream->Add("NULL"); |
| 5788 } | 5887 } |
| 5789 stream->Add("\n"); | 5888 stream->Add("\n"); |
| 5790 } | 5889 } |
| 5791 } | 5890 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5866 LifetimePosition::FromInstructionIndex(first_index).Value()); | 5965 LifetimePosition::FromInstructionIndex(first_index).Value()); |
| 5867 PrintIntProperty( | 5966 PrintIntProperty( |
| 5868 "last_lir_id", | 5967 "last_lir_id", |
| 5869 LifetimePosition::FromInstructionIndex(last_index).Value()); | 5968 LifetimePosition::FromInstructionIndex(last_index).Value()); |
| 5870 } | 5969 } |
| 5871 | 5970 |
| 5872 { | 5971 { |
| 5873 Tag states_tag(this, "states"); | 5972 Tag states_tag(this, "states"); |
| 5874 Tag locals_tag(this, "locals"); | 5973 Tag locals_tag(this, "locals"); |
| 5875 int total = current->phis()->length(); | 5974 int total = current->phis()->length(); |
| 5876 trace_.Add("size %d\n", total); | 5975 PrintIntProperty("size", current->phis()->length()); |
| 5877 trace_.Add("method \"None\""); | 5976 PrintStringProperty("method", "None"); |
| 5878 for (int j = 0; j < total; ++j) { | 5977 for (int j = 0; j < total; ++j) { |
| 5879 HPhi* phi = current->phis()->at(j); | 5978 HPhi* phi = current->phis()->at(j); |
| 5979 PrintIndent(); |
| 5880 trace_.Add("%d ", phi->merged_index()); | 5980 trace_.Add("%d ", phi->merged_index()); |
| 5881 phi->PrintNameTo(&trace_); | 5981 phi->PrintNameTo(&trace_); |
| 5882 trace_.Add(" "); | 5982 trace_.Add(" "); |
| 5883 phi->PrintTo(&trace_); | 5983 phi->PrintTo(&trace_); |
| 5884 trace_.Add("\n"); | 5984 trace_.Add("\n"); |
| 5885 } | 5985 } |
| 5886 } | 5986 } |
| 5887 | 5987 |
| 5888 { | 5988 { |
| 5889 Tag HIR_tag(this, "HIR"); | 5989 Tag HIR_tag(this, "HIR"); |
| 5890 HInstruction* instruction = current->first(); | 5990 HInstruction* instruction = current->first(); |
| 5891 while (instruction != NULL) { | 5991 while (instruction != NULL) { |
| 5892 int bci = 0; | 5992 int bci = 0; |
| 5893 int uses = instruction->UseCount(); | 5993 int uses = instruction->UseCount(); |
| 5994 PrintIndent(); |
| 5894 trace_.Add("%d %d ", bci, uses); | 5995 trace_.Add("%d %d ", bci, uses); |
| 5895 instruction->PrintNameTo(&trace_); | 5996 instruction->PrintNameTo(&trace_); |
| 5896 trace_.Add(" "); | 5997 trace_.Add(" "); |
| 5897 instruction->PrintTo(&trace_); | 5998 instruction->PrintTo(&trace_); |
| 5898 trace_.Add(" <|@\n"); | 5999 trace_.Add(" <|@\n"); |
| 5899 instruction = instruction->next(); | 6000 instruction = instruction->next(); |
| 5900 } | 6001 } |
| 5901 } | 6002 } |
| 5902 | 6003 |
| 5903 | 6004 |
| 5904 if (chunk != NULL) { | 6005 if (chunk != NULL) { |
| 5905 Tag LIR_tag(this, "LIR"); | 6006 Tag LIR_tag(this, "LIR"); |
| 5906 int first_index = current->first_instruction_index(); | 6007 int first_index = current->first_instruction_index(); |
| 5907 int last_index = current->last_instruction_index(); | 6008 int last_index = current->last_instruction_index(); |
| 5908 if (first_index != -1 && last_index != -1) { | 6009 if (first_index != -1 && last_index != -1) { |
| 5909 const ZoneList<LInstruction*>* instructions = chunk->instructions(); | 6010 const ZoneList<LInstruction*>* instructions = chunk->instructions(); |
| 5910 for (int i = first_index; i <= last_index; ++i) { | 6011 for (int i = first_index; i <= last_index; ++i) { |
| 5911 LInstruction* linstr = instructions->at(i); | 6012 LInstruction* linstr = instructions->at(i); |
| 5912 if (linstr != NULL) { | 6013 if (linstr != NULL) { |
| 6014 PrintIndent(); |
| 5913 trace_.Add("%d ", | 6015 trace_.Add("%d ", |
| 5914 LifetimePosition::FromInstructionIndex(i).Value()); | 6016 LifetimePosition::FromInstructionIndex(i).Value()); |
| 5915 linstr->PrintTo(&trace_); | 6017 linstr->PrintTo(&trace_); |
| 5916 trace_.Add(" <|@\n"); | 6018 trace_.Add(" <|@\n"); |
| 5917 } | 6019 } |
| 5918 } | 6020 } |
| 5919 } | 6021 } |
| 5920 } | 6022 } |
| 5921 } | 6023 } |
| 5922 } | 6024 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 5938 | 6040 |
| 5939 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); | 6041 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); |
| 5940 for (int i = 0; i < live_ranges->length(); ++i) { | 6042 for (int i = 0; i < live_ranges->length(); ++i) { |
| 5941 TraceLiveRange(live_ranges->at(i), "object"); | 6043 TraceLiveRange(live_ranges->at(i), "object"); |
| 5942 } | 6044 } |
| 5943 } | 6045 } |
| 5944 | 6046 |
| 5945 | 6047 |
| 5946 void HTracer::TraceLiveRange(LiveRange* range, const char* type) { | 6048 void HTracer::TraceLiveRange(LiveRange* range, const char* type) { |
| 5947 if (range != NULL && !range->IsEmpty()) { | 6049 if (range != NULL && !range->IsEmpty()) { |
| 6050 PrintIndent(); |
| 5948 trace_.Add("%d %s", range->id(), type); | 6051 trace_.Add("%d %s", range->id(), type); |
| 5949 if (range->HasRegisterAssigned()) { | 6052 if (range->HasRegisterAssigned()) { |
| 5950 LOperand* op = range->CreateAssignedOperand(); | 6053 LOperand* op = range->CreateAssignedOperand(); |
| 5951 int assigned_reg = op->index(); | 6054 int assigned_reg = op->index(); |
| 5952 if (op->IsDoubleRegister()) { | 6055 if (op->IsDoubleRegister()) { |
| 5953 trace_.Add(" \"%s\"", | 6056 trace_.Add(" \"%s\"", |
| 5954 DoubleRegister::AllocationIndexToString(assigned_reg)); | 6057 DoubleRegister::AllocationIndexToString(assigned_reg)); |
| 5955 } else { | 6058 } else { |
| 5956 ASSERT(op->IsRegister()); | 6059 ASSERT(op->IsRegister()); |
| 5957 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg)); | 6060 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg)); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6097 } | 6200 } |
| 6098 } | 6201 } |
| 6099 | 6202 |
| 6100 #ifdef DEBUG | 6203 #ifdef DEBUG |
| 6101 if (graph_ != NULL) graph_->Verify(); | 6204 if (graph_ != NULL) graph_->Verify(); |
| 6102 if (allocator_ != NULL) allocator_->Verify(); | 6205 if (allocator_ != NULL) allocator_->Verify(); |
| 6103 #endif | 6206 #endif |
| 6104 } | 6207 } |
| 6105 | 6208 |
| 6106 } } // namespace v8::internal | 6209 } } // namespace v8::internal |
| OLD | NEW |