| 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 // Call to generate entry code: | |
| 342 // - compute frame size and setup frame. | |
| 343 // - allocate local variables on stack. | |
| 344 // - optionally check if number of arguments match. | |
| 345 // - initialize all non-argument locals to null. | |
| 346 // | |
| 347 // Input parameters: | 341 // Input parameters: |
| 348 // RSP : points to return address. | 342 // RSP : points to return address. |
| 349 // RSP + 8 : address of last argument (arg n-1). | 343 // RSP + 8 : address of last argument (arg n-1). |
| 350 // RSP + 8*n : address of first argument (arg 0). | 344 // RSP + 8*n : address of first argument (arg 0). |
| 351 // R10 : arguments descriptor array. | 345 // R10 : arguments descriptor array. |
| 352 void CodeGenerator::GenerateEntryCode() { | 346 void CodeGenerator::GenerateEntryCode() { |
| 353 const Immediate raw_null = | 347 const Immediate raw_null = |
| 354 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 348 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 355 const Function& function = parsed_function_.function(); | 349 const Function& function = parsed_function_.function(); |
| 350 |
| 351 // 1. Compute the frame size and enter the frame (reserving local space |
| 352 // for copied incoming and default arguments and stack-allocated local |
| 353 // variables). |
| 354 // |
| 355 // TODO(regis): We may give up reserving space on stack for args/locals |
| 356 // because pushes of initial values may be more effective than moves. |
| 356 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 357 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 357 const int num_fixed_params = function.num_fixed_parameters(); | 358 const int num_fixed_params = function.num_fixed_parameters(); |
| 358 const int num_opt_params = function.num_optional_parameters(); | 359 const int num_opt_params = function.num_optional_parameters(); |
| 359 const int num_params = num_fixed_params + num_opt_params; | 360 const int num_copied_params = parsed_function_.copied_parameter_count(); |
| 360 int first_param_index; | 361 const int stack_slot_count = |
| 361 int first_local_index; | 362 num_copied_params + parsed_function_.stack_local_count(); |
| 362 int num_copied_params; | 363 set_locals_space_size(stack_slot_count * kWordSize); |
| 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 | |
| 393 // 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 | |
| 395 // 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()); | 364 __ EnterFrame(locals_space_size()); |
| 398 | 365 |
| 399 // We check the number of passed arguments when we have to copy them due to | 366 // 2. Optionally check if the number of arguments matches. We check the |
| 400 // the presence of optional named parameters. | 367 // number of passed arguments when we have to copy them due to the |
| 401 // No such checking code is generated if only fixed parameters are declared, | 368 // presence of optional named parameters. No such checking code is |
| 402 // unless we are debug mode or unless we are compiling a closure. | 369 // generated if only fixed parameters are declared, unless we are in debug |
| 370 // mode or unless we are compiling a closure. |
| 403 if (num_copied_params == 0) { | 371 if (num_copied_params == 0) { |
| 404 #if defined(DEBUG) | 372 #if defined(DEBUG) |
| 405 const bool check_arguments = true; // Always check arguments in debug mode. | 373 const bool check_arguments = true; // Always check arguments in debug mode. |
| 406 #else | 374 #else |
| 407 // The number of arguments passed to closure functions must always be | 375 // The number of arguments passed to closure functions must always be |
| 408 // checked here, because no resolving stub (normally responsible for the | 376 // checked here, because no resolving stub (normally responsible for the |
| 409 // check) is involved in closure calls. | 377 // check) is involved in closure calls. |
| 410 const bool check_arguments = function.IsClosureFunction(); | 378 const bool check_arguments = function.IsClosureFunction(); |
| 411 #endif | 379 #endif |
| 412 if (check_arguments) { | 380 if (check_arguments) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 425 if (function.IsClosureFunction()) { | 393 if (function.IsClosureFunction()) { |
| 426 GenerateCallRuntime(AstNode::kNoId, | 394 GenerateCallRuntime(AstNode::kNoId, |
| 427 0, | 395 0, |
| 428 kClosureArgumentMismatchRuntimeEntry); | 396 kClosureArgumentMismatchRuntimeEntry); |
| 429 } else { | 397 } else { |
| 430 __ Stop("Wrong number of arguments"); | 398 __ Stop("Wrong number of arguments"); |
| 431 } | 399 } |
| 432 __ Bind(&argc_in_range); | 400 __ Bind(&argc_in_range); |
| 433 } | 401 } |
| 434 } else { | 402 } else { |
| 435 ASSERT(first_param_index == -1); | 403 ASSERT(parsed_function_.first_parameter_index() == -1); |
| 436 // Copy positional arguments. | 404 // Copy positional arguments. |
| 437 // Check that no fewer than num_fixed_params positional arguments are passed | 405 // 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. | 406 // 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]. | 407 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i]. |
| 408 const int num_params = num_fixed_params + num_opt_params; |
| 440 | 409 |
| 441 // Total number of args is the first Smi in args descriptor array (R10). | 410 // Total number of args is the first Smi in args descriptor array (R10). |
| 442 __ movq(RBX, FieldAddress(R10, Array::data_offset())); | 411 __ movq(RBX, FieldAddress(R10, Array::data_offset())); |
| 443 // Check that num_args <= num_params. | 412 // Check that num_args <= num_params. |
| 444 Label wrong_num_arguments; | 413 Label wrong_num_arguments; |
| 445 __ cmpq(RBX, Immediate(Smi::RawValue(num_params))); | 414 __ cmpq(RBX, Immediate(Smi::RawValue(num_params))); |
| 446 __ j(GREATER, &wrong_num_arguments); | 415 __ j(GREATER, &wrong_num_arguments); |
| 447 // Number of positional args is the second Smi in descriptor array (R10). | 416 // Number of positional args is the second Smi in descriptor array (R10). |
| 448 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); | 417 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); |
| 449 // Check that num_pos_args >= num_fixed_params. | 418 // Check that num_pos_args >= num_fixed_params. |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 Label null_args_loop, null_args_loop_condition; | 564 Label null_args_loop, null_args_loop_condition; |
| 596 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 565 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 597 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); | 566 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); |
| 598 __ Bind(&null_args_loop); | 567 __ Bind(&null_args_loop); |
| 599 __ movq(original_argument_addr, raw_null); | 568 __ movq(original_argument_addr, raw_null); |
| 600 __ Bind(&null_args_loop_condition); | 569 __ Bind(&null_args_loop_condition); |
| 601 __ decq(RCX); | 570 __ decq(RCX); |
| 602 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 571 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 603 } | 572 } |
| 604 | 573 |
| 605 // Initialize locals. | 574 // 3. Initialize (non-argument) stack-allocated locals to null. |
| 575 // |
| 606 // TODO(regis): For now, always unroll the init loop. Decide later above | 576 // TODO(regis): For now, always unroll the init loop. Decide later above |
| 607 // which threshold to implement a loop. | 577 // which threshold to implement a loop. Consider emitting pushes instead |
| 608 // Consider emitting pushes instead of moves. | 578 // of moves. |
| 609 for (int index = first_local_index; index > first_free_frame_index; index--) { | 579 const int base = parsed_function_.first_stack_local_index(); |
| 610 if (index == first_local_index) { | 580 for (int index = 0; index < parsed_function_.stack_local_count(); ++index) { |
| 581 if (index == 0) { |
| 611 __ movq(RAX, raw_null); | 582 __ movq(RAX, raw_null); |
| 612 } | 583 } |
| 613 __ movq(Address(RBP, index * kWordSize), RAX); | 584 __ movq(Address(RBP, (base - index) * kWordSize), RAX); |
| 614 } | 585 } |
| 615 | 586 |
| 616 // Generate stack overflow check. | 587 // 4. Generate the stack overflow check. |
| 617 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); | 588 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); |
| 618 __ cmpq(RSP, Address(TMP, 0)); | 589 __ cmpq(RSP, Address(TMP, 0)); |
| 619 Label no_stack_overflow; | 590 Label no_stack_overflow; |
| 620 __ j(ABOVE, &no_stack_overflow); | 591 __ j(ABOVE, &no_stack_overflow); |
| 621 GenerateCallRuntime(AstNode::kNoId, | 592 GenerateCallRuntime(AstNode::kNoId, |
| 622 0, | 593 0, |
| 623 kStackOverflowRuntimeEntry); | 594 kStackOverflowRuntimeEntry); |
| 624 __ Bind(&no_stack_overflow); | 595 __ Bind(&no_stack_overflow); |
| 625 } | 596 } |
| 626 | 597 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 node->dst_name()); | 716 node->dst_name()); |
| 746 if (IsResultNeeded(node)) { | 717 if (IsResultNeeded(node)) { |
| 747 __ pushq(RAX); | 718 __ pushq(RAX); |
| 748 } | 719 } |
| 749 } | 720 } |
| 750 | 721 |
| 751 | 722 |
| 752 void CodeGenerator::VisitClosureNode(ClosureNode* node) { | 723 void CodeGenerator::VisitClosureNode(ClosureNode* node) { |
| 753 const Function& function = node->function(); | 724 const Function& function = node->function(); |
| 754 if (function.IsNonImplicitClosureFunction()) { | 725 if (function.IsNonImplicitClosureFunction()) { |
| 755 const int current_context_level = state()->context_level(); | 726 // The context scope may have already been set by the new non-optimizing |
| 756 const ContextScope& context_scope = ContextScope::ZoneHandle( | 727 // compiler. If it was not, set it here. |
| 757 node->scope()->PreserveOuterScope(current_context_level)); | 728 if (function.context_scope() == ContextScope::null()) { |
| 758 ASSERT(!function.HasCode()); | 729 const int current_context_level = state()->context_level(); |
| 759 ASSERT(function.context_scope() == ContextScope::null()); | 730 const ContextScope& context_scope = ContextScope::ZoneHandle( |
| 760 function.set_context_scope(context_scope); | 731 node->scope()->PreserveOuterScope(current_context_level)); |
| 761 } else { | 732 ASSERT(!function.HasCode()); |
| 762 ASSERT(function.context_scope() != ContextScope::null()); | 733 function.set_context_scope(context_scope); |
| 763 if (function.IsImplicitInstanceClosureFunction()) { | |
| 764 node->receiver()->Visit(this); | |
| 765 } | 734 } |
| 735 } else if (function.IsImplicitInstanceClosureFunction()) { |
| 736 node->receiver()->Visit(this); |
| 766 } | 737 } |
| 738 ASSERT(function.context_scope() != ContextScope::null()); |
| 739 |
| 767 // The function type of a closure may have type arguments. In that case, pass | 740 // The function type of a closure may have type arguments. In that case, pass |
| 768 // the type arguments of the instantiator. | 741 // the type arguments of the instantiator. |
| 769 const Class& cls = Class::Handle(function.signature_class()); | 742 const Class& cls = Class::Handle(function.signature_class()); |
| 770 ASSERT(!cls.IsNull()); | 743 ASSERT(!cls.IsNull()); |
| 771 const bool requires_type_arguments = cls.HasTypeArguments(); | 744 const bool requires_type_arguments = cls.HasTypeArguments(); |
| 772 if (requires_type_arguments) { | 745 if (requires_type_arguments) { |
| 773 ASSERT(!function.IsImplicitStaticClosureFunction()); | 746 ASSERT(!function.IsImplicitStaticClosureFunction()); |
| 774 GenerateInstantiatorTypeArguments(node->token_index()); | 747 GenerateInstantiatorTypeArguments(node->token_index()); |
| 775 } | 748 } |
| 776 const Code& stub = Code::Handle( | 749 const Code& stub = Code::Handle( |
| (...skipping 1896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2673 const Error& error = Error::Handle( | 2646 const Error& error = Error::Handle( |
| 2674 Parser::FormatError(script, token_index, "Error", format, args)); | 2647 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2675 va_end(args); | 2648 va_end(args); |
| 2676 Isolate::Current()->long_jump_base()->Jump(1, error); | 2649 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2677 UNREACHABLE(); | 2650 UNREACHABLE(); |
| 2678 } | 2651 } |
| 2679 | 2652 |
| 2680 } // namespace dart | 2653 } // namespace dart |
| 2681 | 2654 |
| 2682 #endif // defined TARGET_ARCH_X64 | 2655 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |