| 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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 | 159 |
| 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 // Input parameters: |
| 170 // R4: arguments descriptor array. |
| 169 void FlowGraphCompiler::CopyParameters() { | 171 void FlowGraphCompiler::CopyParameters() { |
| 170 UNIMPLEMENTED(); | 172 __ Comment("Copy parameters"); |
| 173 const Function& function = parsed_function().function(); |
| 174 LocalScope* scope = parsed_function().node_sequence()->scope(); |
| 175 const int num_fixed_params = function.num_fixed_parameters(); |
| 176 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); |
| 177 const int num_opt_named_params = function.NumOptionalNamedParameters(); |
| 178 const int num_params = |
| 179 num_fixed_params + num_opt_pos_params + num_opt_named_params; |
| 180 ASSERT(function.NumParameters() == num_params); |
| 181 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex); |
| 182 |
| 183 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
| 184 // where num_pos_args is the number of positional arguments passed in. |
| 185 const int min_num_pos_args = num_fixed_params; |
| 186 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 187 |
| 188 __ ldr(R8, FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
| 189 // Check that min_num_pos_args <= num_pos_args. |
| 190 Label wrong_num_arguments; |
| 191 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args)); |
| 192 __ b(&wrong_num_arguments, LT); |
| 193 // Check that num_pos_args <= max_num_pos_args. |
| 194 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args)); |
| 195 __ b(&wrong_num_arguments, GT); |
| 196 |
| 197 // Copy positional arguments. |
| 198 // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied |
| 199 // to fp[kFirstLocalSlotIndex - i]. |
| 200 |
| 201 __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 202 // Since R7 and R8 are Smi, use LSL 1 instead of LSL 2. |
| 203 // Let R7 point to the last passed positional argument, i.e. to |
| 204 // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)]. |
| 205 __ sub(R7, R7, ShifterOperand(R8)); |
| 206 __ add(R7, FP, ShifterOperand(R7, LSL, 1)); |
| 207 __ add(R7, R7, ShifterOperand(kLastParamSlotIndex * kWordSize)); |
| 208 |
| 209 // Let R6 point to the last copied positional argument, i.e. to |
| 210 // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 211 __ AddImmediate(R6, FP, (kFirstLocalSlotIndex + 1) * kWordSize); |
| 212 __ sub(R6, R6, ShifterOperand(R8, LSL, 1)); // R8 is a Smi. |
| 213 __ SmiUntag(R8); |
| 214 Label loop, loop_condition; |
| 215 __ b(&loop_condition); |
| 216 // We do not use the final allocation index of the variable here, i.e. |
| 217 // scope->VariableAt(i)->index(), because captured variables still need |
| 218 // to be copied to the context that is not yet allocated. |
| 219 const Address argument_addr(R7, R8, LSL, 2); |
| 220 const Address copy_addr(R6, R8, LSL, 2); |
| 221 __ Bind(&loop); |
| 222 __ ldr(IP, argument_addr); |
| 223 __ str(IP, copy_addr); |
| 224 __ Bind(&loop_condition); |
| 225 __ subs(R8, R8, ShifterOperand(1)); |
| 226 __ b(&loop, PL); |
| 227 |
| 228 // Copy or initialize optional named arguments. |
| 229 Label all_arguments_processed; |
| 230 if (num_opt_named_params > 0) { |
| 231 // Start by alphabetically sorting the names of the optional parameters. |
| 232 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
| 233 int* opt_param_position = new int[num_opt_named_params]; |
| 234 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 235 LocalVariable* parameter = scope->VariableAt(pos); |
| 236 const String& opt_param_name = parameter->name(); |
| 237 int i = pos - num_fixed_params; |
| 238 while (--i >= 0) { |
| 239 LocalVariable* param_i = opt_param[i]; |
| 240 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 241 ASSERT(result != 0); |
| 242 if (result > 0) break; |
| 243 opt_param[i + 1] = opt_param[i]; |
| 244 opt_param_position[i + 1] = opt_param_position[i]; |
| 245 } |
| 246 opt_param[i + 1] = parameter; |
| 247 opt_param_position[i + 1] = pos; |
| 248 } |
| 249 // Generate code handling each optional parameter in alphabetical order. |
| 250 __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 251 __ ldr(R8, |
| 252 FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); |
| 253 __ SmiUntag(R8); |
| 254 // Let R7 point to the first passed argument, i.e. to |
| 255 // fp[kLastParamSlotIndex + num_args - 1 - 0]; num_args (R7) is Smi. |
| 256 __ add(R7, FP, ShifterOperand(R7, LSL, 1)); |
| 257 __ AddImmediate(R7, R7, (kLastParamSlotIndex - 1) * kWordSize); |
| 258 // Let R6 point to the entry of the first named argument. |
| 259 __ add(R6, R4, ShifterOperand( |
| 260 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); |
| 261 for (int i = 0; i < num_opt_named_params; i++) { |
| 262 Label load_default_value, assign_optional_parameter; |
| 263 const int param_pos = opt_param_position[i]; |
| 264 // Check if this named parameter was passed in. |
| 265 // Load R5 with the name of the argument. |
| 266 __ ldr(R5, Address(R6, ArgumentsDescriptor::name_offset())); |
| 267 ASSERT(opt_param[i]->name().IsSymbol()); |
| 268 __ CompareObject(R5, opt_param[i]->name()); |
| 269 __ b(&load_default_value, NE); |
| 270 // Load R5 with passed-in argument at provided arg_pos, i.e. at |
| 271 // fp[kLastParamSlotIndex + num_args - 1 - arg_pos]. |
| 272 __ ldr(R5, Address(R6, ArgumentsDescriptor::position_offset())); |
| 273 // R5 is arg_pos as Smi. |
| 274 // Point to next named entry. |
| 275 __ add(R6, R6, ShifterOperand(ArgumentsDescriptor::named_entry_size())); |
| 276 __ rsb(R5, R5, ShifterOperand(0)); |
| 277 Address argument_addr(R7, R5, LSL, 1); // R5 is a negative Smi. |
| 278 __ ldr(R5, argument_addr); |
| 279 __ b(&assign_optional_parameter); |
| 280 __ Bind(&load_default_value); |
| 281 // Load R5 with default argument. |
| 282 const Object& value = Object::ZoneHandle( |
| 283 parsed_function().default_parameter_values().At( |
| 284 param_pos - num_fixed_params)); |
| 285 __ LoadObject(R5, value); |
| 286 __ Bind(&assign_optional_parameter); |
| 287 // Assign R5 to fp[kFirstLocalSlotIndex - param_pos]. |
| 288 // We do not use the final allocation index of the variable here, i.e. |
| 289 // scope->VariableAt(i)->index(), because captured variables still need |
| 290 // to be copied to the context that is not yet allocated. |
| 291 const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; |
| 292 const Address param_addr(FP, computed_param_pos * kWordSize); |
| 293 __ str(R5, param_addr); |
| 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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 } else { | 449 } else { |
| 229 AddCurrentDescriptor(PcDescriptors::kEntryPatch, | 450 AddCurrentDescriptor(PcDescriptors::kEntryPatch, |
| 230 Isolate::kNoDeoptId, | 451 Isolate::kNoDeoptId, |
| 231 0); // No token position. | 452 0); // No token position. |
| 232 } | 453 } |
| 233 __ Comment("Enter frame"); | 454 __ Comment("Enter frame"); |
| 234 __ EnterDartFrame((StackSize() * kWordSize)); | 455 __ EnterDartFrame((StackSize() * kWordSize)); |
| 235 } | 456 } |
| 236 | 457 |
| 237 | 458 |
| 459 // Input parameters: |
| 460 // LR: return address. |
| 461 // SP: address of last argument. |
| 462 // FP: caller's frame pointer. |
| 463 // PP: caller's pool pointer. |
| 464 // R5: ic-data. |
| 465 // R4: arguments descriptor array. |
| 238 void FlowGraphCompiler::CompileGraph() { | 466 void FlowGraphCompiler::CompileGraph() { |
| 239 InitCompiler(); | 467 InitCompiler(); |
| 240 if (TryIntrinsify()) { | 468 if (TryIntrinsify()) { |
| 241 // Although this intrinsified code will never be patched, it must satisfy | 469 // Although this intrinsified code will never be patched, it must satisfy |
| 242 // CodePatcher::CodeIsPatchable, which verifies that this code has a minimum | 470 // CodePatcher::CodeIsPatchable, which verifies that this code has a minimum |
| 243 // code size. | 471 // code size. |
| 244 __ bkpt(0); | 472 __ bkpt(0); |
| 245 __ Branch(&StubCode::FixCallersTargetLabel()); | 473 __ Branch(&StubCode::FixCallersTargetLabel()); |
| 246 return; | 474 return; |
| 247 } | 475 } |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 } | 656 } |
| 429 | 657 |
| 430 | 658 |
| 431 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 659 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 432 const ICData& ic_data, | 660 const ICData& ic_data, |
| 433 const Array& arguments_descriptor, | 661 const Array& arguments_descriptor, |
| 434 intptr_t argument_count, | 662 intptr_t argument_count, |
| 435 intptr_t deopt_id, | 663 intptr_t deopt_id, |
| 436 intptr_t token_pos, | 664 intptr_t token_pos, |
| 437 LocationSummary* locs) { | 665 LocationSummary* locs) { |
| 438 UNIMPLEMENTED(); | 666 __ LoadObject(R5, ic_data); |
| 667 __ LoadObject(R4, arguments_descriptor); |
| 668 GenerateDartCall(deopt_id, |
| 669 token_pos, |
| 670 target_label, |
| 671 PcDescriptors::kIcCall, |
| 672 locs); |
| 673 __ Drop(argument_count); |
| 439 } | 674 } |
| 440 | 675 |
| 441 | 676 |
| 442 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 677 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 443 const ICData& ic_data, | 678 const ICData& ic_data, |
| 444 const Array& arguments_descriptor, | 679 const Array& arguments_descriptor, |
| 445 intptr_t argument_count, | 680 intptr_t argument_count, |
| 446 intptr_t deopt_id, | 681 intptr_t deopt_id, |
| 447 intptr_t token_pos, | 682 intptr_t token_pos, |
| 448 LocationSummary* locs) { | 683 LocationSummary* locs) { |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 | 858 |
| 624 | 859 |
| 625 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 860 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
| 626 UNIMPLEMENTED(); | 861 UNIMPLEMENTED(); |
| 627 } | 862 } |
| 628 | 863 |
| 629 | 864 |
| 630 } // namespace dart | 865 } // namespace dart |
| 631 | 866 |
| 632 #endif // defined TARGET_ARCH_ARM | 867 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |