Index: vm/opt_code_generator_ia32.cc |
=================================================================== |
--- vm/opt_code_generator_ia32.cc (revision 2360) |
+++ vm/opt_code_generator_ia32.cc (working copy) |
@@ -36,7 +36,7 @@ |
V(request_result_in_eax, bool, false) \ |
V(result_returned_in_eax, bool, false) \ |
V(fallthrough_label, Label*, NULL) \ |
- V(is_class, const Class*, NULL) \ |
+ V(is_class, const Class*, &Class::ZoneHandle()) \ |
// Class holding information being passed from source to destination. |
@@ -56,9 +56,6 @@ |
} |
bool IsClass(const Class& cls) const { |
- if (is_class() == NULL) { |
- return cls.IsNullClass(); |
- } |
return is_class()->raw() == cls.raw(); |
} |
@@ -207,6 +204,41 @@ |
}; |
+// Maintain classes of locals as defined by a store to that local. |
+// A simple initial implementation, memorizes last typed stores. Does not |
+// scale well for large code pieces. This will be replaced by SSA based |
+// type propagation. |
+class ClassesForLocals : public ZoneAllocated { |
+ public: |
+ ClassesForLocals() : classes_(), locals_() {} |
+ void SetLocalType(const LocalVariable& local, const Class& cls) { |
+ classes_.Add(&cls); |
+ locals_.Add(&local); |
+ } |
+ // If no type is stored/known, we return a null class in 'cls'. |
+ void GetLocalClass(const LocalVariable& local, const Class** cls) const { |
+ for (intptr_t i = locals_.length() - 1; i >=0; i--) { |
+ if (locals_[i]->Equals(local)) { |
+ *cls = classes_[i]; |
+ return; |
+ } |
+ } |
+ *cls = &Class::ZoneHandle(); |
+ } |
+ |
+ void Clear() { |
+ classes_.Clear(); |
+ locals_.Clear(); |
+ } |
+ |
+ private: |
+ GrowableArray<const Class*> classes_; |
+ GrowableArray<const LocalVariable*> locals_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ClassesForLocals); |
+}; |
+ |
+ |
static const char* kGrowableArrayClassName = "GrowableObjectArray"; |
static const char* kGrowableArrayLengthFieldName = "_length"; |
static const char* kGrowableArrayArrayFieldName = "backingArray"; |
@@ -216,6 +248,7 @@ |
Assembler* assembler, const ParsedFunction& parsed_function) |
: CodeGenerator(assembler, parsed_function), |
deoptimization_blobs_(4), |
+ classes_for_locals_(new ClassesForLocals()), |
smi_class_(Class::ZoneHandle(Isolate::Current()->object_store() |
->smi_class())), |
double_class_(Class::ZoneHandle(Isolate::Current()->object_store() |
@@ -430,6 +463,13 @@ |
LoadLocalNode* local_node = node->AsLoadLocalNode(); |
ASSERT(local_node != NULL); |
GenerateLoadVariable(reg, local_node->local()); |
+ if (node->info() != NULL) { |
+ const Class* cls = NULL; |
+ classes_for_locals_->GetLocalClass(local_node->local(), &cls); |
+ if (cls != NULL) { |
+ node->info()->set_is_class(cls); |
+ } |
+ } |
return; |
} |
if (node->AsLiteralNode()) { |
@@ -515,12 +555,20 @@ |
} else { |
GeneratePushVariable(node->local(), EAX); |
} |
+ if (node->info() != NULL) { |
+ const Class* cls = NULL; |
+ classes_for_locals_->GetLocalClass(node->local(), &cls); |
+ if (cls != NULL) { |
+ node->info()->set_is_class(cls); |
+ } |
+ } |
} |
void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
if (FLAG_enable_type_checks) { |
CodeGenerator::VisitStoreLocalNode(node); |
+ classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
return; |
} |
CodeGenInfo value_info(node->value()); |
@@ -552,6 +600,7 @@ |
if (IsResultNeeded(node)) { |
__ pushl(EAX); |
} |
+ classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); |
} |
@@ -893,8 +942,7 @@ |
static bool AreNodesOfSameType(AstNode* a, AstNode* b) { |
ASSERT((a != NULL) && (b != NULL)); |
if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { |
- return a->AsLoadLocalNode()->local().index() == |
- b->AsLoadLocalNode()->local().index(); |
+ return a->AsLoadLocalNode()->local().Equals(b->AsLoadLocalNode()->local()); |
} |
return false; |
} |
@@ -1149,12 +1197,14 @@ |
void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { |
if (FLAG_enable_type_checks) { |
+ classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
CodeGenerator::VisitIncrOpLocalNode(node); |
return; |
} |
const char* kOptMessage = "Inlines IncrOpLocal"; |
ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
if (!AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
+ classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
TraceNotOpt(node, kOptMessage); |
CodeGenerator::VisitIncrOpLocalNode(node); |
return; |
@@ -1185,6 +1235,7 @@ |
__ pushl(ECX); |
} |
} |
+ classes_for_locals_->SetLocalType(node->local(), smi_class_); |
} |
@@ -2623,6 +2674,8 @@ |
void OptimizingCodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) { |
+ // TODO(srdjan): Allow limited forwarding of types across sequence nodes. |
+ classes_for_locals_->Clear(); |
const intptr_t num_context_variables = (node_sequence->scope() != NULL) ? |
node_sequence->scope()->num_context_variables() : 0; |
if (FLAG_enable_type_checks || (num_context_variables > 0)) { |
@@ -2637,6 +2690,7 @@ |
if (node_sequence->label() != NULL) { |
__ Bind(node_sequence->label()->break_label()); |
} |
+ classes_for_locals_->Clear(); |
} |
@@ -2655,6 +2709,20 @@ |
} |
+void OptimizingCodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { |
+ // TODO(srdjan): Set classes for locals. |
+ classes_for_locals_->Clear(); |
+ CodeGenerator::VisitCatchClauseNode(node); |
+} |
+ |
+ |
+void OptimizingCodeGenerator::VisitTryCatchNode(TryCatchNode* node) { |
+ // TODO(srdjan): Set classes for locals. |
+ classes_for_locals_->Clear(); |
+ CodeGenerator::VisitTryCatchNode(node); |
+} |
+ |
+ |
} // namespace dart |
#endif // defined TARGET_ARCH_IA32 |