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

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

Issue 10375017: Remove old x64 code generator. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 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
« no previous file with comments | « runtime/vm/code_generator_x64.h ('k') | runtime/vm/compiler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64)
7
8 #include "vm/code_generator.h"
9
10 #include "lib/error.h"
11 #include "vm/ast_printer.h"
12 #include "vm/class_finalizer.h"
13 #include "vm/code_descriptors.h"
14 #include "vm/dart_entry.h"
15 #include "vm/debugger.h"
16 #include "vm/longjump.h"
17 #include "vm/object.h"
18 #include "vm/object_store.h"
19 #include "vm/parser.h"
20 #include "vm/resolver.h"
21 #include "vm/stub_code.h"
22
23 namespace dart {
24
25 DECLARE_FLAG(bool, print_ast);
26 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables.");
27 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function.");
28 DECLARE_FLAG(bool, enable_type_checks);
29 DECLARE_FLAG(bool, trace_compiler);
30
31 #define __ assembler_->
32
33 CodeGeneratorState::CodeGeneratorState(CodeGenerator* codegen)
34 : StackResource(Isolate::Current()),
35 codegen_(codegen),
36 parent_(codegen->state()) {
37 if (parent_ != NULL) {
38 root_node_ = parent_->root_node_;
39 current_try_index_ = parent_->current_try_index_;
40 } else {
41 root_node_ = NULL;
42 current_try_index_ = CatchClauseNode::kInvalidTryIndex;
43 }
44 codegen_->set_state(this);
45 }
46
47
48 CodeGeneratorState::~CodeGeneratorState() {
49 codegen_->set_state(parent_);
50 }
51
52
53 CodeGenerator::CodeGenerator(Assembler* assembler,
54 const ParsedFunction& parsed_function)
55 : assembler_(assembler),
56 parsed_function_(parsed_function),
57 locals_space_size_(-1),
58 state_(NULL),
59 pc_descriptors_list_(NULL),
60 stackmap_builder_(NULL),
61 exception_handlers_list_(NULL),
62 try_index_(CatchClauseNode::kInvalidTryIndex),
63 context_level_(0) {
64 ASSERT(assembler_ != NULL);
65 ASSERT(parsed_function.node_sequence() != NULL);
66 ASSERT(Isolate::Current()->long_jump_base()->IsSafeToJump());
67 pc_descriptors_list_ = new DescriptorList();
68 // We do not build any stack maps in the unoptimizing compiler.
69 exception_handlers_list_ = new ExceptionHandlerList();
70 }
71
72
73 bool CodeGenerator::IsResultNeeded(AstNode* node) const {
74 return !state()->IsRootNode(node);
75 }
76
77
78 // NOTE: First 13 bytes of the code may be patched with a jump instruction. Do
79 // not emit any objects in the first 13 bytes.
80 void CodeGenerator::GenerateCode() {
81 CodeGeneratorState codegen_state(this);
82 if (FLAG_print_scopes && FLAG_print_ast) {
83 // Print the function scope before code generation.
84 AstPrinter::PrintFunctionScope(parsed_function_);
85 }
86 if (FLAG_print_ast) {
87 // Print the function ast before code generation.
88 AstPrinter::PrintFunctionNodes(parsed_function_);
89 }
90 if (FLAG_trace_functions) {
91 // Preserve RBX (ic-data array or object) and R10 (arguments descriptor).
92 __ nop(8);
93 __ pushq(RBX);
94 __ pushq(R10);
95 const Function& function =
96 Function::ZoneHandle(parsed_function_.function().raw());
97 __ LoadObject(RAX, function);
98 __ pushq(RAX);
99 GenerateCallRuntime(AstNode::kNoId,
100 0,
101 kTraceFunctionEntryRuntimeEntry);
102 __ popq(RAX);
103 __ popq(R10);
104 __ popq(RBX);
105 }
106
107 const bool code_generation_finished = TryIntrinsify();
108 // In some cases intrinsifier can generate all code and no AST based
109 // code generation is needed. In some cases slow-paths (e.g., overflows) are
110 // implemented by the AST based code generation and 'code_generation_finished'
111 // is false.
112 if (!code_generation_finished) {
113 GeneratePreEntryCode();
114 GenerateEntryCode();
115 if (FLAG_print_scopes) {
116 // Print the function scope (again) after generating the prologue in order
117 // to see annotations such as allocation indices of locals.
118 if (FLAG_print_ast) {
119 // Second printing.
120 OS::Print("Annotated ");
121 }
122 AstPrinter::PrintFunctionScope(parsed_function_);
123 }
124 parsed_function_.node_sequence()->Visit(this);
125 }
126 // End of code.
127 __ int3();
128 GenerateDeferredCode();
129
130 // Emit function patching code. This will be swapped with the first 13 bytes
131 // at entry point.
132 pc_descriptors_list_->AddDescriptor(PcDescriptors::kPatchCode,
133 assembler_->CodeSize(),
134 AstNode::kNoId,
135 0,
136 -1);
137 __ jmp(&StubCode::FixCallersTargetLabel());
138 }
139
140
141 void CodeGenerator::GenerateDeferredCode() {
142 }
143
144
145 // Pre entry code is called before the frame has been constructed.
146 // Note that first 13 bytes may be patched with a jump.
147 // TODO(srdjan): Add check that no object is inlined in the first
148 // 13 bytes (length of a jump instruction).
149 void CodeGenerator::GeneratePreEntryCode() {
150 // Do not optimize if:
151 // - we count invocations.
152 // - optimization disabled.
153 // - function is marked as non-optimizable.
154 // - type checks are enabled.
155 // TODO(srdjan): Nop's still needed?
156 __ nop(8);
157 __ nop(5);
158 }
159
160
161 void CodeGenerator::FinalizePcDescriptors(const Code& code) {
162 ASSERT(pc_descriptors_list_ != NULL);
163 const PcDescriptors& descriptors = PcDescriptors::Handle(
164 pc_descriptors_list_->FinalizePcDescriptors(code.EntryPoint()));
165 descriptors.Verify(parsed_function_.function().is_optimizable());
166 code.set_pc_descriptors(descriptors);
167 }
168
169
170 void CodeGenerator::FinalizeStackmaps(const Code& code) {
171 if (stackmap_builder_ == NULL) {
172 // The unoptimizing compiler has no stack maps.
173 code.set_stackmaps(Array::Handle());
174 } else {
175 // Finalize the stack map array and add it to the code object.
176 code.set_stackmaps(
177 Array::Handle(stackmap_builder_->FinalizeStackmaps(code)));
178 }
179 }
180
181
182 void CodeGenerator::FinalizeVarDescriptors(const Code& code) {
183 const LocalVarDescriptors& var_descs = LocalVarDescriptors::Handle(
184 parsed_function_.node_sequence()->scope()->GetVarDescriptors());
185 code.set_var_descriptors(var_descs);
186 }
187
188
189 void CodeGenerator::FinalizeExceptionHandlers(const Code& code) {
190 ASSERT(exception_handlers_list_ != NULL);
191 const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
192 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint()));
193 code.set_exception_handlers(handlers);
194 }
195
196
197 void CodeGenerator::GenerateLoadVariable(Register dst,
198 const LocalVariable& variable) {
199 if (variable.is_captured()) {
200 // The variable lives in the context.
201 intptr_t delta = context_level() - variable.owner()->context_level();
202 ASSERT(delta >= 0);
203 Register base = CTX;
204 while (delta-- > 0) {
205 __ movq(dst, FieldAddress(base, Context::parent_offset()));
206 base = dst;
207 }
208 __ movq(dst,
209 FieldAddress(base, Context::variable_offset(variable.index())));
210 } else {
211 // The variable lives in the current stack frame.
212 __ movq(dst, Address(RBP, variable.index() * kWordSize));
213 }
214 }
215
216
217 void CodeGenerator::GenerateStoreVariable(const LocalVariable& variable,
218 Register src,
219 Register scratch) {
220 if (variable.is_captured()) {
221 // The variable lives in the context.
222 intptr_t delta = context_level() - variable.owner()->context_level();
223 ASSERT(delta >= 0);
224 Register base = CTX;
225 while (delta-- > 0) {
226 __ movq(scratch, FieldAddress(base, Context::parent_offset()));
227 base = scratch;
228 }
229 __ StoreIntoObject(
230 base,
231 FieldAddress(base, Context::variable_offset(variable.index())),
232 src);
233 } else {
234 // The variable lives in the current stack frame.
235 __ movq(Address(RBP, variable.index() * kWordSize), src);
236 }
237 }
238
239
240 void CodeGenerator::GeneratePushVariable(const LocalVariable& variable,
241 Register scratch) {
242 if (variable.is_captured()) {
243 // The variable lives in the context.
244 intptr_t delta = context_level() - variable.owner()->context_level();
245 ASSERT(delta >= 0);
246 Register base = CTX;
247 while (delta-- > 0) {
248 __ movq(scratch, FieldAddress(base, Context::parent_offset()));
249 base = scratch;
250 }
251 __ pushq(FieldAddress(base, Context::variable_offset(variable.index())));
252 } else {
253 // The variable lives in the current stack frame.
254 __ pushq(Address(RBP, variable.index() * kWordSize));
255 }
256 }
257
258
259 void CodeGenerator::GenerateInstanceCall(
260 intptr_t node_id,
261 intptr_t token_index,
262 const String& function_name,
263 int num_arguments,
264 const Array& optional_arguments_names,
265 intptr_t num_args_checked) {
266 ASSERT(num_args_checked > 0); // At least receiver check is necessary.
267 // Set up the function name and number of arguments (including the receiver)
268 // to the InstanceCall stub which will resolve the correct entrypoint for
269 // the operator and call it.
270 ICData& ic_data = ICData::ZoneHandle();
271 ic_data = ICData::New(parsed_function().function(),
272 function_name,
273 node_id,
274 num_args_checked);
275 __ LoadObject(RBX, ic_data);
276 __ LoadObject(R10, ArgumentsDescriptor(num_arguments,
277 optional_arguments_names));
278 uword label_address = 0;
279 switch (num_args_checked) {
280 case 1:
281 label_address = StubCode::OneArgCheckInlineCacheEntryPoint();
282 break;
283 case 2:
284 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint();
285 break;
286 default:
287 UNIMPLEMENTED();
288 }
289 ExternalLabel target_label("InlineCache", label_address);
290
291 __ call(&target_label);
292 AddCurrentDescriptor(PcDescriptors::kIcCall,
293 node_id,
294 token_index);
295 __ addq(RSP, Immediate(num_arguments * kWordSize));
296 }
297
298
299 // Check that no fewer than num_fixed_params positional arguments are passed
300 // in and that no more than num_params arguments are passed in.
301 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i].
302 void CodeGenerator::CopyParameters() {
303 const Function& function = parsed_function_.function();
304 LocalScope* scope = parsed_function_.node_sequence()->scope();
305 const int num_fixed_params = function.num_fixed_parameters();
306 const int num_opt_params = function.num_optional_parameters();
307
308 ASSERT(parsed_function_.first_parameter_index() == -1);
309 // Copy positional arguments.
310 // Check that no fewer than num_fixed_params positional arguments are passed
311 // in and that no more than num_params arguments are passed in.
312 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i].
313 const int num_params = num_fixed_params + num_opt_params;
314
315 // Total number of args is the first Smi in args descriptor array (R10).
316 __ movq(RBX, FieldAddress(R10, Array::data_offset()));
317 // Check that num_args <= num_params.
318 Label wrong_num_arguments;
319 __ cmpq(RBX, Immediate(Smi::RawValue(num_params)));
320 __ j(GREATER, &wrong_num_arguments);
321 // Number of positional args is the second Smi in descriptor array (R10).
322 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
323 // Check that num_pos_args >= num_fixed_params.
324 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params)));
325 __ j(LESS, &wrong_num_arguments);
326 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8.
327 // Let RBX point to the last passed positional argument, i.e. to
328 // fp[1 + num_args - (num_pos_args - 1)].
329 __ subq(RBX, RCX);
330 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize));
331 // Let RDI point to the last copied positional argument, i.e. to
332 // fp[-1 - (num_pos_args - 1)].
333 __ SmiUntag(RCX);
334 __ movq(RAX, RCX);
335 __ negq(RAX);
336 __ leaq(RDI, Address(RBP, RAX, TIMES_8, 0));
337 Label loop, loop_condition;
338 __ jmp(&loop_condition, Assembler::kNearJump);
339 // We do not use the final allocation index of the variable here, i.e.
340 // scope->VariableAt(i)->index(), because captured variables still need
341 // to be copied to the context that is not yet allocated.
342 const Address argument_addr(RBX, RCX, TIMES_8, 0);
343 const Address copy_addr(RDI, RCX, TIMES_8, 0);
344 __ Bind(&loop);
345 __ movq(RAX, argument_addr);
346 __ movq(copy_addr, RAX);
347 __ Bind(&loop_condition);
348 __ decq(RCX);
349 __ j(POSITIVE, &loop, Assembler::kNearJump);
350
351 // Copy or initialize optional named arguments.
352 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments.
353 // Start by alphabetically sorting the names of the optional parameters.
354 LocalVariable** opt_param = new LocalVariable*[num_opt_params];
355 int* opt_param_position = new int[num_opt_params];
356 for (int pos = num_fixed_params; pos < num_params; pos++) {
357 LocalVariable* parameter = scope->VariableAt(pos);
358 const String& opt_param_name = parameter->name();
359 int i = pos - num_fixed_params;
360 while (--i >= 0) {
361 LocalVariable* param_i = opt_param[i];
362 const intptr_t result = opt_param_name.CompareTo(param_i->name());
363 ASSERT(result != 0);
364 if (result > 0) break;
365 opt_param[i + 1] = opt_param[i];
366 opt_param_position[i + 1] = opt_param_position[i];
367 }
368 opt_param[i + 1] = parameter;
369 opt_param_position[i + 1] = pos;
370 }
371 // Generate code handling each optional parameter in alphabetical order.
372 // Total number of args is the first Smi in args descriptor array (R10).
373 __ movq(RBX, FieldAddress(R10, Array::data_offset()));
374 // Number of positional args is the second Smi in descriptor array (R10).
375 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
376 __ SmiUntag(RCX);
377 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0].
378 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi.
379 // Let EDI point to the name/pos pair of the first named argument.
380 __ leaq(RDI, FieldAddress(R10, Array::data_offset() + (2 * kWordSize)));
381 for (int i = 0; i < num_opt_params; i++) {
382 // Handle this optional parameter only if k or fewer positional arguments
383 // have been passed, where k is the position of this optional parameter in
384 // the formal parameter list.
385 Label load_default_value, assign_optional_parameter, next_parameter;
386 const int param_pos = opt_param_position[i];
387 __ cmpq(RCX, Immediate(param_pos));
388 __ j(GREATER, &next_parameter, Assembler::kNearJump);
389 // Check if this named parameter was passed in.
390 __ movq(RAX, Address(RDI, 0)); // Load RAX with the name of the argument.
391 __ CompareObject(RAX, opt_param[i]->name());
392 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump);
393 // Load RAX with passed-in argument at provided arg_pos, i.e. at
394 // fp[1 + argc - arg_pos].
395 __ movq(RAX, Address(RDI, kWordSize)); // RAX is arg_pos as Smi.
396 __ addq(RDI, Immediate(2 * kWordSize)); // Point to next name/pos pair.
397 __ negq(RAX);
398 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi.
399 __ movq(RAX, argument_addr);
400 __ jmp(&assign_optional_parameter, Assembler::kNearJump);
401 __ Bind(&load_default_value);
402 // Load RAX with default argument at pos.
403 const Object& value = Object::ZoneHandle(
404 parsed_function_.default_parameter_values().At(
405 param_pos - num_fixed_params));
406 __ LoadObject(RAX, value);
407 __ Bind(&assign_optional_parameter);
408 // Assign RAX to fp[-1 - param_pos].
409 // We do not use the final allocation index of the variable here, i.e.
410 // scope->VariableAt(i)->index(), because captured variables still need
411 // to be copied to the context that is not yet allocated.
412 const Address param_addr(RBP, (-1 - param_pos) * kWordSize);
413 __ movq(param_addr, RAX);
414 __ Bind(&next_parameter);
415 }
416 delete[] opt_param;
417 delete[] opt_param_position;
418 // Check that RDI now points to the null terminator in the array descriptor.
419 const Immediate raw_null =
420 Immediate(reinterpret_cast<intptr_t>(Object::null()));
421 Label all_arguments_processed;
422 __ cmpq(Address(RDI, 0), raw_null);
423 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
424
425 __ Bind(&wrong_num_arguments);
426 if (function.IsClosureFunction()) {
427 GenerateCallRuntime(AstNode::kNoId,
428 0,
429 kClosureArgumentMismatchRuntimeEntry);
430 } else {
431 // Invoke noSuchMethod function.
432 const int kNumArgsChecked = 1;
433 ICData& ic_data = ICData::ZoneHandle();
434 ic_data = ICData::New(parsed_function().function(),
435 String::Handle(function.name()),
436 AstNode::kNoId,
437 kNumArgsChecked);
438 __ LoadObject(RBX, ic_data);
439 // RBP : points to previous frame pointer.
440 // RBP + 8 : points to return address.
441 // RBP + 16 : address of last argument (arg n-1).
442 // RSP + 16 + 8*(n-1) : address of first argument (arg 0).
443 // RBX : ic-data.
444 // R10 : arguments descriptor array.
445 __ call(&StubCode::CallNoSuchMethodFunctionLabel());
446 }
447
448 if (FLAG_trace_functions) {
449 __ pushq(RAX); // Preserve result.
450 __ PushObject(Function::ZoneHandle(function.raw()));
451 GenerateCallRuntime(AstNode::kNoId,
452 0,
453 kTraceFunctionExitRuntimeEntry);
454 __ popq(RAX); // Remove argument.
455 __ popq(RAX); // Restore result.
456 }
457 __ LeaveFrame();
458 __ ret();
459
460 __ Bind(&all_arguments_processed);
461 // Nullify originally passed arguments only after they have been copied and
462 // checked, otherwise noSuchMethod would not see their original values.
463 // This step can be skipped in case we decide that formal parameters are
464 // implicitly final, since garbage collecting the unmodified value is not
465 // an issue anymore.
466
467 // R10 : arguments descriptor array.
468 // Total number of args is the first Smi in args descriptor array (R10).
469 __ movq(RCX, FieldAddress(R10, Array::data_offset()));
470 __ SmiUntag(RCX);
471 Label null_args_loop, null_args_loop_condition;
472 __ jmp(&null_args_loop_condition, Assembler::kNearJump);
473 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize);
474 __ Bind(&null_args_loop);
475 __ movq(original_argument_addr, raw_null);
476 __ Bind(&null_args_loop_condition);
477 __ decq(RCX);
478 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
479 }
480
481
482 // Call to generate entry code:
483 // - compute frame size and setup frame.
484 // - allocate local variables on stack.
485 // - optionally check if number of arguments match.
486 // - initialize all non-argument locals to null.
487 //
488 // Input parameters:
489 // RSP : points to return address.
490 // RSP + 8 : address of last argument (arg n-1).
491 // RSP + 8*n : address of first argument (arg 0).
492 // R10 : arguments descriptor array.
493 void CodeGenerator::GenerateEntryCode() {
494 const Immediate raw_null =
495 Immediate(reinterpret_cast<intptr_t>(Object::null()));
496 const Function& function = parsed_function_.function();
497
498 // 1. Compute the frame size and enter the frame (reserving local space
499 // for copied incoming and default arguments and stack-allocated local
500 // variables).
501 //
502 // TODO(regis): We may give up reserving space on stack for args/locals
503 // because pushes of initial values may be more effective than moves.
504 const int num_fixed_params = function.num_fixed_parameters();
505 const int num_opt_params = function.num_optional_parameters();
506 const int num_copied_params = parsed_function_.copied_parameter_count();
507 const int stack_slot_count =
508 num_copied_params + parsed_function_.stack_local_count();
509 set_locals_space_size(stack_slot_count * kWordSize);
510 __ EnterFrame(locals_space_size());
511
512 // 2. Optionally check if the number of arguments matches. We check the
513 // number of passed arguments when we have to copy them due to the
514 // presence of optional named parameters. No such checking code is
515 // generated if only fixed parameters are declared, unless we are in debug
516 // mode or unless we are compiling a closure.
517 if (num_copied_params == 0) {
518 ASSERT(num_opt_params == 0);
519 #if defined(DEBUG)
520 const bool check_arguments = true; // Always check arguments in debug mode.
521 #else
522 // The number of arguments passed to closure functions must always be
523 // checked here, because no resolving stub (normally responsible for the
524 // check) is involved in closure calls.
525 const bool check_arguments = function.IsClosureFunction();
526 #endif
527 if (check_arguments) {
528 // Check that num_fixed <= argc <= num_params.
529 Label argc_in_range;
530 // Total number of args is the first Smi in args descriptor array (R10).
531 __ movq(RAX, FieldAddress(R10, Array::data_offset()));
532 __ cmpq(RAX, Immediate(Smi::RawValue(num_fixed_params)));
533 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
534 if (function.IsClosureFunction()) {
535 GenerateCallRuntime(AstNode::kNoId,
536 0,
537 kClosureArgumentMismatchRuntimeEntry);
538 } else {
539 __ Stop("Wrong number of arguments");
540 }
541 __ Bind(&argc_in_range);
542 }
543 } else {
544 CopyParameters();
545 }
546
547 // 3. Initialize (non-argument) stack-allocated locals to null.
548 //
549 // TODO(regis): For now, always unroll the init loop. Decide later above
550 // which threshold to implement a loop. Consider emitting pushes instead
551 // of moves.
552 const int base = parsed_function_.first_stack_local_index();
553 for (int index = 0; index < parsed_function_.stack_local_count(); ++index) {
554 if (index == 0) {
555 __ movq(RAX, raw_null);
556 }
557 __ movq(Address(RBP, (base - index) * kWordSize), RAX);
558 }
559
560 // 4. Generate the stack overflow check.
561 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address()));
562 __ cmpq(RSP, Address(TMP, 0));
563 Label no_stack_overflow;
564 __ j(ABOVE, &no_stack_overflow);
565 GenerateCallRuntime(AstNode::kNoId,
566 0,
567 kStackOverflowRuntimeEntry);
568 __ Bind(&no_stack_overflow);
569 }
570
571
572 void CodeGenerator::GenerateReturnEpilog(ReturnNode* node) {
573 // Unchain the context(s) up to context level 0.
574 intptr_t current_context_level = context_level();
575 ASSERT(current_context_level >= 0);
576 if (parsed_function_.saved_context_var() != NULL) {
577 // CTX on entry was saved, but not linked as context parent.
578 GenerateLoadVariable(CTX, *parsed_function_.saved_context_var());
579 } else {
580 while (current_context_level-- > 0) {
581 __ movq(CTX, FieldAddress(CTX, Context::parent_offset()));
582 }
583 }
584 #ifdef DEBUG
585 // Check that the entry stack size matches the exit stack size.
586 __ movq(R10, RBP);
587 __ subq(R10, RSP);
588 ASSERT(locals_space_size() >= 0);
589 __ cmpq(R10, Immediate(locals_space_size()));
590 Label wrong_stack;
591 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump);
592 #endif // DEBUG.
593
594 if (FLAG_trace_functions) {
595 __ pushq(RAX); // Preserve result.
596 const Function& function =
597 Function::ZoneHandle(parsed_function_.function().raw());
598 __ LoadObject(RBX, function);
599 __ pushq(RBX);
600 GenerateCallRuntime(AstNode::kNoId,
601 0,
602 kTraceFunctionExitRuntimeEntry);
603 __ popq(RAX); // Remove argument.
604 __ popq(RAX); // Restore result.
605 }
606 __ LeaveFrame();
607 __ ret();
608
609 // Generate 8 bytes of NOPs so that the debugger can patch the
610 // return pattern with a call to the debug stub.
611 __ nop(1);
612 __ nop(1);
613 __ nop(1);
614 __ nop(1);
615 __ nop(1);
616 __ nop(1);
617 __ nop(1);
618 __ nop(1);
619 AddCurrentDescriptor(PcDescriptors::kReturn,
620 node->id(),
621 node->token_index());
622
623 #ifdef DEBUG
624 __ Bind(&wrong_stack);
625 __ Stop("Exit stack size does not match the entry stack size.");
626 #endif // DEBUG.
627 }
628
629
630 void CodeGenerator::VisitReturnNode(ReturnNode* node) {
631 ASSERT(!IsResultNeeded(node));
632 ASSERT(node->value() != NULL);
633
634 if (!node->value()->IsLiteralNode()) {
635 node->value()->Visit(this);
636 // The result of the return value is now on top of the stack.
637 }
638
639 // Generate inlined code for all finally blocks as we are about to transfer
640 // control out of the 'try' blocks if any.
641 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) {
642 node->InlinedFinallyNodeAt(i)->Visit(this);
643 }
644
645 if (node->value()->IsLiteralNode()) {
646 // Load literal value into RAX.
647 const Object& literal = node->value()->AsLiteralNode()->literal();
648 if (literal.IsSmi()) {
649 __ movq(RAX, Immediate(reinterpret_cast<int64_t>(literal.raw())));
650 } else {
651 __ LoadObject(RAX, literal);
652 }
653 } else {
654 // Pop the previously evaluated result value into RAX.
655 __ popq(RAX);
656 }
657
658 // Generate type check.
659 if (FLAG_enable_type_checks) {
660 const RawFunction::Kind kind = parsed_function().function().kind();
661 const bool is_implicit_getter =
662 (kind == RawFunction::kImplicitGetter) ||
663 (kind == RawFunction::kConstImplicitGetter);
664 const bool is_static = parsed_function().function().is_static();
665 // Implicit getters do not need a type check at return, unless they compute
666 // the initial value of a static field.
667 if (is_static || !is_implicit_getter) {
668 GenerateAssertAssignable(
669 node->id(),
670 node->value()->token_index(),
671 node->value(),
672 AbstractType::ZoneHandle(parsed_function().function().result_type()),
673 String::ZoneHandle(String::NewSymbol("function result")));
674 }
675 }
676 GenerateReturnEpilog(node);
677 }
678
679
680 void CodeGenerator::VisitLiteralNode(LiteralNode* node) {
681 if (!IsResultNeeded(node)) return;
682 __ PushObject(node->literal());
683 }
684
685
686 void CodeGenerator::VisitTypeNode(TypeNode* node) {
687 // Type nodes are handled specially by the code generator.
688 UNREACHABLE();
689 }
690
691
692 void CodeGenerator::VisitAssignableNode(AssignableNode* node) {
693 ASSERT(FLAG_enable_type_checks);
694 node->expr()->Visit(this);
695 __ popq(RAX);
696 GenerateAssertAssignable(node->id(),
697 node->token_index(),
698 node->expr(),
699 node->type(),
700 node->dst_name());
701 if (IsResultNeeded(node)) {
702 __ pushq(RAX);
703 }
704 }
705
706
707 void CodeGenerator::VisitClosureNode(ClosureNode* node) {
708 const Function& function = node->function();
709 if (function.IsNonImplicitClosureFunction()) {
710 // The context scope may have already been set by the new non-optimizing
711 // compiler. If it was not, set it here.
712 if (function.context_scope() == ContextScope::null()) {
713 const intptr_t current_context_level = context_level();
714 const ContextScope& context_scope = ContextScope::ZoneHandle(
715 node->scope()->PreserveOuterScope(current_context_level));
716 ASSERT(!function.HasCode());
717 function.set_context_scope(context_scope);
718 }
719 } else if (function.IsImplicitInstanceClosureFunction()) {
720 node->receiver()->Visit(this);
721 }
722 ASSERT(function.context_scope() != ContextScope::null());
723
724 // The function type of a closure may have type arguments. In that case, pass
725 // the type arguments of the instantiator.
726 const Class& cls = Class::Handle(function.signature_class());
727 ASSERT(!cls.IsNull());
728 const bool requires_type_arguments = cls.HasTypeArguments();
729 if (requires_type_arguments) {
730 ASSERT(!function.IsImplicitStaticClosureFunction());
731 GenerateInstantiatorTypeArguments(node->token_index());
732 }
733 const Code& stub = Code::Handle(
734 StubCode::GetAllocationStubForClosure(function));
735 const ExternalLabel label(function.ToCString(), stub.EntryPoint());
736 GenerateCall(node->token_index(), &label, PcDescriptors::kOther);
737 if (requires_type_arguments) {
738 __ popq(RCX); // Pop type arguments.
739 }
740 if (function.IsImplicitInstanceClosureFunction()) {
741 __ popq(RCX); // Pop receiver.
742 }
743 if (IsResultNeeded(node)) {
744 __ pushq(RAX);
745 }
746 }
747
748
749 void CodeGenerator::VisitPrimaryNode(PrimaryNode* node) {
750 // PrimaryNodes are temporary during parsing.
751 UNREACHABLE();
752 }
753
754
755 void CodeGenerator::VisitCloneContextNode(CloneContextNode *node) {
756 __ PushObject(Object::ZoneHandle()); // Make room for the result.
757 __ pushq(CTX);
758 GenerateCallRuntime(node->id(),
759 node->token_index(), kCloneContextRuntimeEntry);
760 __ popq(RAX);
761 __ popq(CTX); // result: cloned context. Set as current context.
762 }
763
764
765 void CodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) {
766 CodeGeneratorState codegen_state(this);
767 LocalScope* scope = node_sequence->scope();
768 const intptr_t num_context_variables =
769 (scope != NULL) ? scope->num_context_variables() : 0;
770 intptr_t previous_context_level = context_level();
771 if (num_context_variables > 0) {
772 // The loop local scope declares variables that are captured.
773 // Allocate and chain a new context.
774 __ movq(R10, Immediate(num_context_variables));
775 const ExternalLabel label("alloc_context",
776 StubCode::AllocateContextEntryPoint());
777 GenerateCall(node_sequence->token_index(), &label, PcDescriptors::kOther);
778
779 // If this node_sequence is the body of the function being compiled, and if
780 // this function is not a closure, do not link the current context as the
781 // parent of the newly allocated context, as it is not accessible. Instead,
782 // save it in a pre-allocated variable and restore it on exit.
783 if ((node_sequence == parsed_function_.node_sequence()) &&
784 (parsed_function_.saved_context_var() != NULL)) {
785 GenerateStoreVariable(
786 *parsed_function_.saved_context_var(), CTX, kNoRegister);
787 const Immediate raw_null =
788 Immediate(reinterpret_cast<intptr_t>(Object::null()));
789 __ movq(CTX, raw_null);
790 }
791
792 // Chain the new context in RAX to its parent in CTX.
793 __ StoreIntoObject(RAX,
794 FieldAddress(RAX, Context::parent_offset()),
795 CTX);
796 // Set new context as current context.
797 __ movq(CTX, RAX);
798 set_context_level(scope->context_level());
799
800 // If this node_sequence is the body of the function being compiled, copy
801 // the captured parameters from the frame into the context.
802 if (node_sequence == parsed_function_.node_sequence()) {
803 ASSERT(scope->context_level() == 1);
804 const Immediate raw_null =
805 Immediate(reinterpret_cast<intptr_t>(Object::null()));
806 const Function& function = parsed_function_.function();
807 const int num_params = function.NumberOfParameters();
808 int param_frame_index =
809 (num_params == function.num_fixed_parameters()) ? 1 + num_params : -1;
810 for (int pos = 0; pos < num_params; param_frame_index--, pos++) {
811 LocalVariable* parameter = scope->VariableAt(pos);
812 ASSERT(parameter->owner() == scope);
813 if (parameter->is_captured()) {
814 // Copy parameter from local frame to current context.
815 const Address local_addr(RBP, param_frame_index * kWordSize);
816 __ movq(RAX, local_addr);
817 GenerateStoreVariable(*parameter, RAX, R10);
818 // Write NULL to the source location to detect buggy accesses and
819 // allow GC of passed value if it gets overwritten by a new value in
820 // the function.
821 __ movq(local_addr, raw_null);
822 }
823 }
824 }
825 }
826 // If this node_sequence is the body of the function being compiled, generate
827 // code checking the type of the actual arguments.
828 if (FLAG_enable_type_checks &&
829 (node_sequence == parsed_function_.node_sequence())) {
830 GenerateArgumentTypeChecks();
831 }
832 for (int i = 0; i < node_sequence->length(); i++) {
833 AstNode* child_node = node_sequence->NodeAt(i);
834 state()->set_root_node(child_node);
835 child_node->Visit(this);
836 }
837
838 // Unchain the previously allocated context.
839 if ((node_sequence == parsed_function_.node_sequence()) &&
840 (parsed_function_.saved_context_var() != NULL)) {
841 ASSERT(num_context_variables > 0);
842 GenerateLoadVariable(CTX, *parsed_function_.saved_context_var());
843 } else if (num_context_variables > 0) {
844 __ movq(CTX, FieldAddress(CTX, Context::parent_offset()));
845 }
846
847 // If this node sequence is labeled, a break out of the sequence will have
848 // taken care of unchaining the context.
849 if (node_sequence->label() != NULL) {
850 __ Bind(node_sequence->label()->break_label());
851 // Outermost sequence cannot have a label.
852 ASSERT(node_sequence != parsed_function_.node_sequence());
853 }
854 set_context_level(previous_context_level);
855 }
856
857
858 void CodeGenerator::VisitArgumentListNode(ArgumentListNode* arguments) {
859 for (int i = 0; i < arguments->length(); i++) {
860 AstNode* argument = arguments->NodeAt(i);
861 argument->Visit(this);
862 }
863 }
864
865
866 void CodeGenerator::VisitArrayNode(ArrayNode* node) {
867 // Evaluate the array elements.
868 for (int i = 0; i < node->length(); i++) {
869 AstNode* element = node->ElementAt(i);
870 element->Visit(this);
871 }
872
873 const AbstractTypeArguments& element_type = node->type_arguments();
874 const bool instantiate_type_arguments = true;
875 GenerateTypeArguments(node->id(),
876 node->token_index(),
877 element_type,
878 instantiate_type_arguments);
879 __ popq(RBX);
880 __ movq(R10, Immediate(Smi::RawValue(node->length())));
881
882 // Allocate the array.
883 // R10 : Array length as Smi.
884 // RBX : element type for the array.
885 GenerateCall(node->token_index(),
886 &StubCode::AllocateArrayLabel(),
887 PcDescriptors::kOther);
888
889 // Pop the element values from the stack into the array.
890 __ leaq(RCX, FieldAddress(RAX, Array::data_offset()));
891 for (int i = node->length() - 1; i >= 0; i--) {
892 __ popq(Address(RCX, i * kWordSize));
893 }
894
895 if (IsResultNeeded(node)) {
896 __ pushq(RAX);
897 }
898 }
899
900
901 void CodeGenerator::VisitLoadLocalNode(LoadLocalNode* node) {
902 if (node->HasPseudo()) {
903 node->pseudo()->Visit(this);
904 __ popq(RAX); // Discard result.
905 }
906 // Load the value of the local variable and push it onto the expression stack.
907 if (IsResultNeeded(node)) {
908 GeneratePushVariable(node->local(), RAX);
909 }
910 }
911
912
913 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) {
914 node->value()->Visit(this);
915 __ popq(RAX);
916 if (FLAG_enable_type_checks) {
917 GenerateAssertAssignable(node->id(),
918 node->value()->token_index(),
919 node->value(),
920 node->local().type(),
921 node->local().name());
922 }
923 GenerateStoreVariable(node->local(), RAX, R10);
924 if (IsResultNeeded(node)) {
925 __ pushq(RAX);
926 }
927 }
928
929
930 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) {
931 node->instance()->Visit(this);
932 MarkDeoptPoint(node->id(), node->token_index());
933 __ popq(RAX); // Instance.
934 __ movq(RAX, FieldAddress(RAX, node->field().Offset()));
935 if (IsResultNeeded(node)) {
936 __ pushq(RAX);
937 }
938 }
939
940
941 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) {
942 node->instance()->Visit(this);
943 node->value()->Visit(this);
944 MarkDeoptPoint(node->id(), node->token_index());
945 __ popq(RAX); // Value.
946 if (FLAG_enable_type_checks) {
947 GenerateAssertAssignable(node->id(),
948 node->value()->token_index(),
949 node->value(),
950 AbstractType::ZoneHandle(node->field().type()),
951 String::ZoneHandle(node->field().name()));
952 }
953 __ popq(R10); // Instance.
954 __ StoreIntoObject(R10, FieldAddress(R10, node->field().Offset()), RAX);
955 ASSERT(!IsResultNeeded(node));
956 }
957
958
959 // Expects array and index on stack and returns result in RAX.
960 void CodeGenerator::GenerateLoadIndexed(intptr_t node_id,
961 intptr_t token_index) {
962 // Invoke the [] operator on the receiver object with the index as argument.
963 const String& operator_name =
964 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kINDEX)));
965 const int kNumArguments = 2; // Receiver and index.
966 const Array& kNoArgumentNames = Array::Handle();
967 const int kNumArgumentsChecked = 1;
968 GenerateInstanceCall(node_id,
969 token_index,
970 operator_name,
971 kNumArguments,
972 kNoArgumentNames,
973 kNumArgumentsChecked);
974 }
975
976
977 void CodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) {
978 node->array()->Visit(this);
979 // Now compute the index.
980 node->index_expr()->Visit(this);
981 MarkDeoptPoint(node->id(), node->token_index());
982 GenerateLoadIndexed(node->id(), node->token_index());
983 // Result is in RAX.
984 if (IsResultNeeded(node)) {
985 __ pushq(RAX);
986 }
987 }
988
989
990 // Expected arguments.
991 // TOS(0): value.
992 // TOS(1): index.
993 // TOS(2): array.
994 void CodeGenerator::GenerateStoreIndexed(intptr_t node_id,
995 intptr_t token_index,
996 bool preserve_value) {
997 // It is not necessary to generate a type test of the assigned value here,
998 // because the []= operator will check the type of its incoming arguments.
999 if (preserve_value) {
1000 __ popq(RAX);
1001 __ popq(RDX);
1002 __ popq(RCX);
1003 __ pushq(RAX); // Preserve stored value.
1004 __ pushq(RCX); // Restore arguments.
1005 __ pushq(RDX);
1006 __ pushq(RAX);
1007 }
1008 // Invoke the []= operator on the receiver object with index and
1009 // value as arguments.
1010 const String& operator_name =
1011 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kASSIGN_INDEX)));
1012 const int kNumArguments = 3; // Receiver, index and value.
1013 const Array& kNoArgumentNames = Array::Handle();
1014 const int kNumArgumentsChecked = 1;
1015 GenerateInstanceCall(node_id,
1016 token_index,
1017 operator_name,
1018 kNumArguments,
1019 kNoArgumentNames,
1020 kNumArgumentsChecked);
1021 }
1022
1023
1024 void CodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) {
1025 // Compute the receiver object and pass as first argument to call.
1026 node->array()->Visit(this);
1027 // Now compute the index.
1028 node->index_expr()->Visit(this);
1029 // Finally compute the value to assign.
1030 node->value()->Visit(this);
1031 MarkDeoptPoint(node->id(), node->token_index());
1032 GenerateStoreIndexed(node->id(), node->token_index(), IsResultNeeded(node));
1033 }
1034
1035
1036 void CodeGenerator::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
1037 MarkDeoptPoint(node->id(), node->token_index());
1038 __ LoadObject(RDX, node->field());
1039 __ movq(RAX, FieldAddress(RDX, Field::value_offset()));
1040 if (IsResultNeeded(node)) {
1041 __ pushq(RAX);
1042 }
1043 }
1044
1045
1046 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
1047 node->value()->Visit(this);
1048 MarkDeoptPoint(node->id(), node->token_index());
1049 __ popq(RAX); // Value.
1050 if (FLAG_enable_type_checks) {
1051 GenerateAssertAssignable(node->id(),
1052 node->value()->token_index(),
1053 node->value(),
1054 AbstractType::ZoneHandle(node->field().type()),
1055 String::ZoneHandle(node->field().name()));
1056 }
1057 __ LoadObject(RDX, node->field());
1058 __ StoreIntoObject(RDX, FieldAddress(RDX, Field::value_offset()), RAX);
1059 if (IsResultNeeded(node)) {
1060 // The result is the input value.
1061 __ pushq(RAX);
1062 }
1063 }
1064
1065
1066 void CodeGenerator::GenerateLogicalNotOp(UnaryOpNode* node) {
1067 // Generate false if operand is true, otherwise generate true.
1068 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1069 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1070 node->operand()->Visit(this);
1071 MarkDeoptPoint(node->id(), node->token_index());
1072 Label done;
1073 GenerateConditionTypeCheck(node->id(), node->operand()->token_index());
1074 __ popq(RDX);
1075 __ LoadObject(RAX, bool_true);
1076 __ cmpq(RAX, RDX);
1077 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
1078 __ LoadObject(RAX, bool_false);
1079 __ Bind(&done);
1080 if (IsResultNeeded(node)) {
1081 __ pushq(RAX);
1082 }
1083 }
1084
1085
1086 void CodeGenerator::VisitUnaryOpNode(UnaryOpNode* node) {
1087 if (node->kind() == Token::kNOT) {
1088 // "!" cannot be overloaded, therefore inline it.
1089 GenerateLogicalNotOp(node);
1090 return;
1091 }
1092 node->operand()->Visit(this);
1093 if (node->kind() == Token::kADD) {
1094 // TODO(srdjan): Remove this as it is not part of Dart language any longer.
1095 // Unary operator '+' does not exist, it's a NOP, skip it.
1096 if (!IsResultNeeded(node)) {
1097 __ popq(RAX);
1098 }
1099 return;
1100 }
1101 MarkDeoptPoint(node->id(), node->token_index());
1102 String& operator_name = String::ZoneHandle();
1103 if (node->kind() == Token::kSUB) {
1104 operator_name = String::NewSymbol(Token::Str(Token::kNEGATE));
1105 } else {
1106 operator_name = String::NewSymbol(node->Name());
1107 }
1108 const int kNumberOfArguments = 1;
1109 const Array& kNoArgumentNames = Array::Handle();
1110 const int kNumArgumentsChecked = 1;
1111 GenerateInstanceCall(node->id(),
1112 node->token_index(),
1113 operator_name,
1114 kNumberOfArguments,
1115 kNoArgumentNames,
1116 kNumArgumentsChecked);
1117 if (IsResultNeeded(node)) {
1118 __ pushq(RAX);
1119 }
1120 }
1121
1122
1123 static const Class* CoreClass(const char* c_name) {
1124 const String& class_name = String::Handle(String::NewSymbol(c_name));
1125 const Class& cls = Class::ZoneHandle(Library::Handle(
1126 Library::CoreImplLibrary()).LookupClass(class_name));
1127 ASSERT(!cls.IsNull());
1128 return &cls;
1129 }
1130
1131
1132 // If instanceof type test cannot be performed successfully at compile time and
1133 // therefore eliminated, optimize it by adding inlined tests for:
1134 // - NULL -> return false.
1135 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1136 // - Class equality (only if class is not parameterized).
1137 // Inputs:
1138 // - RAX: object.
1139 // Destroys RCX.
1140 // Returns:
1141 // - true or false on stack.
1142 void CodeGenerator::GenerateInstanceOf(intptr_t node_id,
1143 intptr_t token_index,
1144 AstNode* value,
1145 const AbstractType& type,
1146 bool negate_result) {
1147 ASSERT(type.IsFinalized() && !type.IsMalformed());
1148 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1149 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1150
1151 // All objects are instances of type T if Object type is a subtype of type T.
1152 const Type& object_type =
1153 Type::Handle(Isolate::Current()->object_store()->object_type());
1154 Error& malformed_error = Error::Handle();
1155 if (type.IsInstantiated() &&
1156 object_type.IsSubtypeOf(type, &malformed_error)) {
1157 __ PushObject(negate_result ? bool_false : bool_true);
1158 return;
1159 }
1160
1161 // Eliminate the test if it can be performed successfully at compile time.
1162 if ((value != NULL) && value->IsLiteralNode() && type.IsInstantiated()) {
1163 const Instance& literal_value = value->AsLiteralNode()->literal();
1164 const Class& cls = Class::Handle(literal_value.clazz());
1165 if (cls.IsNullClass()) {
1166 ASSERT(literal_value.IsNull() ||
1167 (literal_value.raw() == Object::sentinel()) ||
1168 (literal_value.raw() == Object::transition_sentinel()));
1169 // A null object is only an instance of Object and Dynamic, which has
1170 // already been checked above (if the type is instantiated). So we can
1171 // return false here if the instance is null (and if the type is
1172 // instantiated).
1173 __ PushObject(negate_result ? bool_true : bool_false);
1174 } else {
1175 Error& malformed_error = Error::Handle();
1176 if (literal_value.IsInstanceOf(type,
1177 TypeArguments::Handle(),
1178 &malformed_error)) {
1179 __ PushObject(negate_result ? bool_false : bool_true);
1180 } else {
1181 ASSERT(malformed_error.IsNull());
1182 __ PushObject(negate_result ? bool_true : bool_false);
1183 }
1184 }
1185 return;
1186 }
1187
1188 const Immediate raw_null =
1189 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1190 Label done;
1191 // If type is instantiated and non-parameterized, we can inline code
1192 // checking whether the tested instance is a Smi.
1193 if (type.IsInstantiated()) {
1194 // A null object is only an instance of Object and Dynamic, which has
1195 // already been checked above (if the type is instantiated). So we can
1196 // return false here if the instance is null (and if the type is
1197 // instantiated).
1198 // We can only inline this null check if the type is instantiated at compile
1199 // time, since an uninstantiated type at compile time could be Object or
1200 // Dynamic at run time.
1201 Label non_null;
1202 __ cmpq(RAX, raw_null);
1203 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump);
1204 __ PushObject(negate_result ? bool_true : bool_false);
1205 __ jmp(&done);
1206
1207 __ Bind(&non_null);
1208
1209 const Class& type_class = Class::ZoneHandle(type.type_class());
1210 const bool requires_type_arguments = type_class.HasTypeArguments();
1211 // A Smi object cannot be the instance of a parameterized class.
1212 // A class equality check is only applicable with a dst type of a
1213 // non-parameterized class or with a raw dst type of a parameterized class.
1214 if (requires_type_arguments) {
1215 const AbstractTypeArguments& type_arguments =
1216 AbstractTypeArguments::Handle(type.arguments());
1217 const bool is_raw_type = type_arguments.IsNull() ||
1218 type_arguments.IsRaw(type_arguments.Length());
1219 Label runtime_call;
1220 __ testq(RAX, Immediate(kSmiTagMask));
1221 __ j(ZERO, &runtime_call, Assembler::kNearJump);
1222 // Object not Smi.
1223 if (is_raw_type) {
1224 if (type.IsListInterface()) {
1225 Label push_result;
1226 // TODO(srdjan) also accept List<Object>.
1227 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1228 __ CompareObject(RCX, *CoreClass("ObjectArray"));
1229 __ j(EQUAL, &push_result, Assembler::kNearJump);
1230 __ CompareObject(RCX, *CoreClass("GrowableObjectArray"));
1231 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
1232 __ Bind(&push_result);
1233 __ PushObject(negate_result ? bool_false : bool_true);
1234 __ jmp(&done);
1235 } else if (!type_class.is_interface()) {
1236 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1237 __ CompareObject(RCX, type_class);
1238 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
1239 __ PushObject(negate_result ? bool_false : bool_true);
1240 __ jmp(&done);
1241 }
1242 }
1243 __ Bind(&runtime_call);
1244 // Fall through to runtime call.
1245 } else {
1246 ASSERT(!requires_type_arguments);
1247 // Test if object is Smi and for a couple known test-classes.
1248 Label compare_classes;
1249 __ testq(RAX, Immediate(kSmiTagMask));
1250 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
1251 // Object is Smi.
1252 const Class& smi_class = Class::Handle(Smi::Class());
1253 // TODO(regis): We should introduce a SmiType.
1254 Error& malformed_error = Error::Handle();
1255 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
1256 type_class,
1257 TypeArguments::Handle(),
1258 &malformed_error)) {
1259 __ PushObject(negate_result ? bool_false : bool_true);
1260 } else {
1261 __ PushObject(negate_result ? bool_true : bool_false);
1262 }
1263 __ jmp(&done);
1264
1265 // Compare if the classes are equal.
1266 __ Bind(&compare_classes);
1267 const Class* compare_class = NULL;
1268 if (type.IsStringInterface()) {
1269 compare_class = &Class::ZoneHandle(
1270 Isolate::Current()->object_store()->one_byte_string_class());
1271 } else if (type.IsBoolInterface()) {
1272 compare_class = &Class::ZoneHandle(
1273 Isolate::Current()->object_store()->bool_class());
1274 } else if (!type_class.is_interface()) {
1275 compare_class = &type_class;
1276 }
1277 if (compare_class != NULL) {
1278 Label runtime_call;
1279 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1280 __ CompareObject(RCX, *compare_class);
1281 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
1282 __ PushObject(negate_result ? bool_false : bool_true);
1283 __ jmp(&done, Assembler::kNearJump);
1284 __ Bind(&runtime_call);
1285 }
1286 }
1287 }
1288 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1289 const Immediate location = Immediate(Smi::RawValue(token_index));
1290 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id));
1291 __ pushq(location); // Push the source location.
1292 __ pushq(node_id_as_smi);
1293 __ pushq(RAX); // Push the instance.
1294 __ PushObject(type); // Push the type.
1295 if (!type.IsInstantiated()) {
1296 GenerateInstantiatorTypeArguments(token_index);
1297 } else {
1298 __ pushq(raw_null); // Null instantiator.
1299 }
1300 __ pushq(raw_null); // SubtypeTestCache not yet supported.
1301 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry);
1302 // Pop the two parameters supplied to the runtime entry. The result of the
1303 // instanceof runtime call will be left as the result of the operation.
1304 __ addq(RSP, Immediate(6 * kWordSize));
1305 if (negate_result) {
1306 Label negate_done;
1307 __ popq(RDX);
1308 __ LoadObject(RAX, bool_true);
1309 __ cmpq(RDX, RAX);
1310 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump);
1311 __ LoadObject(RAX, bool_false);
1312 __ Bind(&negate_done);
1313 __ pushq(RAX);
1314 }
1315 __ Bind(&done);
1316 }
1317
1318
1319 // Jumps to label if RCX equals the given class.
1320 // Inputs:
1321 // - RCX: tested class.
1322 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) {
1323 __ CompareObject(RCX, cls);
1324 __ j(EQUAL, label);
1325 }
1326
1327
1328 // If type check cannot be performed successfully at compile time and therefore
1329 // eliminated, optimize it by adding inlined tests for:
1330 // - NULL -> return NULL.
1331 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1332 // - Class equality (only if class is not parameterized).
1333 // Inputs:
1334 // - RAX: object.
1335 // Destroys RCX and RDX.
1336 // Returns:
1337 // - object in RAX for successful assignable check (or throws TypeError).
1338 // Performance notes: positive checks must be quick, negative checks can be slow
1339 // as they throw an exception.
1340 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id,
1341 intptr_t token_index,
1342 AstNode* value,
1343 const AbstractType& dst_type,
1344 const String& dst_name) {
1345 ASSERT(FLAG_enable_type_checks);
1346 ASSERT(token_index >= 0);
1347 ASSERT(!dst_type.IsNull());
1348 ASSERT(dst_type.IsFinalized());
1349
1350 // Any expression is assignable to the Dynamic type and to the Object type.
1351 // Skip the test.
1352 if (!dst_type.IsMalformed() &&
1353 (dst_type.IsDynamicType() || dst_type.IsObjectType())) {
1354 return;
1355 }
1356
1357 // It is a compile-time error to explicitly return a value (including null)
1358 // from a void function. However, functions that do not explicitly return a
1359 // value, implicitly return null. This includes void functions. Therefore, we
1360 // skip the type test here and trust the parser to only return null in void
1361 // function.
1362 if (dst_type.IsVoidType()) {
1363 return;
1364 }
1365
1366 // Eliminate the test if it can be performed successfully at compile time.
1367 if ((value != NULL) && value->IsLiteralNode()) {
1368 const Instance& literal_value = value->AsLiteralNode()->literal();
1369 const Class& cls = Class::Handle(literal_value.clazz());
1370 if (cls.IsNullClass()) {
1371 ASSERT(literal_value.IsNull() ||
1372 (literal_value.raw() == Object::sentinel()) ||
1373 (literal_value.raw() == Object::transition_sentinel()));
1374 return;
1375 }
1376 Error& malformed_error = Error::Handle();
1377 if (!dst_type.IsMalformed() &&
1378 dst_type.IsInstantiated() &&
1379 literal_value.IsInstanceOf(dst_type,
1380 TypeArguments::Handle(),
1381 &malformed_error)) {
1382 return;
1383 }
1384 }
1385
1386 // A null object is always assignable and is returned as result.
1387 const Immediate raw_null =
1388 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1389 Label done, runtime_call;
1390 __ cmpq(RAX, raw_null);
1391 __ j(EQUAL, &done);
1392
1393 // Generate throw new TypeError() if the type is malformed.
1394 if (dst_type.IsMalformed()) {
1395 const Error& error = Error::Handle(dst_type.malformed_error());
1396 const String& error_message = String::ZoneHandle(
1397 String::NewSymbol(error.ToErrorCString()));
1398 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1399 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
1400 __ pushq(RAX); // Push the source object.
1401 __ PushObject(dst_name); // Push the name of the destination.
1402 __ PushObject(error_message);
1403 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry);
1404 // We should never return here.
1405 __ int3();
1406
1407 __ Bind(&done); // For a null object.
1408 return;
1409 }
1410
1411 // If dst_type is instantiated and non-parameterized, we can inline code
1412 // checking whether the assigned instance is a Smi.
1413 if (dst_type.IsInstantiated()) {
1414 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class());
1415 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments();
1416 // A Smi object cannot be the instance of a parameterized class.
1417 // A class equality check is only applicable with a dst type of a
1418 // non-parameterized class or with a raw dst type of a parameterized class.
1419 if (dst_class_has_type_arguments) {
1420 const AbstractTypeArguments& dst_type_arguments =
1421 AbstractTypeArguments::Handle(dst_type.arguments());
1422 const bool is_raw_dst_type = dst_type_arguments.IsNull() ||
1423 dst_type_arguments.IsRaw(dst_type_arguments.Length());
1424 if (is_raw_dst_type) {
1425 // Dynamic type argument, check only classes.
1426 if (dst_type.IsListInterface()) {
1427 // TODO(srdjan) also accept List<Object>.
1428 __ testq(RAX, Immediate(kSmiTagMask));
1429 __ j(ZERO, &runtime_call);
1430 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1431 TestClassAndJump(*CoreClass("ObjectArray"), &done);
1432 TestClassAndJump(*CoreClass("GrowableObjectArray"), &done);
1433 } else if (!dst_type_class.is_interface()) {
1434 __ testq(RAX, Immediate(kSmiTagMask));
1435 __ j(ZERO, &runtime_call);
1436 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1437 TestClassAndJump(dst_type_class, &done);
1438 }
1439 // Fall through to runtime class.
1440 }
1441 } else { // dst_type has NO type arguments.
1442 Label compare_classes;
1443 __ testq(RAX, Immediate(kSmiTagMask));
1444 __ j(NOT_ZERO, &compare_classes);
1445 // Object is Smi.
1446 const Class& smi_class = Class::Handle(Smi::Class());
1447 // TODO(regis): We should introduce a SmiType.
1448 Error& malformed_error = Error::Handle();
1449 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
1450 dst_type_class,
1451 TypeArguments::Handle(),
1452 &malformed_error)) {
1453 // Successful assignable type check: return object in RAX.
1454 __ jmp(&done);
1455 } else {
1456 // Failed assignable type check: call runtime to throw TypeError.
1457 __ jmp(&runtime_call);
1458 }
1459 // Compare if the classes are equal.
1460 __ Bind(&compare_classes);
1461 // If dst_type is an interface, we can skip the class equality check,
1462 // because instances cannot be of an interface type.
1463 if (!dst_type_class.is_interface()) {
1464 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1465 TestClassAndJump(dst_type_class, &done);
1466 } else {
1467 // However, for specific core library interfaces, we can check for
1468 // specific core library classes.
1469 Error& malformed_error = Error::Handle();
1470 if (dst_type.IsBoolInterface()) {
1471 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1472 const Class& bool_class = Class::ZoneHandle(
1473 Isolate::Current()->object_store()->bool_class());
1474 TestClassAndJump(bool_class, &done);
1475 } else if (dst_type.IsSubtypeOf(
1476 Type::Handle(Type::NumberInterface()), &malformed_error)) {
1477 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1478 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) {
1479 // We already checked for Smi above.
1480 const Class& mint_class = Class::ZoneHandle(
1481 Isolate::Current()->object_store()->mint_class());
1482 TestClassAndJump(mint_class, &done);
1483 const Class& bigint_class = Class::ZoneHandle(
1484 Isolate::Current()->object_store()->bigint_class());
1485 TestClassAndJump(bigint_class, &done);
1486 }
1487 if (dst_type.IsDoubleInterface() || dst_type.IsNumberInterface()) {
1488 const Class& double_class = Class::ZoneHandle(
1489 Isolate::Current()->object_store()->double_class());
1490 TestClassAndJump(double_class, &done);
1491 }
1492 } else if (dst_type.IsStringInterface()) {
1493 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1494 const Class& one_byte_string_class = Class::ZoneHandle(
1495 Isolate::Current()->object_store()->one_byte_string_class());
1496 TestClassAndJump(one_byte_string_class, &done);
1497 const Class& two_byte_string_class = Class::ZoneHandle(
1498 Isolate::Current()->object_store()->two_byte_string_class());
1499 TestClassAndJump(two_byte_string_class, &done);
1500 const Class& four_byte_string_class = Class::ZoneHandle(
1501 Isolate::Current()->object_store()->four_byte_string_class());
1502 TestClassAndJump(four_byte_string_class, &done);
1503 } else if (dst_type.IsFunctionInterface()) {
1504 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1505 __ movq(RCX, FieldAddress(RCX, Class::signature_function_offset()));
1506 __ cmpq(RCX, raw_null);
1507 __ j(NOT_EQUAL, &done);
1508 }
1509 }
1510 }
1511 }
1512 __ Bind(&runtime_call);
1513 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1514 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
1515 __ pushq(Immediate(Smi::RawValue(node_id))); // node-id.
1516 __ pushq(RAX); // Push the source object.
1517 __ PushObject(dst_type); // Push the type of the destination.
1518 if (!dst_type.IsInstantiated()) {
1519 GenerateInstantiatorTypeArguments(token_index);
1520 } else {
1521 __ pushq(raw_null); // Null instantiator.
1522 }
1523 __ PushObject(dst_name); // Push the name of the destination.
1524 __ pushq(raw_null); // SubtypeTestCache not yet supported.
1525 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry);
1526 // Pop the parameters supplied to the runtime entry. The result of the
1527 // type check runtime call is the checked value.
1528 __ addq(RSP, Immediate(7 * kWordSize));
1529 __ popq(RAX);
1530
1531 __ Bind(&done);
1532 }
1533
1534
1535 void CodeGenerator::GenerateArgumentTypeChecks() {
1536 const Function& function = parsed_function_.function();
1537 const SequenceNode& sequence_node = *parsed_function_.node_sequence();
1538 LocalScope* scope = sequence_node.scope();
1539 const int num_fixed_params = function.num_fixed_parameters();
1540 const int num_opt_params = function.num_optional_parameters();
1541 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables());
1542 for (int i = 0; i < num_fixed_params + num_opt_params; i++) {
1543 LocalVariable* parameter = scope->VariableAt(i);
1544 GenerateLoadVariable(RAX, *parameter);
1545 GenerateAssertAssignable(sequence_node.ParameterIdAt(i),
1546 parameter->token_index(),
1547 NULL,
1548 parameter->type(),
1549 parameter->name());
1550 }
1551 }
1552
1553
1554 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id,
1555 intptr_t token_index) {
1556 if (!FLAG_enable_type_checks) {
1557 return;
1558 }
1559
1560 // Check that the type of the object on the stack is allowed in conditional
1561 // context.
1562 // Call the runtime if the object is null or not of type bool.
1563 const Immediate raw_null =
1564 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1565 Label runtime_call, done;
1566 __ movq(RAX, Address(RSP, 0));
1567 __ cmpq(RAX, raw_null);
1568 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
1569 __ testq(RAX, Immediate(kSmiTagMask));
1570 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi.
1571 // This check should pass if the receiver's class implements the interface
1572 // 'bool'. Check only class 'Bool' since it is the only legal implementation
1573 // of the interface 'bool'.
1574 const Class& bool_class =
1575 Class::ZoneHandle(Isolate::Current()->object_store()->bool_class());
1576 __ movq(RCX, FieldAddress(RAX, Object::class_offset()));
1577 __ CompareObject(RCX, bool_class);
1578 __ j(EQUAL, &done, Assembler::kNearJump);
1579
1580 __ Bind(&runtime_call);
1581 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
1582 __ pushq(RAX); // Push the source object.
1583 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry);
1584 // We should never return here.
1585 __ int3();
1586
1587 __ Bind(&done);
1588 }
1589
1590
1591 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) {
1592 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1593 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1594 node->left()->Visit(this);
1595
1596 // The instanceof operator needs special handling.
1597 if (Token::IsInstanceofOperator(node->kind())) {
1598 __ popq(RAX); // Left operand.
1599 ASSERT(node->right()->IsTypeNode());
1600 GenerateInstanceOf(node->id(),
1601 node->token_index(),
1602 node->left(),
1603 node->right()->AsTypeNode()->type(),
1604 (node->kind() == Token::kISNOT));
1605 if (!IsResultNeeded(node)) {
1606 __ popq(RAX); // Pop the result of the instanceof operation.
1607 }
1608 return;
1609 }
1610
1611 node->right()->Visit(this);
1612 // Both left and right values on stack.
1613
1614 // '===' and '!==' are not overloadable.
1615 if ((node->kind() == Token::kEQ_STRICT) ||
1616 (node->kind() == Token::kNE_STRICT)) {
1617 __ popq(RDX); // Right operand.
1618 __ popq(RAX); // Left operand.
1619 if (!IsResultNeeded(node)) {
1620 return;
1621 }
1622 Label load_true, done;
1623 __ cmpq(RAX, RDX);
1624 if (node->kind() == Token::kEQ_STRICT) {
1625 __ j(EQUAL, &load_true, Assembler::kNearJump);
1626 } else {
1627 __ j(NOT_EQUAL, &load_true, Assembler::kNearJump);
1628 }
1629 __ LoadObject(RAX, bool_false);
1630 __ jmp(&done, Assembler::kNearJump);
1631 __ Bind(&load_true);
1632 __ LoadObject(RAX, bool_true);
1633 __ Bind(&done);
1634 // Result is in RAX.
1635 __ pushq(RAX);
1636 return;
1637 }
1638
1639 MarkDeoptPoint(node->id(), node->token_index());
1640
1641 // '!=' not overloadable, always implements negation of '=='.
1642 // Call operator for '=='.
1643 if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) {
1644 // Null is a special receiver with a special type and frequently used on
1645 // operators "==" and "!=". Emit inlined code for null so that it does not
1646 // pollute type information at call site.
1647 Label null_done;
1648 {
1649 const Immediate raw_null =
1650 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1651 Label non_null_compare, load_true;
1652 // Check if left argument is null.
1653 __ cmpq(Address(RSP, 1 * kWordSize), raw_null);
1654 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
1655 // Comparison with NULL is "===".
1656 // Load/remove arguments.
1657 __ popq(RDX);
1658 __ popq(RAX);
1659 __ cmpq(RAX, RDX);
1660 if (node->kind() == Token::kEQ) {
1661 __ j(EQUAL, &load_true, Assembler::kNearJump);
1662 } else {
1663 __ j(NOT_EQUAL, &load_true, Assembler::kNearJump);
1664 }
1665 __ LoadObject(RAX, bool_false);
1666 __ jmp(&null_done, Assembler::kNearJump);
1667 __ Bind(&load_true);
1668 __ LoadObject(RAX, bool_true);
1669 __ jmp(&null_done, Assembler::kNearJump);
1670 __ Bind(&non_null_compare);
1671 }
1672 // Do '==' first then negate if necessary,
1673 const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
1674 const int kNumberOfArguments = 2;
1675 const Array& kNoArgumentNames = Array::Handle();
1676 const int kNumArgumentsChecked = 1;
1677 GenerateInstanceCall(node->id(),
1678 node->token_index(),
1679 operator_name,
1680 kNumberOfArguments,
1681 kNoArgumentNames,
1682 kNumArgumentsChecked);
1683
1684 // Result is in RAX. No need to negate if result is not needed.
1685 if ((node->kind() == Token::kNE) && IsResultNeeded(node)) {
1686 // Negate result.
1687 Label load_true, done;
1688 __ LoadObject(RDX, bool_false);
1689 __ cmpq(RAX, RDX);
1690 __ j(EQUAL, &load_true, Assembler::kNearJump);
1691 __ movq(RAX, RDX); // false.
1692 __ jmp(&done, Assembler::kNearJump);
1693 __ Bind(&load_true);
1694 __ LoadObject(RAX, bool_true);
1695 __ Bind(&done);
1696 }
1697 __ Bind(&null_done);
1698 // Result is in RAX.
1699 if (IsResultNeeded(node)) {
1700 __ pushq(RAX);
1701 }
1702 return;
1703 }
1704
1705 // Call operator.
1706 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name());
1707 // Result is in RAX.
1708 if (IsResultNeeded(node)) {
1709 __ pushq(RAX);
1710 }
1711 }
1712
1713
1714 void CodeGenerator::HandleBackwardBranch(
1715 intptr_t loop_id, intptr_t token_index) {
1716 // Use stack overflow check to eventually stop execution of loops.
1717 // This is necessary only if a loop does not have calls.
1718 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address()));
1719 __ cmpq(RSP, Address(TMP, 0));
1720 Label no_stack_overflow;
1721 __ j(ABOVE, &no_stack_overflow);
1722 GenerateCallRuntime(loop_id,
1723 token_index,
1724 kStackOverflowRuntimeEntry);
1725 __ Bind(&no_stack_overflow);
1726 }
1727
1728
1729 void CodeGenerator::VisitWhileNode(WhileNode* node) {
1730 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1731 SourceLabel* label = node->label();
1732 __ Bind(label->continue_label());
1733 node->condition()->Visit(this);
1734 GenerateConditionTypeCheck(node->id(), node->condition()->token_index());
1735 __ popq(RAX);
1736 __ LoadObject(RDX, bool_true);
1737 __ cmpq(RAX, RDX);
1738 __ j(NOT_EQUAL, label->break_label());
1739 node->body()->Visit(this);
1740 HandleBackwardBranch(node->id(), node->token_index());
1741 __ jmp(label->continue_label());
1742 __ Bind(label->break_label());
1743 }
1744
1745
1746 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) {
1747 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1748 SourceLabel* label = node->label();
1749 Label loop;
1750 __ Bind(&loop);
1751 node->body()->Visit(this);
1752 HandleBackwardBranch(node->id(), node->token_index());
1753 __ Bind(label->continue_label());
1754 node->condition()->Visit(this);
1755 GenerateConditionTypeCheck(node->id(), node->condition()->token_index());
1756 __ popq(RAX);
1757 __ LoadObject(RDX, bool_true);
1758 __ cmpq(RAX, RDX);
1759 __ j(EQUAL, &loop);
1760 __ Bind(label->break_label());
1761 }
1762
1763
1764 void CodeGenerator::VisitForNode(ForNode* node) {
1765 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1766 node->initializer()->Visit(this);
1767 SourceLabel* label = node->label();
1768 Label loop;
1769 __ Bind(&loop);
1770 if (node->condition() != NULL) {
1771 node->condition()->Visit(this);
1772 GenerateConditionTypeCheck(node->id(), node->condition()->token_index());
1773 __ popq(RAX);
1774 __ LoadObject(RDX, bool_true);
1775 __ cmpq(RAX, RDX);
1776 __ j(NOT_EQUAL, label->break_label());
1777 }
1778 node->body()->Visit(this);
1779 HandleBackwardBranch(node->id(), node->token_index());
1780 __ Bind(label->continue_label());
1781 node->increment()->Visit(this);
1782 __ jmp(&loop);
1783 __ Bind(label->break_label());
1784 }
1785
1786
1787 void CodeGenerator::VisitJumpNode(JumpNode* node) {
1788 SourceLabel* label = node->label();
1789
1790 // Generate inlined code for all finally blocks as we may transfer
1791 // control out of the 'try' blocks if any.
1792 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) {
1793 node->InlinedFinallyNodeAt(i)->Visit(this);
1794 }
1795
1796 // Unchain the context(s) up to the outer context level of the scope which
1797 // contains the destination label.
1798 ASSERT(label->owner() != NULL);
1799 intptr_t target_context_level = 0;
1800 LocalScope* target_scope = label->owner();
1801 if (target_scope->num_context_variables() > 0) {
1802 // The scope of the target label allocates a context, therefore its outer
1803 // scope is at a lower context level.
1804 target_context_level = target_scope->context_level() - 1;
1805 } else {
1806 // The scope of the target label does not allocate a context, so its outer
1807 // scope is at the same context level. Find it.
1808 while ((target_scope != NULL) &&
1809 (target_scope->num_context_variables() == 0)) {
1810 target_scope = target_scope->parent();
1811 }
1812 if (target_scope != NULL) {
1813 target_context_level = target_scope->context_level();
1814 }
1815 }
1816 ASSERT(target_context_level >= 0);
1817 int current_context_level = context_level();
1818 ASSERT(current_context_level >= target_context_level);
1819 while (current_context_level-- > target_context_level) {
1820 __ movq(CTX, FieldAddress(CTX, Context::parent_offset()));
1821 }
1822
1823 if (node->kind() == Token::kBREAK) {
1824 __ jmp(label->break_label());
1825 } else {
1826 __ jmp(label->continue_label());
1827 }
1828 }
1829
1830
1831 void CodeGenerator::VisitConditionalExprNode(ConditionalExprNode* node) {
1832 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1833 Label false_label, done;
1834 node->condition()->Visit(this);
1835 GenerateConditionTypeCheck(node->id(), node->condition()->token_index());
1836 __ popq(RAX);
1837 __ LoadObject(RDX, bool_true);
1838 __ cmpq(RAX, RDX);
1839 __ j(NOT_EQUAL, &false_label);
1840 node->true_expr()->Visit(this);
1841 __ jmp(&done);
1842 __ Bind(&false_label);
1843 node->false_expr()->Visit(this);
1844 __ Bind(&done);
1845 if (!IsResultNeeded(node)) {
1846 __ popq(RAX);
1847 }
1848 }
1849
1850
1851 void CodeGenerator::VisitSwitchNode(SwitchNode *node) {
1852 SourceLabel* label = node->label();
1853 node->body()->Visit(this);
1854 __ Bind(label->break_label());
1855 }
1856
1857
1858 void CodeGenerator::VisitCaseNode(CaseNode* node) {
1859 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1860 Label case_statements, end_case;
1861
1862 for (int i = 0; i < node->case_expressions()->length(); i++) {
1863 // Load case expression onto stack.
1864 AstNode* case_expr = node->case_expressions()->NodeAt(i);
1865 case_expr->Visit(this);
1866 __ popq(RAX);
1867 __ CompareObject(RAX, bool_true);
1868 // Jump to case clause code if case expression equals switch expression
1869 __ j(EQUAL, &case_statements);
1870 }
1871 // If this case clause contains the default label, fall through to
1872 // case clause code, else skip this clause.
1873 if (!node->contains_default()) {
1874 __ jmp(&end_case);
1875 }
1876
1877 // If there is a label associated with this case clause, bind it.
1878 if (node->label() != NULL) {
1879 __ Bind(node->label()->continue_label());
1880 }
1881
1882 // Generate code for case clause statements. The parser guarantees that
1883 // the code contains a jump, so we should never fall through the end
1884 // of the statements.
1885 __ Bind(&case_statements);
1886 node->statements()->Visit(this);
1887 __ Bind(&end_case);
1888 }
1889
1890
1891 void CodeGenerator::VisitIfNode(IfNode* node) {
1892 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1893 Label false_label;
1894 node->condition()->Visit(this);
1895 GenerateConditionTypeCheck(node->id(), node->condition()->token_index());
1896 __ popq(RAX);
1897 __ LoadObject(RDX, bool_true);
1898 __ cmpq(RAX, RDX);
1899 __ j(NOT_EQUAL, &false_label);
1900 node->true_branch()->Visit(this);
1901 if (node->false_branch() != NULL) {
1902 Label done;
1903 __ jmp(&done);
1904 __ Bind(&false_label);
1905 node->false_branch()->Visit(this);
1906 __ Bind(&done);
1907 } else {
1908 __ Bind(&false_label);
1909 }
1910 }
1911
1912
1913 // Operators '&&' and '||' are not overloadabled, inline them.
1914 void CodeGenerator::GenerateLogicalAndOrOp(BinaryOpNode* node) {
1915 // Generate true if (left == true) op (right == true), otherwise generate
1916 // false, with op being either || or &&.
1917 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1918 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1919 Label load_false, done;
1920 node->left()->Visit(this);
1921 GenerateConditionTypeCheck(node->id(), node->left()->token_index());
1922 __ popq(RAX);
1923 __ LoadObject(RDX, bool_true);
1924 __ cmpq(RAX, RDX);
1925 if (node->kind() == Token::kAND) {
1926 __ j(NOT_EQUAL, &load_false);
1927 } else {
1928 ASSERT(node->kind() == Token::kOR);
1929 __ j(EQUAL, &done);
1930 }
1931 node->right()->Visit(this);
1932 GenerateConditionTypeCheck(node->id(), node->right()->token_index());
1933 __ popq(RAX);
1934 __ LoadObject(RDX, bool_true);
1935 __ cmpq(RAX, RDX);
1936 __ j(EQUAL, &done);
1937 __ Bind(&load_false);
1938 __ LoadObject(RAX, bool_false);
1939 __ Bind(&done);
1940 if (IsResultNeeded(node)) {
1941 __ pushq(RAX);
1942 }
1943 }
1944
1945
1946 // Expect receiver(left operand) and right operand on stack.
1947 // Return result in RAX.
1948 void CodeGenerator::GenerateBinaryOperatorCall(intptr_t node_id,
1949 intptr_t token_index,
1950 const char* name) {
1951 const String& operator_name = String::ZoneHandle(String::NewSymbol(name));
1952 const int kNumberOfArguments = 2;
1953 const Array& kNoArgumentNames = Array::Handle();
1954 const int kNumArgumentsChecked = 2;
1955 GenerateInstanceCall(node_id,
1956 token_index,
1957 operator_name,
1958 kNumberOfArguments,
1959 kNoArgumentNames,
1960 kNumArgumentsChecked);
1961 }
1962
1963
1964 void CodeGenerator::VisitBinaryOpNode(BinaryOpNode* node) {
1965 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
1966 // Operators "&&" and "||" cannot be overloaded, therefore inline them
1967 // instead of calling the operator.
1968 GenerateLogicalAndOrOp(node);
1969 return;
1970 }
1971 node->left()->Visit(this);
1972 node->right()->Visit(this);
1973 MarkDeoptPoint(node->id(), node->token_index());
1974 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name());
1975 if (IsResultNeeded(node)) {
1976 __ pushq(RAX);
1977 }
1978 }
1979
1980
1981 void CodeGenerator::VisitStringConcatNode(StringConcatNode* node) {
1982 const String& cls_name = String::Handle(String::NewSymbol("StringBase"));
1983 const Library& core_lib = Library::Handle(
1984 Isolate::Current()->object_store()->core_library());
1985 const Class& cls = Class::Handle(core_lib.LookupClass(cls_name));
1986 ASSERT(!cls.IsNull());
1987 const String& func_name = String::Handle(String::NewSymbol("_interpolate"));
1988 const int number_of_parameters = 1;
1989 const Function& interpol_func = Function::ZoneHandle(
1990 Resolver::ResolveStatic(cls, func_name,
1991 number_of_parameters,
1992 Array::Handle(),
1993 Resolver::kIsQualified));
1994 ASSERT(!interpol_func.IsNull());
1995
1996 // First try to concatenate and canonicalize the values at compile time.
1997 bool compile_time_interpolation = true;
1998 Array& literals = Array::Handle(Array::New(node->values()->length()));
1999 for (int i = 0; i < node->values()->length(); i++) {
2000 if (node->values()->ElementAt(i)->IsLiteralNode()) {
2001 LiteralNode* lit = node->values()->ElementAt(i)->AsLiteralNode();
2002 literals.SetAt(i, lit->literal());
2003 } else {
2004 compile_time_interpolation = false;
2005 break;
2006 }
2007 }
2008 if (compile_time_interpolation) {
2009 if (!IsResultNeeded(node)) {
2010 return;
2011 }
2012 // Build argument array to pass to the interpolation function.
2013 GrowableArray<const Object*> interpolate_arg;
2014 interpolate_arg.Add(&literals);
2015 const Array& kNoArgumentNames = Array::Handle();
2016 // Call the interpolation function.
2017 String& concatenated = String::ZoneHandle();
2018 concatenated ^= DartEntry::InvokeStatic(interpol_func,
2019 interpolate_arg,
2020 kNoArgumentNames);
2021 if (concatenated.IsUnhandledException()) {
2022 // TODO(hausner): Shouldn't we generate a throw?
2023 // Then remove unused CodeGenerator::ErrorMsg().
2024 ErrorMsg(node->token_index(),
2025 "Exception thrown in CodeGenerator::VisitStringConcatNode");
2026 }
2027 ASSERT(!concatenated.IsNull());
2028 concatenated = String::NewSymbol(concatenated);
2029
2030 __ LoadObject(RAX, concatenated);
2031 __ pushq(RAX);
2032 return;
2033 }
2034
2035 // Could not concatenate at compile time, generate a call to
2036 // interpolation function.
2037 ArgumentListNode* interpol_arg = new ArgumentListNode(node->token_index());
2038 interpol_arg->Add(node->values());
2039 node->values()->Visit(this);
2040 __ LoadObject(RBX, interpol_func);
2041 __ LoadObject(R10, ArgumentsDescriptor(interpol_arg->length(),
2042 interpol_arg->names()));
2043 GenerateCall(node->token_index(),
2044 &StubCode::CallStaticFunctionLabel(),
2045 PcDescriptors::kFuncCall);
2046 __ addq(RSP, Immediate(interpol_arg->length() * kWordSize));
2047 // Result is in RAX.
2048 if (IsResultNeeded(node)) {
2049 __ pushq(RAX);
2050 }
2051 }
2052
2053
2054 void CodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) {
2055 const int number_of_arguments = node->arguments()->length() + 1;
2056 // Compute the receiver object and pass it as first argument to call.
2057 node->receiver()->Visit(this);
2058 // Now compute rest of the arguments to the call.
2059 node->arguments()->Visit(this);
2060 // Some method may be inlined using type feedback, therefore this may be a
2061 // deoptimization point.
2062 MarkDeoptPoint(node->id(), node->token_index());
2063 const int kNumArgumentsChecked = 1;
2064 GenerateInstanceCall(node->id(),
2065 node->token_index(),
2066 node->function_name(),
2067 number_of_arguments,
2068 node->arguments()->names(),
2069 kNumArgumentsChecked);
2070 // Result is in RAX.
2071 if (IsResultNeeded(node)) {
2072 __ pushq(RAX);
2073 }
2074 }
2075
2076
2077 void CodeGenerator::VisitStaticCallNode(StaticCallNode* node) {
2078 node->arguments()->Visit(this);
2079 __ LoadObject(RBX, node->function());
2080 __ LoadObject(R10, ArgumentsDescriptor(node->arguments()->length(),
2081 node->arguments()->names()));
2082 GenerateCall(node->token_index(),
2083 &StubCode::CallStaticFunctionLabel(),
2084 PcDescriptors::kFuncCall);
2085 __ addq(RSP, Immediate(node->arguments()->length() * kWordSize));
2086 // Result is in RAX.
2087 if (IsResultNeeded(node)) {
2088 __ pushq(RAX);
2089 }
2090 }
2091
2092
2093 void CodeGenerator::VisitClosureCallNode(ClosureCallNode* node) {
2094 // The spec states that the closure is evaluated before the arguments.
2095 // Preserve the current context, since it will be overridden by the closure
2096 // context during the call.
2097 __ pushq(CTX);
2098 // Compute the closure object and pass it as first argument to the stub.
2099 node->closure()->Visit(this);
2100 // Now compute the arguments to the call.
2101 node->arguments()->Visit(this);
2102 // Set up the number of arguments (excluding the closure) to the ClosureCall
2103 // stub which will setup the closure context and jump to the entrypoint of the
2104 // closure function (the function will be compiled if it has not already been
2105 // compiled).
2106 // NOTE: The stub accesses the closure before the parameter list.
2107 __ LoadObject(R10, ArgumentsDescriptor(node->arguments()->length(),
2108 node->arguments()->names()));
2109 GenerateCall(node->token_index(),
2110 &StubCode::CallClosureFunctionLabel(),
2111 PcDescriptors::kOther);
2112 __ addq(RSP, Immediate((node->arguments()->length() + 1) * kWordSize));
2113 // Restore the context.
2114 __ popq(CTX);
2115 // Result is in RAX.
2116 if (IsResultNeeded(node)) {
2117 __ pushq(RAX);
2118 }
2119 }
2120
2121
2122 // Pushes the type arguments of the instantiator on the stack.
2123 void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_index) {
2124 const Class& instantiator_class = Class::Handle(
2125 parsed_function().function().owner());
2126 if (instantiator_class.NumTypeParameters() == 0) {
2127 // The type arguments are compile time constants.
2128 AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle();
2129 // TODO(regis): Temporary type should be allocated in new gen heap.
2130 Type& type = Type::Handle(
2131 Type::New(instantiator_class, type_arguments, token_index));
2132 type ^= ClassFinalizer::FinalizeType(
2133 instantiator_class, type, ClassFinalizer::kFinalizeWellFormed);
2134 type_arguments = type.arguments();
2135 __ PushObject(type_arguments);
2136 } else {
2137 ASSERT(parsed_function().instantiator() != NULL);
2138 parsed_function().instantiator()->Visit(this);
2139 Function& outer_function =
2140 Function::Handle(parsed_function().function().raw());
2141 while (outer_function.IsLocalFunction()) {
2142 outer_function = outer_function.parent_function();
2143 }
2144 if (!outer_function.IsFactory()) {
2145 __ popq(RAX); // Pop instantiator.
2146 // The instantiator is the receiver of the caller, which is not a factory.
2147 // The receiver cannot be null; extract its AbstractTypeArguments object.
2148 // Note that in the factory case, the instantiator is the first parameter
2149 // of the factory, i.e. already an AbstractTypeArguments object.
2150 intptr_t type_arguments_instance_field_offset =
2151 instantiator_class.type_arguments_instance_field_offset();
2152 ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments);
2153 __ movq(RAX, FieldAddress(RAX, type_arguments_instance_field_offset));
2154 __ pushq(RAX);
2155 }
2156 }
2157 }
2158
2159
2160 // Pushes the type arguments on the stack in preparation of an allocation call.
2161 // If instantiate_type_arguments is true, the instantiated type arguments
2162 // are pushed on the stack (after an instantiation run time call, if necessary).
2163 // If instantiate_type_arguments is false, the (possibly uninstantiated) type
2164 // arguments are pushed on the stack, as well as the type arguments of the
2165 // instantiator (or the special kNoInstantiator Smi marker, if the type
2166 // arguments are instantiated).
2167 void CodeGenerator::GenerateTypeArguments(
2168 intptr_t node_id,
2169 intptr_t token_index,
2170 const AbstractTypeArguments& type_arguments,
2171 bool instantiate_type_arguments) {
2172 const Immediate raw_null =
2173 Immediate(reinterpret_cast<intptr_t>(Object::null()));
2174 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
2175 // The type arguments are instantiated.
2176 __ PushObject(type_arguments);
2177 if (!instantiate_type_arguments) {
2178 // The type arguments of the instantiator are not needed, since the
2179 // type arguments are instantiated.
2180 __ pushq(Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
2181 }
2182 } else {
2183 // The type arguments are uninstantiated.
2184 GenerateInstantiatorTypeArguments(token_index);
2185 __ popq(RAX); // Pop instantiator.
2186 // RAX is the instantiator AbstractTypeArguments object (or null).
2187 // If the instantiator is null and if the type argument vector
2188 // instantiated from null becomes a vector of Dynamic, then use null as
2189 // the type arguments.
2190 Label type_arguments_instantiated;
2191 const intptr_t len = type_arguments.Length();
2192 if (type_arguments.IsRawInstantiatedRaw(len)) {
2193 __ cmpq(RAX, raw_null);
2194 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
2195 }
2196 // Instantiate non-null type arguments.
2197 if (type_arguments.IsUninstantiatedIdentity()) {
2198 // Check if the instantiator type argument vector is a TypeArguments of a
2199 // matching length and, if so, use it as the instantiated type_arguments.
2200 // No need to check RAX for null (again), because a null instance will
2201 // have the wrong class (Null instead of TypeArguments).
2202 Label type_arguments_uninstantiated;
2203 __ LoadObject(RCX, Class::ZoneHandle(Object::type_arguments_class()));
2204 __ cmpq(RCX, FieldAddress(RAX, Object::class_offset()));
2205 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
2206 __ cmpq(FieldAddress(RAX, TypeArguments::length_offset()),
2207 Immediate(Smi::RawValue(len)));
2208 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
2209 __ Bind(&type_arguments_uninstantiated);
2210 }
2211 if (instantiate_type_arguments) {
2212 // A runtime call to instantiate the type arguments is required.
2213 __ PushObject(Object::ZoneHandle()); // Make room for the result.
2214 __ PushObject(type_arguments);
2215 __ pushq(RAX); // Push instantiator type arguments.
2216 GenerateCallRuntime(node_id,
2217 token_index,
2218 kInstantiateTypeArgumentsRuntimeEntry);
2219 __ popq(RAX); // Pop instantiator type arguments.
2220 __ popq(RAX); // Pop uninstantiated type arguments.
2221 __ popq(RAX); // Pop instantiated type arguments.
2222 __ Bind(&type_arguments_instantiated);
2223 __ pushq(RAX); // Instantiated type arguments.
2224 } else {
2225 // The allocation stub will instantiate the type arguments.
2226 __ PushObject(type_arguments);
2227 __ pushq(RAX); // Instantiator type arguments.
2228 Label type_arguments_pushed;
2229 __ jmp(&type_arguments_pushed, Assembler::kNearJump);
2230
2231 __ Bind(&type_arguments_instantiated);
2232 __ pushq(RAX); // Instantiated type arguments.
2233 __ pushq(Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
2234 __ Bind(&type_arguments_pushed);
2235 }
2236 }
2237 }
2238
2239
2240 void CodeGenerator::VisitConstructorCallNode(ConstructorCallNode* node) {
2241 if (node->constructor().IsFactory()) {
2242 const bool instantiate_type_arguments = true; // First argument to factory.
2243 GenerateTypeArguments(node->id(),
2244 node->token_index(),
2245 node->type_arguments(),
2246 instantiate_type_arguments);
2247 // The top of stack is an instantiated AbstractTypeArguments object
2248 // (or null).
2249 int num_args = node->arguments()->length() + 1; // +1 to include type args.
2250 node->arguments()->Visit(this);
2251 // Call the factory.
2252 __ LoadObject(RBX, node->constructor());
2253 __ LoadObject(R10, ArgumentsDescriptor(num_args,
2254 node->arguments()->names()));
2255 GenerateCall(node->token_index(),
2256 &StubCode::CallStaticFunctionLabel(),
2257 PcDescriptors::kFuncCall);
2258 // Factory constructor returns object in RAX.
2259 __ addq(RSP, Immediate(num_args * kWordSize));
2260 if (IsResultNeeded(node)) {
2261 __ pushq(RAX);
2262 }
2263 return;
2264 }
2265
2266 const Class& cls = Class::ZoneHandle(node->constructor().owner());
2267 const bool requires_type_arguments = cls.HasTypeArguments();
2268 const bool instantiate_type_arguments = false; // Done in stub or runtime.
2269 if (requires_type_arguments) {
2270 GenerateTypeArguments(node->id(),
2271 node->token_index(),
2272 node->type_arguments(),
2273 instantiate_type_arguments);
2274 }
2275
2276 // If cls is parameterized, the type arguments and the instantiator's
2277 // type arguments are on the stack.
2278 // In checked mode, if the type arguments are uninstantiated, they may need to
2279 // be checked against declared bounds at run time.
2280 Error& malformed_error = Error::Handle();
2281 if (FLAG_enable_type_checks &&
2282 requires_type_arguments &&
2283 !node->type_arguments().IsNull() &&
2284 !node->type_arguments().IsInstantiated() &&
2285 !node->type_arguments().IsWithinBoundsOf(cls,
2286 node->type_arguments(),
2287 &malformed_error)) {
2288 // The uninstantiated type arguments cannot be verified to be within their
2289 // bounds at compile time, so verify them at runtime.
2290 // Although the type arguments may be uninstantiated at compile time, they
2291 // may represent the identity vector and may be replaced by the instantiated
2292 // type arguments of the instantiator at run time.
2293 __ popq(RCX); // Pop instantiator type arguments.
2294 __ popq(RAX); // Pop type arguments.
2295
2296 // Push the result place holder initialized to NULL.
2297 __ PushObject(Object::ZoneHandle());
2298 __ pushq(Immediate(Smi::RawValue(node->token_index())));
2299 __ PushObject(cls);
2300 __ pushq(RAX); // Push type arguments.
2301 __ pushq(RCX); // Push instantiator type arguments.
2302 GenerateCallRuntime(node->id(),
2303 node->token_index(),
2304 kAllocateObjectWithBoundsCheckRuntimeEntry);
2305 __ popq(RCX); // Pop instantiator type arguments.
2306 __ popq(RCX); // Pop type arguments.
2307 __ popq(RCX); // Pop class.
2308 __ popq(RCX); // Pop source location.
2309 __ popq(RAX); // Pop new instance.
2310 } else {
2311 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
2312 const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
2313 GenerateCall(node->token_index(), &label, PcDescriptors::kOther);
2314 if (requires_type_arguments) {
2315 __ popq(RCX); // Pop instantiator type arguments.
2316 __ popq(RCX); // Pop type arguments.
2317 }
2318 }
2319
2320 if (IsResultNeeded(node)) {
2321 __ pushq(RAX); // Set up return value from allocate.
2322 }
2323
2324 // First argument(this) for constructor call which follows.
2325 __ pushq(RAX);
2326 // Second argument is the implicit construction phase parameter.
2327 // Run both the constructor initializer list and the constructor body.
2328 __ pushq(Immediate(Smi::RawValue(Function::kCtorPhaseAll)));
2329
2330 // Now setup rest of the arguments for the constructor call.
2331 node->arguments()->Visit(this);
2332
2333 // Call the constructor.
2334 // +2 to include implicit receiver and phase arguments.
2335 int num_args = node->arguments()->length() + 2;
2336 __ LoadObject(RBX, node->constructor());
2337 __ LoadObject(R10, ArgumentsDescriptor(num_args, node->arguments()->names()));
2338 GenerateCall(node->token_index(),
2339 &StubCode::CallStaticFunctionLabel(),
2340 PcDescriptors::kFuncCall);
2341 // Constructors do not return any value.
2342
2343 // Pop out all the other arguments on the stack.
2344 __ addq(RSP, Immediate(num_args * kWordSize));
2345 }
2346
2347
2348 // Expects receiver on stack, returns result in RAX..
2349 void CodeGenerator::GenerateInstanceGetterCall(intptr_t node_id,
2350 intptr_t token_index,
2351 const String& field_name) {
2352 const String& getter_name =
2353 String::ZoneHandle(Field::GetterSymbol(field_name));
2354 const int kNumberOfArguments = 1;
2355 const Array& kNoArgumentNames = Array::Handle();
2356 const int kNumArgumentsChecked = 1;
2357 GenerateInstanceCall(node_id,
2358 token_index,
2359 getter_name,
2360 kNumberOfArguments,
2361 kNoArgumentNames,
2362 kNumArgumentsChecked);
2363 }
2364
2365
2366 // Call to the instance getter.
2367 void CodeGenerator::VisitInstanceGetterNode(InstanceGetterNode* node) {
2368 node->receiver()->Visit(this);
2369 MarkDeoptPoint(node->id(), node->token_index());
2370 GenerateInstanceGetterCall(node->id(),
2371 node->token_index(),
2372 node->field_name());
2373 if (IsResultNeeded(node)) {
2374 __ pushq(RAX);
2375 }
2376 }
2377
2378
2379 // Expects receiver and value on stack.
2380 void CodeGenerator::GenerateInstanceSetterCall(intptr_t node_id,
2381 intptr_t token_index,
2382 const String& field_name) {
2383 const String& setter_name =
2384 String::ZoneHandle(Field::SetterSymbol(field_name));
2385 const int kNumberOfArguments = 2; // receiver + value.
2386 const Array& kNoArgumentNames = Array::Handle();
2387 const int kNumArgumentsChecked = 1;
2388 GenerateInstanceCall(node_id,
2389 token_index,
2390 setter_name,
2391 kNumberOfArguments,
2392 kNoArgumentNames,
2393 kNumArgumentsChecked);
2394 }
2395
2396
2397 // The call to the instance setter implements the assignment to a field.
2398 // The result of the assignment to a field is the value being stored.
2399 void CodeGenerator::VisitInstanceSetterNode(InstanceSetterNode* node) {
2400 // Compute the receiver object and pass it as first argument to call.
2401 node->receiver()->Visit(this);
2402 node->value()->Visit(this);
2403 MarkDeoptPoint(node->id(), node->token_index());
2404 if (IsResultNeeded(node)) {
2405 __ popq(RAX); // value.
2406 __ popq(RDX); // receiver.
2407 __ pushq(RAX); // Preserve value.
2408 __ pushq(RDX); // arg0: receiver.
2409 __ pushq(RAX); // arg1: value.
2410 }
2411 // It is not necessary to generate a type test of the assigned value here,
2412 // because the setter will check the type of its incoming arguments.
2413 GenerateInstanceSetterCall(node->id(),
2414 node->token_index(),
2415 node->field_name());
2416 }
2417
2418
2419 // Return result in RAX.
2420 void CodeGenerator::GenerateStaticGetterCall(intptr_t token_index,
2421 const Class& field_class,
2422 const String& field_name) {
2423 const String& getter_name = String::Handle(Field::GetterName(field_name));
2424 const Function& function =
2425 Function::ZoneHandle(field_class.LookupStaticFunction(getter_name));
2426 ASSERT(!function.IsNull());
2427 __ LoadObject(RBX, function);
2428 const int kNumberOfArguments = 0;
2429 const Array& kNoArgumentNames = Array::Handle();
2430 __ LoadObject(R10, ArgumentsDescriptor(kNumberOfArguments, kNoArgumentNames));
2431 GenerateCall(token_index,
2432 &StubCode::CallStaticFunctionLabel(),
2433 PcDescriptors::kFuncCall);
2434 // No arguments were pushed, hence nothing to pop.
2435 }
2436
2437
2438 // Call to static getter.
2439 void CodeGenerator::VisitStaticGetterNode(StaticGetterNode* node) {
2440 GenerateStaticGetterCall(node->token_index(),
2441 node->cls(),
2442 node->field_name());
2443 // Result is in RAX.
2444 if (IsResultNeeded(node)) {
2445 __ pushq(RAX);
2446 }
2447 }
2448
2449
2450 // Expects value on stack.
2451 void CodeGenerator::GenerateStaticSetterCall(intptr_t token_index,
2452 const Class& field_class,
2453 const String& field_name) {
2454 const String& setter_name = String::Handle(Field::SetterName(field_name));
2455 const Function& function =
2456 Function::ZoneHandle(field_class.LookupStaticFunction(setter_name));
2457 ASSERT(!function.IsNull());
2458 __ LoadObject(RBX, function);
2459 const int kNumberOfArguments = 1; // value.
2460 const Array& kNoArgumentNames = Array::Handle();
2461 __ LoadObject(R10, ArgumentsDescriptor(kNumberOfArguments, kNoArgumentNames));
2462 GenerateCall(token_index,
2463 &StubCode::CallStaticFunctionLabel(),
2464 PcDescriptors::kFuncCall);
2465 __ addq(RSP, Immediate(kNumberOfArguments * kWordSize));
2466 }
2467
2468
2469 // The call to static setter implements assignment to a static field.
2470 // The result of the assignment is the value being stored.
2471 void CodeGenerator::VisitStaticSetterNode(StaticSetterNode* node) {
2472 node->value()->Visit(this);
2473 if (IsResultNeeded(node)) {
2474 // Preserve the original value when returning from setter.
2475 __ movq(RAX, Address(RSP, 0));
2476 __ pushq(RAX); // arg0: value.
2477 }
2478 // It is not necessary to generate a type test of the assigned value here,
2479 // because the setter will check the type of its incoming arguments.
2480 GenerateStaticSetterCall(node->token_index(),
2481 node->cls(),
2482 node->field_name());
2483 }
2484
2485
2486 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) {
2487 // Push the result place holder initialized to NULL.
2488 __ PushObject(Object::ZoneHandle());
2489 // Pass a pointer to the first argument in RAX.
2490 if (!node->has_optional_parameters()) {
2491 __ leaq(RAX, Address(RBP, (1 + node->argument_count()) * kWordSize));
2492 } else {
2493 __ leaq(RAX, Address(RBP, -1 * kWordSize));
2494 }
2495 __ movq(RBX, Immediate(reinterpret_cast<uword>(node->native_c_function())));
2496 __ movq(R10, Immediate(node->argument_count()));
2497 GenerateCall(node->token_index(),
2498 &StubCode::CallNativeCFunctionLabel(),
2499 PcDescriptors::kOther);
2500 // Result is on the stack.
2501 if (!IsResultNeeded(node)) {
2502 __ popq(RAX);
2503 }
2504 }
2505
2506
2507 void CodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) {
2508 // NOTE: The implicit variables ':saved_context', ':exception_var'
2509 // and ':stacktrace_var' can never be captured variables.
2510 // Restore CTX from local variable ':saved_context'.
2511 GenerateLoadVariable(CTX, node->context_var());
2512
2513 // Restore RSP from RBP as we are coming from a throw and the code for
2514 // popping arguments has not been run.
2515 ASSERT(locals_space_size() >= 0);
2516 if (locals_space_size() == 0) {
2517 __ movq(RSP, RBP);
2518 } else {
2519 __ leaq(RSP, Address(RBP, -locals_space_size()));
2520 }
2521
2522 // The JumpToExceptionHandler trampoline code sets up
2523 // - the exception object in RAX (kExceptionObjectReg)
2524 // - the stacktrace object in register RDX (kStackTraceObjectReg)
2525 // We now setup the exception object and the trace object
2526 // so that the handler code has access to these objects.
2527 GenerateStoreVariable(node->exception_var(),
2528 kExceptionObjectReg,
2529 kNoRegister);
2530 GenerateStoreVariable(node->stacktrace_var(),
2531 kStackTraceObjectReg,
2532 kNoRegister);
2533
2534 // Now generate code for the catch handler block.
2535 node->VisitChildren(this);
2536 }
2537
2538
2539 void CodeGenerator::VisitTryCatchNode(TryCatchNode* node) {
2540 CodeGeneratorState codegen_state(this);
2541 int outer_try_index = state()->try_index();
2542 // We are about to generate code for a new try block, generate an
2543 // unique 'try index' for this block and set that try index in
2544 // the code generator state.
2545 int try_index = generate_next_try_index();
2546 state()->set_try_index(try_index);
2547 exception_handlers_list_->AddHandler(try_index, -1);
2548
2549 // Preserve CTX into local variable '%saved_context'.
2550 GenerateStoreVariable(node->context_var(), CTX, kNoRegister);
2551
2552 node->try_block()->Visit(this);
2553
2554 // We are done generating code for the try block.
2555 ASSERT(state()->try_index() > CatchClauseNode::kInvalidTryIndex);
2556 ASSERT(try_index == state()->try_index());
2557 state()->set_try_index(outer_try_index);
2558
2559 CatchClauseNode* catch_block = node->catch_block();
2560 if (catch_block != NULL) {
2561 // Jump over the catch handler block, when exceptions are thrown we
2562 // will end up at the next instruction.
2563 __ jmp(node->end_catch_label()->continue_label());
2564
2565 // Set the corresponding try index for this catch block so
2566 // that we can set the appropriate handler pc when we generate
2567 // code for this catch block.
2568 catch_block->set_try_index(try_index);
2569
2570 // Set the handler pc for this try index in the exception handler
2571 // table.
2572 exception_handlers_list_->SetPcOffset(try_index, assembler_->CodeSize());
2573
2574 // Generate code for the catch block.
2575 catch_block->Visit(this);
2576
2577 // Bind the end of catch blocks label here.
2578 __ Bind(node->end_catch_label()->continue_label());
2579 }
2580
2581 // Generate code for the finally block if one exists.
2582 if (node->finally_block() != NULL) {
2583 node->finally_block()->Visit(this);
2584 }
2585 }
2586
2587
2588 void CodeGenerator::VisitThrowNode(ThrowNode* node) {
2589 node->exception()->Visit(this);
2590 // Exception object is on TOS.
2591 if (node->stacktrace() != NULL) {
2592 node->stacktrace()->Visit(this);
2593 GenerateCallRuntime(node->id(), node->token_index(), kReThrowRuntimeEntry);
2594 } else {
2595 GenerateCallRuntime(node->id(), node->token_index(), kThrowRuntimeEntry);
2596 }
2597 // We should never return here.
2598 __ int3();
2599 }
2600
2601
2602 void CodeGenerator::VisitInlinedFinallyNode(InlinedFinallyNode* node) {
2603 int try_index = state()->try_index();
2604 if (try_index >= 0) {
2605 // We are about to generate code for an inlined finally block. Exceptions
2606 // thrown in this block of code should be treated as though they are
2607 // thrown not from the current try block but the outer try block if any.
2608 // the code generator state.
2609 state()->set_try_index((try_index - 1));
2610 }
2611
2612 // Restore CTX from local variable ':saved_context'.
2613 GenerateLoadVariable(CTX, node->context_var());
2614 node->finally_block()->Visit(this);
2615
2616 if (try_index >= 0) {
2617 state()->set_try_index(try_index);
2618 }
2619 }
2620
2621
2622 void CodeGenerator::GenerateCall(intptr_t token_index,
2623 const ExternalLabel* ext_label,
2624 PcDescriptors::Kind desc_kind) {
2625 __ call(ext_label);
2626 AddCurrentDescriptor(desc_kind, AstNode::kNoId, token_index);
2627 }
2628
2629
2630 void CodeGenerator::GenerateCallRuntime(intptr_t node_id,
2631 intptr_t token_index,
2632 const RuntimeEntry& entry) {
2633 __ CallRuntime(entry);
2634 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index);
2635 }
2636
2637
2638 void CodeGenerator::MarkDeoptPoint(intptr_t node_id,
2639 intptr_t token_index) {
2640 ASSERT(node_id != AstNode::kNoId);
2641 AddCurrentDescriptor(PcDescriptors::kDeopt, node_id, token_index);
2642 }
2643
2644
2645 // Uses current pc position and try-index.
2646 void CodeGenerator::AddCurrentDescriptor(PcDescriptors::Kind kind,
2647 intptr_t node_id,
2648 intptr_t token_index) {
2649 pc_descriptors_list_->AddDescriptor(kind,
2650 assembler_->CodeSize(),
2651 node_id,
2652 token_index,
2653 state()->try_index());
2654 }
2655
2656
2657 void CodeGenerator::ErrorMsg(intptr_t token_index, const char* format, ...) {
2658 va_list args;
2659 va_start(args, format);
2660 const Class& cls = Class::Handle(parsed_function_.function().owner());
2661 const Script& script = Script::Handle(cls.script());
2662 const Error& error = Error::Handle(
2663 Parser::FormatError(script, token_index, "Error", format, args));
2664 va_end(args);
2665 Isolate::Current()->long_jump_base()->Jump(1, error);
2666 UNREACHABLE();
2667 }
2668
2669 } // namespace dart
2670
2671 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/code_generator_x64.h ('k') | runtime/vm/compiler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698