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

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

Issue 9693020: Optional arguments in new compiler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/code_generator.h" 8 #include "vm/code_generator.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 ExternalLabel target_label("InlineCache", label_address); 331 ExternalLabel target_label("InlineCache", label_address);
332 332
333 __ call(&target_label); 333 __ call(&target_label);
334 AddCurrentDescriptor(PcDescriptors::kIcCall, 334 AddCurrentDescriptor(PcDescriptors::kIcCall,
335 node_id, 335 node_id,
336 token_index); 336 token_index);
337 __ addq(RSP, Immediate(num_arguments * kWordSize)); 337 __ addq(RSP, Immediate(num_arguments * kWordSize));
338 } 338 }
339 339
340 340
341 // Check that no fewer than num_fixed_params positional arguments are passed
342 // in and that no more than num_params arguments are passed in.
343 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i].
344 void CodeGenerator::CopyParameters() {
345 const Function& function = parsed_function_.function();
346 LocalScope* scope = parsed_function_.node_sequence()->scope();
347 const int num_fixed_params = function.num_fixed_parameters();
348 const int num_opt_params = function.num_optional_parameters();
349
350 ASSERT(parsed_function_.first_parameter_index() == -1);
351 // Copy positional arguments.
352 // Check that no fewer than num_fixed_params positional arguments are passed
353 // in and that no more than num_params arguments are passed in.
354 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i].
355 const int num_params = num_fixed_params + num_opt_params;
356
357 // Total number of args is the first Smi in args descriptor array (R10).
358 __ movq(RBX, FieldAddress(R10, Array::data_offset()));
359 // Check that num_args <= num_params.
360 Label wrong_num_arguments;
361 __ cmpq(RBX, Immediate(Smi::RawValue(num_params)));
362 __ j(GREATER, &wrong_num_arguments);
363 // Number of positional args is the second Smi in descriptor array (R10).
364 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
365 // Check that num_pos_args >= num_fixed_params.
366 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params)));
367 __ j(LESS, &wrong_num_arguments);
368 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8.
369 // Let RBX point to the last passed positional argument, i.e. to
370 // fp[1 + num_args - (num_pos_args - 1)].
371 __ subq(RBX, RCX);
372 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize));
373 // Let RDI point to the last copied positional argument, i.e. to
374 // fp[-1 - (num_pos_args - 1)].
375 __ SmiUntag(RCX);
376 __ movq(RAX, RCX);
377 __ negq(RAX);
378 __ leaq(RDI, Address(RBP, RAX, TIMES_8, 0));
379 Label loop, loop_condition;
380 __ jmp(&loop_condition, Assembler::kNearJump);
381 // We do not use the final allocation index of the variable here, i.e.
382 // scope->VariableAt(i)->index(), because captured variables still need
383 // to be copied to the context that is not yet allocated.
384 const Address argument_addr(RBX, RCX, TIMES_8, 0);
385 const Address copy_addr(RDI, RCX, TIMES_8, 0);
386 __ Bind(&loop);
387 __ movq(RAX, argument_addr);
388 __ movq(copy_addr, RAX);
389 __ Bind(&loop_condition);
390 __ decq(RCX);
391 __ j(POSITIVE, &loop, Assembler::kNearJump);
392
393 // Copy or initialize optional named arguments.
394 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments.
395 // Start by alphabetically sorting the names of the optional parameters.
396 LocalVariable** opt_param = new LocalVariable*[num_opt_params];
397 int* opt_param_position = new int[num_opt_params];
398 for (int pos = num_fixed_params; pos < num_params; pos++) {
399 LocalVariable* parameter = scope->VariableAt(pos);
400 const String& opt_param_name = parameter->name();
401 int i = pos - num_fixed_params;
402 while (--i >= 0) {
403 LocalVariable* param_i = opt_param[i];
404 const intptr_t result = opt_param_name.CompareTo(param_i->name());
405 ASSERT(result != 0);
406 if (result > 0) break;
407 opt_param[i + 1] = opt_param[i];
408 opt_param_position[i + 1] = opt_param_position[i];
409 }
410 opt_param[i + 1] = parameter;
411 opt_param_position[i + 1] = pos;
412 }
413 // Generate code handling each optional parameter in alphabetical order.
414 // Total number of args is the first Smi in args descriptor array (R10).
415 __ movq(RBX, FieldAddress(R10, Array::data_offset()));
416 // Number of positional args is the second Smi in descriptor array (R10).
417 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
418 __ SmiUntag(RCX);
419 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0].
420 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi.
421 // Let EDI point to the name/pos pair of the first named argument.
422 __ leaq(RDI, FieldAddress(R10, Array::data_offset() + (2 * kWordSize)));
423 for (int i = 0; i < num_opt_params; i++) {
424 // Handle this optional parameter only if k or fewer positional arguments
425 // have been passed, where k is the position of this optional parameter in
426 // the formal parameter list.
427 Label load_default_value, assign_optional_parameter, next_parameter;
428 const int param_pos = opt_param_position[i];
429 __ cmpq(RCX, Immediate(param_pos));
430 __ j(GREATER, &next_parameter, Assembler::kNearJump);
431 // Check if this named parameter was passed in.
432 __ movq(RAX, Address(RDI, 0)); // Load RAX with the name of the argument.
433 __ CompareObject(RAX, opt_param[i]->name());
434 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump);
435 // Load RAX with passed-in argument at provided arg_pos, i.e. at
436 // fp[1 + argc - arg_pos].
437 __ movq(RAX, Address(RDI, kWordSize)); // RAX is arg_pos as Smi.
438 __ addq(RDI, Immediate(2 * kWordSize)); // Point to next name/pos pair.
439 __ negq(RAX);
440 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi.
441 __ movq(RAX, argument_addr);
442 __ jmp(&assign_optional_parameter, Assembler::kNearJump);
443 __ Bind(&load_default_value);
444 // Load RAX with default argument at pos.
445 const Object& value = Object::ZoneHandle(
446 parsed_function_.default_parameter_values().At(
447 param_pos - num_fixed_params));
448 __ LoadObject(RAX, value);
449 __ Bind(&assign_optional_parameter);
450 // Assign RAX to fp[-1 - param_pos].
451 // We do not use the final allocation index of the variable here, i.e.
452 // scope->VariableAt(i)->index(), because captured variables still need
453 // to be copied to the context that is not yet allocated.
454 const Address param_addr(RBP, (-1 - param_pos) * kWordSize);
455 __ movq(param_addr, RAX);
456 __ Bind(&next_parameter);
457 }
458 delete[] opt_param;
459 delete[] opt_param_position;
460 // Check that RDI now points to the null terminator in the array descriptor.
461 const Immediate raw_null =
462 Immediate(reinterpret_cast<intptr_t>(Object::null()));
463 Label all_arguments_processed;
464 __ cmpq(Address(RDI, 0), raw_null);
465 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
466
467 __ Bind(&wrong_num_arguments);
468 if (function.IsClosureFunction()) {
469 GenerateCallRuntime(AstNode::kNoId,
470 0,
471 kClosureArgumentMismatchRuntimeEntry);
472 } else {
473 // Invoke noSuchMethod function.
474 const int kNumArgsChecked = 1;
475 ICData& ic_data = ICData::ZoneHandle();
476 ic_data = ICData::New(parsed_function().function(),
477 String::Handle(function.name()),
478 AstNode::kNoId,
479 kNumArgsChecked);
480 __ LoadObject(RBX, ic_data);
481 // RBP : points to previous frame pointer.
482 // RBP + 8 : points to return address.
483 // RBP + 16 : address of last argument (arg n-1).
484 // RSP + 16 + 8*(n-1) : address of first argument (arg 0).
485 // RBX : ic-data.
486 // R10 : arguments descriptor array.
487 __ call(&StubCode::CallNoSuchMethodFunctionLabel());
488 }
489
490 if (FLAG_trace_functions) {
491 __ pushq(RAX); // Preserve result.
492 __ PushObject(Function::ZoneHandle(function.raw()));
493 GenerateCallRuntime(AstNode::kNoId,
494 0,
495 kTraceFunctionExitRuntimeEntry);
496 __ popq(RAX); // Remove argument.
497 __ popq(RAX); // Restore result.
498 }
499 __ LeaveFrame();
500 __ ret();
501
502 __ Bind(&all_arguments_processed);
503 // Nullify originally passed arguments only after they have been copied and
504 // checked, otherwise noSuchMethod would not see their original values.
505 // This step can be skipped in case we decide that formal parameters are
506 // implicitly final, since garbage collecting the unmodified value is not
507 // an issue anymore.
508
509 // R10 : arguments descriptor array.
510 // Total number of args is the first Smi in args descriptor array (R10).
511 __ movq(RCX, FieldAddress(R10, Array::data_offset()));
512 __ SmiUntag(RCX);
513 Label null_args_loop, null_args_loop_condition;
514 __ jmp(&null_args_loop_condition, Assembler::kNearJump);
515 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize);
516 __ Bind(&null_args_loop);
517 __ movq(original_argument_addr, raw_null);
518 __ Bind(&null_args_loop_condition);
519 __ decq(RCX);
520 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
521 }
522
523
341 // Call to generate entry code: 524 // Call to generate entry code:
342 // - compute frame size and setup frame. 525 // - compute frame size and setup frame.
343 // - allocate local variables on stack. 526 // - allocate local variables on stack.
344 // - optionally check if number of arguments match. 527 // - optionally check if number of arguments match.
345 // - initialize all non-argument locals to null. 528 // - initialize all non-argument locals to null.
346 // 529 //
347 // Input parameters: 530 // Input parameters:
348 // RSP : points to return address. 531 // RSP : points to return address.
349 // RSP + 8 : address of last argument (arg n-1). 532 // RSP + 8 : address of last argument (arg n-1).
350 // RSP + 8*n : address of first argument (arg 0). 533 // RSP + 8*n : address of first argument (arg 0).
351 // R10 : arguments descriptor array. 534 // R10 : arguments descriptor array.
352 void CodeGenerator::GenerateEntryCode() { 535 void CodeGenerator::GenerateEntryCode() {
353 const Immediate raw_null = 536 const Immediate raw_null =
354 Immediate(reinterpret_cast<intptr_t>(Object::null())); 537 Immediate(reinterpret_cast<intptr_t>(Object::null()));
355 const Function& function = parsed_function_.function(); 538 const Function& function = parsed_function_.function();
356 LocalScope* scope = parsed_function_.node_sequence()->scope(); 539 LocalScope* scope = parsed_function_.node_sequence()->scope();
357 const int num_fixed_params = function.num_fixed_parameters(); 540 const int num_fixed_params = function.num_fixed_parameters();
358 const int num_opt_params = function.num_optional_parameters(); 541 const int num_opt_params = function.num_optional_parameters();
359 const int num_params = num_fixed_params + num_opt_params; 542 const int num_copied_params = parsed_function_.copied_parameter_count();
360 int first_param_index; 543 const int stack_slot_count = parsed_function_.local_count();
361 int first_local_index; 544 set_locals_space_size(stack_slot_count * kWordSize);
362 int num_copied_params;
363 // Assign indices to parameters and locals.
364 if (num_params == num_fixed_params) {
365 // No need to copy incoming arguments.
366 // The body of the function will access parameter i at fp[1 + num_fixed - i]
367 // and local variable j at fp[-1 - j].
368 first_param_index = 1 + num_params;
369 first_local_index = -1;
370 num_copied_params = 0;
371 } else {
372 // The body of the function will access copied parameter i at fp[-1 - i]
373 // and local j at fp[-1 - num_params - j].
374 first_param_index = -1;
375 first_local_index = -1 - num_params;
376 num_copied_params = num_params;
377 ASSERT(num_copied_params > 0);
378 }
379
380 // Allocate parameters and local variables, either in the local frame or in
381 // the context(s).
382 LocalScope* context_owner = NULL; // No context needed so far.
383 int first_free_frame_index =
384 scope->AllocateVariables(first_param_index,
385 num_params,
386 first_local_index,
387 scope, // Initial loop owner.
388 &context_owner);
389 // Frame indices are relative to the frame pointer and are decreasing.
390 ASSERT(first_free_frame_index <= first_local_index);
391 const int num_locals = first_local_index - first_free_frame_index;
392 545
393 // Reserve local space for copied incoming and default arguments and locals. 546 // Reserve local space for copied incoming and default arguments and locals.
394 // TODO(regis): We may give up reserving space on stack for args/locals 547 // TODO(regis): We may give up reserving space on stack for args/locals
395 // because pushes of initial values may be more effective than moves. 548 // because pushes of initial values may be more effective than moves.
396 set_locals_space_size((num_copied_params + num_locals) * kWordSize);
397 __ EnterFrame(locals_space_size()); 549 __ EnterFrame(locals_space_size());
398 550
399 // We check the number of passed arguments when we have to copy them due to 551 // We check the number of passed arguments when we have to copy them due to
400 // the presence of optional named parameters. 552 // the presence of optional named parameters.
401 // No such checking code is generated if only fixed parameters are declared, 553 // No such checking code is generated if only fixed parameters are declared,
402 // unless we are debug mode or unless we are compiling a closure. 554 // unless we are debug mode or unless we are compiling a closure.
403 if (num_copied_params == 0) { 555 if (num_copied_params == 0) {
556 ASSERT(num_opt_params == 0);
404 #if defined(DEBUG) 557 #if defined(DEBUG)
405 const bool check_arguments = true; // Always check arguments in debug mode. 558 const bool check_arguments = true; // Always check arguments in debug mode.
406 #else 559 #else
407 // The number of arguments passed to closure functions must always be 560 // The number of arguments passed to closure functions must always be
408 // checked here, because no resolving stub (normally responsible for the 561 // checked here, because no resolving stub (normally responsible for the
409 // check) is involved in closure calls. 562 // check) is involved in closure calls.
410 const bool check_arguments = function.IsClosureFunction(); 563 const bool check_arguments = function.IsClosureFunction();
411 #endif 564 #endif
412 if (check_arguments) { 565 if (check_arguments) {
413 // Check that num_fixed <= argc <= num_params. 566 // Check that num_fixed <= argc <= num_params.
414 Label argc_in_range; 567 Label argc_in_range;
415 // Total number of args is the first Smi in args descriptor array (R10). 568 // Total number of args is the first Smi in args descriptor array (R10).
416 __ movq(RAX, FieldAddress(R10, Array::data_offset())); 569 __ movq(RAX, FieldAddress(R10, Array::data_offset()));
417 if (num_opt_params == 0) { 570 __ cmpq(RAX, Immediate(Smi::RawValue(num_fixed_params)));
418 __ cmpq(RAX, Immediate(Smi::RawValue(num_fixed_params))); 571 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
419 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
420 } else {
421 __ subq(RAX, Immediate(Smi::RawValue(num_fixed_params)));
422 __ cmpq(RAX, Immediate(Smi::RawValue(num_opt_params)));
423 __ j(BELOW_EQUAL, &argc_in_range, Assembler::kNearJump);
424 }
425 if (function.IsClosureFunction()) { 572 if (function.IsClosureFunction()) {
426 GenerateCallRuntime(AstNode::kNoId, 573 GenerateCallRuntime(AstNode::kNoId,
427 0, 574 0,
428 kClosureArgumentMismatchRuntimeEntry); 575 kClosureArgumentMismatchRuntimeEntry);
429 } else { 576 } else {
430 __ Stop("Wrong number of arguments"); 577 __ Stop("Wrong number of arguments");
431 } 578 }
432 __ Bind(&argc_in_range); 579 __ Bind(&argc_in_range);
433 } 580 }
434 } else { 581 } else {
435 ASSERT(first_param_index == -1); 582 CopyParameters();
436 // Copy positional arguments.
437 // Check that no fewer than num_fixed_params positional arguments are passed
438 // in and that no more than num_params arguments are passed in.
439 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i].
440
441 // Total number of args is the first Smi in args descriptor array (R10).
442 __ movq(RBX, FieldAddress(R10, Array::data_offset()));
443 // Check that num_args <= num_params.
444 Label wrong_num_arguments;
445 __ cmpq(RBX, Immediate(Smi::RawValue(num_params)));
446 __ j(GREATER, &wrong_num_arguments);
447 // Number of positional args is the second Smi in descriptor array (R10).
448 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
449 // Check that num_pos_args >= num_fixed_params.
450 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params)));
451 __ j(LESS, &wrong_num_arguments);
452 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8.
453 // Let RBX point to the last passed positional argument, i.e. to
454 // fp[1 + num_args - (num_pos_args - 1)].
455 __ subq(RBX, RCX);
456 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize));
457 // Let RDI point to the last copied positional argument, i.e. to
458 // fp[-1 - (num_pos_args - 1)].
459 __ SmiUntag(RCX);
460 __ movq(RAX, RCX);
461 __ negq(RAX);
462 __ leaq(RDI, Address(RBP, RAX, TIMES_8, 0));
463 Label loop, loop_condition;
464 __ jmp(&loop_condition, Assembler::kNearJump);
465 // We do not use the final allocation index of the variable here, i.e.
466 // scope->VariableAt(i)->index(), because captured variables still need
467 // to be copied to the context that is not yet allocated.
468 const Address argument_addr(RBX, RCX, TIMES_8, 0);
469 const Address copy_addr(RDI, RCX, TIMES_8, 0);
470 __ Bind(&loop);
471 __ movq(RAX, argument_addr);
472 __ movq(copy_addr, RAX);
473 __ Bind(&loop_condition);
474 __ decq(RCX);
475 __ j(POSITIVE, &loop, Assembler::kNearJump);
476
477 // Copy or initialize optional named arguments.
478 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments.
479 // Start by alphabetically sorting the names of the optional parameters.
480 LocalVariable** opt_param = new LocalVariable*[num_opt_params];
481 int* opt_param_position = new int[num_opt_params];
482 for (int pos = num_fixed_params; pos < num_params; pos++) {
483 LocalVariable* parameter = scope->VariableAt(pos);
484 const String& opt_param_name = parameter->name();
485 int i = pos - num_fixed_params;
486 while (--i >= 0) {
487 LocalVariable* param_i = opt_param[i];
488 const intptr_t result = opt_param_name.CompareTo(param_i->name());
489 ASSERT(result != 0);
490 if (result > 0) break;
491 opt_param[i + 1] = opt_param[i];
492 opt_param_position[i + 1] = opt_param_position[i];
493 }
494 opt_param[i + 1] = parameter;
495 opt_param_position[i + 1] = pos;
496 }
497 // Generate code handling each optional parameter in alphabetical order.
498 // Total number of args is the first Smi in args descriptor array (R10).
499 __ movq(RBX, FieldAddress(R10, Array::data_offset()));
500 // Number of positional args is the second Smi in descriptor array (R10).
501 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize)));
502 __ SmiUntag(RCX);
503 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0].
504 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi.
505 // Let EDI point to the name/pos pair of the first named argument.
506 __ leaq(RDI, FieldAddress(R10, Array::data_offset() + (2 * kWordSize)));
507 for (int i = 0; i < num_opt_params; i++) {
508 // Handle this optional parameter only if k or fewer positional arguments
509 // have been passed, where k is the position of this optional parameter in
510 // the formal parameter list.
511 Label load_default_value, assign_optional_parameter, next_parameter;
512 const int param_pos = opt_param_position[i];
513 __ cmpq(RCX, Immediate(param_pos));
514 __ j(GREATER, &next_parameter, Assembler::kNearJump);
515 // Check if this named parameter was passed in.
516 __ movq(RAX, Address(RDI, 0)); // Load RAX with the name of the argument.
517 __ CompareObject(RAX, opt_param[i]->name());
518 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump);
519 // Load RAX with passed-in argument at provided arg_pos, i.e. at
520 // fp[1 + argc - arg_pos].
521 __ movq(RAX, Address(RDI, kWordSize)); // RAX is arg_pos as Smi.
522 __ addq(RDI, Immediate(2 * kWordSize)); // Point to next name/pos pair.
523 __ negq(RAX);
524 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi.
525 __ movq(RAX, argument_addr);
526 __ jmp(&assign_optional_parameter, Assembler::kNearJump);
527 __ Bind(&load_default_value);
528 // Load RAX with default argument at pos.
529 const Object& value = Object::ZoneHandle(
530 parsed_function_.default_parameter_values().At(
531 param_pos - num_fixed_params));
532 __ LoadObject(RAX, value);
533 __ Bind(&assign_optional_parameter);
534 // Assign RAX to fp[-1 - param_pos].
535 // We do not use the final allocation index of the variable here, i.e.
536 // scope->VariableAt(i)->index(), because captured variables still need
537 // to be copied to the context that is not yet allocated.
538 const Address param_addr(RBP, (-1 - param_pos) * kWordSize);
539 __ movq(param_addr, RAX);
540 __ Bind(&next_parameter);
541 }
542 delete[] opt_param;
543 delete[] opt_param_position;
544 // Check that RDI now points to the null terminator in the array descriptor.
545 Label all_arguments_processed;
546 __ cmpq(Address(RDI, 0), raw_null);
547 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
548
549 __ Bind(&wrong_num_arguments);
550 if (function.IsClosureFunction()) {
551 GenerateCallRuntime(AstNode::kNoId,
552 0,
553 kClosureArgumentMismatchRuntimeEntry);
554 } else {
555 // Invoke noSuchMethod function.
556 const int kNumArgsChecked = 1;
557 ICData& ic_data = ICData::ZoneHandle();
558 ic_data = ICData::New(parsed_function().function(),
559 String::Handle(function.name()),
560 AstNode::kNoId,
561 kNumArgsChecked);
562 __ LoadObject(RBX, ic_data);
563 // RBP : points to previous frame pointer.
564 // RBP + 8 : points to return address.
565 // RBP + 16 : address of last argument (arg n-1).
566 // RSP + 16 + 8*(n-1) : address of first argument (arg 0).
567 // RBX : ic-data.
568 // R10 : arguments descriptor array.
569 __ call(&StubCode::CallNoSuchMethodFunctionLabel());
570 }
571
572 if (FLAG_trace_functions) {
573 __ pushq(RAX); // Preserve result.
574 __ PushObject(Function::ZoneHandle(function.raw()));
575 GenerateCallRuntime(AstNode::kNoId,
576 0,
577 kTraceFunctionExitRuntimeEntry);
578 __ popq(RAX); // Remove argument.
579 __ popq(RAX); // Restore result.
580 }
581 __ LeaveFrame();
582 __ ret();
583
584 __ Bind(&all_arguments_processed);
585 // Nullify originally passed arguments only after they have been copied and
586 // checked, otherwise noSuchMethod would not see their original values.
587 // This step can be skipped in case we decide that formal parameters are
588 // implicitly final, since garbage collecting the unmodified value is not
589 // an issue anymore.
590
591 // R10 : arguments descriptor array.
592 // Total number of args is the first Smi in args descriptor array (R10).
593 __ movq(RCX, FieldAddress(R10, Array::data_offset()));
594 __ SmiUntag(RCX);
595 Label null_args_loop, null_args_loop_condition;
596 __ jmp(&null_args_loop_condition, Assembler::kNearJump);
597 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize);
598 __ Bind(&null_args_loop);
599 __ movq(original_argument_addr, raw_null);
600 __ Bind(&null_args_loop_condition);
601 __ decq(RCX);
602 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
603 } 583 }
604 584
605 // Initialize locals. 585 // Initialize locals.
606 // TODO(regis): For now, always unroll the init loop. Decide later above 586 // TODO(regis): For now, always unroll the init loop. Decide later above
607 // which threshold to implement a loop. 587 // which threshold to implement a loop.
608 // Consider emitting pushes instead of moves. 588 // Consider emitting pushes instead of moves.
609 for (int index = first_local_index; index > first_free_frame_index; index--) { 589 const int base = parsed_function_.first_local_index();
610 if (index == first_local_index) { 590 for (int index = 0; index < parsed_function_.local_count(); ++index) {
591 if (index == 0) {
611 __ movq(RAX, raw_null); 592 __ movq(RAX, raw_null);
612 } 593 }
613 __ movq(Address(RBP, index * kWordSize), RAX); 594 __ movq(Address(RBP, (base - index) * kWordSize), RAX);
614 } 595 }
615 596
616 // Generate stack overflow check. 597 // Generate stack overflow check.
617 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); 598 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address()));
618 __ cmpq(RSP, Address(TMP, 0)); 599 __ cmpq(RSP, Address(TMP, 0));
619 Label no_stack_overflow; 600 Label no_stack_overflow;
620 __ j(ABOVE, &no_stack_overflow); 601 __ j(ABOVE, &no_stack_overflow);
621 GenerateCallRuntime(AstNode::kNoId, 602 GenerateCallRuntime(AstNode::kNoId,
622 0, 603 0,
623 kStackOverflowRuntimeEntry); 604 kStackOverflowRuntimeEntry);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
744 node->type(), 725 node->type(),
745 node->dst_name()); 726 node->dst_name());
746 if (IsResultNeeded(node)) { 727 if (IsResultNeeded(node)) {
747 __ pushq(RAX); 728 __ pushq(RAX);
748 } 729 }
749 } 730 }
750 731
751 732
752 void CodeGenerator::VisitClosureNode(ClosureNode* node) { 733 void CodeGenerator::VisitClosureNode(ClosureNode* node) {
753 const Function& function = node->function(); 734 const Function& function = node->function();
754 if (function.IsNonImplicitClosureFunction()) { 735 if (function.IsNonImplicitClosureFunction() &&
736 (function.context_scope() == ContextScope::null())) {
755 const int current_context_level = state()->context_level(); 737 const int current_context_level = state()->context_level();
756 const ContextScope& context_scope = ContextScope::ZoneHandle( 738 const ContextScope& context_scope = ContextScope::ZoneHandle(
757 node->scope()->PreserveOuterScope(current_context_level)); 739 node->scope()->PreserveOuterScope(current_context_level));
758 ASSERT(!function.HasCode()); 740 ASSERT(!function.HasCode());
759 ASSERT(function.context_scope() == ContextScope::null());
760 function.set_context_scope(context_scope); 741 function.set_context_scope(context_scope);
761 } else { 742 } else {
762 ASSERT(function.context_scope() != ContextScope::null());
763 if (function.IsImplicitInstanceClosureFunction()) { 743 if (function.IsImplicitInstanceClosureFunction()) {
764 node->receiver()->Visit(this); 744 node->receiver()->Visit(this);
765 } 745 }
766 } 746 }
747 ASSERT(function.context_scope() != ContextScope::null());
748
767 // The function type of a closure may have type arguments. In that case, pass 749 // The function type of a closure may have type arguments. In that case, pass
768 // the type arguments of the instantiator. 750 // the type arguments of the instantiator.
769 const Class& cls = Class::Handle(function.signature_class()); 751 const Class& cls = Class::Handle(function.signature_class());
770 ASSERT(!cls.IsNull()); 752 ASSERT(!cls.IsNull());
771 const bool requires_type_arguments = cls.HasTypeArguments(); 753 const bool requires_type_arguments = cls.HasTypeArguments();
772 if (requires_type_arguments) { 754 if (requires_type_arguments) {
773 ASSERT(!function.IsImplicitStaticClosureFunction()); 755 ASSERT(!function.IsImplicitStaticClosureFunction());
774 GenerateInstantiatorTypeArguments(node->token_index()); 756 GenerateInstantiatorTypeArguments(node->token_index());
775 } 757 }
776 const Code& stub = Code::Handle( 758 const Code& stub = Code::Handle(
(...skipping 1896 matching lines...) Expand 10 before | Expand all | Expand 10 after
2673 const Error& error = Error::Handle( 2655 const Error& error = Error::Handle(
2674 Parser::FormatError(script, token_index, "Error", format, args)); 2656 Parser::FormatError(script, token_index, "Error", format, args));
2675 va_end(args); 2657 va_end(args);
2676 Isolate::Current()->long_jump_base()->Jump(1, error); 2658 Isolate::Current()->long_jump_base()->Jump(1, error);
2677 UNREACHABLE(); 2659 UNREACHABLE();
2678 } 2660 }
2679 2661
2680 } // namespace dart 2662 } // namespace dart
2681 2663
2682 #endif // defined TARGET_ARCH_X64 2664 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698