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

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

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

Powered by Google App Engine
This is Rietveld 408576698