Index: runtime/vm/flow_graph_compiler_ia32.cc |
=================================================================== |
--- runtime/vm/flow_graph_compiler_ia32.cc (revision 12003) |
+++ 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); |
} |