| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 | 366 |
| 367 // Input parameters: | 367 // Input parameters: |
| 368 // ESP : points to return address. | 368 // ESP : points to return address. |
| 369 // ESP + 4 : address of last argument (arg n-1). | 369 // ESP + 4 : address of last argument (arg n-1). |
| 370 // ESP + 4*n : address of first argument (arg 0). | 370 // ESP + 4*n : address of first argument (arg 0). |
| 371 // EDX : arguments descriptor array. | 371 // EDX : arguments descriptor array. |
| 372 void CodeGenerator::GenerateEntryCode() { | 372 void CodeGenerator::GenerateEntryCode() { |
| 373 const Immediate raw_null = | 373 const Immediate raw_null = |
| 374 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 374 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 375 const Function& function = parsed_function_.function(); | 375 const Function& function = parsed_function_.function(); |
| 376 const bool is_instance_native_closure = |
| 377 function.is_native() && function.IsImplicitInstanceClosureFunction(); |
| 376 | 378 |
| 377 // 1. Compute the frame size and enter the frame (reserving local space | 379 // 1. Compute the frame size and enter the frame (reserving local space |
| 378 // for copied incoming and default arguments and stack-allocated local | 380 // for copied incoming and default arguments and stack-allocated local |
| 379 // variables). | 381 // variables). |
| 380 // | 382 // |
| 381 // TODO(regis): We may give up reserving space on stack for args/locals | 383 // TODO(regis): We may give up reserving space on stack for args/locals |
| 382 // because pushes of initial values may be more effective than moves. | 384 // because pushes of initial values may be more effective than moves. |
| 383 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 385 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 384 const int num_fixed_params = function.num_fixed_parameters(); | 386 const int num_fixed_params = function.num_fixed_parameters(); |
| 385 const int num_opt_params = function.num_optional_parameters(); | 387 const int num_opt_params = function.num_optional_parameters(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | 436 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
| 435 // Check that num_args <= num_params. | 437 // Check that num_args <= num_params. |
| 436 Label wrong_num_arguments; | 438 Label wrong_num_arguments; |
| 437 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); | 439 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); |
| 438 __ j(GREATER, &wrong_num_arguments); | 440 __ j(GREATER, &wrong_num_arguments); |
| 439 // Number of positional args is the second Smi in descriptor array (EDX). | 441 // Number of positional args is the second Smi in descriptor array (EDX). |
| 440 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | 442 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
| 441 // Check that num_pos_args >= num_fixed_params. | 443 // Check that num_pos_args >= num_fixed_params. |
| 442 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); | 444 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); |
| 443 __ j(LESS, &wrong_num_arguments); | 445 __ j(LESS, &wrong_num_arguments); |
| 446 |
| 444 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. | 447 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. |
| 445 // Let EBX point to the last passed positional argument, i.e. to | 448 // Let EBX point to the last passed positional argument, i.e. to |
| 446 // fp[1 + num_args - (num_pos_args - 1)]. | 449 // fp[1 + num_args - (num_pos_args - 1)]. |
| 447 __ subl(EBX, ECX); | 450 __ subl(EBX, ECX); |
| 448 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); | 451 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); |
| 449 // Let EDI point to the last copied positional argument, i.e. to | 452 // Let EDI point to the last copied positional argument, i.e. to |
| 450 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. | 453 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 451 const int index = ParsedFunction::kFirstLocalSlotIndex + 1; | 454 int implicit_this_param_pos = is_instance_native_closure ? -1 : 0; |
| 455 const int index = |
| 456 ParsedFunction::kFirstLocalSlotIndex + 1 + implicit_this_param_pos; |
| 457 // First copy captured receiver if function is an implicit native closure. |
| 458 if (is_instance_native_closure) { |
| 459 __ movl(EAX, FieldAddress(CTX, Context::variable_offset(0))); |
| 460 __ movl(Address(EBP, (index * kWordSize)), EAX); |
| 461 } |
| 452 __ leal(EDI, Address(EBP, (index * kWordSize))); | 462 __ leal(EDI, Address(EBP, (index * kWordSize))); |
| 453 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. | 463 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. |
| 454 __ subl(EDI, ECX); | 464 __ subl(EDI, ECX); |
| 455 __ SmiUntag(ECX); | 465 __ SmiUntag(ECX); |
| 456 Label loop, loop_condition; | 466 Label loop, loop_condition; |
| 457 __ jmp(&loop_condition, Assembler::kNearJump); | 467 __ jmp(&loop_condition, Assembler::kNearJump); |
| 458 // We do not use the final allocation index of the variable here, i.e. | 468 // We do not use the final allocation index of the variable here, i.e. |
| 459 // scope->VariableAt(i)->index(), because captured variables still need | 469 // scope->VariableAt(i)->index(), because captured variables still need |
| 460 // to be copied to the context that is not yet allocated. | 470 // to be copied to the context that is not yet allocated. |
| 461 const Address argument_addr(EBX, ECX, TIMES_4, 0); | 471 const Address argument_addr(EBX, ECX, TIMES_4, 0); |
| 462 const Address copy_addr(EDI, ECX, TIMES_4, 0); | 472 const Address copy_addr(EDI, ECX, TIMES_4, 0); |
| 463 __ Bind(&loop); | 473 __ Bind(&loop); |
| 464 __ movl(EAX, argument_addr); | 474 __ movl(EAX, argument_addr); |
| 465 __ movl(copy_addr, EAX); | 475 __ movl(copy_addr, EAX); |
| 466 __ Bind(&loop_condition); | 476 __ Bind(&loop_condition); |
| 467 __ decl(ECX); | 477 __ decl(ECX); |
| 468 __ j(POSITIVE, &loop, Assembler::kNearJump); | 478 __ j(POSITIVE, &loop, Assembler::kNearJump); |
| 469 | 479 |
| 470 // Copy or initialize optional named arguments. | 480 // Copy or initialize optional named arguments. |
| 471 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments. | 481 Label all_arguments_processed; |
| 472 // Start by alphabetically sorting the names of the optional parameters. | 482 if (num_opt_params > 0) { |
| 473 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; | 483 // Start by alphabetically sorting the names of the optional parameters. |
| 474 int* opt_param_position = new int[num_opt_params]; | 484 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; |
| 475 for (int pos = num_fixed_params; pos < num_params; pos++) { | 485 int* opt_param_position = new int[num_opt_params]; |
| 476 LocalVariable* parameter = scope->VariableAt(pos); | 486 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 477 const String& opt_param_name = parameter->name(); | 487 LocalVariable* parameter = scope->VariableAt(pos); |
| 478 int i = pos - num_fixed_params; | 488 const String& opt_param_name = parameter->name(); |
| 479 while (--i >= 0) { | 489 int i = pos - num_fixed_params; |
| 480 LocalVariable* param_i = opt_param[i]; | 490 while (--i >= 0) { |
| 481 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 491 LocalVariable* param_i = opt_param[i]; |
| 482 ASSERT(result != 0); | 492 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 483 if (result > 0) break; | 493 ASSERT(result != 0); |
| 484 opt_param[i + 1] = opt_param[i]; | 494 if (result > 0) break; |
| 485 opt_param_position[i + 1] = opt_param_position[i]; | 495 opt_param[i + 1] = opt_param[i]; |
| 496 opt_param_position[i + 1] = opt_param_position[i]; |
| 497 } |
| 498 opt_param[i + 1] = parameter; |
| 499 opt_param_position[i + 1] = pos; |
| 486 } | 500 } |
| 487 opt_param[i + 1] = parameter; | 501 // Generate code handling each optional parameter in alphabetical order. |
| 488 opt_param_position[i + 1] = pos; | 502 // Total number of args is the first Smi in args descriptor array (EDX). |
| 503 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
| 504 // Number of positional args is the second Smi in descriptor array (EDX). |
| 505 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
| 506 __ SmiUntag(ECX); |
| 507 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 508 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); |
| 509 // Let EDI point to the name/pos pair of the first named argument. |
| 510 __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize))); |
| 511 for (int i = 0; i < num_opt_params; i++) { |
| 512 // Handle this optional parameter only if k or fewer positional args |
| 513 // have been passed, where k is the position of this optional parameter |
| 514 // in the formal parameter list. |
| 515 Label load_default_value, assign_optional_parameter, next_parameter; |
| 516 const int param_pos = opt_param_position[i]; |
| 517 __ cmpl(ECX, Immediate(param_pos)); |
| 518 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 519 // Check if this named parameter was passed in. |
| 520 __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the arg. |
| 521 __ CompareObject(EAX, opt_param[i]->name()); |
| 522 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 523 // Load EAX with passed-in argument at provided arg_pos, i.e. at |
| 524 // fp[1 + argc - arg_pos]. |
| 525 __ movl(EAX, Address(EDI, kWordSize)); // EAX is arg_pos as Smi. |
| 526 __ addl(EDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. |
| 527 __ negl(EAX); |
| 528 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. |
| 529 __ movl(EAX, argument_addr); |
| 530 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 531 __ Bind(&load_default_value); |
| 532 // Load EAX with default argument at pos. |
| 533 const Object& value = Object::ZoneHandle( |
| 534 parsed_function_.default_parameter_values().At( |
| 535 param_pos - num_fixed_params)); |
| 536 __ LoadObject(EAX, value); |
| 537 __ Bind(&assign_optional_parameter); |
| 538 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 539 // We do not use the final allocation index of the variable here, i.e. |
| 540 // scope->VariableAt(i)->index(), because captured variables still need |
| 541 // to be copied to the context that is not yet allocated. |
| 542 intptr_t computed_param_pos = (ParsedFunction::kFirstLocalSlotIndex - |
| 543 param_pos + implicit_this_param_pos); |
| 544 const Address param_addr(EBP, (computed_param_pos * kWordSize)); |
| 545 __ movl(param_addr, EAX); |
| 546 __ Bind(&next_parameter); |
| 547 } |
| 548 delete[] opt_param; |
| 549 delete[] opt_param_position; |
| 550 // Check that EDI now points to null terminator in the array descriptor. |
| 551 __ cmpl(Address(EDI, 0), raw_null); |
| 552 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 553 } else { |
| 554 ASSERT(is_instance_native_closure); |
| 555 __ jmp(&all_arguments_processed, Assembler::kNearJump); |
| 489 } | 556 } |
| 490 // Generate code handling each optional parameter in alphabetical order. | |
| 491 // Total number of args is the first Smi in args descriptor array (EDX). | |
| 492 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | |
| 493 // Number of positional args is the second Smi in descriptor array (EDX). | |
| 494 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | |
| 495 __ SmiUntag(ECX); | |
| 496 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. | |
| 497 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); | |
| 498 // Let EDI point to the name/pos pair of the first named argument. | |
| 499 __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize))); | |
| 500 for (int i = 0; i < num_opt_params; i++) { | |
| 501 // Handle this optional parameter only if k or fewer positional arguments | |
| 502 // have been passed, where k is the position of this optional parameter in | |
| 503 // the formal parameter list. | |
| 504 Label load_default_value, assign_optional_parameter, next_parameter; | |
| 505 const int param_pos = opt_param_position[i]; | |
| 506 __ cmpl(ECX, Immediate(param_pos)); | |
| 507 __ j(GREATER, &next_parameter, Assembler::kNearJump); | |
| 508 // Check if this named parameter was passed in. | |
| 509 __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the argument. | |
| 510 __ CompareObject(EAX, opt_param[i]->name()); | |
| 511 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | |
| 512 // Load EAX with passed-in argument at provided arg_pos, i.e. at | |
| 513 // fp[1 + argc - arg_pos]. | |
| 514 __ movl(EAX, Address(EDI, kWordSize)); // EAX is arg_pos as Smi. | |
| 515 __ addl(EDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. | |
| 516 __ negl(EAX); | |
| 517 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. | |
| 518 __ movl(EAX, argument_addr); | |
| 519 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | |
| 520 __ Bind(&load_default_value); | |
| 521 // Load EAX with default argument at pos. | |
| 522 const Object& value = Object::ZoneHandle( | |
| 523 parsed_function_.default_parameter_values().At( | |
| 524 param_pos - num_fixed_params)); | |
| 525 __ LoadObject(EAX, value); | |
| 526 __ Bind(&assign_optional_parameter); | |
| 527 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. | |
| 528 // We do not use the final allocation index of the variable here, i.e. | |
| 529 // scope->VariableAt(i)->index(), because captured variables still need | |
| 530 // to be copied to the context that is not yet allocated. | |
| 531 const Address param_addr( | |
| 532 EBP, (ParsedFunction::kFirstLocalSlotIndex - param_pos) * kWordSize); | |
| 533 __ movl(param_addr, EAX); | |
| 534 __ Bind(&next_parameter); | |
| 535 } | |
| 536 delete[] opt_param; | |
| 537 delete[] opt_param_position; | |
| 538 // Check that EDI now points to the null terminator in the array descriptor. | |
| 539 Label all_arguments_processed; | |
| 540 __ cmpl(Address(EDI, 0), raw_null); | |
| 541 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | |
| 542 | 557 |
| 543 __ Bind(&wrong_num_arguments); | 558 __ Bind(&wrong_num_arguments); |
| 544 if (locals_space_size() != 0) { | 559 if (locals_space_size() != 0) { |
| 545 // We need to unwind the space we reserved for locals and copied | 560 // We need to unwind the space we reserved for locals and copied |
| 546 // parameters. The NoSuchMethodFunction stub does not expect to | 561 // parameters. The NoSuchMethodFunction stub does not expect to |
| 547 // see that area on the stack. | 562 // see that area on the stack. |
| 548 __ addl(ESP, Immediate(locals_space_size())); | 563 __ addl(ESP, Immediate(locals_space_size())); |
| 549 } | 564 } |
| 550 if (function.IsClosureFunction()) { | 565 if (function.IsClosureFunction()) { |
| 551 GenerateCallRuntime(AstNode::kNoId, | 566 GenerateCallRuntime(AstNode::kNoId, |
| (...skipping 2208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2760 } | 2775 } |
| 2761 // It is not necessary to generate a type test of the assigned value here, | 2776 // It is not necessary to generate a type test of the assigned value here, |
| 2762 // because the setter will check the type of its incoming arguments. | 2777 // because the setter will check the type of its incoming arguments. |
| 2763 GenerateStaticSetterCall(node->token_index(), | 2778 GenerateStaticSetterCall(node->token_index(), |
| 2764 node->cls(), | 2779 node->cls(), |
| 2765 node->field_name()); | 2780 node->field_name()); |
| 2766 } | 2781 } |
| 2767 | 2782 |
| 2768 | 2783 |
| 2769 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) { | 2784 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) { |
| 2785 intptr_t argument_count = node->argument_count(); |
| 2786 if (node->is_native_instance_closure()) { |
| 2787 argument_count += 1; |
| 2788 } |
| 2789 |
| 2770 // Push the result place holder initialized to NULL. | 2790 // Push the result place holder initialized to NULL. |
| 2771 __ PushObject(Object::ZoneHandle()); | 2791 __ PushObject(Object::ZoneHandle()); |
| 2772 // Pass a pointer to the first argument in EAX. | 2792 // Pass a pointer to the first argument in EAX. |
| 2773 if (!node->has_optional_parameters()) { | 2793 if (!node->has_optional_parameters() && !node->is_native_instance_closure()) { |
| 2774 __ leal(EAX, Address(EBP, (1 + node->argument_count()) * kWordSize)); | 2794 __ leal(EAX, Address(EBP, (1 + argument_count) * kWordSize)); |
| 2775 } else { | 2795 } else { |
| 2776 __ leal(EAX, | 2796 __ leal(EAX, |
| 2777 Address(EBP, ParsedFunction::kFirstLocalSlotIndex * kWordSize)); | 2797 Address(EBP, ParsedFunction::kFirstLocalSlotIndex * kWordSize)); |
| 2778 } | 2798 } |
| 2779 __ movl(ECX, Immediate(reinterpret_cast<uword>(node->native_c_function()))); | 2799 __ movl(ECX, Immediate(reinterpret_cast<uword>(node->native_c_function()))); |
| 2780 __ movl(EDX, Immediate(node->argument_count())); | 2800 __ movl(EDX, Immediate(argument_count)); |
| 2781 GenerateCall(node->token_index(), | 2801 GenerateCall(node->token_index(), |
| 2782 &StubCode::CallNativeCFunctionLabel(), | 2802 &StubCode::CallNativeCFunctionLabel(), |
| 2783 PcDescriptors::kOther); | 2803 PcDescriptors::kOther); |
| 2784 // Result is on the stack. | 2804 // Result is on the stack. |
| 2785 if (!IsResultNeeded(node)) { | 2805 if (!IsResultNeeded(node)) { |
| 2786 __ popl(EAX); | 2806 __ popl(EAX); |
| 2787 } | 2807 } |
| 2788 } | 2808 } |
| 2789 | 2809 |
| 2790 | 2810 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2943 const Error& error = Error::Handle( | 2963 const Error& error = Error::Handle( |
| 2944 Parser::FormatError(script, token_index, "Error", format, args)); | 2964 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2945 va_end(args); | 2965 va_end(args); |
| 2946 Isolate::Current()->long_jump_base()->Jump(1, error); | 2966 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2947 UNREACHABLE(); | 2967 UNREACHABLE(); |
| 2948 } | 2968 } |
| 2949 | 2969 |
| 2950 } // namespace dart | 2970 } // namespace dart |
| 2951 | 2971 |
| 2952 #endif // defined TARGET_ARCH_IA32 | 2972 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |