Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 160 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 160 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
| 161 if (is_optimizing()) return; | 161 if (is_optimizing()) return; |
| 162 Definition* defn = instr->AsDefinition(); | 162 Definition* defn = instr->AsDefinition(); |
| 163 if ((defn != NULL) && defn->is_used()) { | 163 if ((defn != NULL) && defn->is_used()) { |
| 164 __ Push(defn->locs()->out().reg()); | 164 __ Push(defn->locs()->out().reg()); |
| 165 } | 165 } |
| 166 } | 166 } |
| 167 | 167 |
| 168 | 168 |
| 169 void FlowGraphCompiler::CopyParameters() { | 169 void FlowGraphCompiler::CopyParameters() { |
| 170 UNIMPLEMENTED(); | 170 __ 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
| |
| 171 const Function& function = parsed_function().function(); | |
| 172 LocalScope* scope = parsed_function().node_sequence()->scope(); | |
| 173 const int num_fixed_params = function.num_fixed_parameters(); | |
| 174 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); | |
| 175 const int num_opt_named_params = function.NumOptionalNamedParameters(); | |
| 176 const int num_params = | |
| 177 num_fixed_params + num_opt_pos_params + num_opt_named_params; | |
| 178 ASSERT(function.NumParameters() == num_params); | |
| 179 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex); | |
| 180 | |
| 181 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | |
| 182 // where num_pos_args is the number of positional arguments passed in. | |
| 183 const int min_num_pos_args = num_fixed_params; | |
| 184 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | |
| 185 | |
| 186 __ ldr(R8, FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | |
| 187 // Check that min_num_pos_args <= num_pos_args. | |
| 188 Label wrong_num_arguments; | |
| 189 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args)); | |
| 190 __ b(&wrong_num_arguments, LT); | |
| 191 // Check that num_pos_args <= max_num_pos_args. | |
| 192 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args)); | |
| 193 __ b(&wrong_num_arguments, GT); | |
| 194 | |
| 195 // Copy positional arguments. | |
| 196 // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied | |
| 197 // to fp[kFirstLocalSlotIndex - i]. | |
| 198 | |
| 199 __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | |
| 200 // Since R7 and R8 are Smi, use LSL 1 instead of LSL 2. | |
| 201 // Let R7 point to the last passed positional argument, i.e. to | |
| 202 // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)]. | |
| 203 __ sub(R7, R7, ShifterOperand(R8)); | |
| 204 __ add(R7, FP, ShifterOperand(R7, LSL, 1)); | |
| 205 __ add(R7, R7, ShifterOperand(kLastParamSlotIndex * kWordSize)); | |
| 206 | |
| 207 // Let R6 point to the last copied positional argument, i.e. to | |
| 208 // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. | |
| 209 __ AddImmediate(R6, FP, (kFirstLocalSlotIndex + 1) * kWordSize); | |
| 210 __ sub(R6, R6, ShifterOperand(R8, LSL, 1)); // R8 is a Smi. | |
| 211 __ SmiUntag(R8); | |
| 212 Label loop, loop_condition; | |
| 213 __ b(&loop_condition); | |
| 214 // We do not use the final allocation index of the variable here, i.e. | |
| 215 // scope->VariableAt(i)->index(), because captured variables still need | |
| 216 // to be copied to the context that is not yet allocated. | |
| 217 const Address argument_addr(R7, R8, LSL, 2); | |
| 218 const Address copy_addr(R6, R8, LSL, 2); | |
| 219 __ Bind(&loop); | |
| 220 __ ldr(IP, argument_addr); | |
| 221 __ str(IP, copy_addr); | |
| 222 __ Bind(&loop_condition); | |
| 223 __ subs(R8, R8, ShifterOperand(1)); | |
| 224 __ b(&loop, PL); | |
| 225 | |
| 226 // Copy or initialize optional named arguments. | |
| 227 Label all_arguments_processed; | |
| 228 if (num_opt_named_params > 0) { | |
| 229 // Start by alphabetically sorting the names of the optional parameters. | |
| 230 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | |
| 231 int* opt_param_position = new int[num_opt_named_params]; | |
| 232 for (int pos = num_fixed_params; pos < num_params; pos++) { | |
| 233 LocalVariable* parameter = scope->VariableAt(pos); | |
| 234 const String& opt_param_name = parameter->name(); | |
| 235 int i = pos - num_fixed_params; | |
| 236 while (--i >= 0) { | |
| 237 LocalVariable* param_i = opt_param[i]; | |
| 238 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | |
| 239 ASSERT(result != 0); | |
| 240 if (result > 0) break; | |
| 241 opt_param[i + 1] = opt_param[i]; | |
| 242 opt_param_position[i + 1] = opt_param_position[i]; | |
| 243 } | |
| 244 opt_param[i + 1] = parameter; | |
| 245 opt_param_position[i + 1] = pos; | |
| 246 } | |
| 247 // Generate code handling each optional parameter in alphabetical order. | |
| 248 __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | |
| 249 __ ldr(R8, | |
| 250 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | |
| 251 __ SmiUntag(R8); | |
| 252 // 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
| |
| 253 // Let R7 point to the first passed argument, i.e. to | |
| 254 // fp[kLastParamSlotIndex + num_args - 1 - 0]; num_args (R7) is Smi. | |
| 255 __ add(R7, FP, ShifterOperand(R7, LSL, 1)); | |
| 256 __ AddImmediate(R7, R7, (kLastParamSlotIndex - 1) * kWordSize); | |
| 257 // Let R6 point to the entry of the first named argument. | |
| 258 __ add(R6, R4, ShifterOperand( | |
| 259 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); | |
| 260 for (int i = 0; i < num_opt_named_params; i++) { | |
| 261 Label load_default_value, assign_optional_parameter, next_parameter; | |
| 262 const int param_pos = opt_param_position[i]; | |
| 263 // Check if this named parameter was passed in. | |
| 264 // Load R5 with the name of the argument. | |
| 265 __ ldr(R5, Address(R6, ArgumentsDescriptor::name_offset())); | |
| 266 ASSERT(opt_param[i]->name().IsSymbol()); | |
| 267 __ CompareObject(R5, opt_param[i]->name()); | |
| 268 __ b(&load_default_value, NE); | |
| 269 // Load R5 with passed-in argument at provided arg_pos, i.e. at | |
| 270 // fp[kLastParamSlotIndex + num_args - 1 - arg_pos]. | |
| 271 __ ldr(R5, Address(R6, ArgumentsDescriptor::position_offset())); | |
| 272 // R5 is arg_pos as Smi. | |
| 273 // Point to next named entry. | |
| 274 __ add(R6, R6, ShifterOperand(ArgumentsDescriptor::named_entry_size())); | |
| 275 __ rsb(R5, R5, ShifterOperand(0)); | |
| 276 Address argument_addr(R7, R5, LSL, 1); // R5 is a negative Smi. | |
| 277 __ ldr(R5, argument_addr); | |
| 278 __ b(&assign_optional_parameter); | |
| 279 __ Bind(&load_default_value); | |
| 280 // Load R5 with default argument. | |
| 281 const Object& value = Object::ZoneHandle( | |
| 282 parsed_function().default_parameter_values().At( | |
| 283 param_pos - num_fixed_params)); | |
| 284 __ LoadObject(R5, value); | |
| 285 __ Bind(&assign_optional_parameter); | |
| 286 // Assign R5 to fp[kFirstLocalSlotIndex - param_pos]. | |
| 287 // We do not use the final allocation index of the variable here, i.e. | |
| 288 // scope->VariableAt(i)->index(), because captured variables still need | |
| 289 // to be copied to the context that is not yet allocated. | |
| 290 const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; | |
| 291 const Address param_addr(FP, computed_param_pos * kWordSize); | |
| 292 __ str(R5, param_addr); | |
| 293 __ 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
| |
| 294 } | |
| 295 delete[] opt_param; | |
| 296 delete[] opt_param_position; | |
| 297 // Check that R6 now points to the null terminator in the array descriptor. | |
| 298 __ ldr(R5, Address(R6, 0)); | |
| 299 __ CompareImmediate(R5, reinterpret_cast<int32_t>(Object::null())); | |
| 300 __ b(&all_arguments_processed, EQ); | |
| 301 } else { | |
| 302 ASSERT(num_opt_pos_params > 0); | |
| 303 __ ldr(R8, | |
| 304 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | |
| 305 __ SmiUntag(R8); | |
| 306 for (int i = 0; i < num_opt_pos_params; i++) { | |
| 307 Label next_parameter; | |
| 308 // Handle this optional positional parameter only if k or fewer positional | |
| 309 // arguments have been passed, where k is param_pos, the position of this | |
| 310 // optional parameter in the formal parameter list. | |
| 311 const int param_pos = num_fixed_params + i; | |
| 312 __ CompareImmediate(R8, param_pos); | |
| 313 __ b(&next_parameter, GT); | |
| 314 // Load R5 with default argument. | |
| 315 const Object& value = Object::ZoneHandle( | |
| 316 parsed_function().default_parameter_values().At(i)); | |
| 317 __ LoadObject(R5, value); | |
| 318 // Assign R5 to fp[kFirstLocalSlotIndex - param_pos]. | |
| 319 // We do not use the final allocation index of the variable here, i.e. | |
| 320 // scope->VariableAt(i)->index(), because captured variables still need | |
| 321 // to be copied to the context that is not yet allocated. | |
| 322 const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; | |
| 323 const Address param_addr(FP, computed_param_pos * kWordSize); | |
| 324 __ str(R5, param_addr); | |
| 325 __ Bind(&next_parameter); | |
| 326 } | |
| 327 __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | |
| 328 __ SmiUntag(R7); | |
| 329 // Check that R8 equals R7, i.e. no named arguments passed. | |
| 330 __ cmp(R8, ShifterOperand(R7)); | |
| 331 __ b(&all_arguments_processed, EQ); | |
| 332 } | |
| 333 | |
| 334 __ Bind(&wrong_num_arguments); | |
| 335 if (StackSize() != 0) { | |
| 336 // We need to unwind the space we reserved for locals and copied parameters. | |
| 337 // The NoSuchMethodFunction stub does not expect to see that area on the | |
| 338 // stack. | |
| 339 __ AddImmediate(SP, StackSize() * kWordSize); | |
| 340 } | |
| 341 // The call below has an empty stackmap because we have just | |
| 342 // dropped the spill slots. | |
| 343 BitmapBuilder* empty_stack_bitmap = new BitmapBuilder(); | |
| 344 | |
| 345 // Invoke noSuchMethod function passing the original name of the function. | |
| 346 // If the function is a closure function, use "call" as the original name. | |
| 347 const String& name = String::Handle( | |
| 348 function.IsClosureFunction() ? Symbols::Call().raw() : function.name()); | |
| 349 const int kNumArgsChecked = 1; | |
| 350 const ICData& ic_data = ICData::ZoneHandle( | |
| 351 ICData::New(function, name, Isolate::kNoDeoptId, kNumArgsChecked)); | |
| 352 __ LoadObject(R5, ic_data); | |
| 353 // FP - 4 : saved PP, object pool pointer of caller. | |
| 354 // FP + 0 : previous frame pointer. | |
| 355 // FP + 4 : return address. | |
| 356 // FP + 8 : PC marker, for easy identification of RawInstruction obj. | |
| 357 // FP + 12: last argument (arg n-1). | |
| 358 // SP + 0 : saved PP. | |
| 359 // SP + 16 + 4*(n-1) : first argument (arg 0). | |
| 360 // R5 : ic-data. | |
| 361 // R4 : arguments descriptor array. | |
| 362 __ BranchLink(&StubCode::CallNoSuchMethodFunctionLabel()); | |
| 363 if (is_optimizing()) { | |
| 364 stackmap_table_builder_->AddEntry(assembler()->CodeSize(), | |
| 365 empty_stack_bitmap, | |
| 366 0); // No registers. | |
| 367 } | |
| 368 // The noSuchMethod call may return. | |
| 369 __ LeaveDartFrame(); | |
| 370 __ Ret(); | |
| 371 | |
| 372 __ Bind(&all_arguments_processed); | |
| 373 // Nullify originally passed arguments only after they have been copied and | |
| 374 // checked, otherwise noSuchMethod would not see their original values. | |
| 375 // This step can be skipped in case we decide that formal parameters are | |
| 376 // implicitly final, since garbage collecting the unmodified value is not | |
| 377 // an issue anymore. | |
| 378 | |
| 379 // R4 : arguments descriptor array. | |
| 380 __ ldr(R8, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | |
| 381 __ SmiUntag(R8); | |
| 382 __ add(R7, FP, ShifterOperand(kLastParamSlotIndex * kWordSize)); | |
| 383 const Address original_argument_addr(R7, R8, LSL, 2); | |
| 384 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); | |
| 385 Label null_args_loop, null_args_loop_condition; | |
| 386 __ b(&null_args_loop_condition); | |
| 387 __ Bind(&null_args_loop); | |
| 388 __ str(IP, original_argument_addr); | |
| 389 __ Bind(&null_args_loop_condition); | |
| 390 __ subs(R8, R8, ShifterOperand(1)); | |
| 391 __ b(&null_args_loop, PL); | |
| 171 } | 392 } |
| 172 | 393 |
| 173 | 394 |
| 174 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 395 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 175 UNIMPLEMENTED(); | 396 UNIMPLEMENTED(); |
| 176 } | 397 } |
| 177 | 398 |
| 178 | 399 |
| 179 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 400 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 180 UNIMPLEMENTED(); | 401 UNIMPLEMENTED(); |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 } | 649 } |
| 429 | 650 |
| 430 | 651 |
| 431 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 652 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 432 const ICData& ic_data, | 653 const ICData& ic_data, |
| 433 const Array& arguments_descriptor, | 654 const Array& arguments_descriptor, |
| 434 intptr_t argument_count, | 655 intptr_t argument_count, |
| 435 intptr_t deopt_id, | 656 intptr_t deopt_id, |
| 436 intptr_t token_pos, | 657 intptr_t token_pos, |
| 437 LocationSummary* locs) { | 658 LocationSummary* locs) { |
| 438 UNIMPLEMENTED(); | 659 __ LoadObject(R5, ic_data); |
| 660 __ LoadObject(R4, arguments_descriptor); | |
| 661 GenerateDartCall(deopt_id, | |
| 662 token_pos, | |
| 663 target_label, | |
| 664 PcDescriptors::kIcCall, | |
| 665 locs); | |
| 666 __ Drop(argument_count); | |
| 439 } | 667 } |
| 440 | 668 |
| 441 | 669 |
| 442 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 670 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 443 const ICData& ic_data, | 671 const ICData& ic_data, |
| 444 const Array& arguments_descriptor, | 672 const Array& arguments_descriptor, |
| 445 intptr_t argument_count, | 673 intptr_t argument_count, |
| 446 intptr_t deopt_id, | 674 intptr_t deopt_id, |
| 447 intptr_t token_pos, | 675 intptr_t token_pos, |
| 448 LocationSummary* locs) { | 676 LocationSummary* locs) { |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 623 | 851 |
| 624 | 852 |
| 625 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 853 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
| 626 UNIMPLEMENTED(); | 854 UNIMPLEMENTED(); |
| 627 } | 855 } |
| 628 | 856 |
| 629 | 857 |
| 630 } // namespace dart | 858 } // namespace dart |
| 631 | 859 |
| 632 #endif // defined TARGET_ARCH_ARM | 860 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |