Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ | 5 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ |
| 6 #define VM_INTERMEDIATE_LANGUAGE_H_ | 6 #define VM_INTERMEDIATE_LANGUAGE_H_ |
| 7 | 7 |
| 8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
| 9 #include "vm/ast.h" | 9 #include "vm/ast.h" |
| 10 #include "vm/growable_array.h" | 10 #include "vm/growable_array.h" |
| 11 #include "vm/handles_impl.h" | 11 #include "vm/handles_impl.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 class FlowGraphVisitor; | 16 class FlowGraphVisitor; |
| 17 class LocalVariable; | 17 class LocalVariable; |
| 18 | 18 |
| 19 // M is a two argument macro. It is applied to each concrete value's | 19 // M is a two argument macro. It is applied to each concrete value's |
| 20 // typename and classname. | 20 // typename and classname. |
| 21 #define FOR_EACH_VALUE(M) \ | 21 #define FOR_EACH_VALUE(M) \ |
| 22 M(Temp, TempVal) \ | 22 M(Temp, TempVal) \ |
| 23 M(Use, UseVal) \ | |
| 23 M(Constant, ConstantVal) \ | 24 M(Constant, ConstantVal) \ |
| 24 | 25 |
| 25 | 26 |
| 26 // M is a two argument macro. It is applied to each concrete instruction's | 27 // M is a two argument macro. It is applied to each concrete instruction's |
| 27 // (including the values) typename and classname. | 28 // (including the values) typename and classname. |
| 28 #define FOR_EACH_COMPUTATION(M) \ | 29 #define FOR_EACH_COMPUTATION(M) \ |
| 29 FOR_EACH_VALUE(M) \ | 30 FOR_EACH_VALUE(M) \ |
| 30 M(AssertAssignable, AssertAssignableComp) \ | 31 M(AssertAssignable, AssertAssignableComp) \ |
| 31 M(AssertBoolean, AssertBooleanComp) \ | 32 M(AssertBoolean, AssertBooleanComp) \ |
| 32 M(CurrentContext, CurrentContextComp) \ | 33 M(CurrentContext, CurrentContextComp) \ |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 | 112 |
| 112 intptr_t index() const { return index_; } | 113 intptr_t index() const { return index_; } |
| 113 | 114 |
| 114 private: | 115 private: |
| 115 const intptr_t index_; | 116 const intptr_t index_; |
| 116 | 117 |
| 117 DISALLOW_COPY_AND_ASSIGN(TempVal); | 118 DISALLOW_COPY_AND_ASSIGN(TempVal); |
| 118 }; | 119 }; |
| 119 | 120 |
| 120 | 121 |
| 122 // Definitions and uses are mutually recursive. | |
| 123 class Definition; | |
| 124 | |
| 125 class UseVal : public Value { | |
| 126 public: | |
| 127 explicit UseVal(Definition* definition) : definition_(definition) { } | |
| 128 | |
| 129 DECLARE_VALUE(Use) | |
| 130 | |
| 131 Definition* definition() const { return definition_; } | |
| 132 | |
| 133 private: | |
| 134 Definition* const definition_; | |
| 135 | |
| 136 DISALLOW_COPY_AND_ASSIGN(UseVal); | |
| 137 }; | |
| 138 | |
| 139 | |
| 121 class ConstantVal: public Value { | 140 class ConstantVal: public Value { |
| 122 public: | 141 public: |
| 123 explicit ConstantVal(const Object& value) : value_(value) { | 142 explicit ConstantVal(const Object& value) : value_(value) { |
| 124 ASSERT(value.IsZoneHandle()); | 143 ASSERT(value.IsZoneHandle()); |
| 125 } | 144 } |
| 126 | 145 |
| 127 DECLARE_VALUE(Constant) | 146 DECLARE_VALUE(Constant) |
| 128 | 147 |
| 129 const Object& value() const { return value_; } | 148 const Object& value() const { return value_; } |
| 130 | 149 |
| (...skipping 890 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1021 }; | 1040 }; |
| 1022 | 1041 |
| 1023 | 1042 |
| 1024 #undef DECLARE_COMPUTATION | 1043 #undef DECLARE_COMPUTATION |
| 1025 | 1044 |
| 1026 | 1045 |
| 1027 // Instructions. | 1046 // Instructions. |
| 1028 // | 1047 // |
| 1029 // <Instruction> ::= JoinEntry <Instruction> | 1048 // <Instruction> ::= JoinEntry <Instruction> |
| 1030 // | TargetEntry <Instruction> | 1049 // | TargetEntry <Instruction> |
| 1031 // | PickTemp <int> <int> <Instruction> | |
| 1032 // | TuckTemp <int> <int> <Instruction> | |
| 1033 // | Do <Computation> <Instruction> | 1050 // | Do <Computation> <Instruction> |
| 1034 // | Bind <int> <Computation> <Instruction> | |
| 1035 // | Return <Value> | 1051 // | Return <Value> |
| 1036 // | Branch <Value> <Instruction> <Instruction> | 1052 // | Branch <Value> <Instruction> <Instruction> |
| 1053 // <Definition> ::= PickTemp <int> <int> <Instruction> | |
| 1054 // | TuckTemp <int> <int> <Instruction> | |
| 1055 // | Bind <int> <Computation> <Instruction> | |
| 1037 | 1056 |
| 1038 // M is a single argument macro. It is applied to each concrete instruction | 1057 // M is a single argument macro. It is applied to each concrete instruction |
| 1039 // type name. The concrete instruction classes are the name with Instr | 1058 // type name. The concrete instruction classes are the name with Instr |
| 1040 // concatenated. | 1059 // concatenated. |
| 1041 #define FOR_EACH_INSTRUCTION(M) \ | 1060 #define FOR_EACH_INSTRUCTION(M) \ |
| 1042 M(JoinEntry) \ | 1061 M(JoinEntry) \ |
| 1043 M(TargetEntry) \ | 1062 M(TargetEntry) \ |
| 1063 M(Do) \ | |
| 1064 M(Bind) \ | |
| 1044 M(PickTemp) \ | 1065 M(PickTemp) \ |
| 1045 M(TuckTemp) \ | 1066 M(TuckTemp) \ |
| 1046 M(Do) \ | |
| 1047 M(Bind) \ | |
| 1048 M(Return) \ | 1067 M(Return) \ |
| 1049 M(Throw) \ | 1068 M(Throw) \ |
| 1050 M(ReThrow) \ | 1069 M(ReThrow) \ |
| 1051 M(Branch) \ | 1070 M(Branch) \ |
| 1052 | 1071 |
| 1053 | 1072 |
| 1054 // Forward declarations for Instruction classes. | 1073 // Forward declarations for Instruction classes. |
| 1055 class BlockEntryInstr; | 1074 class BlockEntryInstr; |
| 1056 #define FORWARD_DECLARATION(type) class type##Instr; | 1075 #define FORWARD_DECLARATION(type) class type##Instr; |
| 1057 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) | 1076 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1237 | 1256 |
| 1238 private: | 1257 private: |
| 1239 BlockEntryInstr* predecessor_; | 1258 BlockEntryInstr* predecessor_; |
| 1240 Instruction* successor_; | 1259 Instruction* successor_; |
| 1241 const intptr_t try_index_; | 1260 const intptr_t try_index_; |
| 1242 | 1261 |
| 1243 DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr); | 1262 DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr); |
| 1244 }; | 1263 }; |
| 1245 | 1264 |
| 1246 | 1265 |
| 1247 // The non-optimizing compiler assumes that there is exactly one use of | |
| 1248 // every temporary so they can be deallocated at their use. Some AST nodes, | |
| 1249 // e.g., expr0[expr1]++, violate this assumption (there are two uses of each | |
| 1250 // of the values expr0 and expr1). | |
| 1251 // | |
| 1252 // PickTemp is used to name (with 'destination') a copy of a live temporary | |
| 1253 // (named 'source') without counting as the use of the source. | |
| 1254 class PickTempInstr : public Instruction { | |
| 1255 public: | |
| 1256 PickTempInstr(intptr_t dst, intptr_t src) | |
| 1257 : destination_(dst), source_(src), successor_(NULL) { } | |
| 1258 | |
| 1259 DECLARE_INSTRUCTION(PickTemp) | |
| 1260 | |
| 1261 intptr_t destination() const { return destination_; } | |
| 1262 intptr_t source() const { return source_; } | |
| 1263 | |
| 1264 virtual Instruction* StraightLineSuccessor() const { | |
| 1265 return successor_; | |
| 1266 } | |
| 1267 virtual void SetSuccessor(Instruction* instr) { | |
| 1268 ASSERT(successor_ == NULL && instr != NULL); | |
| 1269 successor_ = instr; | |
| 1270 } | |
| 1271 | |
| 1272 private: | |
| 1273 const intptr_t destination_; | |
| 1274 const intptr_t source_; | |
| 1275 Instruction* successor_; | |
| 1276 | |
| 1277 DISALLOW_COPY_AND_ASSIGN(PickTempInstr); | |
| 1278 }; | |
| 1279 | |
| 1280 | |
| 1281 // The non-optimizing compiler assumes that temporary definitions and uses | |
| 1282 // obey a stack discipline, so they can be allocated and deallocated with | |
| 1283 // push and pop. Some Some AST nodes, e.g., expr++, violate this assumption | |
| 1284 // (the value expr+1 is produced after the value of expr, and also consumed | |
| 1285 // after it). | |
| 1286 // | |
| 1287 // We 'preallocate' temporaries (named with 'destination') such as the one | |
| 1288 // for expr+1 and use TuckTemp to mutate them by overwriting them with a | |
| 1289 // copy of a temporary (named with 'source'). | |
| 1290 class TuckTempInstr : public Instruction { | |
| 1291 public: | |
| 1292 TuckTempInstr(intptr_t dst, intptr_t src) | |
| 1293 : destination_(dst), source_(src), successor_(NULL) { } | |
| 1294 | |
| 1295 DECLARE_INSTRUCTION(TuckTemp) | |
| 1296 | |
| 1297 intptr_t destination() const { return destination_; } | |
| 1298 intptr_t source() const { return source_; } | |
| 1299 | |
| 1300 virtual Instruction* StraightLineSuccessor() const { | |
| 1301 return successor_; | |
| 1302 } | |
| 1303 virtual void SetSuccessor(Instruction* instr) { | |
| 1304 ASSERT(successor_ == NULL && instr != NULL); | |
| 1305 successor_ = instr; | |
| 1306 } | |
| 1307 | |
| 1308 private: | |
| 1309 const intptr_t destination_; | |
| 1310 const intptr_t source_; | |
| 1311 Instruction* successor_; | |
| 1312 | |
| 1313 DISALLOW_COPY_AND_ASSIGN(TuckTempInstr); | |
| 1314 }; | |
| 1315 | |
| 1316 | |
| 1317 class DoInstr : public Instruction { | 1266 class DoInstr : public Instruction { |
| 1318 public: | 1267 public: |
| 1319 explicit DoInstr(Computation* comp) | 1268 explicit DoInstr(Computation* comp) |
| 1320 : computation_(comp), successor_(NULL) { } | 1269 : computation_(comp), successor_(NULL) { } |
| 1321 | 1270 |
| 1322 DECLARE_INSTRUCTION(Do) | 1271 DECLARE_INSTRUCTION(Do) |
| 1323 | 1272 |
| 1324 Computation* computation() const { return computation_; } | 1273 Computation* computation() const { return computation_; } |
| 1325 | 1274 |
| 1326 virtual Instruction* StraightLineSuccessor() const { | 1275 virtual Instruction* StraightLineSuccessor() const { |
| 1327 return successor_; | 1276 return successor_; |
| 1328 } | 1277 } |
| 1329 virtual void SetSuccessor(Instruction* instr) { | 1278 virtual void SetSuccessor(Instruction* instr) { |
| 1330 ASSERT(successor_ == NULL); | 1279 ASSERT(successor_ == NULL); |
| 1331 successor_ = instr; | 1280 successor_ = instr; |
| 1332 } | 1281 } |
| 1333 | 1282 |
| 1334 private: | 1283 private: |
| 1335 Computation* computation_; | 1284 Computation* computation_; |
| 1336 Instruction* successor_; | 1285 Instruction* successor_; |
| 1337 | 1286 |
| 1338 DISALLOW_COPY_AND_ASSIGN(DoInstr); | 1287 DISALLOW_COPY_AND_ASSIGN(DoInstr); |
| 1339 }; | 1288 }; |
| 1340 | 1289 |
| 1341 | 1290 |
| 1342 class BindInstr : public Instruction { | 1291 class Definition : public Instruction { |
| 1292 public: | |
| 1293 explicit Definition(intptr_t temp_index) : temp_index_(temp_index) { } | |
| 1294 | |
| 1295 intptr_t temp_index() const { return temp_index_; } | |
|
srdjan
2012/04/24 22:02:18
Why don't you need DECLARE_INSTRUCTION(Definition)
Kevin Millikin (Google)
2012/04/25 08:50:51
Because it's an abstract, not concrete, instructio
| |
| 1296 | |
| 1297 private: | |
| 1298 const intptr_t temp_index_; | |
| 1299 | |
| 1300 DISALLOW_COPY_AND_ASSIGN(Definition); | |
| 1301 }; | |
| 1302 | |
| 1303 | |
| 1304 class BindInstr : public Definition { | |
| 1343 public: | 1305 public: |
| 1344 BindInstr(intptr_t temp_index, Computation* computation) | 1306 BindInstr(intptr_t temp_index, Computation* computation) |
| 1345 : temp_index_(temp_index), computation_(computation), successor_(NULL) { } | 1307 : Definition(temp_index), computation_(computation), successor_(NULL) { } |
| 1346 | 1308 |
| 1347 DECLARE_INSTRUCTION(Bind) | 1309 DECLARE_INSTRUCTION(Bind) |
| 1348 | 1310 |
| 1349 intptr_t temp_index() const { return temp_index_; } | |
| 1350 Computation* computation() const { return computation_; } | 1311 Computation* computation() const { return computation_; } |
| 1351 | 1312 |
| 1352 virtual Instruction* StraightLineSuccessor() const { | 1313 virtual Instruction* StraightLineSuccessor() const { |
| 1353 return successor_; | 1314 return successor_; |
| 1354 } | 1315 } |
| 1355 virtual void SetSuccessor(Instruction* instr) { | 1316 virtual void SetSuccessor(Instruction* instr) { |
| 1356 ASSERT(successor_ == NULL); | 1317 ASSERT(successor_ == NULL); |
| 1357 successor_ = instr; | 1318 successor_ = instr; |
| 1358 } | 1319 } |
| 1359 | 1320 |
| 1360 private: | 1321 private: |
| 1361 const intptr_t temp_index_; | |
| 1362 Computation* computation_; | 1322 Computation* computation_; |
| 1363 Instruction* successor_; | 1323 Instruction* successor_; |
| 1364 | 1324 |
| 1365 DISALLOW_COPY_AND_ASSIGN(BindInstr); | 1325 DISALLOW_COPY_AND_ASSIGN(BindInstr); |
| 1366 }; | 1326 }; |
| 1367 | 1327 |
| 1368 | 1328 |
| 1329 // The non-optimizing compiler assumes that there is exactly one use of | |
| 1330 // every temporary so they can be deallocated at their use. Some AST nodes, | |
| 1331 // e.g., expr0[expr1]++, violate this assumption (there are two uses of each | |
| 1332 // of the values expr0 and expr1). | |
| 1333 // | |
| 1334 // PickTemp is used to name (with 'destination') a copy of a live temporary | |
| 1335 // (named 'source') without counting as the use of the source. | |
| 1336 class PickTempInstr : public Definition { | |
| 1337 public: | |
| 1338 PickTempInstr(intptr_t temp_index, intptr_t source) | |
| 1339 : Definition(temp_index), source_(source), successor_(NULL) { } | |
| 1340 | |
| 1341 DECLARE_INSTRUCTION(PickTemp) | |
| 1342 | |
| 1343 intptr_t source() const { return source_; } | |
| 1344 | |
| 1345 virtual Instruction* StraightLineSuccessor() const { | |
| 1346 return successor_; | |
| 1347 } | |
| 1348 virtual void SetSuccessor(Instruction* instr) { | |
| 1349 ASSERT(successor_ == NULL && instr != NULL); | |
| 1350 successor_ = instr; | |
| 1351 } | |
| 1352 | |
| 1353 private: | |
| 1354 const intptr_t source_; | |
| 1355 Instruction* successor_; | |
| 1356 | |
| 1357 DISALLOW_COPY_AND_ASSIGN(PickTempInstr); | |
| 1358 }; | |
| 1359 | |
| 1360 | |
| 1361 // The non-optimizing compiler assumes that temporary definitions and uses | |
| 1362 // obey a stack discipline, so they can be allocated and deallocated with | |
| 1363 // push and pop. Some Some AST nodes, e.g., expr++, violate this assumption | |
| 1364 // (the value expr+1 is produced after the value of expr, and also consumed | |
| 1365 // after it). | |
| 1366 // | |
| 1367 // We 'preallocate' temporaries (named with 'destination') such as the one | |
| 1368 // for expr+1 and use TuckTemp to mutate them by overwriting them with a | |
| 1369 // copy of a temporary (named with 'source'). | |
| 1370 class TuckTempInstr : public Instruction { | |
| 1371 public: | |
| 1372 TuckTempInstr(intptr_t destination, intptr_t source) | |
| 1373 : destination_(destination), source_(source), successor_(NULL) { } | |
| 1374 | |
| 1375 DECLARE_INSTRUCTION(TuckTemp) | |
| 1376 | |
| 1377 intptr_t destination() const { return destination_; } | |
| 1378 intptr_t source() const { return source_; } | |
| 1379 | |
| 1380 virtual Instruction* StraightLineSuccessor() const { | |
| 1381 return successor_; | |
| 1382 } | |
| 1383 virtual void SetSuccessor(Instruction* instr) { | |
| 1384 ASSERT(successor_ == NULL && instr != NULL); | |
| 1385 successor_ = instr; | |
| 1386 } | |
| 1387 | |
| 1388 private: | |
| 1389 const intptr_t destination_; | |
| 1390 const intptr_t source_; | |
| 1391 Instruction* successor_; | |
| 1392 | |
| 1393 DISALLOW_COPY_AND_ASSIGN(TuckTempInstr); | |
| 1394 }; | |
| 1395 | |
| 1396 | |
| 1369 class ReturnInstr : public Instruction { | 1397 class ReturnInstr : public Instruction { |
| 1370 public: | 1398 public: |
| 1371 ReturnInstr(intptr_t node_id, intptr_t token_index, Value* value) | 1399 ReturnInstr(intptr_t node_id, intptr_t token_index, Value* value) |
| 1372 : node_id_(node_id), token_index_(token_index), value_(value) { | 1400 : node_id_(node_id), token_index_(token_index), value_(value) { |
| 1373 ASSERT(value_ != NULL); | 1401 ASSERT(value_ != NULL); |
| 1374 } | 1402 } |
| 1375 | 1403 |
| 1376 DECLARE_INSTRUCTION(Return) | 1404 DECLARE_INSTRUCTION(Return) |
| 1377 | 1405 |
| 1378 Value* value() const { return value_; } | 1406 Value* value() const { return value_; } |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1551 const GrowableArray<BlockEntryInstr*>& block_order_; | 1579 const GrowableArray<BlockEntryInstr*>& block_order_; |
| 1552 | 1580 |
| 1553 private: | 1581 private: |
| 1554 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); | 1582 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); |
| 1555 }; | 1583 }; |
| 1556 | 1584 |
| 1557 | 1585 |
| 1558 } // namespace dart | 1586 } // namespace dart |
| 1559 | 1587 |
| 1560 #endif // VM_INTERMEDIATE_LANGUAGE_H_ | 1588 #endif // VM_INTERMEDIATE_LANGUAGE_H_ |
| OLD | NEW |