| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 if (is_optimizing()) { | 167 if (is_optimizing()) { |
| 168 return; | 168 return; |
| 169 } | 169 } |
| 170 Definition* defn = instr->AsDefinition(); | 170 Definition* defn = instr->AsDefinition(); |
| 171 if ((defn != NULL) && defn->is_used()) { | 171 if ((defn != NULL) && defn->is_used()) { |
| 172 __ Push(defn->locs()->out(0).reg()); | 172 __ Push(defn->locs()->out(0).reg()); |
| 173 } | 173 } |
| 174 } | 174 } |
| 175 | 175 |
| 176 | 176 |
| 177 // Input parameters: |
| 178 // R4: arguments descriptor array. |
| 177 void FlowGraphCompiler::CopyParameters() { | 179 void FlowGraphCompiler::CopyParameters() { |
| 178 UNIMPLEMENTED(); | 180 __ Comment("Copy parameters"); |
| 181 const Function& function = parsed_function().function(); |
| 182 LocalScope* scope = parsed_function().node_sequence()->scope(); |
| 183 const int num_fixed_params = function.num_fixed_parameters(); |
| 184 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); |
| 185 const int num_opt_named_params = function.NumOptionalNamedParameters(); |
| 186 const int num_params = |
| 187 num_fixed_params + num_opt_pos_params + num_opt_named_params; |
| 188 ASSERT(function.NumParameters() == num_params); |
| 189 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); |
| 190 |
| 191 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
| 192 // where num_pos_args is the number of positional arguments passed in. |
| 193 const int min_num_pos_args = num_fixed_params; |
| 194 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 195 |
| 196 __ LoadFieldFromOffset( |
| 197 R8, R4, ArgumentsDescriptor::positional_count_offset()); |
| 198 // Check that min_num_pos_args <= num_pos_args. |
| 199 Label wrong_num_arguments; |
| 200 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args), PP); |
| 201 __ b(&wrong_num_arguments, LT); |
| 202 // Check that num_pos_args <= max_num_pos_args. |
| 203 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args), PP); |
| 204 __ b(&wrong_num_arguments, GT); |
| 205 |
| 206 // Copy positional arguments. |
| 207 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
| 208 // to fp[kFirstLocalSlotFromFp - i]. |
| 209 |
| 210 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); |
| 211 // Since R7 and R8 are Smi, use LSL 2 instead of LSL 3. |
| 212 // Let R7 point to the last passed positional argument, i.e. to |
| 213 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
| 214 __ sub(R7, R7, Operand(R8)); |
| 215 __ add(R7, FP, Operand(R7, LSL, 2)); |
| 216 __ add(R7, R7, Operand((kParamEndSlotFromFp + 1) * kWordSize)); |
| 217 |
| 218 // Let R6 point to the last copied positional argument, i.e. to |
| 219 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. |
| 220 __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize, PP); |
| 221 __ sub(R6, R6, Operand(R8, LSL, 2)); // R8 is a Smi. |
| 222 __ SmiUntag(R8); |
| 223 Label loop, loop_condition; |
| 224 __ b(&loop_condition); |
| 225 // We do not use the final allocation index of the variable here, i.e. |
| 226 // scope->VariableAt(i)->index(), because captured variables still need |
| 227 // to be copied to the context that is not yet allocated. |
| 228 const Address argument_addr(R7, R8, UXTX, Address::Scaled); |
| 229 const Address copy_addr(R6, R8, UXTX, Address::Scaled); |
| 230 __ Bind(&loop); |
| 231 __ ldr(TMP, argument_addr); |
| 232 __ str(TMP, copy_addr); |
| 233 __ Bind(&loop_condition); |
| 234 __ subs(R8, R8, Operand(1)); |
| 235 __ b(&loop, PL); |
| 236 |
| 237 // Copy or initialize optional named arguments. |
| 238 Label all_arguments_processed; |
| 239 #ifdef DEBUG |
| 240 const bool check_correct_named_args = true; |
| 241 #else |
| 242 const bool check_correct_named_args = function.IsClosureFunction(); |
| 243 #endif |
| 244 if (num_opt_named_params > 0) { |
| 245 // Start by alphabetically sorting the names of the optional parameters. |
| 246 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
| 247 int* opt_param_position = new int[num_opt_named_params]; |
| 248 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 249 LocalVariable* parameter = scope->VariableAt(pos); |
| 250 const String& opt_param_name = parameter->name(); |
| 251 int i = pos - num_fixed_params; |
| 252 while (--i >= 0) { |
| 253 LocalVariable* param_i = opt_param[i]; |
| 254 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 255 ASSERT(result != 0); |
| 256 if (result > 0) break; |
| 257 opt_param[i + 1] = opt_param[i]; |
| 258 opt_param_position[i + 1] = opt_param_position[i]; |
| 259 } |
| 260 opt_param[i + 1] = parameter; |
| 261 opt_param_position[i + 1] = pos; |
| 262 } |
| 263 // Generate code handling each optional parameter in alphabetical order. |
| 264 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); |
| 265 __ LoadFieldFromOffset( |
| 266 R8, R4, ArgumentsDescriptor::positional_count_offset()); |
| 267 __ SmiUntag(R8); |
| 268 // Let R7 point to the first passed argument, i.e. to |
| 269 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. |
| 270 __ add(R7, FP, Operand(R7, LSL, 2)); |
| 271 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize, PP); |
| 272 // Let R6 point to the entry of the first named argument. |
| 273 __ add(R6, R4, Operand( |
| 274 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); |
| 275 for (int i = 0; i < num_opt_named_params; i++) { |
| 276 Label load_default_value, assign_optional_parameter; |
| 277 const int param_pos = opt_param_position[i]; |
| 278 // Check if this named parameter was passed in. |
| 279 // Load R5 with the name of the argument. |
| 280 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset()); |
| 281 ASSERT(opt_param[i]->name().IsSymbol()); |
| 282 __ CompareObject(R5, opt_param[i]->name(), PP); |
| 283 __ b(&load_default_value, NE); |
| 284 // Load R5 with passed-in argument at provided arg_pos, i.e. at |
| 285 // fp[kParamEndSlotFromFp + num_args - arg_pos]. |
| 286 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset()); |
| 287 // R5 is arg_pos as Smi. |
| 288 // Point to next named entry. |
| 289 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); |
| 290 // Negate and untag R5 so we can use in scaled address mode. |
| 291 __ subs(R5, ZR, Operand(R5, ASR, 1)); |
| 292 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged. |
| 293 __ ldr(R5, argument_addr); |
| 294 __ b(&assign_optional_parameter); |
| 295 __ Bind(&load_default_value); |
| 296 // Load R5 with default argument. |
| 297 const Object& value = Object::ZoneHandle( |
| 298 parsed_function().default_parameter_values().At( |
| 299 param_pos - num_fixed_params)); |
| 300 __ LoadObject(R5, value, PP); |
| 301 __ Bind(&assign_optional_parameter); |
| 302 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 303 // We do not use the final allocation index of the variable here, i.e. |
| 304 // scope->VariableAt(i)->index(), because captured variables still need |
| 305 // to be copied to the context that is not yet allocated. |
| 306 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 307 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); |
| 308 } |
| 309 delete[] opt_param; |
| 310 delete[] opt_param_position; |
| 311 if (check_correct_named_args) { |
| 312 // Check that R6 now points to the null terminator in the arguments |
| 313 // descriptor. |
| 314 __ ldr(R5, Address(R6)); |
| 315 __ LoadObject(TMP, Object::null_object(), PP); |
| 316 __ CompareRegisters(R5, TMP); |
| 317 __ b(&all_arguments_processed, EQ); |
| 318 } |
| 319 } else { |
| 320 ASSERT(num_opt_pos_params > 0); |
| 321 __ LoadFieldFromOffset( |
| 322 R8, R4, ArgumentsDescriptor::positional_count_offset()); |
| 323 __ SmiUntag(R8); |
| 324 for (int i = 0; i < num_opt_pos_params; i++) { |
| 325 Label next_parameter; |
| 326 // Handle this optional positional parameter only if k or fewer positional |
| 327 // arguments have been passed, where k is param_pos, the position of this |
| 328 // optional parameter in the formal parameter list. |
| 329 const int param_pos = num_fixed_params + i; |
| 330 __ CompareImmediate(R8, param_pos, PP); |
| 331 __ b(&next_parameter, GT); |
| 332 // Load R5 with default argument. |
| 333 const Object& value = Object::ZoneHandle( |
| 334 parsed_function().default_parameter_values().At(i)); |
| 335 __ LoadObject(R5, value, PP); |
| 336 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 337 // We do not use the final allocation index of the variable here, i.e. |
| 338 // scope->VariableAt(i)->index(), because captured variables still need |
| 339 // to be copied to the context that is not yet allocated. |
| 340 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 341 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); |
| 342 __ Bind(&next_parameter); |
| 343 } |
| 344 if (check_correct_named_args) { |
| 345 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); |
| 346 __ SmiUntag(R7); |
| 347 // Check that R8 equals R7, i.e. no named arguments passed. |
| 348 __ CompareRegisters(R8, R7); |
| 349 __ b(&all_arguments_processed, EQ); |
| 350 } |
| 351 } |
| 352 |
| 353 __ Bind(&wrong_num_arguments); |
| 354 if (function.IsClosureFunction()) { |
| 355 // Invoke noSuchMethod function passing "call" as the original name. |
| 356 const int kNumArgsChecked = 1; |
| 357 const ICData& ic_data = ICData::ZoneHandle( |
| 358 ICData::New(function, Symbols::Call(), Object::empty_array(), |
| 359 Isolate::kNoDeoptId, kNumArgsChecked)); |
| 360 __ LoadObject(R5, ic_data, PP); |
| 361 __ LeaveDartFrame(); // The arguments are still on the stack. |
| 362 __ Branch(&StubCode::CallNoSuchMethodFunctionLabel(), PP); |
| 363 // The noSuchMethod call may return to the caller, but not here. |
| 364 __ hlt(0); |
| 365 } else if (check_correct_named_args) { |
| 366 __ Stop("Wrong arguments"); |
| 367 } |
| 368 |
| 369 __ Bind(&all_arguments_processed); |
| 370 // Nullify originally passed arguments only after they have been copied and |
| 371 // checked, otherwise noSuchMethod would not see their original values. |
| 372 // This step can be skipped in case we decide that formal parameters are |
| 373 // implicitly final, since garbage collecting the unmodified value is not |
| 374 // an issue anymore. |
| 375 |
| 376 // R4 : arguments descriptor array. |
| 377 __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset()); |
| 378 __ SmiUntag(R8); |
| 379 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); |
| 380 const Address original_argument_addr(R7, R8, UXTX, Address::Scaled); |
| 381 __ LoadObject(TMP, Object::null_object(), PP); |
| 382 Label null_args_loop, null_args_loop_condition; |
| 383 __ b(&null_args_loop_condition); |
| 384 __ Bind(&null_args_loop); |
| 385 __ str(TMP, original_argument_addr); |
| 386 __ Bind(&null_args_loop_condition); |
| 387 __ subs(R8, R8, Operand(1)); |
| 388 __ b(&null_args_loop, PL); |
| 179 } | 389 } |
| 180 | 390 |
| 181 | 391 |
| 182 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 392 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 183 UNIMPLEMENTED(); | 393 UNIMPLEMENTED(); |
| 184 } | 394 } |
| 185 | 395 |
| 186 | 396 |
| 187 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 397 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 188 UNIMPLEMENTED(); | 398 UNIMPLEMENTED(); |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 905 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 696 UNIMPLEMENTED(); | 906 UNIMPLEMENTED(); |
| 697 } | 907 } |
| 698 | 908 |
| 699 | 909 |
| 700 #undef __ | 910 #undef __ |
| 701 | 911 |
| 702 } // namespace dart | 912 } // namespace dart |
| 703 | 913 |
| 704 #endif // defined TARGET_ARCH_ARM64 | 914 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |