| Index: runtime/vm/flow_graph_compiler_ia32.cc
|
| ===================================================================
|
| --- runtime/vm/flow_graph_compiler_ia32.cc (revision 11998)
|
| +++ runtime/vm/flow_graph_compiler_ia32.cc (working copy)
|
| @@ -21,6 +21,7 @@
|
| DECLARE_FLAG(bool, enable_type_checks);
|
| DECLARE_FLAG(bool, print_ast);
|
| DECLARE_FLAG(bool, print_scopes);
|
| +DECLARE_FLAG(bool, reject_named_argument_as_positional);
|
| DECLARE_FLAG(bool, trace_functions);
|
|
|
|
|
| @@ -620,29 +621,36 @@
|
| function.is_native() && function.IsImplicitInstanceClosureFunction();
|
| LocalScope* scope = parsed_function().node_sequence()->scope();
|
| const int num_fixed_params = function.num_fixed_parameters();
|
| - const int num_opt_params = function.num_optional_parameters();
|
| + const int num_opt_pos_params = function.num_optional_positional_parameters();
|
| + int num_opt_named_params = function.num_optional_named_parameters();
|
| + const int num_params =
|
| + num_fixed_params + num_opt_pos_params + num_opt_named_params;
|
| int implicit_this_param_pos = is_native_instance_closure ? -1 : 0;
|
| ASSERT(parsed_function().first_parameter_index() ==
|
| ParsedFunction::kFirstLocalSlotIndex + implicit_this_param_pos);
|
| - // Copy positional arguments.
|
| - // Check that no fewer than num_fixed_params positional arguments are passed
|
| - // in and that no more than num_params arguments are passed in.
|
| - // Passed argument i at fp[1 + argc - i]
|
| - // copied to fp[ParsedFunction::kFirstLocalSlotIndex - i].
|
| - const int num_params = num_fixed_params + num_opt_params;
|
|
|
| - // Total number of args is the first Smi in args descriptor array (EDX).
|
| - __ movl(EBX, FieldAddress(EDX, Array::data_offset()));
|
| - // Check that num_args <= num_params.
|
| - Label wrong_num_arguments;
|
| - __ cmpl(EBX, Immediate(Smi::RawValue(num_params)));
|
| - __ j(GREATER, &wrong_num_arguments);
|
| + // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args,
|
| + // where num_pos_args is the number of positional arguments passed in.
|
| + const int min_num_pos_args = num_fixed_params;
|
| + const int max_num_pos_args = num_fixed_params + num_opt_pos_params +
|
| + (FLAG_reject_named_argument_as_positional ? 0 : num_opt_named_params);
|
| +
|
| // Number of positional args is the second Smi in descriptor array (EDX).
|
| __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize)));
|
| - // Check that num_pos_args >= num_fixed_params.
|
| - __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params)));
|
| + // Check that min_num_pos_args <= num_pos_args.
|
| + Label wrong_num_arguments;
|
| + __ cmpl(ECX, Immediate(Smi::RawValue(min_num_pos_args)));
|
| __ j(LESS, &wrong_num_arguments);
|
| + // Check that num_pos_args <= max_num_pos_args.
|
| + __ cmpl(ECX, Immediate(Smi::RawValue(max_num_pos_args)));
|
| + __ j(GREATER, &wrong_num_arguments);
|
|
|
| + // Copy positional arguments.
|
| + // Argument i passed at fp[1 + num_args - i] is copied
|
| + // to fp[ParsedFunction::kFirstLocalSlotIndex - i].
|
| +
|
| + // Total number of args is the first Smi in args descriptor array (EDX).
|
| + __ movl(EBX, FieldAddress(EDX, Array::data_offset()));
|
| // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4.
|
| // Let EBX point to the last passed positional argument, i.e. to
|
| // fp[1 + num_args - (num_pos_args - 1)].
|
| @@ -677,13 +685,18 @@
|
| __ j(POSITIVE, &loop, Assembler::kNearJump);
|
|
|
| // Copy or initialize optional named arguments.
|
| +
|
| + if (!FLAG_reject_named_argument_as_positional) {
|
| + // Treat optional positional parameters as optional named parameters.
|
| + num_opt_named_params += num_opt_pos_params;
|
| + }
|
| const Immediate raw_null =
|
| Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| Label all_arguments_processed;
|
| - if (num_opt_params > 0) {
|
| + if (num_opt_named_params > 0) {
|
| // Start by alphabetically sorting the names of the optional parameters.
|
| - LocalVariable** opt_param = new LocalVariable*[num_opt_params];
|
| - int* opt_param_position = new int[num_opt_params];
|
| + LocalVariable** opt_param = new LocalVariable*[num_opt_named_params];
|
| + int* opt_param_position = new int[num_opt_named_params];
|
| for (int pos = num_fixed_params; pos < num_params; pos++) {
|
| LocalVariable* parameter = scope->VariableAt(pos);
|
| const String& opt_param_name = parameter->name();
|
| @@ -709,14 +722,16 @@
|
| __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); // EBX is Smi.
|
| // Let EDI point to the name/pos pair of the first named argument.
|
| __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize)));
|
| - for (int i = 0; i < num_opt_params; i++) {
|
| - // Handle this optional parameter only if k or fewer positional arguments
|
| - // have been passed, where k is the position of this optional parameter in
|
| - // the formal parameter list.
|
| + for (int i = 0; i < num_opt_named_params; i++) {
|
| Label load_default_value, assign_optional_parameter, next_parameter;
|
| const int param_pos = opt_param_position[i];
|
| - __ cmpl(ECX, Immediate(param_pos));
|
| - __ j(GREATER, &next_parameter, Assembler::kNearJump);
|
| + if (!FLAG_reject_named_argument_as_positional) {
|
| + // Handle this optional parameter only if k or fewer positional
|
| + // arguments have been passed, where k is the position of this optional
|
| + // parameter in the formal parameter list.
|
| + __ cmpl(ECX, Immediate(param_pos));
|
| + __ j(GREATER, &next_parameter, Assembler::kNearJump);
|
| + }
|
| // Check if this named parameter was passed in.
|
| __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the argument.
|
| ASSERT(opt_param[i]->name().IsSymbol());
|
| @@ -731,7 +746,7 @@
|
| __ movl(EAX, argument_addr);
|
| __ jmp(&assign_optional_parameter, Assembler::kNearJump);
|
| __ Bind(&load_default_value);
|
| - // Load EAX with default argument at pos.
|
| + // Load EAX with default argument.
|
| const Object& value = Object::ZoneHandle(
|
| parsed_function().default_parameter_values().At(
|
| param_pos - num_fixed_params));
|
| @@ -752,6 +767,39 @@
|
| // Check that EDI now points to the null terminator in the array descriptor.
|
| __ cmpl(Address(EDI, 0), raw_null);
|
| __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
|
| + } else if (num_opt_pos_params > 0) {
|
| + ASSERT(FLAG_reject_named_argument_as_positional);
|
| + // Number of positional args is the second Smi in descriptor array (EDX).
|
| + __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize)));
|
| + __ SmiUntag(ECX);
|
| + for (int i = 0; i < num_opt_pos_params; i++) {
|
| + Label next_parameter;
|
| + // Handle this optional positonal parameter only if k or fewer positional
|
| + // arguments have been passed, where k is param_pos, the position of this
|
| + // optional parameter in the formal parameter list.
|
| + const int param_pos = num_fixed_params + i;
|
| + __ cmpl(ECX, Immediate(param_pos));
|
| + __ j(GREATER, &next_parameter, Assembler::kNearJump);
|
| + // Load RAX with default argument.
|
| + const Object& value = Object::ZoneHandle(
|
| + parsed_function().default_parameter_values().At(i));
|
| + __ LoadObject(EAX, value);
|
| + // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos].
|
| + // We do not use the final allocation index of the variable here, i.e.
|
| + // scope->VariableAt(i)->index(), because captured variables still need
|
| + // to be copied to the context that is not yet allocated.
|
| + intptr_t computed_param_pos = (ParsedFunction::kFirstLocalSlotIndex -
|
| + param_pos + implicit_this_param_pos);
|
| + const Address param_addr(EBP, (computed_param_pos * kWordSize));
|
| + __ movl(param_addr, EAX);
|
| + __ Bind(&next_parameter);
|
| + }
|
| + // Total number of args is the first Smi in args descriptor array (EDX).
|
| + __ movl(EBX, FieldAddress(EDX, Array::data_offset()));
|
| + __ SmiUntag(EBX);
|
| + // Check that ECX equals EBX, i.e. no named arguments passed.
|
| + __ cmpl(ECX, EBX);
|
| + __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
|
| } else {
|
| ASSERT(is_native_instance_closure);
|
| __ jmp(&all_arguments_processed, Assembler::kNearJump);
|
| @@ -764,8 +812,8 @@
|
| // stack.
|
| __ addl(ESP, Immediate(StackSize() * kWordSize));
|
| }
|
| - // The calls below have empty stackmaps because we have just dropped the
|
| - // spill slots.
|
| + // The calls immediately below have empty stackmaps because we have just
|
| + // dropped the spill slots.
|
| BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
|
| if (function.IsClosureFunction()) {
|
| // We do not use GenerateCallRuntime because of the non-standard (empty)
|
| @@ -799,7 +847,6 @@
|
| 0); // No registers.
|
| }
|
|
|
| -
|
| if (FLAG_trace_functions) {
|
| __ pushl(EAX); // Preserve result.
|
| __ PushObject(Function::ZoneHandle(function.raw()));
|
| @@ -906,9 +953,9 @@
|
| // Specialized version of entry code from CodeGenerator::GenerateEntryCode.
|
| const Function& function = parsed_function().function();
|
|
|
| - const int parameter_count = function.num_fixed_parameters();
|
| - const int copied_parameter_count = parsed_function().copied_parameter_count();
|
| - const int local_count = parsed_function().stack_local_count();
|
| + const int num_fixed_params = function.num_fixed_parameters();
|
| + const int num_copied_params = parsed_function().num_copied_params();
|
| + const int num_locals = parsed_function().num_stack_locals();
|
| __ Comment("Enter frame");
|
| if (IsLeaf()) {
|
| AssemblerMacros::EnterDartLeafFrame(assembler(), (StackSize() * kWordSize));
|
| @@ -926,13 +973,14 @@
|
| }
|
|
|
| // We check the number of passed arguments when we have to copy them due to
|
| - // the presence of optional named parameters.
|
| + // the presence of optional parameters.
|
| // No such checking code is generated if only fixed parameters are declared,
|
| // unless we are debug mode or unless we are compiling a closure.
|
| LocalVariable* saved_args_desc_var =
|
| parsed_function().GetSavedArgumentsDescriptorVar();
|
| - if (copied_parameter_count == 0) {
|
| + if (num_copied_params == 0) {
|
| #ifdef DEBUG
|
| + ASSERT(!parsed_function().function().HasOptionalParameters());
|
| const bool check_arguments = true;
|
| #else
|
| const bool check_arguments = function.IsClosureFunction();
|
| @@ -943,7 +991,7 @@
|
| Label argc_in_range;
|
| // Total number of args is the first Smi in args descriptor array (EDX).
|
| __ movl(EAX, FieldAddress(EDX, Array::data_offset()));
|
| - __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count)));
|
| + __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params)));
|
| __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
|
| if (function.IsClosureFunction()) {
|
| GenerateCallRuntime(function.token_pos(),
|
| @@ -974,13 +1022,13 @@
|
|
|
| // In unoptimized code, initialize (non-argument) stack allocated slots to
|
| // null. This does not cover the saved_args_desc_var slot.
|
| - if (!is_optimizing() && (local_count > 0)) {
|
| + if (!is_optimizing() && (num_locals > 0)) {
|
| __ Comment("Initialize spill slots");
|
| const intptr_t slot_base = parsed_function().first_stack_local_index();
|
| const Immediate raw_null =
|
| Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| __ movl(EAX, raw_null);
|
| - for (intptr_t i = 0; i < local_count; ++i) {
|
| + for (intptr_t i = 0; i < num_locals; ++i) {
|
| // Subtract index i (locals lie at lower addresses than EBP).
|
| __ movl(Address(EBP, (slot_base - i) * kWordSize), EAX);
|
| }
|
|
|