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 |