[VM/AOT] Fix handling of errors from compiling static initializers

* CompileStaticInitializer() should check result of Compile()
  and should not leave sticky error. If left, this sticky error
  could be picked up by compilation of some unrelated static
  initializer. Also, assertions are added to make sure that code
  which explicitly or implicitly relies on sticky errors is not
  getting an error on entry.

* CompileStaticInitializerIgnoreErrors() clears sticky errors to
  ignore them.

* Added inline bailout reason for cyclic static fields.
  This guards against inlining of code which uses a field into static
  initializer. This code might not be called so it should not trigger
  compilation error eagerly.

Change-Id: I52da6f4cd05556125fd1a628b665dcc11621a4f7
Reviewed-on: https://dart-review.googlesource.com/28523
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2017-12-12 19:29:08 +00:00 committed by commit-bot@chromium.org
parent 2aed87a133
commit 73b265e348
3 changed files with 28 additions and 6 deletions

View file

@ -417,6 +417,7 @@ void Precompiler::DoCompileAll(
// can be used. Also ensures lookup of entry points won't miss functions
// because their class hasn't been finalized yet.
FinalizeAllClasses();
ASSERT(Error::Handle(Z, T->sticky_error()).IsNull());
ClassFinalizer::SortClasses();
TypeRangeCache trc(this, T, I->class_table()->NumCids());
@ -424,6 +425,7 @@ void Precompiler::DoCompileAll(
// Precompile static initializers to compute result type information.
PrecompileStaticInitializers();
ASSERT(Error::Handle(Z, T->sticky_error()).IsNull());
// Precompile constructors to compute type information for final fields.
ClassFinalizer::ClearAllCode();
@ -526,6 +528,9 @@ void Precompiler::DoCompileAll(
}
static void CompileStaticInitializerIgnoreErrors(const Field& field) {
ASSERT(Error::Handle(Thread::Current()->zone(),
Thread::Current()->sticky_error())
.IsNull());
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
const Function& initializer =
@ -538,7 +543,11 @@ static void CompileStaticInitializerIgnoreErrors(const Field& field) {
} else {
// Ignore compile-time errors here. If the field is actually used,
// the error will be reported later during Iterate().
Thread::Current()->clear_sticky_error();
}
ASSERT(Error::Handle(Thread::Current()->zone(),
Thread::Current()->sticky_error())
.IsNull());
}
void Precompiler::PrecompileStaticInitializers() {
@ -1419,6 +1428,7 @@ RawFunction* Precompiler::CompileStaticInitializer(const Field& field,
Thread* thread = Thread::Current();
StackZone stack_zone(thread);
Zone* zone = stack_zone.GetZone();
ASSERT(Error::Handle(zone, thread->sticky_error()).IsNull());
ParsedFunction* parsed_function;
// Check if this field is coming from the Kernel binary.
@ -1433,7 +1443,12 @@ RawFunction* Precompiler::CompileStaticInitializer(const Field& field,
PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
parsed_function,
/* optimized = */ true);
helper.Compile(&pipeline);
if (!helper.Compile(&pipeline)) {
Error& error = Error::Handle(zone, thread->sticky_error());
ASSERT(!error.IsNull());
Jump(error);
UNREACHABLE();
}
if (compute_type && field.is_final()) {
intptr_t result_cid = pipeline.result_type().ToCid();
@ -1454,6 +1469,8 @@ RawFunction* Precompiler::CompileStaticInitializer(const Field& field,
Disassembler::DisassembleCode(parsed_function->function(), code,
/* optimized = */ true);
}
ASSERT(Error::Handle(zone, thread->sticky_error()).IsNull());
return parsed_function->function().raw();
}

View file

@ -2517,6 +2517,7 @@ bool StreamingConstantEvaluator::IsCached(intptr_t offset) {
Instance& StreamingConstantEvaluator::EvaluateExpression(intptr_t offset,
bool reset_position) {
ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
if (!GetCachedConstant(offset, &result_)) {
ASSERT(IsAllowedToEvaluate());
intptr_t original_offset = builder_->ReaderOffset();
@ -2784,12 +2785,16 @@ void StreamingConstantEvaluator::EvaluateStaticGet() {
NameIndex target =
builder_->ReadCanonicalNameReference(); // read target_reference.
ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
if (H.IsField(target)) {
const Field& field = Field::Handle(Z, H.LookupFieldByKernelField(target));
if (!field.is_const()) {
H.ReportError(script_, position, "Not a constant field.");
}
if (field.StaticValue() == Object::transition_sentinel().raw()) {
builder_->InlineBailout(
"kernel::StreamingConstantEvaluator::EvaluateStaticGet::Cyclic");
H.ReportError(script_, position, "Not a constant expression.");
} else if (field.StaticValue() == Object::sentinel().raw()) {
field.SetStaticValue(Object::transition_sentinel());
@ -3634,6 +3639,7 @@ void StreamingFlowGraphBuilder::SetupDefaultParameterValues() {
Fragment StreamingFlowGraphBuilder::BuildFieldInitializer(
NameIndex canonical_name) {
ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
Field& field =
Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name));
if (PeekTag() == kNullLiteral) {
@ -3651,6 +3657,7 @@ Fragment StreamingFlowGraphBuilder::BuildFieldInitializer(
Fragment StreamingFlowGraphBuilder::BuildInitializers(
const Class& parent_class) {
ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
Fragment instructions;
// Start by getting the position of the constructors initializer.
@ -4298,6 +4305,7 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(bool constructor) {
}
FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) {
ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
const Function& function = parsed_function()->function();
// Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used
@ -6337,6 +6345,7 @@ Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) {
}
Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
intptr_t offset = ReaderOffset() - 1; // Include the tag.
TokenPosition position = ReadPosition(); // read position.

View file

@ -1206,7 +1206,6 @@ cyclic_type_variable_test/03: Crash
cyclic_type_variable_test/04: Crash
cyclic_type_variable_test/none: Crash
external_test/13: Crash
final_syntax_test/09: Crash
optional_named_parameters_test/06: Crash
optional_named_parameters_test/08: Crash
regress_29025_test: Crash
@ -1521,7 +1520,6 @@ const_constructor2_test/12: CompileTimeError # Issue 31402 (Invocation arguments
const_constructor2_test/20: MissingCompileTimeError
const_constructor2_test/22: MissingCompileTimeError
const_constructor2_test/24: MissingCompileTimeError
const_constructor3_test/04: Crash # kernel_binary_flowgraph.cc: 2857: error: expected: !function.IsNull()
const_constructor_nonconst_field_test/01: MissingCompileTimeError # Fasta bug: Non-const expression in field initializer.
const_dynamic_type_literal_test/02: MissingCompileTimeError
const_dynamic_type_literal_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
@ -1538,8 +1536,7 @@ const_native_factory_test: MissingCompileTimeError
const_native_factory_test/01: MissingCompileTimeError # Fasta bug: Issue 29763
const_nested_test: RuntimeError # KernelVM bug: Constant evaluation.
const_optional_args_test/01: MissingCompileTimeError # Fasta bug: Default parameter values must be const.
const_redirecting_factory_test: Crash # kernel_binary_flowgraph.cc: 2857: error: expected: !function.IsNull(); previous error: CompileTimeError # Issue 31402 (Field declaration)
const_redirecting_factory_test: CompileTimeError # Issue 31402 (Field declaration)
const_switch2_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
const_syntax_test/05: MissingCompileTimeError # KernelVM bug: Constant evaluation.
const_types_test/01: MissingCompileTimeError
@ -1704,7 +1701,6 @@ final_attempt_reinitialization_test/02: MissingCompileTimeError # Issue 29900
final_for_in_variable_test: MissingCompileTimeError
final_param_test: MissingCompileTimeError
final_super_field_set_test: MissingCompileTimeError
final_syntax_test/09: Crash
final_variable_assignment_test/01: MissingCompileTimeError
final_variable_assignment_test/02: MissingCompileTimeError
final_variable_assignment_test/03: MissingCompileTimeError