Detect circular dependencies in compile time constants
Fix issue 1681
R=srdjan@google.com
Review URL: https://codereview.chromium.org//22897019
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@26491 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index e53b5d9..a4b7ec6 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -63,6 +63,7 @@
utf_library_(Library::null()),
libraries_(GrowableObjectArray::null()),
pending_classes_(GrowableObjectArray::null()),
+ pending_functions_(GrowableObjectArray::null()),
sticky_error_(Error::null()),
unhandled_exception_handler_(String::null()),
empty_context_(Context::null()),
@@ -105,6 +106,9 @@
ASSERT(this->out_of_memory() == Instance::null());
ASSERT(this->preallocated_stack_trace() == Stacktrace::null());
+ ASSERT(this->pending_functions() == GrowableObjectArray::null());
+ this->pending_functions_ = GrowableObjectArray::New();
+
Object& result = Object::Handle();
const Library& library = Library::Handle(Library::CoreLibrary());
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 48e711a..6ccdff9 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -349,6 +349,10 @@
pending_classes_ = value.raw();
}
+ RawGrowableObjectArray* pending_functions() const {
+ return pending_functions_;
+ }
+
RawError* sticky_error() const { return sticky_error_; }
void set_sticky_error(const Error& value) {
ASSERT(!value.IsNull());
@@ -485,6 +489,7 @@
RawLibrary* utf_library_;
RawGrowableObjectArray* libraries_;
RawGrowableObjectArray* pending_classes_;
+ RawGrowableObjectArray* pending_functions_;
RawError* sticky_error_;
RawString* unhandled_exception_handler_;
RawContext* empty_context_;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 89d7731..1e96917 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -255,7 +255,8 @@
current_class_(Class::Handle(isolate_)),
library_(Library::Handle(isolate_, library.raw())),
try_blocks_list_(NULL),
- last_used_try_index_(CatchClauseNode::kInvalidTryIndex) {
+ last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
+ unregister_pending_function_(false) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!library.IsNull());
}
@@ -284,7 +285,8 @@
isolate_,
parsed_function->function().origin()).library())),
try_blocks_list_(NULL),
- last_used_try_index_(CatchClauseNode::kInvalidTryIndex) {
+ last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
+ unregister_pending_function_(false) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
if (FLAG_enable_type_checks) {
@@ -293,6 +295,19 @@
}
+Parser::~Parser() {
+ if (unregister_pending_function_) {
+ const GrowableObjectArray& pending_functions =
+ GrowableObjectArray::Handle(
+ isolate()->object_store()->pending_functions());
+ ASSERT(pending_functions.Length() > 0);
+ ASSERT(pending_functions.At(pending_functions.Length()-1) ==
+ current_function().raw());
+ pending_functions.RemoveLast();
+ }
+}
+
+
void Parser::SetScript(const Script & script, intptr_t token_pos) {
script_ = script.raw();
tokens_iterator_.SetStream(TokenStream::Handle(script.tokens()), token_pos);
@@ -2360,6 +2375,23 @@
}
+void Parser::CheckRecursiveInvocation() {
+ const GrowableObjectArray& pending_functions =
+ GrowableObjectArray::Handle(
+ isolate()->object_store()->pending_functions());
+ for (int i = 0; i < pending_functions.Length(); i++) {
+ if (pending_functions.At(i) == current_function().raw()) {
+ const String& fname =
+ String::Handle(current_function().UserVisibleName());
+ ErrorMsg("circular dependency for function %s", fname.ToCString());
+ }
+ }
+ ASSERT(!unregister_pending_function_);
+ pending_functions.Add(current_function());
+ unregister_pending_function_ = true;
+}
+
+
// Parser is at the opening parenthesis of the formal parameter declaration
// of function. Parse the formal parameters, initializers and code.
SequenceNode* Parser::ParseConstructor(const Function& func,
@@ -2372,6 +2404,8 @@
const Class& cls = Class::Handle(func.Owner());
ASSERT(!cls.IsNull());
+ CheckRecursiveInvocation();
+
if (func.IsImplicitConstructor()) {
// Special case: implicit constructor.
// The parser adds an implicit default constructor when a class
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 2af08c2..b2fbf97 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -182,6 +182,7 @@
Parser(const Script& script, const Library& library, intptr_t token_pos);
Parser(const Script& script, ParsedFunction* function, intptr_t token_pos);
+ ~Parser();
// The function for which we will generate code.
const Function& current_function() const;
@@ -320,6 +321,8 @@
const Error& prev_error, intptr_t token_pos, const char* format, ...)
PRINTF_ATTRIBUTE(4, 5);
+ void CheckRecursiveInvocation();
+
const Instance& EvaluateConstExpr(AstNode* expr);
AstNode* RunStaticFieldInitializer(const Field& field);
RawObject* EvaluateConstConstructorCall(
@@ -693,6 +696,8 @@
intptr_t AllocateTryIndex() { return ++last_used_try_index_; }
intptr_t last_used_try_index_;
+ bool unregister_pending_function_;
+
DISALLOW_COPY_AND_ASSIGN(Parser);
};
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 102fbbf..c52aec6 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -138,7 +138,6 @@
Language/12_Expressions/01_Constants_A01_t01: fail # co19 issue 522
Language/12_Expressions/01_Constants_A16_t01: fail # co19 issue 525
Language/12_Expressions/01_Constants_A16_t02: fail # co19 issue 525
-Language/12_Expressions/01_Constants_A17_t03: crash # Dart issue 1681
Language/12_Expressions/03_Numbers_A01_t01: fail # co19 issue 522
Language/12_Expressions/03_Numbers_A01_t02: fail # co19 issue 522
Language/12_Expressions/03_Numbers_A01_t03: fail # co19 issue 522