Index: runtime/vm/compiler.cc |
=================================================================== |
--- runtime/vm/compiler.cc (revision 3862) |
+++ runtime/vm/compiler.cc (working copy) |
@@ -11,7 +11,9 @@ |
#include "vm/code_patcher.h" |
#include "vm/dart_entry.h" |
#include "vm/disassembler.h" |
+#include "vm/exceptions.h" |
#include "vm/flags.h" |
+#include "vm/longjump.h" |
#include "vm/object.h" |
#include "vm/object_store.h" |
#include "vm/opt_code_generator.h" |
@@ -35,7 +37,10 @@ |
ASSERT(arguments.Count() == kCompileFunctionRuntimeEntry.argument_count()); |
const Function& function = Function::CheckedHandle(arguments.At(0)); |
ASSERT(!function.HasCode()); |
- Compiler::CompileFunction(function); |
+ const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
+ if (!error.IsNull()) { |
+ Exceptions::PropagateError(error); |
+ } |
} |
@@ -65,223 +70,271 @@ |
} |
-void Compiler::Compile(const Library& library, const Script& script) { |
- if (FLAG_trace_compiler) { |
- HANDLESCOPE(Isolate::Current()); |
- const String& script_url = String::Handle(script.url()); |
- // TODO(iposva): Extract script kind. |
- OS::Print("Compiling %s '%s'\n", "", script_url.ToCString()); |
+RawError* Compiler::Compile(const Library& library, const Script& script) { |
+ Isolate* isolate = Isolate::Current(); |
+ Error& error = Error::Handle(); |
+ LongJump* base = isolate->long_jump_base(); |
+ LongJump jump; |
+ isolate->set_long_jump_base(&jump); |
+ if (setjmp(*jump.Set()) == 0) { |
+ if (FLAG_trace_compiler) { |
+ HANDLESCOPE(isolate); |
+ const String& script_url = String::Handle(script.url()); |
+ // TODO(iposva): Extract script kind. |
+ OS::Print("Compiling %s '%s'\n", "", script_url.ToCString()); |
+ } |
+ const String& library_key = String::Handle(library.private_key()); |
+ script.Tokenize(library_key); |
+ Parser::ParseCompilationUnit(library, script); |
+ } else { |
+ error = isolate->object_store()->sticky_error(); |
+ isolate->object_store()->clear_sticky_error(); |
} |
- const String& library_key = String::Handle(library.private_key()); |
- script.Tokenize(library_key); |
- Parser::ParseCompilationUnit(library, script); |
+ isolate->set_long_jump_base(base); |
+ return error.raw(); |
} |
-static void CompileFunctionHelper(const Function& function, bool optimized) { |
- TIMERSCOPE(time_compilation); |
- ParsedFunction parsed_function(function); |
- const char* function_fullname = function.ToFullyQualifiedCString(); |
- if (FLAG_trace_compiler) { |
- OS::Print("Compiling %sfunction: '%s' @ token %d\n", |
- (optimized ? "optimized " : ""), |
- function_fullname, |
- function.token_index()); |
- } |
- Parser::ParseFunction(&parsed_function); |
- CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); |
- ASSERT(code_index_table != NULL); |
- Assembler assembler; |
- if (optimized) { |
- // Transition to optimized code only from unoptimized code ... for now. |
- ASSERT(function.HasCode()); |
- ASSERT(!Code::Handle(function.code()).is_optimized()); |
- // Do not use type feedback to optimize a function that was deoptimized. |
- if (parsed_function.function().deoptimization_counter() < |
- FLAG_deoptimization_counter_threshold) { |
- ExtractTypeFeedback(Code::Handle(parsed_function.function().code()), |
- parsed_function.node_sequence()); |
- } |
- OptimizingCodeGenerator code_gen(&assembler, parsed_function); |
- code_gen.GenerateCode(); |
- Code& code = Code::Handle( |
- Code::FinalizeCode(function_fullname, &assembler)); |
- code.set_is_optimized(true); |
- code_gen.FinalizePcDescriptors(code); |
- code_gen.FinalizeExceptionHandlers(code); |
- function.SetCode(code); |
- code_index_table->AddFunction(function); |
- CodePatcher::PatchEntry(Code::Handle(function.unoptimized_code())); |
+static RawError* CompileFunctionHelper(const Function& function, |
+ bool optimized) { |
+ Isolate* isolate = Isolate::Current(); |
+ Error& error = Error::Handle(); |
+ LongJump* base = isolate->long_jump_base(); |
+ LongJump jump; |
+ isolate->set_long_jump_base(&jump); |
+ if (setjmp(*jump.Set()) == 0) { |
+ TIMERSCOPE(time_compilation); |
+ ParsedFunction parsed_function(function); |
+ const char* function_fullname = function.ToFullyQualifiedCString(); |
if (FLAG_trace_compiler) { |
- OS::Print("--> patching entry 0x%x\n", |
- Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ OS::Print("Compiling %sfunction: '%s' @ token %d\n", |
+ (optimized ? "optimized " : ""), |
+ function_fullname, |
+ function.token_index()); |
} |
- } else { |
- // Unoptimized code. |
- if (Code::Handle(function.unoptimized_code()).IsNull()) { |
- ASSERT(Code::Handle(function.code()).IsNull()); |
- // Compiling first time. |
- CodeGenerator code_gen(&assembler, parsed_function); |
+ Parser::ParseFunction(&parsed_function); |
+ CodeIndexTable* code_index_table = isolate->code_index_table(); |
+ ASSERT(code_index_table != NULL); |
+ Assembler assembler; |
+ if (optimized) { |
+ // Transition to optimized code only from unoptimized code ... for now. |
+ ASSERT(function.HasCode()); |
+ ASSERT(!Code::Handle(function.code()).is_optimized()); |
+ // Do not use type feedback to optimize a function that was deoptimized. |
+ if (parsed_function.function().deoptimization_counter() < |
+ FLAG_deoptimization_counter_threshold) { |
+ ExtractTypeFeedback(Code::Handle(parsed_function.function().code()), |
+ parsed_function.node_sequence()); |
+ } |
+ OptimizingCodeGenerator code_gen(&assembler, parsed_function); |
code_gen.GenerateCode(); |
- const Code& code = |
- Code::Handle(Code::FinalizeCode(function_fullname, &assembler)); |
- code.set_is_optimized(false); |
+ Code& code = Code::Handle( |
+ Code::FinalizeCode(function_fullname, &assembler)); |
+ code.set_is_optimized(true); |
code_gen.FinalizePcDescriptors(code); |
- code_gen.FinalizeVarDescriptors(code); |
code_gen.FinalizeExceptionHandlers(code); |
- function.set_unoptimized_code(code); |
function.SetCode(code); |
- ASSERT(CodePatcher::CodeIsPatchable(code)); |
code_index_table->AddFunction(function); |
- } else { |
- // Disable optimized code. |
- const Code& optimized_code = Code::Handle(function.code()); |
- ASSERT(optimized_code.is_optimized()); |
- CodePatcher::PatchEntry(Code::Handle(function.code())); |
+ CodePatcher::PatchEntry(Code::Handle(function.unoptimized_code())); |
if (FLAG_trace_compiler) { |
OS::Print("--> patching entry 0x%x\n", |
- Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ Code::Handle(function.unoptimized_code()).EntryPoint()); |
} |
- // Use previously compiled code. |
- function.SetCode(Code::Handle(function.unoptimized_code())); |
- CodePatcher::RestoreEntry(Code::Handle(function.unoptimized_code())); |
- if (FLAG_trace_compiler) { |
- OS::Print("--> restoring entry at 0x%x\n", |
- Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ } else { |
+ // Unoptimized code. |
+ if (Code::Handle(function.unoptimized_code()).IsNull()) { |
+ ASSERT(Code::Handle(function.code()).IsNull()); |
+ // Compiling first time. |
+ CodeGenerator code_gen(&assembler, parsed_function); |
+ code_gen.GenerateCode(); |
+ const Code& code = |
+ Code::Handle(Code::FinalizeCode(function_fullname, &assembler)); |
+ code.set_is_optimized(false); |
+ code_gen.FinalizePcDescriptors(code); |
+ code_gen.FinalizeVarDescriptors(code); |
+ code_gen.FinalizeExceptionHandlers(code); |
+ function.set_unoptimized_code(code); |
+ function.SetCode(code); |
+ ASSERT(CodePatcher::CodeIsPatchable(code)); |
+ code_index_table->AddFunction(function); |
+ } else { |
+ // Disable optimized code. |
+ const Code& optimized_code = Code::Handle(function.code()); |
+ ASSERT(optimized_code.is_optimized()); |
+ CodePatcher::PatchEntry(Code::Handle(function.code())); |
+ if (FLAG_trace_compiler) { |
+ OS::Print("--> patching entry 0x%x\n", |
+ Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ } |
+ // Use previously compiled code. |
+ function.SetCode(Code::Handle(function.unoptimized_code())); |
+ CodePatcher::RestoreEntry(Code::Handle(function.unoptimized_code())); |
+ if (FLAG_trace_compiler) { |
+ OS::Print("--> restoring entry at 0x%x\n", |
+ Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ } |
} |
} |
- } |
- if (FLAG_trace_compiler) { |
- OS::Print("--> '%s' entry: 0x%x\n", |
- function_fullname, Code::Handle(function.code()).EntryPoint()); |
- } |
- if (FLAG_disassemble) { |
- OS::Print("Code for %sfunction '%s' {\n", |
- optimized ? "optimized " : "", function_fullname); |
- const Code& code = Code::Handle(function.code()); |
- const Instructions& instructions = |
- Instructions::Handle(code.instructions()); |
- uword start = instructions.EntryPoint(); |
- Disassembler::Disassemble(start, start + assembler.CodeSize()); |
- OS::Print("}\n"); |
- OS::Print("Pointer offsets for function: {\n"); |
- for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { |
- const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
- Object& obj = Object::Handle(); |
- obj = *reinterpret_cast<RawObject**>(addr); |
- OS::Print(" %d : 0x%x '%s'\n", |
- code.GetPointerOffsetAt(i), addr, obj.ToCString()); |
+ if (FLAG_trace_compiler) { |
+ OS::Print("--> '%s' entry: 0x%x\n", |
+ function_fullname, Code::Handle(function.code()).EntryPoint()); |
} |
- OS::Print("}\n"); |
- OS::Print("PC Descriptors for function '%s' {\n", function_fullname); |
- OS::Print("(pc, kind, id, try-index, token-index)\n"); |
- const PcDescriptors& descriptors = |
- PcDescriptors::Handle(code.pc_descriptors()); |
- OS::Print("%s", descriptors.ToCString()); |
- OS::Print("}\n"); |
- OS::Print("Variable Descriptors for function '%s' {\n", function_fullname); |
- const LocalVarDescriptors& var_descriptors = |
- LocalVarDescriptors::Handle(code.var_descriptors()); |
- intptr_t var_desc_length = |
- var_descriptors.IsNull() ? 0 : var_descriptors.Length(); |
- String& var_name = String::Handle(); |
- for (intptr_t i = 0; i < var_desc_length; i++) { |
- var_name = var_descriptors.GetName(i); |
- intptr_t scope_id, begin_pos, end_pos; |
- var_descriptors.GetScopeInfo(i, &scope_id, &begin_pos, &end_pos); |
- intptr_t slot = var_descriptors.GetSlotIndex(i); |
- OS::Print(" var %s scope %ld (valid %d-%d) offset %ld\n", |
- var_name.ToCString(), scope_id, begin_pos, end_pos, slot); |
+ if (FLAG_disassemble) { |
+ OS::Print("Code for %sfunction '%s' {\n", |
+ optimized ? "optimized " : "", function_fullname); |
+ const Code& code = Code::Handle(function.code()); |
+ const Instructions& instructions = |
+ Instructions::Handle(code.instructions()); |
+ uword start = instructions.EntryPoint(); |
+ Disassembler::Disassemble(start, start + assembler.CodeSize()); |
+ OS::Print("}\n"); |
+ OS::Print("Pointer offsets for function: {\n"); |
+ for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { |
+ const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
+ Object& obj = Object::Handle(); |
+ obj = *reinterpret_cast<RawObject**>(addr); |
+ OS::Print(" %d : 0x%x '%s'\n", |
+ code.GetPointerOffsetAt(i), addr, obj.ToCString()); |
+ } |
+ OS::Print("}\n"); |
+ OS::Print("PC Descriptors for function '%s' {\n", function_fullname); |
+ OS::Print("(pc, kind, id, try-index, token-index)\n"); |
+ const PcDescriptors& descriptors = |
+ PcDescriptors::Handle(code.pc_descriptors()); |
+ OS::Print("%s", descriptors.ToCString()); |
+ OS::Print("}\n"); |
+ OS::Print("Variable Descriptors for function '%s' {\n", |
+ function_fullname); |
+ const LocalVarDescriptors& var_descriptors = |
+ LocalVarDescriptors::Handle(code.var_descriptors()); |
+ intptr_t var_desc_length = |
+ var_descriptors.IsNull() ? 0 : var_descriptors.Length(); |
+ String& var_name = String::Handle(); |
+ for (intptr_t i = 0; i < var_desc_length; i++) { |
+ var_name = var_descriptors.GetName(i); |
+ intptr_t scope_id, begin_pos, end_pos; |
+ var_descriptors.GetScopeInfo(i, &scope_id, &begin_pos, &end_pos); |
+ intptr_t slot = var_descriptors.GetSlotIndex(i); |
+ OS::Print(" var %s scope %ld (valid %d-%d) offset %ld\n", |
+ var_name.ToCString(), scope_id, begin_pos, end_pos, slot); |
+ } |
+ OS::Print("}\n"); |
+ OS::Print("Exception Handlers for function '%s' {\n", function_fullname); |
+ const ExceptionHandlers& handlers = |
+ ExceptionHandlers::Handle(code.exception_handlers()); |
+ OS::Print("%s", handlers.ToCString()); |
+ OS::Print("}\n"); |
} |
- OS::Print("}\n"); |
- OS::Print("Exception Handlers for function '%s' {\n", function_fullname); |
- const ExceptionHandlers& handlers = |
- ExceptionHandlers::Handle(code.exception_handlers()); |
- OS::Print("%s", handlers.ToCString()); |
- OS::Print("}\n"); |
+ } else { |
+ // We got an error during compilation. |
+ error = isolate->object_store()->sticky_error(); |
+ isolate->object_store()->clear_sticky_error(); |
} |
+ isolate->set_long_jump_base(base); |
+ return error.raw(); |
} |
-void Compiler::CompileFunction(const Function& function) { |
- CompileFunctionHelper(function, false); |
+RawError* Compiler::CompileFunction(const Function& function) { |
+ return CompileFunctionHelper(function, false); |
} |
-void Compiler::CompileOptimizedFunction(const Function& function) { |
- CompileFunctionHelper(function, true); |
+RawError* Compiler::CompileOptimizedFunction(const Function& function) { |
+ return CompileFunctionHelper(function, true); |
} |
-void Compiler::CompileAllFunctions(const Class& cls) { |
- Array& functions = Array::Handle(cls.functions()); |
- Function& func = Function::Handle(); |
- for (int i = 0; i < functions.Length(); i++) { |
- func ^= functions.At(i); |
- ASSERT(!func.IsNull()); |
- if (!func.HasCode() && !func.IsAbstract()) { |
- CompileFunction(func); |
+RawError* Compiler::CompileAllFunctions(const Class& cls) { |
+ Isolate* isolate = Isolate::Current(); |
+ Error& error = Error::Handle(); |
+ LongJump* base = isolate->long_jump_base(); |
+ LongJump jump; |
+ isolate->set_long_jump_base(&jump); |
+ if (setjmp(*jump.Set()) == 0) { |
+ Array& functions = Array::Handle(cls.functions()); |
+ Function& func = Function::Handle(); |
+ for (int i = 0; i < functions.Length(); i++) { |
+ func ^= functions.At(i); |
+ ASSERT(!func.IsNull()); |
+ if (!func.HasCode() && !func.IsAbstract()) { |
+ const Error& error = Error::Handle(CompileFunction(func)); |
+ if (!error.IsNull()) { |
+ return error.raw(); |
+ } |
+ } |
} |
+ } else { |
+ error = isolate->object_store()->sticky_error(); |
+ isolate->object_store()->clear_sticky_error(); |
} |
+ isolate->set_long_jump_base(base); |
+ return error.raw(); |
} |
-RawInstance* Compiler::ExecuteOnce(SequenceNode* fragment) { |
- if (FLAG_trace_compiler) { |
- OS::Print("compiling expression: "); |
- AstPrinter::PrintNode(fragment); |
- } |
+RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
+ Isolate* isolate = Isolate::Current(); |
+ Object& result = Object::Handle(); |
+ LongJump* base = isolate->long_jump_base(); |
+ LongJump jump; |
+ isolate->set_long_jump_base(&jump); |
+ if (setjmp(*jump.Set()) == 0) { |
+ if (FLAG_trace_compiler) { |
+ OS::Print("compiling expression: "); |
+ AstPrinter::PrintNode(fragment); |
+ } |
- // Create a dummy function object for the code generator. |
- const char* kEvalConst = "eval_const"; |
- const Function& func = Function::Handle(Function::New( |
- String::Handle(String::NewSymbol(kEvalConst)), |
- RawFunction::kConstImplicitGetter, |
- true, // static function. |
- false, // not const function. |
- fragment->token_index())); |
+ // Create a dummy function object for the code generator. |
+ const char* kEvalConst = "eval_const"; |
+ const Function& func = Function::Handle(Function::New( |
+ String::Handle(String::NewSymbol(kEvalConst)), |
+ RawFunction::kConstImplicitGetter, |
+ true, // static function. |
+ false, // not const function. |
+ fragment->token_index())); |
- func.set_result_type(Type::Handle(Type::DynamicType())); |
- func.set_num_fixed_parameters(0); |
- func.set_num_optional_parameters(0); |
+ func.set_result_type(Type::Handle(Type::DynamicType())); |
+ func.set_num_fixed_parameters(0); |
+ func.set_num_optional_parameters(0); |
- // The function needs to be associated with a named Class: the interface |
- // Function fits the bill. |
- func.set_owner(Class::Handle( |
- Type::Handle(Type::FunctionInterface()).type_class())); |
+ // The function needs to be associated with a named Class: the interface |
+ // Function fits the bill. |
+ func.set_owner(Class::Handle( |
+ Type::Handle(Type::FunctionInterface()).type_class())); |
- // We compile the function here, even though InvokeStatic() below |
- // would compile func automatically. We are checking fewer invariants |
- // here. |
- ParsedFunction parsed_function(func); |
- parsed_function.set_node_sequence(fragment); |
- parsed_function.set_default_parameter_values(Array::Handle()); |
+ // We compile the function here, even though InvokeStatic() below |
+ // would compile func automatically. We are checking fewer invariants |
+ // here. |
+ ParsedFunction parsed_function(func); |
+ parsed_function.set_node_sequence(fragment); |
+ parsed_function.set_default_parameter_values(Array::Handle()); |
- Assembler assembler; |
- CodeGenerator code_gen(&assembler, parsed_function); |
- code_gen.GenerateCode(); |
- const Code& code = Code::Handle(Code::FinalizeCode(kEvalConst, &assembler)); |
+ Assembler assembler; |
+ CodeGenerator code_gen(&assembler, parsed_function); |
+ code_gen.GenerateCode(); |
+ const Code& code = Code::Handle(Code::FinalizeCode(kEvalConst, &assembler)); |
- func.SetCode(code); |
- CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); |
- ASSERT(code_index_table != NULL); |
- code_index_table->AddFunction(func); |
- // TODO(hausner): We need a way to remove these one-time execution |
- // functions from the global code description (PC mapping) tables so |
- // we don't pollute the system unnecessarily with stale data. |
- code_gen.FinalizePcDescriptors(code); |
- code_gen.FinalizeExceptionHandlers(code); |
+ func.SetCode(code); |
+ CodeIndexTable* code_index_table = isolate->code_index_table(); |
+ ASSERT(code_index_table != NULL); |
+ code_index_table->AddFunction(func); |
+ // TODO(hausner): We need a way to remove these one-time execution |
+ // functions from the global code description (PC mapping) tables so |
+ // we don't pollute the system unnecessarily with stale data. |
+ code_gen.FinalizePcDescriptors(code); |
+ code_gen.FinalizeExceptionHandlers(code); |
- GrowableArray<const Object*> arguments; // no arguments. |
- const Array& kNoArgumentNames = Array::Handle(); |
- Instance& result = Instance::Handle( |
- DartEntry::InvokeStatic(func, |
- arguments, |
- kNoArgumentNames)); |
- if (result.IsUnhandledException()) { |
- // TODO(srdjan): implement proper exit from compiler. |
- UNIMPLEMENTED(); |
+ GrowableArray<const Object*> arguments; // no arguments. |
+ const Array& kNoArgumentNames = Array::Handle(); |
+ result = DartEntry::InvokeStatic(func, |
+ arguments, |
+ kNoArgumentNames); |
+ } else { |
+ result = isolate->object_store()->sticky_error(); |
+ isolate->object_store()->clear_sticky_error(); |
} |
+ isolate->set_long_jump_base(base); |
return result.raw(); |
} |