Chromium Code Reviews| Index: runtime/vm/flow_graph_compiler_arm.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_compiler_arm.cc (revision 20365) |
| +++ runtime/vm/flow_graph_compiler_arm.cc (working copy) |
| @@ -167,7 +167,228 @@ |
| void FlowGraphCompiler::CopyParameters() { |
| - UNIMPLEMENTED(); |
| + __ Comment("Copy parameters"); |
|
zra
2013/03/22 16:45:10
Maybe add a comment explaining register contents o
regis
2013/03/22 17:26:11
Added comment here and in FlowGraphCompiler::Compi
|
| + const Function& function = parsed_function().function(); |
| + LocalScope* scope = parsed_function().node_sequence()->scope(); |
| + const int num_fixed_params = function.num_fixed_parameters(); |
| + const int num_opt_pos_params = function.NumOptionalPositionalParameters(); |
| + const int num_opt_named_params = function.NumOptionalNamedParameters(); |
| + const int num_params = |
| + num_fixed_params + num_opt_pos_params + num_opt_named_params; |
| + ASSERT(function.NumParameters() == num_params); |
| + ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex); |
| + |
| + // 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; |
| + |
| + __ ldr(R8, FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
| + // Check that min_num_pos_args <= num_pos_args. |
| + Label wrong_num_arguments; |
| + __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args)); |
| + __ b(&wrong_num_arguments, LT); |
| + // Check that num_pos_args <= max_num_pos_args. |
| + __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args)); |
| + __ b(&wrong_num_arguments, GT); |
| + |
| + // Copy positional arguments. |
| + // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied |
| + // to fp[kFirstLocalSlotIndex - i]. |
| + |
| + __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| + // Since R7 and R8 are Smi, use LSL 1 instead of LSL 2. |
| + // Let R7 point to the last passed positional argument, i.e. to |
| + // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)]. |
| + __ sub(R7, R7, ShifterOperand(R8)); |
| + __ add(R7, FP, ShifterOperand(R7, LSL, 1)); |
| + __ add(R7, R7, ShifterOperand(kLastParamSlotIndex * kWordSize)); |
| + |
| + // Let R6 point to the last copied positional argument, i.e. to |
| + // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| + __ AddImmediate(R6, FP, (kFirstLocalSlotIndex + 1) * kWordSize); |
| + __ sub(R6, R6, ShifterOperand(R8, LSL, 1)); // R8 is a Smi. |
| + __ SmiUntag(R8); |
| + Label loop, loop_condition; |
| + __ b(&loop_condition); |
| + // 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. |
| + const Address argument_addr(R7, R8, LSL, 2); |
| + const Address copy_addr(R6, R8, LSL, 2); |
| + __ Bind(&loop); |
| + __ ldr(IP, argument_addr); |
| + __ str(IP, copy_addr); |
| + __ Bind(&loop_condition); |
| + __ subs(R8, R8, ShifterOperand(1)); |
| + __ b(&loop, PL); |
| + |
| + // Copy or initialize optional named arguments. |
| + Label all_arguments_processed; |
| + if (num_opt_named_params > 0) { |
| + // Start by alphabetically sorting the names of the optional parameters. |
| + 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(); |
| + int i = pos - num_fixed_params; |
| + while (--i >= 0) { |
| + LocalVariable* param_i = opt_param[i]; |
| + const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| + ASSERT(result != 0); |
| + if (result > 0) break; |
| + opt_param[i + 1] = opt_param[i]; |
| + opt_param_position[i + 1] = opt_param_position[i]; |
| + } |
| + opt_param[i + 1] = parameter; |
| + opt_param_position[i + 1] = pos; |
| + } |
| + // Generate code handling each optional parameter in alphabetical order. |
| + __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| + __ ldr(R8, |
| + FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
| + __ SmiUntag(R8); |
| + // Let R7 point to the first passed argument, i.e. to fp[1 + argc - 0]. |
|
zra
2013/03/22 16:45:10
Is this comment outdated?
regis
2013/03/22 17:26:11
Yes. I forgot to remove the old version. The newer
|
| + // Let R7 point to the first passed argument, i.e. to |
| + // fp[kLastParamSlotIndex + num_args - 1 - 0]; num_args (R7) is Smi. |
| + __ add(R7, FP, ShifterOperand(R7, LSL, 1)); |
| + __ AddImmediate(R7, R7, (kLastParamSlotIndex - 1) * kWordSize); |
| + // Let R6 point to the entry of the first named argument. |
| + __ add(R6, R4, ShifterOperand( |
| + ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); |
| + 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]; |
| + // Check if this named parameter was passed in. |
| + // Load R5 with the name of the argument. |
| + __ ldr(R5, Address(R6, ArgumentsDescriptor::name_offset())); |
| + ASSERT(opt_param[i]->name().IsSymbol()); |
| + __ CompareObject(R5, opt_param[i]->name()); |
| + __ b(&load_default_value, NE); |
| + // Load R5 with passed-in argument at provided arg_pos, i.e. at |
| + // fp[kLastParamSlotIndex + num_args - 1 - arg_pos]. |
| + __ ldr(R5, Address(R6, ArgumentsDescriptor::position_offset())); |
| + // R5 is arg_pos as Smi. |
| + // Point to next named entry. |
| + __ add(R6, R6, ShifterOperand(ArgumentsDescriptor::named_entry_size())); |
| + __ rsb(R5, R5, ShifterOperand(0)); |
| + Address argument_addr(R7, R5, LSL, 1); // R5 is a negative Smi. |
| + __ ldr(R5, argument_addr); |
| + __ b(&assign_optional_parameter); |
| + __ Bind(&load_default_value); |
| + // Load R5 with default argument. |
| + const Object& value = Object::ZoneHandle( |
| + parsed_function().default_parameter_values().At( |
| + param_pos - num_fixed_params)); |
| + __ LoadObject(R5, value); |
| + __ Bind(&assign_optional_parameter); |
| + // Assign R5 to fp[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. |
| + const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; |
| + const Address param_addr(FP, computed_param_pos * kWordSize); |
| + __ str(R5, param_addr); |
| + __ Bind(&next_parameter); |
|
zra
2013/03/22 16:45:10
Does anything branch to here?
regis
2013/03/22 17:26:11
Good catch. This is left over code from a previous
|
| + } |
| + delete[] opt_param; |
| + delete[] opt_param_position; |
| + // Check that R6 now points to the null terminator in the array descriptor. |
| + __ ldr(R5, Address(R6, 0)); |
| + __ CompareImmediate(R5, reinterpret_cast<int32_t>(Object::null())); |
| + __ b(&all_arguments_processed, EQ); |
| + } else { |
| + ASSERT(num_opt_pos_params > 0); |
| + __ ldr(R8, |
| + FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
| + __ SmiUntag(R8); |
| + for (int i = 0; i < num_opt_pos_params; i++) { |
| + Label next_parameter; |
| + // Handle this optional positional 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; |
| + __ CompareImmediate(R8, param_pos); |
| + __ b(&next_parameter, GT); |
| + // Load R5 with default argument. |
| + const Object& value = Object::ZoneHandle( |
| + parsed_function().default_parameter_values().At(i)); |
| + __ LoadObject(R5, value); |
| + // Assign R5 to fp[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. |
| + const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; |
| + const Address param_addr(FP, computed_param_pos * kWordSize); |
| + __ str(R5, param_addr); |
| + __ Bind(&next_parameter); |
| + } |
| + __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| + __ SmiUntag(R7); |
| + // Check that R8 equals R7, i.e. no named arguments passed. |
| + __ cmp(R8, ShifterOperand(R7)); |
| + __ b(&all_arguments_processed, EQ); |
| + } |
| + |
| + __ Bind(&wrong_num_arguments); |
| + if (StackSize() != 0) { |
| + // We need to unwind the space we reserved for locals and copied parameters. |
| + // The NoSuchMethodFunction stub does not expect to see that area on the |
| + // stack. |
| + __ AddImmediate(SP, StackSize() * kWordSize); |
| + } |
| + // The call below has an empty stackmap because we have just |
| + // dropped the spill slots. |
| + BitmapBuilder* empty_stack_bitmap = new BitmapBuilder(); |
| + |
| + // Invoke noSuchMethod function passing the original name of the function. |
| + // If the function is a closure function, use "call" as the original name. |
| + const String& name = String::Handle( |
| + function.IsClosureFunction() ? Symbols::Call().raw() : function.name()); |
| + const int kNumArgsChecked = 1; |
| + const ICData& ic_data = ICData::ZoneHandle( |
| + ICData::New(function, name, Isolate::kNoDeoptId, kNumArgsChecked)); |
| + __ LoadObject(R5, ic_data); |
| + // FP - 4 : saved PP, object pool pointer of caller. |
| + // FP + 0 : previous frame pointer. |
| + // FP + 4 : return address. |
| + // FP + 8 : PC marker, for easy identification of RawInstruction obj. |
| + // FP + 12: last argument (arg n-1). |
| + // SP + 0 : saved PP. |
| + // SP + 16 + 4*(n-1) : first argument (arg 0). |
| + // R5 : ic-data. |
| + // R4 : arguments descriptor array. |
| + __ BranchLink(&StubCode::CallNoSuchMethodFunctionLabel()); |
| + if (is_optimizing()) { |
| + stackmap_table_builder_->AddEntry(assembler()->CodeSize(), |
| + empty_stack_bitmap, |
| + 0); // No registers. |
| + } |
| + // The noSuchMethod call may return. |
| + __ LeaveDartFrame(); |
| + __ Ret(); |
| + |
| + __ Bind(&all_arguments_processed); |
| + // Nullify originally passed arguments only after they have been copied and |
| + // checked, otherwise noSuchMethod would not see their original values. |
| + // This step can be skipped in case we decide that formal parameters are |
| + // implicitly final, since garbage collecting the unmodified value is not |
| + // an issue anymore. |
| + |
| + // R4 : arguments descriptor array. |
| + __ ldr(R8, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| + __ SmiUntag(R8); |
| + __ add(R7, FP, ShifterOperand(kLastParamSlotIndex * kWordSize)); |
| + const Address original_argument_addr(R7, R8, LSL, 2); |
| + __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); |
| + Label null_args_loop, null_args_loop_condition; |
| + __ b(&null_args_loop_condition); |
| + __ Bind(&null_args_loop); |
| + __ str(IP, original_argument_addr); |
| + __ Bind(&null_args_loop_condition); |
| + __ subs(R8, R8, ShifterOperand(1)); |
| + __ b(&null_args_loop, PL); |
| } |
| @@ -435,7 +656,14 @@ |
| intptr_t deopt_id, |
| intptr_t token_pos, |
| LocationSummary* locs) { |
| - UNIMPLEMENTED(); |
| + __ LoadObject(R5, ic_data); |
| + __ LoadObject(R4, arguments_descriptor); |
| + GenerateDartCall(deopt_id, |
| + token_pos, |
| + target_label, |
| + PcDescriptors::kIcCall, |
| + locs); |
| + __ Drop(argument_count); |
| } |