| 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 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/dart_entry.h" | 8 #include "vm/dart_entry.h" |
| 9 #include "vm/flow_graph_allocator.h" | 9 #include "vm/flow_graph_allocator.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/locations.h" | 12 #include "vm/locations.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/os.h" | 15 #include "vm/os.h" |
| 16 #include "vm/scopes.h" | 16 #include "vm/scopes.h" |
| 17 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 18 #include "vm/symbols.h" | 18 #include "vm/symbols.h" |
| 19 | 19 |
| 20 namespace dart { | 20 namespace dart { |
| 21 | 21 |
| 22 DECLARE_FLAG(bool, enable_type_checks); | 22 DECLARE_FLAG(bool, enable_type_checks); |
| 23 | 23 |
| 24 | 24 |
| 25 intptr_t Definition::Hashcode() const { | 25 intptr_t Instruction::Hashcode() const { |
| 26 intptr_t result = tag(); | 26 intptr_t result = tag(); |
| 27 for (intptr_t i = 0; i < InputCount(); ++i) { | 27 for (intptr_t i = 0; i < InputCount(); ++i) { |
| 28 Value* value = InputAt(i); | 28 Value* value = InputAt(i); |
| 29 intptr_t j = value->definition()->ssa_temp_index(); | 29 intptr_t j = value->definition()->ssa_temp_index(); |
| 30 result = result * 31 + j; | 30 result = result * 31 + j; |
| 31 } | 31 } |
| 32 return result; | 32 return result; |
| 33 } | 33 } |
| 34 | 34 |
| 35 | 35 |
| 36 bool Definition::Equals(Definition* other) const { | 36 bool Instruction::Equals(Instruction* other) const { |
| 37 if (tag() != other->tag()) return false; | 37 if (tag() != other->tag()) return false; |
| 38 for (intptr_t i = 0; i < InputCount(); ++i) { | 38 for (intptr_t i = 0; i < InputCount(); ++i) { |
| 39 if (!InputAt(i)->Equals(other->InputAt(i))) return false; | 39 if (!InputAt(i)->Equals(other->InputAt(i))) return false; |
| 40 } | 40 } |
| 41 return AttributesEqual(other); | 41 return AttributesEqual(other); |
| 42 } | 42 } |
| 43 | 43 |
| 44 | 44 |
| 45 bool Value::Equals(Value* other) const { | 45 bool Value::Equals(Value* other) const { |
| 46 return definition() == other->definition(); | 46 return definition() == other->definition(); |
| 47 } | 47 } |
| 48 | 48 |
| 49 | 49 |
| 50 bool CheckClassInstr::AttributesEqual(Definition* other) const { | 50 bool CheckClassInstr::AttributesEqual(Instruction* other) const { |
| 51 CheckClassInstr* other_check = other->AsCheckClass(); | 51 CheckClassInstr* other_check = other->AsCheckClass(); |
| 52 ASSERT(other_check != NULL); | 52 ASSERT(other_check != NULL); |
| 53 if (unary_checks().NumberOfChecks() != | 53 if (unary_checks().NumberOfChecks() != |
| 54 other_check->unary_checks().NumberOfChecks()) { | 54 other_check->unary_checks().NumberOfChecks()) { |
| 55 return false; | 55 return false; |
| 56 } | 56 } |
| 57 for (intptr_t i = 0; i < unary_checks().NumberOfChecks(); ++i) { | 57 for (intptr_t i = 0; i < unary_checks().NumberOfChecks(); ++i) { |
| 58 // TODO(fschneider): Make sure ic_data are sorted to hit more cases. | 58 // TODO(fschneider): Make sure ic_data are sorted to hit more cases. |
| 59 if (unary_checks().GetReceiverClassIdAt(i) != | 59 if (unary_checks().GetReceiverClassIdAt(i) != |
| 60 other_check->unary_checks().GetReceiverClassIdAt(i)) { | 60 other_check->unary_checks().GetReceiverClassIdAt(i)) { |
| 61 return false; | 61 return false; |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 return true; | 64 return true; |
| 65 } | 65 } |
| 66 | 66 |
| 67 | 67 |
| 68 bool CheckArrayBoundInstr::AttributesEqual(Definition* other) const { | 68 bool CheckArrayBoundInstr::AttributesEqual(Instruction* other) const { |
| 69 CheckArrayBoundInstr* other_check = other->AsCheckArrayBound(); | 69 CheckArrayBoundInstr* other_check = other->AsCheckArrayBound(); |
| 70 ASSERT(other_check != NULL); | 70 ASSERT(other_check != NULL); |
| 71 return array_type() == other_check->array_type(); | 71 return array_type() == other_check->array_type(); |
| 72 } | 72 } |
| 73 | 73 |
| 74 | 74 |
| 75 bool StrictCompareInstr::AttributesEqual(Definition* other) const { | 75 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { |
| 76 StrictCompareInstr* other_op = other->AsStrictCompare(); | 76 StrictCompareInstr* other_op = other->AsStrictCompare(); |
| 77 ASSERT(other_op != NULL); | 77 ASSERT(other_op != NULL); |
| 78 return kind() == other_op->kind(); | 78 return kind() == other_op->kind(); |
| 79 } | 79 } |
| 80 | 80 |
| 81 | 81 |
| 82 bool BinarySmiOpInstr::AttributesEqual(Definition* other) const { | 82 bool BinarySmiOpInstr::AttributesEqual(Instruction* other) const { |
| 83 BinarySmiOpInstr* other_op = other->AsBinarySmiOp(); | 83 BinarySmiOpInstr* other_op = other->AsBinarySmiOp(); |
| 84 ASSERT(other_op != NULL); | 84 ASSERT(other_op != NULL); |
| 85 return op_kind() == other_op->op_kind(); | 85 return op_kind() == other_op->op_kind(); |
| 86 } | 86 } |
| 87 | 87 |
| 88 | 88 |
| 89 bool LoadFieldInstr::AttributesEqual(Definition* other) const { | 89 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
| 90 LoadFieldInstr* other_load = other->AsLoadField(); | 90 LoadFieldInstr* other_load = other->AsLoadField(); |
| 91 ASSERT(other_load != NULL); | 91 ASSERT(other_load != NULL); |
| 92 ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) || | 92 ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) || |
| 93 ((immutable_ == other_load->immutable_) && | 93 ((immutable_ == other_load->immutable_) && |
| 94 (ResultCid() == other_load->ResultCid()))); | 94 (ResultCid() == other_load->ResultCid()))); |
| 95 return offset_in_bytes() == other_load->offset_in_bytes(); | 95 return offset_in_bytes() == other_load->offset_in_bytes(); |
| 96 } | 96 } |
| 97 | 97 |
| 98 | 98 |
| 99 bool LoadStaticFieldInstr::AttributesEqual(Definition* other) const { | 99 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { |
| 100 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); | 100 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); |
| 101 ASSERT(other_load != NULL); | 101 ASSERT(other_load != NULL); |
| 102 // Assert that the field is initialized. | 102 // Assert that the field is initialized. |
| 103 ASSERT(field().value() != Object::sentinel()); | 103 ASSERT(field().value() != Object::sentinel()); |
| 104 ASSERT(field().value() != Object::transition_sentinel()); | 104 ASSERT(field().value() != Object::transition_sentinel()); |
| 105 return field().raw() == other_load->field().raw(); | 105 return field().raw() == other_load->field().raw(); |
| 106 } | 106 } |
| 107 | 107 |
| 108 | 108 |
| 109 bool ConstantInstr::AttributesEqual(Definition* other) const { | 109 bool ConstantInstr::AttributesEqual(Instruction* other) const { |
| 110 ConstantInstr* other_constant = other->AsConstant(); | 110 ConstantInstr* other_constant = other->AsConstant(); |
| 111 ASSERT(other_constant != NULL); | 111 ASSERT(other_constant != NULL); |
| 112 return (value().raw() == other_constant->value().raw()); | 112 return (value().raw() == other_constant->value().raw()); |
| 113 } | 113 } |
| 114 | 114 |
| 115 | 115 |
| 116 // Returns true if the value represents a constant. | 116 // Returns true if the value represents a constant. |
| 117 bool Value::BindsToConstant() const { | 117 bool Value::BindsToConstant() const { |
| 118 return definition()->IsConstant(); | 118 return definition()->IsConstant(); |
| 119 } | 119 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 prev_instr->set_next(next_instr); | 218 prev_instr->set_next(next_instr); |
| 219 next_instr->set_previous(prev_instr); | 219 next_instr->set_previous(prev_instr); |
| 220 // Reset successor and previous instruction to indicate | 220 // Reset successor and previous instruction to indicate |
| 221 // that the instruction is removed from the graph. | 221 // that the instruction is removed from the graph. |
| 222 set_previous(NULL); | 222 set_previous(NULL); |
| 223 set_next(NULL); | 223 set_next(NULL); |
| 224 return return_previous ? prev_instr : next_instr; | 224 return return_previous ? prev_instr : next_instr; |
| 225 } | 225 } |
| 226 | 226 |
| 227 | 227 |
| 228 void Definition::InsertBefore(Instruction* next) { | 228 void Instruction::InsertBefore(Instruction* next) { |
| 229 ASSERT(previous_ == NULL); | 229 ASSERT(previous_ == NULL); |
| 230 ASSERT(next_ == NULL); | 230 ASSERT(next_ == NULL); |
| 231 next_ = next; | 231 next_ = next; |
| 232 previous_ = next->previous_; | 232 previous_ = next->previous_; |
| 233 next->previous_ = this; | 233 next->previous_ = this; |
| 234 previous_->next_ = this; | 234 previous_->next_ = this; |
| 235 } | 235 } |
| 236 | 236 |
| 237 | 237 |
| 238 void Definition::InsertAfter(Instruction* prev) { | 238 void Instruction::InsertAfter(Instruction* prev) { |
| 239 ASSERT(previous_ == NULL); | 239 ASSERT(previous_ == NULL); |
| 240 ASSERT(next_ == NULL); | 240 ASSERT(next_ == NULL); |
| 241 previous_ = prev; | 241 previous_ = prev; |
| 242 next_ = prev->next_; | 242 next_ = prev->next_; |
| 243 next_->previous_ = this; | 243 next_->previous_ = this; |
| 244 previous_->next_ = this; | 244 previous_->next_ = this; |
| 245 } | 245 } |
| 246 | 246 |
| 247 | 247 |
| 248 BlockEntryInstr* Definition::GetBlock() const { | 248 BlockEntryInstr* Instruction::GetBlock() const { |
| 249 // TODO(fschneider): Implement a faster way to get the block of an | 249 // TODO(fschneider): Implement a faster way to get the block of an |
| 250 // instruction. | 250 // instruction. |
| 251 ASSERT(previous() != NULL); | 251 ASSERT(previous() != NULL); |
| 252 Instruction* result = previous(); | 252 Instruction* result = previous(); |
| 253 while (!result->IsBlockEntry()) result = result->previous(); | 253 while (!result->IsBlockEntry()) result = result->previous(); |
| 254 return result->AsBlockEntry(); | 254 return result->AsBlockEntry(); |
| 255 } | 255 } |
| 256 | 256 |
| 257 | 257 |
| 258 void ForwardInstructionIterator::RemoveCurrentFromGraph() { | 258 void ForwardInstructionIterator::RemoveCurrentFromGraph() { |
| (...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1193 RawAbstractType* CheckArrayBoundInstr::CompileType() const { | 1193 RawAbstractType* CheckArrayBoundInstr::CompileType() const { |
| 1194 return AbstractType::null(); | 1194 return AbstractType::null(); |
| 1195 } | 1195 } |
| 1196 | 1196 |
| 1197 | 1197 |
| 1198 RawAbstractType* CheckEitherNonSmiInstr::CompileType() const { | 1198 RawAbstractType* CheckEitherNonSmiInstr::CompileType() const { |
| 1199 return AbstractType::null(); | 1199 return AbstractType::null(); |
| 1200 } | 1200 } |
| 1201 | 1201 |
| 1202 | 1202 |
| 1203 // Optimizations that eliminate or simplify individual computations. | 1203 // Optimizations that eliminate or simplify individual instructions. |
| 1204 Instruction* Instruction::Canonicalize() { |
| 1205 return this; |
| 1206 } |
| 1207 |
| 1208 |
| 1204 Definition* Definition::Canonicalize() { | 1209 Definition* Definition::Canonicalize() { |
| 1205 return this; | 1210 return this; |
| 1206 } | 1211 } |
| 1207 | 1212 |
| 1208 | 1213 |
| 1209 Definition* StrictCompareInstr::Canonicalize() { | 1214 Definition* StrictCompareInstr::Canonicalize() { |
| 1210 if (!right()->BindsToConstant()) return this; | 1215 if (!right()->BindsToConstant()) return this; |
| 1211 const Object& right_constant = right()->BoundConstant(); | 1216 const Object& right_constant = right()->BoundConstant(); |
| 1212 Definition* left_defn = left()->definition(); | 1217 Definition* left_defn = left()->definition(); |
| 1213 // TODO(fschneider): Handle other cases: e === false and e !== true/false. | 1218 // TODO(fschneider): Handle other cases: e === false and e !== true/false. |
| 1214 // Handles e === true. | 1219 // Handles e === true. |
| 1215 if ((kind() == Token::kEQ_STRICT) && | 1220 if ((kind() == Token::kEQ_STRICT) && |
| 1216 (right_constant.raw() == Bool::True()) && | 1221 (right_constant.raw() == Bool::True()) && |
| 1217 (left()->ResultCid() == kBoolCid)) { | 1222 (left()->ResultCid() == kBoolCid)) { |
| 1218 // Return left subexpression as the replacement for this instruction. | 1223 // Return left subexpression as the replacement for this instruction. |
| 1219 return left_defn; | 1224 return left_defn; |
| 1220 } | 1225 } |
| 1221 return this; | 1226 return this; |
| 1222 } | 1227 } |
| 1223 | 1228 |
| 1224 | 1229 |
| 1225 Definition* CheckClassInstr::Canonicalize() { | 1230 Instruction* CheckClassInstr::Canonicalize() { |
| 1226 const intptr_t v_cid = value()->ResultCid(); | 1231 const intptr_t v_cid = value()->ResultCid(); |
| 1227 const intptr_t num_checks = unary_checks().NumberOfChecks(); | 1232 const intptr_t num_checks = unary_checks().NumberOfChecks(); |
| 1228 if ((num_checks == 1) && | 1233 if ((num_checks == 1) && |
| 1229 (v_cid == unary_checks().GetReceiverClassIdAt(0))) { | 1234 (v_cid == unary_checks().GetReceiverClassIdAt(0))) { |
| 1230 // No checks needed. | 1235 // No checks needed. |
| 1231 return NULL; | 1236 return NULL; |
| 1232 } | 1237 } |
| 1233 return this; | 1238 return this; |
| 1234 } | 1239 } |
| 1235 | 1240 |
| 1236 | 1241 |
| 1237 Definition* CheckSmiInstr::Canonicalize() { | 1242 Instruction* CheckSmiInstr::Canonicalize() { |
| 1238 return (value()->ResultCid() == kSmiCid) ? NULL : this; | 1243 return (value()->ResultCid() == kSmiCid) ? NULL : this; |
| 1239 } | 1244 } |
| 1240 | 1245 |
| 1241 | 1246 |
| 1242 Definition* CheckEitherNonSmiInstr::Canonicalize() { | 1247 Instruction* CheckEitherNonSmiInstr::Canonicalize() { |
| 1243 if ((left()->ResultCid() == kDoubleCid) || | 1248 if ((left()->ResultCid() == kDoubleCid) || |
| 1244 (right()->ResultCid() == kDoubleCid)) { | 1249 (right()->ResultCid() == kDoubleCid)) { |
| 1245 return NULL; // Remove from the graph. | 1250 return NULL; // Remove from the graph. |
| 1246 } | 1251 } |
| 1247 return this; | 1252 return this; |
| 1248 } | 1253 } |
| 1249 | 1254 |
| 1250 | 1255 |
| 1251 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and | 1256 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and |
| 1252 // PrepareEntry). Only assembly code that can be shared across all architectures | 1257 // PrepareEntry). Only assembly code that can be shared across all architectures |
| (...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1748 value->set_use_index(use_index++); | 1753 value->set_use_index(use_index++); |
| 1749 value->AddToEnvUseList(); | 1754 value->AddToEnvUseList(); |
| 1750 } | 1755 } |
| 1751 instr->env()->outer_ = copy; | 1756 instr->env()->outer_ = copy; |
| 1752 } | 1757 } |
| 1753 | 1758 |
| 1754 | 1759 |
| 1755 #undef __ | 1760 #undef __ |
| 1756 | 1761 |
| 1757 } // namespace dart | 1762 } // namespace dart |
| OLD | NEW |