Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(281)

Side by Side Diff: runtime/vm/flow_graph_compiler_ia32.cc

Issue 10458027: Started new compiler for ia32. Getters and setters can be intrinsified within the new compiler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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/globals.h" // Needed here to get TARGET_ARCH_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/flow_graph_compiler.h" 8 #include "vm/flow_graph_compiler.h"
9 9
10 #include "vm/ast_printer.h"
10 #include "vm/compiler_stats.h" 11 #include "vm/compiler_stats.h"
12 #include "vm/debugger.h"
13 #include "vm/il_printer.h"
14 #include "vm/intrinsifier.h"
15 #include "vm/locations.h"
11 #include "vm/longjump.h" 16 #include "vm/longjump.h"
17 #include "vm/stub_code.h"
12 18
13 namespace dart { 19 namespace dart {
14 20
21 DECLARE_FLAG(bool, code_comments);
15 DECLARE_FLAG(bool, compiler_stats); 22 DECLARE_FLAG(bool, compiler_stats);
23 DECLARE_FLAG(bool, enable_type_checks);
24 DECLARE_FLAG(bool, intrinsify);
25 DECLARE_FLAG(bool, optimization_counter_threshold);
26 DECLARE_FLAG(bool, print_ast);
27 DECLARE_FLAG(bool, print_scopes);
28 DECLARE_FLAG(bool, report_usage_count);
29 DECLARE_FLAG(bool, trace_functions);
30
31
32 class DeoptimizationStub : public ZoneAllocated {
33 public:
34 DeoptimizationStub(intptr_t deopt_id,
35 intptr_t deopt_token_index,
36 intptr_t try_index,
37 DeoptReasonId reason)
38 : deopt_id_(deopt_id),
39 deopt_token_index_(deopt_token_index),
40 try_index_(try_index),
41 reason_(reason),
42 registers_(2),
43 entry_label_() {}
44
45 void Push(Register reg) { registers_.Add(reg); }
46 Label* entry_label() { return &entry_label_; }
47
48 void GenerateCode(FlowGraphCompiler* compiler);
49
50 private:
51 const intptr_t deopt_id_;
52 const intptr_t deopt_token_index_;
53 const intptr_t try_index_;
54 const DeoptReasonId reason_;
55 GrowableArray<Register> registers_;
56 Label entry_label_;
57
58 DISALLOW_COPY_AND_ASSIGN(DeoptimizationStub);
59 };
60
61
62 void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) {
63 Assembler* assem = compiler->assembler();
64 #define __ assem->
65 __ Comment("Deopt stub for id %d", deopt_id_);
66 __ Bind(entry_label());
67 for (intptr_t i = 0; i < registers_.length(); i++) {
68 __ pushl(registers_[i]);
69 }
70 __ movl(EAX, Immediate(Smi::RawValue(reason_)));
71 __ call(&StubCode::DeoptimizeLabel());
72 compiler->AddCurrentDescriptor(PcDescriptors::kOther,
73 deopt_id_,
74 deopt_token_index_,
75 try_index_);
76 #undef __
77 }
78
79
80 FlowGraphCompiler::FlowGraphCompiler(
81 Assembler* assembler,
82 const ParsedFunction& parsed_function,
83 const GrowableArray<BlockEntryInstr*>& block_order,
84 bool is_optimizing)
85 : FlowGraphVisitor(block_order),
86 assembler_(assembler),
87 parsed_function_(parsed_function),
88 block_info_(block_order.length()),
89 current_block_(NULL),
90 pc_descriptors_list_(NULL),
91 stackmap_builder_(NULL),
92 exception_handlers_list_(NULL),
93 deopt_stubs_(),
94 is_optimizing_(is_optimizing) {
95 }
96
97
98 FlowGraphCompiler::~FlowGraphCompiler() {
99 // BlockInfos are zone-allocated, so their destructors are not called.
100 // Verify the labels explicitly here.
101 for (int i = 0; i < block_info_.length(); ++i) {
102 ASSERT(!block_info_[i]->label.IsLinked());
103 ASSERT(!block_info_[i]->label.HasNear());
104 }
105 }
106
107
108 void FlowGraphCompiler::InitCompiler() {
109 pc_descriptors_list_ = new DescriptorList();
110 exception_handlers_list_ = new ExceptionHandlerList();
111 block_info_.Clear();
112 for (int i = 0; i < block_order_.length(); ++i) {
113 block_info_.Add(new BlockInfo());
114 }
115 }
116
16 117
17 void FlowGraphCompiler::Bailout(const char* reason) { 118 void FlowGraphCompiler::Bailout(const char* reason) {
18 const char* kFormat = "FlowGraphCompiler Bailout: %s."; 119 const char* kFormat = "FlowGraphCompiler Bailout: %s.";
19 intptr_t len = OS::SNPrint(NULL, 0, kFormat, reason) + 1; 120 intptr_t len = OS::SNPrint(NULL, 0, kFormat, reason) + 1;
20 char* chars = reinterpret_cast<char*>( 121 char* chars = reinterpret_cast<char*>(
21 Isolate::Current()->current_zone()->Allocate(len)); 122 Isolate::Current()->current_zone()->Allocate(len));
22 OS::SNPrint(chars, len, kFormat, reason); 123 OS::SNPrint(chars, len, kFormat, reason);
23 const Error& error = Error::Handle( 124 const Error& error = Error::Handle(
24 LanguageError::New(String::Handle(String::New(chars)))); 125 LanguageError::New(String::Handle(String::New(chars))));
25 Isolate::Current()->long_jump_base()->Jump(1, error); 126 Isolate::Current()->long_jump_base()->Jump(1, error);
26 } 127 }
27 128
28 129
130 // Uses current pc position and try-index.
131 void FlowGraphCompiler::AddCurrentDescriptor(PcDescriptors::Kind kind,
132 intptr_t cid,
133 intptr_t token_index,
134 intptr_t try_index) {
135 pc_descriptors_list_->AddDescriptor(kind,
136 assembler_->CodeSize(),
137 cid,
138 token_index,
139 try_index);
140 }
141
142 #define __ assembler_->
143
144 void FlowGraphCompiler::IntrinsifyGetter() {
145 // TOS: return address.
146 // +1 : receiver.
147 // Sequence node has one return node, its input is load field node.
148 const SequenceNode& sequence_node = *parsed_function_.node_sequence();
149 ASSERT(sequence_node.length() == 1);
150 ASSERT(sequence_node.NodeAt(0)->IsReturnNode());
151 const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode();
152 ASSERT(return_node.value()->IsLoadInstanceFieldNode());
153 const LoadInstanceFieldNode& load_node =
154 *return_node.value()->AsLoadInstanceFieldNode();
155 __ movl(EAX, Address(ESP, 1 * kWordSize));
156 __ movl(EAX, FieldAddress(EAX, load_node.field().Offset()));
157 __ ret();
158 }
159
160
161 void FlowGraphCompiler::IntrinsifySetter() {
162 // TOS: return address.
163 // +1 : value
164 // +2 : receiver.
165 // Sequence node has one store node and one return NULL node.
166 const SequenceNode& sequence_node = *parsed_function_.node_sequence();
167 ASSERT(sequence_node.length() == 2);
168 ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode());
169 ASSERT(sequence_node.NodeAt(1)->IsReturnNode());
170 const StoreInstanceFieldNode& store_node =
171 *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
172 __ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver.
173 __ movl(EBX, Address(ESP, 1 * kWordSize)); // Value.
174 __ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX);
175 const Immediate raw_null =
176 Immediate(reinterpret_cast<intptr_t>(Object::null()));
177 __ movl(EAX, raw_null);
178 __ ret();
179 }
180
181
182 intptr_t FlowGraphCompiler::StackSize() const {
183 return parsed_function_.stack_local_count() +
184 parsed_function_.copied_parameter_count();
185 }
186
187
188 bool FlowGraphCompiler::CanOptimize() {
189 return
190 !FLAG_report_usage_count &&
191 (FLAG_optimization_counter_threshold >= 0) &&
192 !Isolate::Current()->debugger()->IsActive();
193 }
194
195
196 // Returns 'true' if code generation for this function is complete, i.e.,
197 // no fall-through to regular code is needed.
198 bool FlowGraphCompiler::TryIntrinsify() {
199 if (!CanOptimize()) return false;
200 // Intrinsification skips arguments checks, therefore disable if in checked
201 // mode.
202 if (FLAG_intrinsify && !FLAG_trace_functions && !FLAG_enable_type_checks) {
203 if ((parsed_function_.function().kind() == RawFunction::kImplicitGetter)) {
204 IntrinsifyGetter();
205 return true;
206 }
207 if ((parsed_function_.function().kind() == RawFunction::kImplicitSetter)) {
208 IntrinsifySetter();
209 return true;
210 }
211 }
212 // Even if an intrinsified version of the function was successfully
213 // generated, it may fall through to the non-intrinsified method body.
214 if (!FLAG_trace_functions) {
215 return Intrinsifier::Intrinsify(parsed_function_.function(), assembler_);
216 }
217 return false;
218 }
219
220
221 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid,
222 intptr_t token_index,
223 intptr_t try_index,
224 const RuntimeEntry& entry) {
225 __ CallRuntime(entry);
226 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index);
227 }
228
229
230 void FlowGraphCompiler::CopyParameters() {
231 Bailout("Copy Parameters");
232 }
233
234
29 void FlowGraphCompiler::CompileGraph() { 235 void FlowGraphCompiler::CompileGraph() {
30 Bailout("CompileGraph"); 236 InitCompiler();
237 if (TryIntrinsify()) {
238 __ int3();
239 __ jmp(&StubCode::FixCallersTargetLabel());
240 return;
241 }
242 // Specialized version of entry code from CodeGenerator::GenerateEntryCode.
243 const Function& function = parsed_function_.function();
244
245 const int parameter_count = function.num_fixed_parameters();
246 const int num_copied_params = parsed_function_.copied_parameter_count();
247 const int local_count = parsed_function_.stack_local_count();
248 AssemblerMacros::EnterDartFrame(assembler_, (StackSize() * kWordSize));
249 // We check the number of passed arguments when we have to copy them due to
250 // the presence of optional named parameters.
251 // No such checking code is generated if only fixed parameters are declared,
252 // unless we are debug mode or unless we are compiling a closure.
253 if (num_copied_params == 0) {
254 #ifdef DEBUG
255 const bool check_arguments = true;
256 #else
257 const bool check_arguments = function.IsClosureFunction();
258 #endif
259 if (check_arguments) {
260 // Check that num_fixed <= argc <= num_params.
261 Label argc_in_range;
262 // Total number of args is the first Smi in args descriptor array (R10).
regis 2012/05/30 08:58:20 R10 -> EDX
srdjan 2012/05/30 16:20:39 Done.
263 __ movl(EAX, FieldAddress(EDX, Array::data_offset()));
264 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count)));
265 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
266 if (function.IsClosureFunction()) {
267 GenerateCallRuntime(AstNode::kNoId,
268 function.token_index(),
269 CatchClauseNode::kInvalidTryIndex,
270 kClosureArgumentMismatchRuntimeEntry);
271 } else {
272 __ Stop("Wrong number of arguments");
273 }
274 __ Bind(&argc_in_range);
275 }
276 } else {
277 CopyParameters();
278 }
279 // Initialize (non-argument) stack allocated locals to null.
280 if (local_count > 0) {
281 const Immediate raw_null =
282 Immediate(reinterpret_cast<intptr_t>(Object::null()));
283 __ movl(EAX, raw_null);
284 const int base = parsed_function_.first_stack_local_index();
285 for (int i = 0; i < local_count; ++i) {
286 // Subtract index i (locals lie at lower addresses than EBP).
287 __ movl(Address(EBP, (base - i) * kWordSize), EAX);
288 }
289 }
290
291 // Generate stack overflow check.
292 __ cmpl(ESP,
293 Address::Absolute(Isolate::Current()->stack_limit_address()));
294 Label no_stack_overflow;
295 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump);
296 GenerateCallRuntime(AstNode::kNoId,
297 function.token_index(),
298 CatchClauseNode::kInvalidTryIndex,
299 kStackOverflowRuntimeEntry);
300 __ Bind(&no_stack_overflow);
301
302 if (FLAG_print_scopes) {
303 // Print the function scope (again) after generating the prologue in order
304 // to see annotations such as allocation indices of locals.
305 if (FLAG_print_ast) {
306 // Second printing.
307 OS::Print("Annotated ");
308 }
309 AstPrinter::PrintFunctionScope(parsed_function_);
310 }
311
312 VisitBlocks();
313
314 __ int3();
315 GenerateDeferredCode();
316 // Emit function patching code. This will be swapped with the first 13 bytes
regis 2012/05/30 08:58:20 13 bytes? Isn't it just 5 bytes in 32-bit mode?
srdjan 2012/05/30 16:20:39 Done.
317 // at entry point.
318 pc_descriptors_list_->AddDescriptor(PcDescriptors::kPatchCode,
319 assembler_->CodeSize(),
320 AstNode::kNoId,
321 0,
322 -1);
323 __ jmp(&StubCode::FixCallersTargetLabel());
324 }
325
326
327 void FlowGraphCompiler::GenerateDeferredCode() {
328 for (intptr_t i = 0; i < deopt_stubs_.length(); i++) {
329 deopt_stubs_[i]->GenerateCode(this);
330 }
331 }
332
333
334 void FlowGraphCompiler::EmitComment(Instruction* instr) {
335 char buffer[80];
336 BufferFormatter f(buffer, sizeof(buffer));
337 instr->PrintTo(&f);
338 __ Comment("@%d: %s", instr->cid(), buffer);
339 }
340
341
342 void FlowGraphCompiler::BailoutOnInstruction(Instruction* instr) {
343 char buffer[80];
344 BufferFormatter f(buffer, sizeof(buffer));
345 instr->PrintTo(&f);
346 Bailout(buffer);
347 }
348
349
350 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
351 LocationSummary* locs = instr->locs();
352 ASSERT(locs != NULL);
353
354 locs->AllocateRegisters();
355
356 // Load instruction inputs into allocated registers.
357 for (intptr_t i = locs->input_count() - 1; i >= 0; i--) {
358 Location loc = locs->in(i);
359 ASSERT(loc.kind() == Location::kRegister);
360 __ popl(loc.reg());
361 }
362 }
363
364
365 void FlowGraphCompiler::VisitBlocks() {
366 for (intptr_t i = 0; i < block_order_.length(); ++i) {
367 __ Comment("B%d", i);
368 // Compile the block entry.
369 current_block_ = block_order_[i];
370 Instruction* instr = current_block()->Accept(this);
371 // Compile all successors until an exit, branch, or a block entry.
372 while ((instr != NULL) && !instr->IsBlockEntry()) {
373 if (FLAG_code_comments) EmitComment(instr);
374 if (instr->locs() == NULL) {
375 BailoutOnInstruction(instr);
376 } else {
377 EmitInstructionPrologue(instr);
378 instr->EmitNativeCode(this);
379 instr = instr->StraightLineSuccessor();
380 }
381 }
382 BlockEntryInstr* successor =
383 (instr == NULL) ? NULL : instr->AsBlockEntry();
384 if (successor != NULL) {
385 // Block ended with a "goto". We can fall through if it is the
386 // next block in the list. Otherwise, we need a jump.
387 if ((i == block_order_.length() - 1) ||
388 (block_order_[i + 1] != successor)) {
389 __ jmp(&block_info_[successor->postorder_number()]->label);
390 }
391 }
392 }
31 } 393 }
32 394
33 395
34 void FlowGraphCompiler::FinalizePcDescriptors(const Code& code) { 396 void FlowGraphCompiler::FinalizePcDescriptors(const Code& code) {
35 UNIMPLEMENTED(); 397 ASSERT(pc_descriptors_list_ != NULL);
398 const PcDescriptors& descriptors = PcDescriptors::Handle(
399 pc_descriptors_list_->FinalizePcDescriptors(code.EntryPoint()));
400 descriptors.Verify(parsed_function_.function().is_optimizable());
401 code.set_pc_descriptors(descriptors);
36 } 402 }
37 403
38 404
39 void FlowGraphCompiler::FinalizeStackmaps(const Code& code) { 405 void FlowGraphCompiler::FinalizeStackmaps(const Code& code) {
40 UNIMPLEMENTED(); 406 if (stackmap_builder_ == NULL) {
407 // The unoptimizing compiler has no stack maps.
408 code.set_stackmaps(Array::Handle());
409 } else {
410 // Finalize the stack map array and add it to the code object.
411 code.set_stackmaps(
412 Array::Handle(stackmap_builder_->FinalizeStackmaps(code)));
413 }
41 } 414 }
42 415
43 416
44 void FlowGraphCompiler::FinalizeVarDescriptors(const Code& code) { 417 void FlowGraphCompiler::FinalizeVarDescriptors(const Code& code) {
45 UNIMPLEMENTED(); 418 const LocalVarDescriptors& var_descs = LocalVarDescriptors::Handle(
419 parsed_function_.node_sequence()->scope()->GetVarDescriptors());
420 code.set_var_descriptors(var_descs);
46 } 421 }
47 422
48 423
49 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { 424 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) {
50 UNIMPLEMENTED(); 425 ASSERT(exception_handlers_list_ != NULL);
426 const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
427 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint()));
428 code.set_exception_handlers(handlers);
51 } 429 }
52 430
53 431
54 void FlowGraphCompiler::FinalizeComments(const Code& code) { 432 void FlowGraphCompiler::FinalizeComments(const Code& code) {
55 UNIMPLEMENTED(); 433 code.set_comments(assembler_->GetCodeComments());
56 } 434 }
57 435
436 #undef __
58 437
59 } // namespace dart 438 } // namespace dart
60 439
61 #endif // defined TARGET_ARCH_IA32 440 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698