| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |