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_implicit_native_closure = | |
377 function.is_native() && function.IsImplicitClosureFunction(); | |
regis
2012/06/15 17:13:34
You should be using IsImplicitInstanceClosureFunct
siva
2012/06/16 00:25:43
Nice catch. Thanks for finding this.
On 2012/06/1
| |
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_implicit_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_implicit_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_implicit_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_implicit_native_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_implicit_native_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 |