| 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 = | 
|  | 211           var_descriptors.IsNull() ? 0 : var_descriptors.Length(); | 
|  | 212       String& var_name = String::Handle(); | 
|  | 213       for (intptr_t i = 0; i < var_desc_length; i++) { | 
|  | 214         var_name = var_descriptors.GetName(i); | 
|  | 215         intptr_t scope_id, begin_pos, end_pos; | 
|  | 216         var_descriptors.GetScopeInfo(i, &scope_id, &begin_pos, &end_pos); | 
|  | 217         intptr_t slot = var_descriptors.GetSlotIndex(i); | 
|  | 218         OS::Print("  var %s scope %ld (valid %d-%d) offset %ld\n", | 
|  | 219                   var_name.ToCString(), scope_id, begin_pos, end_pos, slot); | 
|  | 220       } | 
|  | 221       OS::Print("}\n"); | 
|  | 222       OS::Print("Exception Handlers for function '%s' {\n", function_fullname); | 
|  | 223       const ExceptionHandlers& handlers = | 
|  | 224           ExceptionHandlers::Handle(code.exception_handlers()); | 
|  | 225       OS::Print("%s", handlers.ToCString()); | 
|  | 226       OS::Print("}\n"); | 
|  | 227     } | 
|  | 228   } else { | 
|  | 229     // We got an error during compilation. | 
|  | 230     error = isolate->object_store()->sticky_error(); | 
|  | 231     isolate->object_store()->clear_sticky_error(); | 
|  | 232   } | 
|  | 233   isolate->set_long_jump_base(base); | 
|  | 234   return error.raw(); | 
|  | 235 } | 
|  | 236 | 
|  | 237 | 
|  | 238 RawError* Compiler::CompileFunction(const Function& function) { | 
|  | 239   return CompileFunctionHelper(function, false); | 
|  | 240 } | 
|  | 241 | 
|  | 242 | 
|  | 243 RawError* Compiler::CompileOptimizedFunction(const Function& function) { | 
|  | 244   return CompileFunctionHelper(function, true); | 
|  | 245 } | 
|  | 246 | 
|  | 247 | 
|  | 248 RawError* Compiler::CompileAllFunctions(const Class& cls) { | 
|  | 249   Isolate* isolate = Isolate::Current(); | 
|  | 250   Error& error = Error::Handle(); | 
|  | 251   LongJump* base = isolate->long_jump_base(); | 
|  | 252   LongJump jump; | 
|  | 253   isolate->set_long_jump_base(&jump); | 
|  | 254   if (setjmp(*jump.Set()) == 0) { | 
|  | 255     Array& functions = Array::Handle(cls.functions()); | 
|  | 256     Function& func = Function::Handle(); | 
|  | 257     for (int i = 0; i < functions.Length(); i++) { | 
|  | 258       func ^= functions.At(i); | 
|  | 259       ASSERT(!func.IsNull()); | 
|  | 260       if (!func.HasCode() && !func.IsAbstract()) { | 
|  | 261         const Error& error = Error::Handle(CompileFunction(func)); | 
|  | 262         if (!error.IsNull()) { | 
|  | 263           return error.raw(); | 
|  | 264         } | 
|  | 265       } | 
|  | 266     } | 
|  | 267   } else { | 
|  | 268     error = isolate->object_store()->sticky_error(); | 
|  | 269     isolate->object_store()->clear_sticky_error(); | 
|  | 270   } | 
|  | 271   isolate->set_long_jump_base(base); | 
|  | 272   return error.raw(); | 
|  | 273 } | 
|  | 274 | 
|  | 275 | 
|  | 276 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) { | 
|  | 277   Isolate* isolate = Isolate::Current(); | 
|  | 278   Object& result = Object::Handle(); | 
|  | 279   LongJump* base = isolate->long_jump_base(); | 
|  | 280   LongJump jump; | 
|  | 281   isolate->set_long_jump_base(&jump); | 
|  | 282   if (setjmp(*jump.Set()) == 0) { | 
|  | 283     if (FLAG_trace_compiler) { | 
|  | 284       OS::Print("compiling expression: "); | 
|  | 285       AstPrinter::PrintNode(fragment); | 
|  | 286     } | 
|  | 287 | 
|  | 288     // Create a dummy function object for the code generator. | 
|  | 289     const char* kEvalConst = "eval_const"; | 
|  | 290     const Function& func = Function::Handle(Function::New( | 
|  | 291         String::Handle(String::NewSymbol(kEvalConst)), | 
|  | 292         RawFunction::kConstImplicitGetter, | 
|  | 293         true,  // static function. | 
|  | 294         false,  // not const function. | 
|  | 295         fragment->token_index())); | 
|  | 296 | 
|  | 297     func.set_result_type(Type::Handle(Type::DynamicType())); | 
|  | 298     func.set_num_fixed_parameters(0); | 
|  | 299     func.set_num_optional_parameters(0); | 
|  | 300 | 
|  | 301     // The function needs to be associated with a named Class: the interface | 
|  | 302     // Function fits the bill. | 
|  | 303     func.set_owner(Class::Handle( | 
|  | 304         Type::Handle(Type::FunctionInterface()).type_class())); | 
|  | 305 | 
|  | 306     // We compile the function here, even though InvokeStatic() below | 
|  | 307     // would compile func automatically. We are checking fewer invariants | 
|  | 308     // here. | 
|  | 309     ParsedFunction parsed_function(func); | 
|  | 310     parsed_function.set_node_sequence(fragment); | 
|  | 311     parsed_function.set_default_parameter_values(Array::Handle()); | 
|  | 312 | 
|  | 313     Assembler assembler; | 
|  | 314     CodeGenerator code_gen(&assembler, parsed_function); | 
| 106     code_gen.GenerateCode(); | 315     code_gen.GenerateCode(); | 
| 107     Code& code = Code::Handle( | 316     const Code& code = Code::Handle(Code::FinalizeCode(kEvalConst, &assembler)); | 
| 108         Code::FinalizeCode(function_fullname, &assembler)); | 317 | 
| 109     code.set_is_optimized(true); | 318     func.SetCode(code); | 
|  | 319     CodeIndexTable* code_index_table = isolate->code_index_table(); | 
|  | 320     ASSERT(code_index_table != NULL); | 
|  | 321     code_index_table->AddFunction(func); | 
|  | 322     // TODO(hausner): We need a way to remove these one-time execution | 
|  | 323     // functions from the global code description (PC mapping) tables so | 
|  | 324     // we don't pollute the system unnecessarily with stale data. | 
| 110     code_gen.FinalizePcDescriptors(code); | 325     code_gen.FinalizePcDescriptors(code); | 
| 111     code_gen.FinalizeExceptionHandlers(code); | 326     code_gen.FinalizeExceptionHandlers(code); | 
| 112     function.SetCode(code); | 327 | 
| 113     code_index_table->AddFunction(function); | 328     GrowableArray<const Object*> arguments;  // no arguments. | 
| 114     CodePatcher::PatchEntry(Code::Handle(function.unoptimized_code())); | 329     const Array& kNoArgumentNames = Array::Handle(); | 
| 115     if (FLAG_trace_compiler) { | 330     result = DartEntry::InvokeStatic(func, | 
| 116       OS::Print("--> patching entry 0x%x\n", | 331                                      arguments, | 
| 117           Code::Handle(function.unoptimized_code()).EntryPoint()); | 332                                      kNoArgumentNames); | 
| 118     } | 333   } else { | 
| 119   } else { | 334     result = isolate->object_store()->sticky_error(); | 
| 120     // Unoptimized code. | 335     isolate->object_store()->clear_sticky_error(); | 
| 121     if (Code::Handle(function.unoptimized_code()).IsNull()) { | 336   } | 
| 122       ASSERT(Code::Handle(function.code()).IsNull()); | 337   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 = |  | 
| 186         var_descriptors.IsNull() ? 0 : var_descriptors.Length(); |  | 
| 187     String& var_name = String::Handle(); |  | 
| 188     for (intptr_t i = 0; i < var_desc_length; i++) { |  | 
| 189       var_name = var_descriptors.GetName(i); |  | 
| 190       intptr_t scope_id, begin_pos, end_pos; |  | 
| 191       var_descriptors.GetScopeInfo(i, &scope_id, &begin_pos, &end_pos); |  | 
| 192       intptr_t slot = var_descriptors.GetSlotIndex(i); |  | 
| 193       OS::Print("  var %s scope %ld (valid %d-%d) offset %ld\n", |  | 
| 194                 var_name.ToCString(), scope_id, begin_pos, end_pos, slot); |  | 
| 195     } |  | 
| 196     OS::Print("}\n"); |  | 
| 197     OS::Print("Exception Handlers for function '%s' {\n", function_fullname); |  | 
| 198     const ExceptionHandlers& handlers = |  | 
| 199         ExceptionHandlers::Handle(code.exception_handlers()); |  | 
| 200     OS::Print("%s", handlers.ToCString()); |  | 
| 201     OS::Print("}\n"); |  | 
| 202   } |  | 
| 203 } |  | 
| 204 |  | 
| 205 |  | 
| 206 void Compiler::CompileFunction(const Function& function) { |  | 
| 207   CompileFunctionHelper(function, false); |  | 
| 208 } |  | 
| 209 |  | 
| 210 |  | 
| 211 void Compiler::CompileOptimizedFunction(const Function& function) { |  | 
| 212   CompileFunctionHelper(function, true); |  | 
| 213 } |  | 
| 214 |  | 
| 215 |  | 
| 216 void Compiler::CompileAllFunctions(const Class& cls) { |  | 
| 217   Array& functions = Array::Handle(cls.functions()); |  | 
| 218   Function& func = Function::Handle(); |  | 
| 219   for (int i = 0; i < functions.Length(); i++) { |  | 
| 220     func ^= functions.At(i); |  | 
| 221     ASSERT(!func.IsNull()); |  | 
| 222     if (!func.HasCode() && !func.IsAbstract()) { |  | 
| 223       CompileFunction(func); |  | 
| 224     } |  | 
| 225   } |  | 
| 226 } |  | 
| 227 |  | 
| 228 |  | 
| 229 RawInstance* Compiler::ExecuteOnce(SequenceNode* fragment) { |  | 
| 230   if (FLAG_trace_compiler) { |  | 
| 231     OS::Print("compiling expression: "); |  | 
| 232     AstPrinter::PrintNode(fragment); |  | 
| 233   } |  | 
| 234 |  | 
| 235   // Create a dummy function object for the code generator. |  | 
| 236   const char* kEvalConst = "eval_const"; |  | 
| 237   const Function& func = Function::Handle(Function::New( |  | 
| 238       String::Handle(String::NewSymbol(kEvalConst)), |  | 
| 239       RawFunction::kConstImplicitGetter, |  | 
| 240       true,  // static function. |  | 
| 241       false,  // not const function. |  | 
| 242       fragment->token_index())); |  | 
| 243 |  | 
| 244   func.set_result_type(Type::Handle(Type::DynamicType())); |  | 
| 245   func.set_num_fixed_parameters(0); |  | 
| 246   func.set_num_optional_parameters(0); |  | 
| 247 |  | 
| 248   // The function needs to be associated with a named Class: the interface |  | 
| 249   // Function fits the bill. |  | 
| 250   func.set_owner(Class::Handle( |  | 
| 251       Type::Handle(Type::FunctionInterface()).type_class())); |  | 
| 252 |  | 
| 253   // We compile the function here, even though InvokeStatic() below |  | 
| 254   // would compile func automatically. We are checking fewer invariants |  | 
| 255   // here. |  | 
| 256   ParsedFunction parsed_function(func); |  | 
| 257   parsed_function.set_node_sequence(fragment); |  | 
| 258   parsed_function.set_default_parameter_values(Array::Handle()); |  | 
| 259 |  | 
| 260   Assembler assembler; |  | 
| 261   CodeGenerator code_gen(&assembler, parsed_function); |  | 
| 262   code_gen.GenerateCode(); |  | 
| 263   const Code& code = Code::Handle(Code::FinalizeCode(kEvalConst, &assembler)); |  | 
| 264 |  | 
| 265   func.SetCode(code); |  | 
| 266   CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); |  | 
| 267   ASSERT(code_index_table != NULL); |  | 
| 268   code_index_table->AddFunction(func); |  | 
| 269   // TODO(hausner): We need a way to remove these one-time execution |  | 
| 270   // functions from the global code description (PC mapping) tables so |  | 
| 271   // we don't pollute the system unnecessarily with stale data. |  | 
| 272   code_gen.FinalizePcDescriptors(code); |  | 
| 273   code_gen.FinalizeExceptionHandlers(code); |  | 
| 274 |  | 
| 275   GrowableArray<const Object*> arguments;  // no arguments. |  | 
| 276   const Array& kNoArgumentNames = Array::Handle(); |  | 
| 277   Instance& result = Instance::Handle( |  | 
| 278       DartEntry::InvokeStatic(func, |  | 
| 279                               arguments, |  | 
| 280                               kNoArgumentNames)); |  | 
| 281   if (result.IsUnhandledException()) { |  | 
| 282     // TODO(srdjan): implement proper exit from compiler. |  | 
| 283     UNIMPLEMENTED(); |  | 
| 284   } |  | 
| 285   return result.raw(); | 338   return result.raw(); | 
| 286 } | 339 } | 
| 287 | 340 | 
| 288 | 341 | 
| 289 }  // namespace dart | 342 }  // namespace dart | 
| OLD | NEW | 
|---|