| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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/compiler.h" | 5 #include "vm/compiler.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/code_index_table.h" | 10 #include "vm/code_index_table.h" |
| 11 #include "vm/code_patcher.h" | 11 #include "vm/code_patcher.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/disassembler.h" | 13 #include "vm/disassembler.h" |
| 14 #include "vm/exceptions.h" |
| 14 #include "vm/flags.h" | 15 #include "vm/flags.h" |
| 16 #include "vm/longjump.h" |
| 15 #include "vm/object.h" | 17 #include "vm/object.h" |
| 16 #include "vm/object_store.h" | 18 #include "vm/object_store.h" |
| 17 #include "vm/opt_code_generator.h" | 19 #include "vm/opt_code_generator.h" |
| 18 #include "vm/os.h" | 20 #include "vm/os.h" |
| 19 #include "vm/parser.h" | 21 #include "vm/parser.h" |
| 20 #include "vm/scanner.h" | 22 #include "vm/scanner.h" |
| 21 #include "vm/timer.h" | 23 #include "vm/timer.h" |
| 22 | 24 |
| 23 namespace dart { | 25 namespace dart { |
| 24 | 26 |
| 25 DEFINE_FLAG(bool, disassemble, false, "Disassemble dart code."); | 27 DEFINE_FLAG(bool, disassemble, false, "Disassemble dart code."); |
| 26 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); | 28 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations."); |
| 27 DEFINE_FLAG(int, deoptimization_counter_threshold, 5, | 29 DEFINE_FLAG(int, deoptimization_counter_threshold, 5, |
| 28 "How many times we allow deoptimization before we disallow" | 30 "How many times we allow deoptimization before we disallow" |
| 29 " certain optimizations"); | 31 " certain optimizations"); |
| 30 | 32 |
| 31 | 33 |
| 32 // Compile a function. Should call only if the function has not been compiled. | 34 // Compile a function. Should call only if the function has not been compiled. |
| 33 // Arg0: function object. | 35 // Arg0: function object. |
| 34 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { | 36 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) { |
| 35 ASSERT(arguments.Count() == kCompileFunctionRuntimeEntry.argument_count()); | 37 ASSERT(arguments.Count() == kCompileFunctionRuntimeEntry.argument_count()); |
| 36 const Function& function = Function::CheckedHandle(arguments.At(0)); | 38 const Function& function = Function::CheckedHandle(arguments.At(0)); |
| 37 ASSERT(!function.HasCode()); | 39 ASSERT(!function.HasCode()); |
| 38 Compiler::CompileFunction(function); | 40 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
| 41 if (!error.IsNull()) { |
| 42 Exceptions::PropagateError(error); |
| 43 } |
| 39 } | 44 } |
| 40 | 45 |
| 41 | 46 |
| 42 // Extracts IC data associated with a node id. | 47 // Extracts IC data associated with a node id. |
| 43 // TODO(srdjan): Check performance impact of node id search loop. | 48 // TODO(srdjan): Check performance impact of node id search loop. |
| 44 static void ExtractTypeFeedback(const Code& code, | 49 static void ExtractTypeFeedback(const Code& code, |
| 45 SequenceNode* sequence_node) { | 50 SequenceNode* sequence_node) { |
| 46 ASSERT(!code.IsNull() && !code.is_optimized()); | 51 ASSERT(!code.IsNull() && !code.is_optimized()); |
| 47 GrowableArray<AstNode*> all_nodes; | 52 GrowableArray<AstNode*> all_nodes; |
| 48 sequence_node->CollectAllNodes(&all_nodes); | 53 sequence_node->CollectAllNodes(&all_nodes); |
| 49 GrowableArray<intptr_t> node_ids; | 54 GrowableArray<intptr_t> node_ids; |
| 50 GrowableArray<const Array*> arrays; | 55 GrowableArray<const Array*> arrays; |
| 51 code.ExtractIcDataArraysAtCalls(&node_ids, &arrays); | 56 code.ExtractIcDataArraysAtCalls(&node_ids, &arrays); |
| 52 for (intptr_t i = 0; i < node_ids.length(); i++) { | 57 for (intptr_t i = 0; i < node_ids.length(); i++) { |
| 53 intptr_t node_id = node_ids[i]; | 58 intptr_t node_id = node_ids[i]; |
| 54 bool found_node = false; | 59 bool found_node = false; |
| 55 for (intptr_t n = 0; n < all_nodes.length(); n++) { | 60 for (intptr_t n = 0; n < all_nodes.length(); n++) { |
| 56 if (all_nodes[n]->HasId(node_id)) { | 61 if (all_nodes[n]->HasId(node_id)) { |
| 57 found_node = true; | 62 found_node = true; |
| 58 // Make sure we assign ic data array only once. | 63 // Make sure we assign ic data array only once. |
| 59 ASSERT(all_nodes[n]->ICDataAtId(node_id).NumberOfChecks() == 0); | 64 ASSERT(all_nodes[n]->ICDataAtId(node_id).NumberOfChecks() == 0); |
| 60 all_nodes[n]->SetIcDataArrayAtId(node_id, *arrays[i]); | 65 all_nodes[n]->SetIcDataArrayAtId(node_id, *arrays[i]); |
| 61 } | 66 } |
| 62 } | 67 } |
| 63 ASSERT(found_node); | 68 ASSERT(found_node); |
| 64 } | 69 } |
| 65 } | 70 } |
| 66 | 71 |
| 67 | 72 |
| 68 void Compiler::Compile(const Library& library, const Script& script) { | 73 RawError* Compiler::Compile(const Library& library, const Script& script) { |
| 69 if (FLAG_trace_compiler) { | 74 Isolate* isolate = Isolate::Current(); |
| 70 HANDLESCOPE(Isolate::Current()); | 75 Error& error = Error::Handle(); |
| 71 const String& script_url = String::Handle(script.url()); | 76 LongJump* base = isolate->long_jump_base(); |
| 72 // TODO(iposva): Extract script kind. | 77 LongJump jump; |
| 73 OS::Print("Compiling %s '%s'\n", "", script_url.ToCString()); | 78 isolate->set_long_jump_base(&jump); |
| 74 } | 79 if (setjmp(*jump.Set()) == 0) { |
| 75 const String& library_key = String::Handle(library.private_key()); | 80 if (FLAG_trace_compiler) { |
| 76 script.Tokenize(library_key); | 81 HANDLESCOPE(isolate); |
| 77 Parser::ParseCompilationUnit(library, script); | 82 const String& script_url = String::Handle(script.url()); |
| 78 } | 83 // TODO(iposva): Extract script kind. |
| 79 | 84 OS::Print("Compiling %s '%s'\n", "", script_url.ToCString()); |
| 80 | 85 } |
| 81 static void CompileFunctionHelper(const Function& function, bool optimized) { | 86 const String& library_key = String::Handle(library.private_key()); |
| 82 TIMERSCOPE(time_compilation); | 87 script.Tokenize(library_key); |
| 83 ParsedFunction parsed_function(function); | 88 Parser::ParseCompilationUnit(library, script); |
| 84 const char* function_fullname = function.ToFullyQualifiedCString(); | 89 } else { |
| 85 if (FLAG_trace_compiler) { | 90 error = isolate->object_store()->sticky_error(); |
| 86 OS::Print("Compiling %sfunction: '%s' @ token %d\n", | 91 isolate->object_store()->clear_sticky_error(); |
| 87 (optimized ? "optimized " : ""), | 92 } |
| 88 function_fullname, | 93 isolate->set_long_jump_base(base); |
| 89 function.token_index()); | 94 return error.raw(); |
| 90 } | 95 } |
| 91 Parser::ParseFunction(&parsed_function); | 96 |
| 92 CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); | 97 |
| 93 ASSERT(code_index_table != NULL); | 98 static RawError* CompileFunctionHelper(const Function& function, |
| 94 Assembler assembler; | 99 bool optimized) { |
| 95 if (optimized) { | 100 Isolate* isolate = Isolate::Current(); |
| 96 // Transition to optimized code only from unoptimized code ... for now. | 101 Error& error = Error::Handle(); |
| 97 ASSERT(function.HasCode()); | 102 LongJump* base = isolate->long_jump_base(); |
| 98 ASSERT(!Code::Handle(function.code()).is_optimized()); | 103 LongJump jump; |
| 99 // Do not use type feedback to optimize a function that was deoptimized. | 104 isolate->set_long_jump_base(&jump); |
| 100 if (parsed_function.function().deoptimization_counter() < | 105 if (setjmp(*jump.Set()) == 0) { |
| 101 FLAG_deoptimization_counter_threshold) { | 106 TIMERSCOPE(time_compilation); |
| 102 ExtractTypeFeedback(Code::Handle(parsed_function.function().code()), | 107 ParsedFunction parsed_function(function); |
| 103 parsed_function.node_sequence()); | 108 const char* function_fullname = function.ToFullyQualifiedCString(); |
| 104 } | 109 if (FLAG_trace_compiler) { |
| 105 OptimizingCodeGenerator code_gen(&assembler, parsed_function); | 110 OS::Print("Compiling %sfunction: '%s' @ token %d\n", |
| 111 (optimized ? "optimized " : ""), |
| 112 function_fullname, |
| 113 function.token_index()); |
| 114 } |
| 115 Parser::ParseFunction(&parsed_function); |
| 116 CodeIndexTable* code_index_table = isolate->code_index_table(); |
| 117 ASSERT(code_index_table != NULL); |
| 118 Assembler assembler; |
| 119 if (optimized) { |
| 120 // Transition to optimized code only from unoptimized code ... for now. |
| 121 ASSERT(function.HasCode()); |
| 122 ASSERT(!Code::Handle(function.code()).is_optimized()); |
| 123 // Do not use type feedback to optimize a function that was deoptimized. |
| 124 if (parsed_function.function().deoptimization_counter() < |
| 125 FLAG_deoptimization_counter_threshold) { |
| 126 ExtractTypeFeedback(Code::Handle(parsed_function.function().code()), |
| 127 parsed_function.node_sequence()); |
| 128 } |
| 129 OptimizingCodeGenerator code_gen(&assembler, parsed_function); |
| 130 code_gen.GenerateCode(); |
| 131 Code& code = Code::Handle( |
| 132 Code::FinalizeCode(function_fullname, &assembler)); |
| 133 code.set_is_optimized(true); |
| 134 code_gen.FinalizePcDescriptors(code); |
| 135 code_gen.FinalizeExceptionHandlers(code); |
| 136 function.SetCode(code); |
| 137 code_index_table->AddFunction(function); |
| 138 CodePatcher::PatchEntry(Code::Handle(function.unoptimized_code())); |
| 139 if (FLAG_trace_compiler) { |
| 140 OS::Print("--> patching entry 0x%x\n", |
| 141 Code::Handle(function.unoptimized_code()).EntryPoint()); |
| 142 } |
| 143 } else { |
| 144 // Unoptimized code. |
| 145 if (Code::Handle(function.unoptimized_code()).IsNull()) { |
| 146 ASSERT(Code::Handle(function.code()).IsNull()); |
| 147 // Compiling first time. |
| 148 CodeGenerator code_gen(&assembler, parsed_function); |
| 149 code_gen.GenerateCode(); |
| 150 const Code& code = |
| 151 Code::Handle(Code::FinalizeCode(function_fullname, &assembler)); |
| 152 code.set_is_optimized(false); |
| 153 code_gen.FinalizePcDescriptors(code); |
| 154 code_gen.FinalizeVarDescriptors(code); |
| 155 code_gen.FinalizeExceptionHandlers(code); |
| 156 function.set_unoptimized_code(code); |
| 157 function.SetCode(code); |
| 158 ASSERT(CodePatcher::CodeIsPatchable(code)); |
| 159 code_index_table->AddFunction(function); |
| 160 } else { |
| 161 // Disable optimized code. |
| 162 const Code& optimized_code = Code::Handle(function.code()); |
| 163 ASSERT(optimized_code.is_optimized()); |
| 164 CodePatcher::PatchEntry(Code::Handle(function.code())); |
| 165 if (FLAG_trace_compiler) { |
| 166 OS::Print("--> patching entry 0x%x\n", |
| 167 Code::Handle(function.unoptimized_code()).EntryPoint()); |
| 168 } |
| 169 // Use previously compiled code. |
| 170 function.SetCode(Code::Handle(function.unoptimized_code())); |
| 171 CodePatcher::RestoreEntry(Code::Handle(function.unoptimized_code())); |
| 172 if (FLAG_trace_compiler) { |
| 173 OS::Print("--> restoring entry at 0x%x\n", |
| 174 Code::Handle(function.unoptimized_code()).EntryPoint()); |
| 175 } |
| 176 } |
| 177 } |
| 178 if (FLAG_trace_compiler) { |
| 179 OS::Print("--> '%s' entry: 0x%x\n", |
| 180 function_fullname, Code::Handle(function.code()).EntryPoint()); |
| 181 } |
| 182 if (FLAG_disassemble) { |
| 183 OS::Print("Code for %sfunction '%s' {\n", |
| 184 optimized ? "optimized " : "", function_fullname); |
| 185 const Code& code = Code::Handle(function.code()); |
| 186 const Instructions& instructions = |
| 187 Instructions::Handle(code.instructions()); |
| 188 uword start = instructions.EntryPoint(); |
| 189 Disassembler::Disassemble(start, start + assembler.CodeSize()); |
| 190 OS::Print("}\n"); |
| 191 OS::Print("Pointer offsets for function: {\n"); |
| 192 for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { |
| 193 const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
| 194 Object& obj = Object::Handle(); |
| 195 obj = *reinterpret_cast<RawObject**>(addr); |
| 196 OS::Print(" %d : 0x%x '%s'\n", |
| 197 code.GetPointerOffsetAt(i), addr, obj.ToCString()); |
| 198 } |
| 199 OS::Print("}\n"); |
| 200 OS::Print("PC Descriptors for function '%s' {\n", function_fullname); |
| 201 OS::Print("(pc, kind, id, try-index, token-index)\n"); |
| 202 const PcDescriptors& descriptors = |
| 203 PcDescriptors::Handle(code.pc_descriptors()); |
| 204 OS::Print("%s", descriptors.ToCString()); |
| 205 OS::Print("}\n"); |
| 206 OS::Print("Variable Descriptors for function '%s' {\n", |
| 207 function_fullname); |
| 208 const LocalVarDescriptors& var_descriptors = |
| 209 LocalVarDescriptors::Handle(code.var_descriptors()); |
| 210 intptr_t var_desc_length = var_descriptors.Length(); |
| 211 String& var_name = String::Handle(); |
| 212 for (intptr_t i = 0; i < var_desc_length; i++) { |
| 213 var_name = var_descriptors.GetName(i); |
| 214 intptr_t scope_id, ignore; |
| 215 var_descriptors.GetScopeInfo(i, &scope_id, &ignore, &ignore); |
| 216 intptr_t slot = var_descriptors.GetSlotIndex(i); |
| 217 OS::Print(" var %s scope %ld offset %ld\n", |
| 218 var_name.ToCString(), scope_id, slot); |
| 219 } |
| 220 OS::Print("}\n"); |
| 221 OS::Print("Exception Handlers for function '%s' {\n", function_fullname); |
| 222 const ExceptionHandlers& handlers = |
| 223 ExceptionHandlers::Handle(code.exception_handlers()); |
| 224 OS::Print("%s", handlers.ToCString()); |
| 225 OS::Print("}\n"); |
| 226 } |
| 227 } else { |
| 228 // We got an error during compilation. |
| 229 error = isolate->object_store()->sticky_error(); |
| 230 isolate->object_store()->clear_sticky_error(); |
| 231 } |
| 232 isolate->set_long_jump_base(base); |
| 233 return error.raw(); |
| 234 } |
| 235 |
| 236 |
| 237 RawError* Compiler::CompileFunction(const Function& function) { |
| 238 return CompileFunctionHelper(function, false); |
| 239 } |
| 240 |
| 241 |
| 242 RawError* Compiler::CompileOptimizedFunction(const Function& function) { |
| 243 return CompileFunctionHelper(function, true); |
| 244 } |
| 245 |
| 246 |
| 247 RawError* Compiler::CompileAllFunctions(const Class& cls) { |
| 248 Isolate* isolate = Isolate::Current(); |
| 249 Error& error = Error::Handle(); |
| 250 LongJump* base = isolate->long_jump_base(); |
| 251 LongJump jump; |
| 252 isolate->set_long_jump_base(&jump); |
| 253 if (setjmp(*jump.Set()) == 0) { |
| 254 Array& functions = Array::Handle(cls.functions()); |
| 255 Function& func = Function::Handle(); |
| 256 for (int i = 0; i < functions.Length(); i++) { |
| 257 func ^= functions.At(i); |
| 258 ASSERT(!func.IsNull()); |
| 259 if (!func.HasCode() && !func.IsAbstract()) { |
| 260 const Error& error = Error::Handle(CompileFunction(func)); |
| 261 if (!error.IsNull()) { |
| 262 return error.raw(); |
| 263 } |
| 264 } |
| 265 } |
| 266 } else { |
| 267 error = isolate->object_store()->sticky_error(); |
| 268 isolate->object_store()->clear_sticky_error(); |
| 269 } |
| 270 isolate->set_long_jump_base(base); |
| 271 return error.raw(); |
| 272 } |
| 273 |
| 274 |
| 275 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { |
| 276 Isolate* isolate = Isolate::Current(); |
| 277 Object& result = Object::Handle(); |
| 278 LongJump* base = isolate->long_jump_base(); |
| 279 LongJump jump; |
| 280 isolate->set_long_jump_base(&jump); |
| 281 if (setjmp(*jump.Set()) == 0) { |
| 282 if (FLAG_trace_compiler) { |
| 283 OS::Print("compiling expression: "); |
| 284 AstPrinter::PrintNode(fragment); |
| 285 } |
| 286 |
| 287 // Create a dummy function object for the code generator. |
| 288 const char* kEvalConst = "eval_const"; |
| 289 const Function& func = Function::Handle(Function::New( |
| 290 String::Handle(String::NewSymbol(kEvalConst)), |
| 291 RawFunction::kConstImplicitGetter, |
| 292 true, // static function. |
| 293 false, // not const function. |
| 294 fragment->token_index())); |
| 295 |
| 296 func.set_result_type(Type::Handle(Type::DynamicType())); |
| 297 func.set_num_fixed_parameters(0); |
| 298 func.set_num_optional_parameters(0); |
| 299 |
| 300 // The function needs to be associated with a named Class: the interface |
| 301 // Function fits the bill. |
| 302 func.set_owner(Class::Handle( |
| 303 Type::Handle(Type::FunctionInterface()).type_class())); |
| 304 |
| 305 // We compile the function here, even though InvokeStatic() below |
| 306 // would compile func automatically. We are checking fewer invariants |
| 307 // here. |
| 308 ParsedFunction parsed_function(func); |
| 309 parsed_function.set_node_sequence(fragment); |
| 310 parsed_function.set_default_parameter_values(Array::Handle()); |
| 311 |
| 312 Assembler assembler; |
| 313 CodeGenerator code_gen(&assembler, parsed_function); |
| 106 code_gen.GenerateCode(); | 314 code_gen.GenerateCode(); |
| 107 Code& code = Code::Handle( | 315 const Code& code = Code::Handle(Code::FinalizeCode(kEvalConst, &assembler)); |
| 108 Code::FinalizeCode(function_fullname, &assembler)); | 316 |
| 109 code.set_is_optimized(true); | 317 func.SetCode(code); |
| 318 CodeIndexTable* code_index_table = isolate->code_index_table(); |
| 319 ASSERT(code_index_table != NULL); |
| 320 code_index_table->AddFunction(func); |
| 321 // TODO(hausner): We need a way to remove these one-time execution |
| 322 // functions from the global code description (PC mapping) tables so |
| 323 // we don't pollute the system unnecessarily with stale data. |
| 110 code_gen.FinalizePcDescriptors(code); | 324 code_gen.FinalizePcDescriptors(code); |
| 111 code_gen.FinalizeExceptionHandlers(code); | 325 code_gen.FinalizeExceptionHandlers(code); |
| 112 function.SetCode(code); | 326 |
| 113 code_index_table->AddFunction(function); | 327 GrowableArray<const Object*> arguments; // no arguments. |
| 114 CodePatcher::PatchEntry(Code::Handle(function.unoptimized_code())); | 328 const Array& kNoArgumentNames = Array::Handle(); |
| 115 if (FLAG_trace_compiler) { | 329 result = DartEntry::InvokeStatic(func, |
| 116 OS::Print("--> patching entry 0x%x\n", | 330 arguments, |
| 117 Code::Handle(function.unoptimized_code()).EntryPoint()); | 331 kNoArgumentNames); |
| 118 } | 332 } else { |
| 119 } else { | 333 result = isolate->object_store()->sticky_error(); |
| 120 // Unoptimized code. | 334 isolate->object_store()->clear_sticky_error(); |
| 121 if (Code::Handle(function.unoptimized_code()).IsNull()) { | 335 } |
| 122 ASSERT(Code::Handle(function.code()).IsNull()); | 336 isolate->set_long_jump_base(base); |
| 123 // Compiling first time. | |
| 124 CodeGenerator code_gen(&assembler, parsed_function); | |
| 125 code_gen.GenerateCode(); | |
| 126 const Code& code = | |
| 127 Code::Handle(Code::FinalizeCode(function_fullname, &assembler)); | |
| 128 code.set_is_optimized(false); | |
| 129 code_gen.FinalizePcDescriptors(code); | |
| 130 code_gen.FinalizeVarDescriptors(code); | |
| 131 code_gen.FinalizeExceptionHandlers(code); | |
| 132 function.set_unoptimized_code(code); | |
| 133 function.SetCode(code); | |
| 134 ASSERT(CodePatcher::CodeIsPatchable(code)); | |
| 135 code_index_table->AddFunction(function); | |
| 136 } else { | |
| 137 // Disable optimized code. | |
| 138 const Code& optimized_code = Code::Handle(function.code()); | |
| 139 ASSERT(optimized_code.is_optimized()); | |
| 140 CodePatcher::PatchEntry(Code::Handle(function.code())); | |
| 141 if (FLAG_trace_compiler) { | |
| 142 OS::Print("--> patching entry 0x%x\n", | |
| 143 Code::Handle(function.unoptimized_code()).EntryPoint()); | |
| 144 } | |
| 145 // Use previously compiled code. | |
| 146 function.SetCode(Code::Handle(function.unoptimized_code())); | |
| 147 CodePatcher::RestoreEntry(Code::Handle(function.unoptimized_code())); | |
| 148 if (FLAG_trace_compiler) { | |
| 149 OS::Print("--> restoring entry at 0x%x\n", | |
| 150 Code::Handle(function.unoptimized_code()).EntryPoint()); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 if (FLAG_trace_compiler) { | |
| 155 OS::Print("--> '%s' entry: 0x%x\n", | |
| 156 function_fullname, Code::Handle(function.code()).EntryPoint()); | |
| 157 } | |
| 158 if (FLAG_disassemble) { | |
| 159 OS::Print("Code for %sfunction '%s' {\n", | |
| 160 optimized ? "optimized " : "", function_fullname); | |
| 161 const Code& code = Code::Handle(function.code()); | |
| 162 const Instructions& instructions = | |
| 163 Instructions::Handle(code.instructions()); | |
| 164 uword start = instructions.EntryPoint(); | |
| 165 Disassembler::Disassemble(start, start + assembler.CodeSize()); | |
| 166 OS::Print("}\n"); | |
| 167 OS::Print("Pointer offsets for function: {\n"); | |
| 168 for (intptr_t i = 0; i < code.pointer_offsets_length(); i++) { | |
| 169 const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); | |
| 170 Object& obj = Object::Handle(); | |
| 171 obj = *reinterpret_cast<RawObject**>(addr); | |
| 172 OS::Print(" %d : 0x%x '%s'\n", | |
| 173 code.GetPointerOffsetAt(i), addr, obj.ToCString()); | |
| 174 } | |
| 175 OS::Print("}\n"); | |
| 176 OS::Print("PC Descriptors for function '%s' {\n", function_fullname); | |
| 177 OS::Print("(pc, kind, id, try-index, token-index)\n"); | |
| 178 const PcDescriptors& descriptors = | |
| 179 PcDescriptors::Handle(code.pc_descriptors()); | |
| 180 OS::Print("%s", descriptors.ToCString()); | |
| 181 OS::Print("}\n"); | |
| 182 OS::Print("Variable Descriptors for function '%s' {\n", function_fullname); | |
| 183 const LocalVarDescriptors& var_descriptors = | |
| 184 LocalVarDescriptors::Handle(code.var_descriptors()); | |
| 185 intptr_t var_desc_length = var_descriptors.Length(); | |
| 186 String& var_name = String::Handle(); | |
| 187 for (intptr_t i = 0; i < var_desc_length; i++) { | |
| 188 var_name = var_descriptors.GetName(i); | |
| 189 intptr_t scope_id, ignore; | |
| 190 var_descriptors.GetScopeInfo(i, &scope_id, &ignore, &ignore); | |
| 191 intptr_t slot = var_descriptors.GetSlotIndex(i); | |
| 192 OS::Print(" var %s scope %ld offset %ld\n", | |
| 193 var_name.ToCString(), scope_id, slot); | |
| 194 } | |
| 195 OS::Print("}\n"); | |
| 196 OS::Print("Exception Handlers for function '%s' {\n", function_fullname); | |
| 197 const ExceptionHandlers& handlers = | |
| 198 ExceptionHandlers::Handle(code.exception_handlers()); | |
| 199 OS::Print("%s", handlers.ToCString()); | |
| 200 OS::Print("}\n"); | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 | |
| 205 void Compiler::CompileFunction(const Function& function) { | |
| 206 CompileFunctionHelper(function, false); | |
| 207 } | |
| 208 | |
| 209 | |
| 210 void Compiler::CompileOptimizedFunction(const Function& function) { | |
| 211 CompileFunctionHelper(function, true); | |
| 212 } | |
| 213 | |
| 214 | |
| 215 void Compiler::CompileAllFunctions(const Class& cls) { | |
| 216 Array& functions = Array::Handle(cls.functions()); | |
| 217 Function& func = Function::Handle(); | |
| 218 for (int i = 0; i < functions.Length(); i++) { | |
| 219 func ^= functions.At(i); | |
| 220 ASSERT(!func.IsNull()); | |
| 221 if (!func.HasCode() && !func.IsAbstract()) { | |
| 222 CompileFunction(func); | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 | |
| 228 RawInstance* Compiler::ExecuteOnce(SequenceNode* fragment) { | |
| 229 if (FLAG_trace_compiler) { | |
| 230 OS::Print("compiling expression: "); | |
| 231 AstPrinter::PrintNode(fragment); | |
| 232 } | |
| 233 | |
| 234 // Create a dummy function object for the code generator. | |
| 235 const char* kEvalConst = "eval_const"; | |
| 236 const Function& func = Function::Handle(Function::New( | |
| 237 String::Handle(String::NewSymbol(kEvalConst)), | |
| 238 RawFunction::kConstImplicitGetter, | |
| 239 true, // static function. | |
| 240 false, // not const function. | |
| 241 fragment->token_index())); | |
| 242 | |
| 243 func.set_result_type(Type::Handle(Type::DynamicType())); | |
| 244 func.set_num_fixed_parameters(0); | |
| 245 func.set_num_optional_parameters(0); | |
| 246 | |
| 247 // The function needs to be associated with a named Class: the interface | |
| 248 // Function fits the bill. | |
| 249 func.set_owner(Class::Handle( | |
| 250 Type::Handle(Type::FunctionInterface()).type_class())); | |
| 251 | |
| 252 // We compile the function here, even though InvokeStatic() below | |
| 253 // would compile func automatically. We are checking fewer invariants | |
| 254 // here. | |
| 255 ParsedFunction parsed_function(func); | |
| 256 parsed_function.set_node_sequence(fragment); | |
| 257 parsed_function.set_default_parameter_values(Array::Handle()); | |
| 258 | |
| 259 Assembler assembler; | |
| 260 CodeGenerator code_gen(&assembler, parsed_function); | |
| 261 code_gen.GenerateCode(); | |
| 262 const Code& code = Code::Handle(Code::FinalizeCode(kEvalConst, &assembler)); | |
| 263 | |
| 264 func.SetCode(code); | |
| 265 CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); | |
| 266 ASSERT(code_index_table != NULL); | |
| 267 code_index_table->AddFunction(func); | |
| 268 // TODO(hausner): We need a way to remove these one-time execution | |
| 269 // functions from the global code description (PC mapping) tables so | |
| 270 // we don't pollute the system unnecessarily with stale data. | |
| 271 code_gen.FinalizePcDescriptors(code); | |
| 272 code_gen.FinalizeExceptionHandlers(code); | |
| 273 | |
| 274 GrowableArray<const Object*> arguments; // no arguments. | |
| 275 const Array& kNoArgumentNames = Array::Handle(); | |
| 276 Instance& result = Instance::Handle( | |
| 277 DartEntry::InvokeStatic(func, | |
| 278 arguments, | |
| 279 kNoArgumentNames)); | |
| 280 if (result.IsUnhandledException()) { | |
| 281 // TODO(srdjan): implement proper exit from compiler. | |
| 282 UNIMPLEMENTED(); | |
| 283 } | |
| 284 return result.raw(); | 337 return result.raw(); |
| 285 } | 338 } |
| 286 | 339 |
| 287 | 340 |
| 288 } // namespace dart | 341 } // namespace dart |
| OLD | NEW |