Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: runtime/vm/flow_graph_compiler_arm64.cc

Issue 1264543002: Simplify constant pool usage in arm64 code generator (by removing extra argument (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 57
58 58
59 bool FlowGraphCompiler::SupportsHardwareDivision() { 59 bool FlowGraphCompiler::SupportsHardwareDivision() {
60 return true; 60 return true;
61 } 61 }
62 62
63 63
64 void FlowGraphCompiler::EnterIntrinsicMode() { 64 void FlowGraphCompiler::EnterIntrinsicMode() {
65 ASSERT(!intrinsic_mode()); 65 ASSERT(!intrinsic_mode());
66 intrinsic_mode_ = true; 66 intrinsic_mode_ = true;
67 assembler()->set_constant_pool_allowed(false); 67 ASSERT(!assembler()->constant_pool_allowed());
68 } 68 }
69 69
70 70
71 void FlowGraphCompiler::ExitIntrinsicMode() { 71 void FlowGraphCompiler::ExitIntrinsicMode() {
72 ASSERT(intrinsic_mode()); 72 ASSERT(intrinsic_mode());
73 intrinsic_mode_ = false; 73 intrinsic_mode_ = false;
74 assembler()->set_constant_pool_allowed(true);
75 } 74 }
76 75
77 76
78 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, 77 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
79 DeoptInfoBuilder* builder, 78 DeoptInfoBuilder* builder,
80 const Array& deopt_table) { 79 const Array& deopt_table) {
81 if (deopt_env_ == NULL) { 80 if (deopt_env_ == NULL) {
82 ++builder->current_info_number_; 81 ++builder->current_info_number_;
83 return TypedData::null(); 82 return TypedData::null();
84 } 83 }
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 Assembler* assem = compiler->assembler(); 178 Assembler* assem = compiler->assembler();
180 #define __ assem-> 179 #define __ assem->
181 __ Comment("%s", Name()); 180 __ Comment("%s", Name());
182 __ Bind(entry_label()); 181 __ Bind(entry_label());
183 if (FLAG_trap_on_deoptimization) { 182 if (FLAG_trap_on_deoptimization) {
184 __ brk(0); 183 __ brk(0);
185 } 184 }
186 185
187 ASSERT(deopt_env() != NULL); 186 ASSERT(deopt_env() != NULL);
188 187
189 __ BranchLink(&StubCode::DeoptimizeLabel(), PP); 188 __ BranchLink(&StubCode::DeoptimizeLabel());
190 set_pc_offset(assem->CodeSize()); 189 set_pc_offset(assem->CodeSize());
191 #undef __ 190 #undef __
192 } 191 }
193 192
194 193
195 #define __ assembler()-> 194 #define __ assembler()->
196 195
197 196
198 // Fall through if bool_register contains null. 197 // Fall through if bool_register contains null.
199 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, 198 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
200 Label* is_true, 199 Label* is_true,
201 Label* is_false) { 200 Label* is_false) {
202 Label fall_through; 201 Label fall_through;
203 __ CompareObject(bool_register, Object::null_object(), PP); 202 __ CompareObject(bool_register, Object::null_object());
204 __ b(&fall_through, EQ); 203 __ b(&fall_through, EQ);
205 __ CompareObject(bool_register, Bool::True(), PP); 204 __ CompareObject(bool_register, Bool::True());
206 __ b(is_true, EQ); 205 __ b(is_true, EQ);
207 __ b(is_false); 206 __ b(is_false);
208 __ Bind(&fall_through); 207 __ Bind(&fall_through);
209 } 208 }
210 209
211 210
212 // R0: instance (must be preserved). 211 // R0: instance (must be preserved).
213 // R1: instantiator type arguments (if used). 212 // R1: instantiator type arguments (if used).
214 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( 213 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
215 TypeTestStubKind test_kind, 214 TypeTestStubKind test_kind,
216 Register instance_reg, 215 Register instance_reg,
217 Register type_arguments_reg, 216 Register type_arguments_reg,
218 Register temp_reg, 217 Register temp_reg,
219 Label* is_instance_lbl, 218 Label* is_instance_lbl,
220 Label* is_not_instance_lbl) { 219 Label* is_not_instance_lbl) {
221 ASSERT(instance_reg == R0); 220 ASSERT(instance_reg == R0);
222 ASSERT(temp_reg == kNoRegister); // Unused on ARM. 221 ASSERT(temp_reg == kNoRegister); // Unused on ARM.
223 const SubtypeTestCache& type_test_cache = 222 const SubtypeTestCache& type_test_cache =
224 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 223 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
225 __ LoadUniqueObject(R2, type_test_cache, PP); 224 __ LoadUniqueObject(R2, type_test_cache);
226 if (test_kind == kTestTypeOneArg) { 225 if (test_kind == kTestTypeOneArg) {
227 ASSERT(type_arguments_reg == kNoRegister); 226 ASSERT(type_arguments_reg == kNoRegister);
228 __ LoadObject(R1, Object::null_object(), PP); 227 __ LoadObject(R1, Object::null_object());
229 __ BranchLink(&StubCode::Subtype1TestCacheLabel(), PP); 228 __ BranchLink(&StubCode::Subtype1TestCacheLabel());
230 } else if (test_kind == kTestTypeTwoArgs) { 229 } else if (test_kind == kTestTypeTwoArgs) {
231 ASSERT(type_arguments_reg == kNoRegister); 230 ASSERT(type_arguments_reg == kNoRegister);
232 __ LoadObject(R1, Object::null_object(), PP); 231 __ LoadObject(R1, Object::null_object());
233 __ BranchLink(&StubCode::Subtype2TestCacheLabel(), PP); 232 __ BranchLink(&StubCode::Subtype2TestCacheLabel());
234 } else if (test_kind == kTestTypeThreeArgs) { 233 } else if (test_kind == kTestTypeThreeArgs) {
235 ASSERT(type_arguments_reg == R1); 234 ASSERT(type_arguments_reg == R1);
236 __ BranchLink(&StubCode::Subtype3TestCacheLabel(), PP); 235 __ BranchLink(&StubCode::Subtype3TestCacheLabel());
237 } else { 236 } else {
238 UNREACHABLE(); 237 UNREACHABLE();
239 } 238 }
240 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. 239 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False.
241 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); 240 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl);
242 return type_test_cache.raw(); 241 return type_test_cache.raw();
243 } 242 }
244 243
245 244
246 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 245 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
(...skipping 28 matching lines...) Expand all
275 const intptr_t from_index = num_type_args - num_type_params; 274 const intptr_t from_index = num_type_args - num_type_params;
276 const TypeArguments& type_arguments = 275 const TypeArguments& type_arguments =
277 TypeArguments::ZoneHandle(type.arguments()); 276 TypeArguments::ZoneHandle(type.arguments());
278 const bool is_raw_type = type_arguments.IsNull() || 277 const bool is_raw_type = type_arguments.IsNull() ||
279 type_arguments.IsRaw(from_index, num_type_params); 278 type_arguments.IsRaw(from_index, num_type_params);
280 // Signature class is an instantiated parameterized type. 279 // Signature class is an instantiated parameterized type.
281 if (!type_class.IsSignatureClass()) { 280 if (!type_class.IsSignatureClass()) {
282 if (is_raw_type) { 281 if (is_raw_type) {
283 const Register kClassIdReg = R2; 282 const Register kClassIdReg = R2;
284 // dynamic type argument, check only classes. 283 // dynamic type argument, check only classes.
285 __ LoadClassId(kClassIdReg, kInstanceReg, PP); 284 __ LoadClassId(kClassIdReg, kInstanceReg);
286 __ CompareImmediate(kClassIdReg, type_class.id(), PP); 285 __ CompareImmediate(kClassIdReg, type_class.id());
287 __ b(is_instance_lbl, EQ); 286 __ b(is_instance_lbl, EQ);
288 // List is a very common case. 287 // List is a very common case.
289 if (IsListClass(type_class)) { 288 if (IsListClass(type_class)) {
290 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); 289 GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
291 } 290 }
292 return GenerateSubtype1TestCacheLookup( 291 return GenerateSubtype1TestCacheLookup(
293 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 292 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
294 } 293 }
295 // If one type argument only, check if type argument is Object or dynamic. 294 // If one type argument only, check if type argument is Object or dynamic.
296 if (type_arguments.Length() == 1) { 295 if (type_arguments.Length() == 1) {
(...skipping 23 matching lines...) Expand all
320 is_instance_lbl, 319 is_instance_lbl,
321 is_not_instance_lbl); 320 is_not_instance_lbl);
322 } 321 }
323 322
324 323
325 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, 324 void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
326 const GrowableArray<intptr_t>& class_ids, 325 const GrowableArray<intptr_t>& class_ids,
327 Label* is_equal_lbl, 326 Label* is_equal_lbl,
328 Label* is_not_equal_lbl) { 327 Label* is_not_equal_lbl) {
329 for (intptr_t i = 0; i < class_ids.length(); i++) { 328 for (intptr_t i = 0; i < class_ids.length(); i++) {
330 __ CompareImmediate(class_id_reg, class_ids[i], PP); 329 __ CompareImmediate(class_id_reg, class_ids[i]);
331 __ b(is_equal_lbl, EQ); 330 __ b(is_equal_lbl, EQ);
332 } 331 }
333 __ b(is_not_equal_lbl); 332 __ b(is_not_equal_lbl);
334 } 333 }
335 334
336 335
337 // Testing against an instantiated type with no arguments, without 336 // Testing against an instantiated type with no arguments, without
338 // SubtypeTestCache. 337 // SubtypeTestCache.
339 // R0: instance being type checked (preserved). 338 // R0: instance being type checked (preserved).
340 // Clobbers R2, R3. 339 // Clobbers R2, R3.
(...skipping 15 matching lines...) Expand all
356 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), 355 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
357 type_class, 356 type_class,
358 TypeArguments::Handle(), 357 TypeArguments::Handle(),
359 NULL)) { 358 NULL)) {
360 __ b(is_instance_lbl, EQ); 359 __ b(is_instance_lbl, EQ);
361 } else { 360 } else {
362 __ b(is_not_instance_lbl, EQ); 361 __ b(is_not_instance_lbl, EQ);
363 } 362 }
364 // Compare if the classes are equal. 363 // Compare if the classes are equal.
365 const Register kClassIdReg = R2; 364 const Register kClassIdReg = R2;
366 __ LoadClassId(kClassIdReg, kInstanceReg, PP); 365 __ LoadClassId(kClassIdReg, kInstanceReg);
367 __ CompareImmediate(kClassIdReg, type_class.id(), PP); 366 __ CompareImmediate(kClassIdReg, type_class.id());
368 __ b(is_instance_lbl, EQ); 367 __ b(is_instance_lbl, EQ);
369 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted 368 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
370 // interfaces. 369 // interfaces.
371 // Bool interface can be implemented only by core class Bool. 370 // Bool interface can be implemented only by core class Bool.
372 if (type.IsBoolType()) { 371 if (type.IsBoolType()) {
373 __ CompareImmediate(kClassIdReg, kBoolCid, PP); 372 __ CompareImmediate(kClassIdReg, kBoolCid);
374 __ b(is_instance_lbl, EQ); 373 __ b(is_instance_lbl, EQ);
375 __ b(is_not_instance_lbl); 374 __ b(is_not_instance_lbl);
376 return false; 375 return false;
377 } 376 }
378 if (type.IsFunctionType()) { 377 if (type.IsFunctionType()) {
379 // Check if instance is a closure. 378 // Check if instance is a closure.
380 __ LoadClassById(R3, kClassIdReg, PP); 379 __ LoadClassById(R3, kClassIdReg);
381 __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset(), PP); 380 __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset());
382 __ CompareObject(R3, Object::null_object(), PP); 381 __ CompareObject(R3, Object::null_object());
383 __ b(is_instance_lbl, NE); 382 __ b(is_instance_lbl, NE);
384 } 383 }
385 // Custom checking for numbers (Smi, Mint, Bigint and Double). 384 // Custom checking for numbers (Smi, Mint, Bigint and Double).
386 // Note that instance is not Smi (checked above). 385 // Note that instance is not Smi (checked above).
387 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { 386 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
388 GenerateNumberTypeCheck( 387 GenerateNumberTypeCheck(
389 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); 388 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
390 return false; 389 return false;
391 } 390 }
392 if (type.IsStringType()) { 391 if (type.IsStringType()) {
(...skipping 12 matching lines...) Expand all
405 // TODO(srdjan): Implement a quicker subtype check, as type test 404 // TODO(srdjan): Implement a quicker subtype check, as type test
406 // arrays can grow too high, but they may be useful when optimizing 405 // arrays can grow too high, but they may be useful when optimizing
407 // code (type-feedback). 406 // code (type-feedback).
408 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 407 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
409 intptr_t token_pos, 408 intptr_t token_pos,
410 const Class& type_class, 409 const Class& type_class,
411 Label* is_instance_lbl, 410 Label* is_instance_lbl,
412 Label* is_not_instance_lbl) { 411 Label* is_not_instance_lbl) {
413 __ Comment("Subtype1TestCacheLookup"); 412 __ Comment("Subtype1TestCacheLookup");
414 const Register kInstanceReg = R0; 413 const Register kInstanceReg = R0;
415 __ LoadClass(R1, kInstanceReg, PP); 414 __ LoadClass(R1, kInstanceReg);
416 // R1: instance class. 415 // R1: instance class.
417 // Check immediate superclass equality. 416 // Check immediate superclass equality.
418 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset(), PP); 417 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
419 __ LoadFieldFromOffset(R2, R2, Type::type_class_offset(), PP); 418 __ LoadFieldFromOffset(R2, R2, Type::type_class_offset());
420 __ CompareObject(R2, type_class, PP); 419 __ CompareObject(R2, type_class);
421 __ b(is_instance_lbl, EQ); 420 __ b(is_instance_lbl, EQ);
422 421
423 const Register kTypeArgumentsReg = kNoRegister; 422 const Register kTypeArgumentsReg = kNoRegister;
424 const Register kTempReg = kNoRegister; 423 const Register kTempReg = kNoRegister;
425 return GenerateCallSubtypeTestStub(kTestTypeOneArg, 424 return GenerateCallSubtypeTestStub(kTestTypeOneArg,
426 kInstanceReg, 425 kInstanceReg,
427 kTypeArgumentsReg, 426 kTypeArgumentsReg,
428 kTempReg, 427 kTempReg,
429 is_instance_lbl, 428 is_instance_lbl,
430 is_not_instance_lbl); 429 is_not_instance_lbl);
431 } 430 }
432 431
433 432
434 // Generates inlined check if 'type' is a type parameter or type itself 433 // Generates inlined check if 'type' is a type parameter or type itself
435 // R0: instance (preserved). 434 // R0: instance (preserved).
436 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 435 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
437 intptr_t token_pos, 436 intptr_t token_pos,
438 const AbstractType& type, 437 const AbstractType& type,
439 Label* is_instance_lbl, 438 Label* is_instance_lbl,
440 Label* is_not_instance_lbl) { 439 Label* is_not_instance_lbl) {
441 __ Comment("UninstantiatedTypeTest"); 440 __ Comment("UninstantiatedTypeTest");
442 ASSERT(!type.IsInstantiated()); 441 ASSERT(!type.IsInstantiated());
443 // Skip check if destination is a dynamic type. 442 // Skip check if destination is a dynamic type.
444 if (type.IsTypeParameter()) { 443 if (type.IsTypeParameter()) {
445 const TypeParameter& type_param = TypeParameter::Cast(type); 444 const TypeParameter& type_param = TypeParameter::Cast(type);
446 // Load instantiator (or null) and instantiator type arguments on stack. 445 // Load instantiator (or null) and instantiator type arguments on stack.
447 __ ldr(R1, Address(SP)); // Get instantiator type arguments. 446 __ ldr(R1, Address(SP)); // Get instantiator type arguments.
448 // R1: instantiator type arguments. 447 // R1: instantiator type arguments.
449 // Check if type arguments are null, i.e. equivalent to vector of dynamic. 448 // Check if type arguments are null, i.e. equivalent to vector of dynamic.
450 __ CompareObject(R1, Object::null_object(), PP); 449 __ CompareObject(R1, Object::null_object());
451 __ b(is_instance_lbl, EQ); 450 __ b(is_instance_lbl, EQ);
452 __ LoadFieldFromOffset( 451 __ LoadFieldFromOffset(
453 R2, R1, TypeArguments::type_at_offset(type_param.index()), PP); 452 R2, R1, TypeArguments::type_at_offset(type_param.index()));
454 // R2: concrete type of type. 453 // R2: concrete type of type.
455 // Check if type argument is dynamic. 454 // Check if type argument is dynamic.
456 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()), PP); 455 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()));
457 __ b(is_instance_lbl, EQ); 456 __ b(is_instance_lbl, EQ);
458 __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType()), PP); 457 __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType()));
459 __ b(is_instance_lbl, EQ); 458 __ b(is_instance_lbl, EQ);
460 459
461 // For Smi check quickly against int and num interfaces. 460 // For Smi check quickly against int and num interfaces.
462 Label not_smi; 461 Label not_smi;
463 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? 462 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi?
464 __ b(&not_smi, NE); 463 __ b(&not_smi, NE);
465 __ CompareObject(R2, Type::ZoneHandle(Type::IntType()), PP); 464 __ CompareObject(R2, Type::ZoneHandle(Type::IntType()));
466 __ b(is_instance_lbl, EQ); 465 __ b(is_instance_lbl, EQ);
467 __ CompareObject(R2, Type::ZoneHandle(Type::Number()), PP); 466 __ CompareObject(R2, Type::ZoneHandle(Type::Number()));
468 __ b(is_instance_lbl, EQ); 467 __ b(is_instance_lbl, EQ);
469 // Smi must be handled in runtime. 468 // Smi must be handled in runtime.
470 Label fall_through; 469 Label fall_through;
471 __ b(&fall_through); 470 __ b(&fall_through);
472 471
473 __ Bind(&not_smi); 472 __ Bind(&not_smi);
474 // R1: instantiator type arguments. 473 // R1: instantiator type arguments.
475 // R0: instance. 474 // R0: instance.
476 const Register kInstanceReg = R0; 475 const Register kInstanceReg = R0;
477 const Register kTypeArgumentsReg = R1; 476 const Register kTypeArgumentsReg = R1;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 // If type is instantiated and non-parameterized, we can inline code 585 // If type is instantiated and non-parameterized, we can inline code
587 // checking whether the tested instance is a Smi. 586 // checking whether the tested instance is a Smi.
588 if (type.IsInstantiated()) { 587 if (type.IsInstantiated()) {
589 // A null object is only an instance of Object and dynamic, which has 588 // A null object is only an instance of Object and dynamic, which has
590 // already been checked above (if the type is instantiated). So we can 589 // already been checked above (if the type is instantiated). So we can
591 // return false here if the instance is null (and if the type is 590 // return false here if the instance is null (and if the type is
592 // instantiated). 591 // instantiated).
593 // We can only inline this null check if the type is instantiated at compile 592 // We can only inline this null check if the type is instantiated at compile
594 // time, since an uninstantiated type at compile time could be Object or 593 // time, since an uninstantiated type at compile time could be Object or
595 // dynamic at run time. 594 // dynamic at run time.
596 __ CompareObject(R0, Object::null_object(), PP); 595 __ CompareObject(R0, Object::null_object());
597 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); 596 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ);
598 } 597 }
599 598
600 // Generate inline instanceof test. 599 // Generate inline instanceof test.
601 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 600 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
602 test_cache = GenerateInlineInstanceof(token_pos, type, 601 test_cache = GenerateInlineInstanceof(token_pos, type,
603 &is_instance, &is_not_instance); 602 &is_instance, &is_not_instance);
604 603
605 // test_cache is null if there is no fall-through. 604 // test_cache is null if there is no fall-through.
606 Label done; 605 Label done;
607 if (!test_cache.IsNull()) { 606 if (!test_cache.IsNull()) {
608 // Generate runtime call. 607 // Generate runtime call.
609 // Load instantiator (R2) and its type arguments (R1). 608 // Load instantiator (R2) and its type arguments (R1).
610 __ ldr(R1, Address(SP, 0 * kWordSize)); 609 __ ldr(R1, Address(SP, 0 * kWordSize));
611 __ ldr(R2, Address(SP, 1 * kWordSize)); 610 __ ldr(R2, Address(SP, 1 * kWordSize));
612 __ PushObject(Object::null_object(), PP); // Make room for the result. 611 __ PushObject(Object::null_object()); // Make room for the result.
613 __ Push(R0); // Push the instance. 612 __ Push(R0); // Push the instance.
614 __ PushObject(type, PP); // Push the type. 613 __ PushObject(type); // Push the type.
615 // Push instantiator (R2) and its type arguments (R1). 614 // Push instantiator (R2) and its type arguments (R1).
616 __ Push(R2); 615 __ Push(R2);
617 __ Push(R1); 616 __ Push(R1);
618 __ LoadUniqueObject(R0, test_cache, PP); 617 __ LoadUniqueObject(R0, test_cache);
619 __ Push(R0); 618 __ Push(R0);
620 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); 619 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
621 // Pop the parameters supplied to the runtime entry. The result of the 620 // Pop the parameters supplied to the runtime entry. The result of the
622 // instanceof runtime call will be left as the result of the operation. 621 // instanceof runtime call will be left as the result of the operation.
623 __ Drop(5); 622 __ Drop(5);
624 if (negate_result) { 623 if (negate_result) {
625 __ Pop(R1); 624 __ Pop(R1);
626 __ LoadObject(R0, Bool::True(), PP); 625 __ LoadObject(R0, Bool::True());
627 __ CompareRegisters(R1, R0); 626 __ CompareRegisters(R1, R0);
628 __ b(&done, NE); 627 __ b(&done, NE);
629 __ LoadObject(R0, Bool::False(), PP); 628 __ LoadObject(R0, Bool::False());
630 } else { 629 } else {
631 __ Pop(R0); 630 __ Pop(R0);
632 } 631 }
633 __ b(&done); 632 __ b(&done);
634 } 633 }
635 __ Bind(&is_not_instance); 634 __ Bind(&is_not_instance);
636 __ LoadObject(R0, Bool::Get(negate_result), PP); 635 __ LoadObject(R0, Bool::Get(negate_result));
637 __ b(&done); 636 __ b(&done);
638 637
639 __ Bind(&is_instance); 638 __ Bind(&is_instance);
640 __ LoadObject(R0, Bool::Get(!negate_result), PP); 639 __ LoadObject(R0, Bool::Get(!negate_result));
641 __ Bind(&done); 640 __ Bind(&done);
642 // Remove instantiator (R2) and its type arguments (R1). 641 // Remove instantiator (R2) and its type arguments (R1).
643 __ Drop(2); 642 __ Drop(2);
644 } 643 }
645 644
646 645
647 // Optimize assignable type check by adding inlined tests for: 646 // Optimize assignable type check by adding inlined tests for:
648 // - NULL -> return NULL. 647 // - NULL -> return NULL.
649 // - Smi -> compile time subtype check (only if dst class is not parameterized). 648 // - Smi -> compile time subtype check (only if dst class is not parameterized).
650 // - Class equality (only if class is not parameterized). 649 // - Class equality (only if class is not parameterized).
(...skipping 14 matching lines...) Expand all
665 ASSERT(!dst_type.IsNull()); 664 ASSERT(!dst_type.IsNull());
666 ASSERT(dst_type.IsFinalized()); 665 ASSERT(dst_type.IsFinalized());
667 // Assignable check is skipped in FlowGraphBuilder, not here. 666 // Assignable check is skipped in FlowGraphBuilder, not here.
668 ASSERT(dst_type.IsMalformedOrMalbounded() || 667 ASSERT(dst_type.IsMalformedOrMalbounded() ||
669 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 668 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
670 // Preserve instantiator (R2) and its type arguments (R1). 669 // Preserve instantiator (R2) and its type arguments (R1).
671 __ Push(R2); 670 __ Push(R2);
672 __ Push(R1); 671 __ Push(R1);
673 // A null object is always assignable and is returned as result. 672 // A null object is always assignable and is returned as result.
674 Label is_assignable, runtime_call; 673 Label is_assignable, runtime_call;
675 __ CompareObject(R0, Object::null_object(), PP); 674 __ CompareObject(R0, Object::null_object());
676 __ b(&is_assignable, EQ); 675 __ b(&is_assignable, EQ);
677 676
678 // Generate throw new TypeError() if the type is malformed or malbounded. 677 // Generate throw new TypeError() if the type is malformed or malbounded.
679 if (dst_type.IsMalformedOrMalbounded()) { 678 if (dst_type.IsMalformedOrMalbounded()) {
680 __ PushObject(Object::null_object(), PP); // Make room for the result. 679 __ PushObject(Object::null_object()); // Make room for the result.
681 __ Push(R0); // Push the source object. 680 __ Push(R0); // Push the source object.
682 __ PushObject(dst_name, PP); // Push the name of the destination. 681 __ PushObject(dst_name); // Push the name of the destination.
683 __ PushObject(dst_type, PP); // Push the type of the destination. 682 __ PushObject(dst_type); // Push the type of the destination.
684 GenerateRuntimeCall(token_pos, 683 GenerateRuntimeCall(token_pos,
685 deopt_id, 684 deopt_id,
686 kBadTypeErrorRuntimeEntry, 685 kBadTypeErrorRuntimeEntry,
687 3, 686 3,
688 locs); 687 locs);
689 // We should never return here. 688 // We should never return here.
690 __ brk(0); 689 __ brk(0);
691 690
692 __ Bind(&is_assignable); // For a null object. 691 __ Bind(&is_assignable); // For a null object.
693 // Restore instantiator (R2) and its type arguments (R1). 692 // Restore instantiator (R2) and its type arguments (R1).
694 __ Pop(R1); 693 __ Pop(R1);
695 __ Pop(R2); 694 __ Pop(R2);
696 return; 695 return;
697 } 696 }
698 697
699 // Generate inline type check, linking to runtime call if not assignable. 698 // Generate inline type check, linking to runtime call if not assignable.
700 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 699 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
701 test_cache = GenerateInlineInstanceof(token_pos, dst_type, 700 test_cache = GenerateInlineInstanceof(token_pos, dst_type,
702 &is_assignable, &runtime_call); 701 &is_assignable, &runtime_call);
703 702
704 __ Bind(&runtime_call); 703 __ Bind(&runtime_call);
705 // Load instantiator (R2) and its type arguments (R1). 704 // Load instantiator (R2) and its type arguments (R1).
706 __ ldr(R1, Address(SP)); 705 __ ldr(R1, Address(SP));
707 __ ldr(R2, Address(SP, 1 * kWordSize)); 706 __ ldr(R2, Address(SP, 1 * kWordSize));
708 __ PushObject(Object::null_object(), PP); // Make room for the result. 707 __ PushObject(Object::null_object()); // Make room for the result.
709 __ Push(R0); // Push the source object. 708 __ Push(R0); // Push the source object.
710 __ PushObject(dst_type, PP); // Push the type of the destination. 709 __ PushObject(dst_type); // Push the type of the destination.
711 // Push instantiator (R2) and its type arguments (R1). 710 // Push instantiator (R2) and its type arguments (R1).
712 __ Push(R2); 711 __ Push(R2);
713 __ Push(R1); 712 __ Push(R1);
714 __ PushObject(dst_name, PP); // Push the name of the destination. 713 __ PushObject(dst_name); // Push the name of the destination.
715 __ LoadUniqueObject(R0, test_cache, PP); 714 __ LoadUniqueObject(R0, test_cache);
716 __ Push(R0); 715 __ Push(R0);
717 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); 716 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
718 // Pop the parameters supplied to the runtime entry. The result of the 717 // Pop the parameters supplied to the runtime entry. The result of the
719 // type check runtime call is the checked value. 718 // type check runtime call is the checked value.
720 __ Drop(6); 719 __ Drop(6);
721 __ Pop(R0); 720 __ Pop(R0);
722 721
723 __ Bind(&is_assignable); 722 __ Bind(&is_assignable);
724 // Restore instantiator (R2) and its type arguments (R1). 723 // Restore instantiator (R2) and its type arguments (R1).
725 __ Pop(R1); 724 __ Pop(R1);
(...skipping 25 matching lines...) Expand all
751 num_fixed_params + num_opt_pos_params + num_opt_named_params; 750 num_fixed_params + num_opt_pos_params + num_opt_named_params;
752 ASSERT(function.NumParameters() == num_params); 751 ASSERT(function.NumParameters() == num_params);
753 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp); 752 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp);
754 753
755 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, 754 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args,
756 // where num_pos_args is the number of positional arguments passed in. 755 // where num_pos_args is the number of positional arguments passed in.
757 const int min_num_pos_args = num_fixed_params; 756 const int min_num_pos_args = num_fixed_params;
758 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; 757 const int max_num_pos_args = num_fixed_params + num_opt_pos_params;
759 758
760 __ LoadFieldFromOffset( 759 __ LoadFieldFromOffset(
761 R8, R4, ArgumentsDescriptor::positional_count_offset(), PP); 760 R8, R4, ArgumentsDescriptor::positional_count_offset());
762 // Check that min_num_pos_args <= num_pos_args. 761 // Check that min_num_pos_args <= num_pos_args.
763 Label wrong_num_arguments; 762 Label wrong_num_arguments;
764 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args), PP); 763 __ CompareImmediate(R8, Smi::RawValue(min_num_pos_args));
765 __ b(&wrong_num_arguments, LT); 764 __ b(&wrong_num_arguments, LT);
766 // Check that num_pos_args <= max_num_pos_args. 765 // Check that num_pos_args <= max_num_pos_args.
767 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args), PP); 766 __ CompareImmediate(R8, Smi::RawValue(max_num_pos_args));
768 __ b(&wrong_num_arguments, GT); 767 __ b(&wrong_num_arguments, GT);
769 768
770 // Copy positional arguments. 769 // Copy positional arguments.
771 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied 770 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied
772 // to fp[kFirstLocalSlotFromFp - i]. 771 // to fp[kFirstLocalSlotFromFp - i].
773 772
774 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP); 773 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
775 // Since R7 and R8 are Smi, use LSL 2 instead of LSL 3. 774 // Since R7 and R8 are Smi, use LSL 2 instead of LSL 3.
776 // Let R7 point to the last passed positional argument, i.e. to 775 // Let R7 point to the last passed positional argument, i.e. to
777 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. 776 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)].
778 __ sub(R7, R7, Operand(R8)); 777 __ sub(R7, R7, Operand(R8));
779 __ add(R7, FP, Operand(R7, LSL, 2)); 778 __ add(R7, FP, Operand(R7, LSL, 2));
780 __ add(R7, R7, Operand((kParamEndSlotFromFp + 1) * kWordSize)); 779 __ add(R7, R7, Operand((kParamEndSlotFromFp + 1) * kWordSize));
781 780
782 // Let R6 point to the last copied positional argument, i.e. to 781 // Let R6 point to the last copied positional argument, i.e. to
783 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. 782 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)].
784 __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize, PP); 783 __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize);
785 __ sub(R6, R6, Operand(R8, LSL, 2)); // R8 is a Smi. 784 __ sub(R6, R6, Operand(R8, LSL, 2)); // R8 is a Smi.
786 __ SmiUntag(R8); 785 __ SmiUntag(R8);
787 Label loop, loop_condition; 786 Label loop, loop_condition;
788 __ b(&loop_condition); 787 __ b(&loop_condition);
789 // We do not use the final allocation index of the variable here, i.e. 788 // We do not use the final allocation index of the variable here, i.e.
790 // scope->VariableAt(i)->index(), because captured variables still need 789 // scope->VariableAt(i)->index(), because captured variables still need
791 // to be copied to the context that is not yet allocated. 790 // to be copied to the context that is not yet allocated.
792 const Address argument_addr(R7, R8, UXTX, Address::Scaled); 791 const Address argument_addr(R7, R8, UXTX, Address::Scaled);
793 const Address copy_addr(R6, R8, UXTX, Address::Scaled); 792 const Address copy_addr(R6, R8, UXTX, Address::Scaled);
794 __ Bind(&loop); 793 __ Bind(&loop);
(...skipping 23 matching lines...) Expand all
818 const intptr_t result = opt_param_name.CompareTo(param_i->name()); 817 const intptr_t result = opt_param_name.CompareTo(param_i->name());
819 ASSERT(result != 0); 818 ASSERT(result != 0);
820 if (result > 0) break; 819 if (result > 0) break;
821 opt_param[i + 1] = opt_param[i]; 820 opt_param[i + 1] = opt_param[i];
822 opt_param_position[i + 1] = opt_param_position[i]; 821 opt_param_position[i + 1] = opt_param_position[i];
823 } 822 }
824 opt_param[i + 1] = parameter; 823 opt_param[i + 1] = parameter;
825 opt_param_position[i + 1] = pos; 824 opt_param_position[i + 1] = pos;
826 } 825 }
827 // Generate code handling each optional parameter in alphabetical order. 826 // Generate code handling each optional parameter in alphabetical order.
828 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP); 827 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
829 __ LoadFieldFromOffset( 828 __ LoadFieldFromOffset(
830 R8, R4, ArgumentsDescriptor::positional_count_offset(), PP); 829 R8, R4, ArgumentsDescriptor::positional_count_offset());
831 __ SmiUntag(R8); 830 __ SmiUntag(R8);
832 // Let R7 point to the first passed argument, i.e. to 831 // Let R7 point to the first passed argument, i.e. to
833 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. 832 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi.
834 __ add(R7, FP, Operand(R7, LSL, 2)); 833 __ add(R7, FP, Operand(R7, LSL, 2));
835 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize, PP); 834 __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize);
836 // Let R6 point to the entry of the first named argument. 835 // Let R6 point to the entry of the first named argument.
837 __ add(R6, R4, Operand( 836 __ add(R6, R4, Operand(
838 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag)); 837 ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag));
839 for (int i = 0; i < num_opt_named_params; i++) { 838 for (int i = 0; i < num_opt_named_params; i++) {
840 Label load_default_value, assign_optional_parameter; 839 Label load_default_value, assign_optional_parameter;
841 const int param_pos = opt_param_position[i]; 840 const int param_pos = opt_param_position[i];
842 // Check if this named parameter was passed in. 841 // Check if this named parameter was passed in.
843 // Load R5 with the name of the argument. 842 // Load R5 with the name of the argument.
844 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset(), PP); 843 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::name_offset());
845 ASSERT(opt_param[i]->name().IsSymbol()); 844 ASSERT(opt_param[i]->name().IsSymbol());
846 __ CompareObject(R5, opt_param[i]->name(), PP); 845 __ CompareObject(R5, opt_param[i]->name());
847 __ b(&load_default_value, NE); 846 __ b(&load_default_value, NE);
848 // Load R5 with passed-in argument at provided arg_pos, i.e. at 847 // Load R5 with passed-in argument at provided arg_pos, i.e. at
849 // fp[kParamEndSlotFromFp + num_args - arg_pos]. 848 // fp[kParamEndSlotFromFp + num_args - arg_pos].
850 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset(), PP); 849 __ LoadFromOffset(R5, R6, ArgumentsDescriptor::position_offset());
851 // R5 is arg_pos as Smi. 850 // R5 is arg_pos as Smi.
852 // Point to next named entry. 851 // Point to next named entry.
853 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); 852 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size()));
854 // Negate and untag R5 so we can use in scaled address mode. 853 // Negate and untag R5 so we can use in scaled address mode.
855 __ subs(R5, ZR, Operand(R5, ASR, 1)); 854 __ subs(R5, ZR, Operand(R5, ASR, 1));
856 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged. 855 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged.
857 __ ldr(R5, argument_addr); 856 __ ldr(R5, argument_addr);
858 __ b(&assign_optional_parameter); 857 __ b(&assign_optional_parameter);
859 __ Bind(&load_default_value); 858 __ Bind(&load_default_value);
860 // Load R5 with default argument. 859 // Load R5 with default argument.
861 const Object& value = Object::ZoneHandle( 860 const Object& value = Object::ZoneHandle(
862 parsed_function().default_parameter_values().At( 861 parsed_function().default_parameter_values().At(
863 param_pos - num_fixed_params)); 862 param_pos - num_fixed_params));
864 __ LoadObject(R5, value, PP); 863 __ LoadObject(R5, value);
865 __ Bind(&assign_optional_parameter); 864 __ Bind(&assign_optional_parameter);
866 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. 865 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
867 // We do not use the final allocation index of the variable here, i.e. 866 // We do not use the final allocation index of the variable here, i.e.
868 // scope->VariableAt(i)->index(), because captured variables still need 867 // scope->VariableAt(i)->index(), because captured variables still need
869 // to be copied to the context that is not yet allocated. 868 // to be copied to the context that is not yet allocated.
870 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; 869 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
871 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize, PP); 870 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize);
872 } 871 }
873 delete[] opt_param; 872 delete[] opt_param;
874 delete[] opt_param_position; 873 delete[] opt_param_position;
875 if (check_correct_named_args) { 874 if (check_correct_named_args) {
876 // Check that R6 now points to the null terminator in the arguments 875 // Check that R6 now points to the null terminator in the arguments
877 // descriptor. 876 // descriptor.
878 __ ldr(R5, Address(R6)); 877 __ ldr(R5, Address(R6));
879 __ CompareObject(R5, Object::null_object(), PP); 878 __ CompareObject(R5, Object::null_object());
880 __ b(&all_arguments_processed, EQ); 879 __ b(&all_arguments_processed, EQ);
881 } 880 }
882 } else { 881 } else {
883 ASSERT(num_opt_pos_params > 0); 882 ASSERT(num_opt_pos_params > 0);
884 __ LoadFieldFromOffset( 883 __ LoadFieldFromOffset(
885 R8, R4, ArgumentsDescriptor::positional_count_offset(), PP); 884 R8, R4, ArgumentsDescriptor::positional_count_offset());
886 __ SmiUntag(R8); 885 __ SmiUntag(R8);
887 for (int i = 0; i < num_opt_pos_params; i++) { 886 for (int i = 0; i < num_opt_pos_params; i++) {
888 Label next_parameter; 887 Label next_parameter;
889 // Handle this optional positional parameter only if k or fewer positional 888 // Handle this optional positional parameter only if k or fewer positional
890 // arguments have been passed, where k is param_pos, the position of this 889 // arguments have been passed, where k is param_pos, the position of this
891 // optional parameter in the formal parameter list. 890 // optional parameter in the formal parameter list.
892 const int param_pos = num_fixed_params + i; 891 const int param_pos = num_fixed_params + i;
893 __ CompareImmediate(R8, param_pos, PP); 892 __ CompareImmediate(R8, param_pos);
894 __ b(&next_parameter, GT); 893 __ b(&next_parameter, GT);
895 // Load R5 with default argument. 894 // Load R5 with default argument.
896 const Object& value = Object::ZoneHandle( 895 const Object& value = Object::ZoneHandle(
897 parsed_function().default_parameter_values().At(i)); 896 parsed_function().default_parameter_values().At(i));
898 __ LoadObject(R5, value, PP); 897 __ LoadObject(R5, value);
899 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. 898 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
900 // We do not use the final allocation index of the variable here, i.e. 899 // We do not use the final allocation index of the variable here, i.e.
901 // scope->VariableAt(i)->index(), because captured variables still need 900 // scope->VariableAt(i)->index(), because captured variables still need
902 // to be copied to the context that is not yet allocated. 901 // to be copied to the context that is not yet allocated.
903 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; 902 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
904 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize, PP); 903 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize);
905 __ Bind(&next_parameter); 904 __ Bind(&next_parameter);
906 } 905 }
907 if (check_correct_named_args) { 906 if (check_correct_named_args) {
908 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset(), PP); 907 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
909 __ SmiUntag(R7); 908 __ SmiUntag(R7);
910 // Check that R8 equals R7, i.e. no named arguments passed. 909 // Check that R8 equals R7, i.e. no named arguments passed.
911 __ CompareRegisters(R8, R7); 910 __ CompareRegisters(R8, R7);
912 __ b(&all_arguments_processed, EQ); 911 __ b(&all_arguments_processed, EQ);
913 } 912 }
914 } 913 }
915 914
916 __ Bind(&wrong_num_arguments); 915 __ Bind(&wrong_num_arguments);
917 if (function.IsClosureFunction()) { 916 if (function.IsClosureFunction()) {
917 ASSERT(assembler()->constant_pool_allowed());
918 __ LeaveDartFrame(); // The arguments are still on the stack. 918 __ LeaveDartFrame(); // The arguments are still on the stack.
919 // Do not use caller's pool ptr in branch.
920 ASSERT(!assembler()->constant_pool_allowed());
919 __ BranchPatchable(&StubCode::CallClosureNoSuchMethodLabel()); 921 __ BranchPatchable(&StubCode::CallClosureNoSuchMethodLabel());
922 __ set_constant_pool_allowed(true);
920 // The noSuchMethod call may return to the caller, but not here. 923 // The noSuchMethod call may return to the caller, but not here.
921 } else if (check_correct_named_args) { 924 } else if (check_correct_named_args) {
922 __ Stop("Wrong arguments"); 925 __ Stop("Wrong arguments");
923 } 926 }
924 927
925 __ Bind(&all_arguments_processed); 928 __ Bind(&all_arguments_processed);
926 // Nullify originally passed arguments only after they have been copied and 929 // Nullify originally passed arguments only after they have been copied and
927 // checked, otherwise noSuchMethod would not see their original values. 930 // checked, otherwise noSuchMethod would not see their original values.
928 // This step can be skipped in case we decide that formal parameters are 931 // This step can be skipped in case we decide that formal parameters are
929 // implicitly final, since garbage collecting the unmodified value is not 932 // implicitly final, since garbage collecting the unmodified value is not
930 // an issue anymore. 933 // an issue anymore.
931 934
932 // R4 : arguments descriptor array. 935 // R4 : arguments descriptor array.
933 __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset(), PP); 936 __ LoadFieldFromOffset(R8, R4, ArgumentsDescriptor::count_offset());
934 __ SmiUntag(R8); 937 __ SmiUntag(R8);
935 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); 938 __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize));
936 const Address original_argument_addr(R7, R8, UXTX, Address::Scaled); 939 const Address original_argument_addr(R7, R8, UXTX, Address::Scaled);
937 __ LoadObject(TMP, Object::null_object(), PP); 940 __ LoadObject(TMP, Object::null_object());
938 Label null_args_loop, null_args_loop_condition; 941 Label null_args_loop, null_args_loop_condition;
939 __ b(&null_args_loop_condition); 942 __ b(&null_args_loop_condition);
940 __ Bind(&null_args_loop); 943 __ Bind(&null_args_loop);
941 __ str(TMP, original_argument_addr); 944 __ str(TMP, original_argument_addr);
942 __ Bind(&null_args_loop_condition); 945 __ Bind(&null_args_loop_condition);
943 __ subs(R8, R8, Operand(1)); 946 __ subs(R8, R8, Operand(1));
944 __ b(&null_args_loop, PL); 947 __ b(&null_args_loop, PL);
945 } 948 }
946 949
947 950
948 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { 951 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
949 // LR: return address. 952 // LR: return address.
950 // SP: receiver. 953 // SP: receiver.
951 // Sequence node has one return node, its input is load field node. 954 // Sequence node has one return node, its input is load field node.
952 __ Comment("Inlined Getter"); 955 __ Comment("Inlined Getter");
953 __ LoadFromOffset(R0, SP, 0 * kWordSize, PP); 956 __ LoadFromOffset(R0, SP, 0 * kWordSize);
954 __ LoadFromOffset(R0, R0, offset - kHeapObjectTag, PP); 957 __ LoadFromOffset(R0, R0, offset - kHeapObjectTag);
955 __ ret(); 958 __ ret();
956 } 959 }
957 960
958 961
959 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { 962 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
960 // LR: return address. 963 // LR: return address.
961 // SP+1: receiver. 964 // SP+1: receiver.
962 // SP+0: value. 965 // SP+0: value.
963 // Sequence node has one store node and one return NULL node. 966 // Sequence node has one store node and one return NULL node.
964 __ Comment("Inlined Setter"); 967 __ Comment("Inlined Setter");
965 __ LoadFromOffset(R0, SP, 1 * kWordSize, PP); // Receiver. 968 __ LoadFromOffset(R0, SP, 1 * kWordSize); // Receiver.
966 __ LoadFromOffset(R1, SP, 0 * kWordSize, PP); // Value. 969 __ LoadFromOffset(R1, SP, 0 * kWordSize); // Value.
967 __ StoreIntoObjectOffset(R0, offset, R1, PP); 970 __ StoreIntoObjectOffset(R0, offset, R1);
968 __ LoadObject(R0, Object::null_object(), PP); 971 __ LoadObject(R0, Object::null_object());
969 __ ret(); 972 __ ret();
970 } 973 }
971 974
972 975
973 void FlowGraphCompiler::EmitFrameEntry() { 976 void FlowGraphCompiler::EmitFrameEntry() {
974 const Function& function = parsed_function().function(); 977 const Function& function = parsed_function().function();
975 Register new_pp = kNoPP; 978 Register new_pp = kNoRegister;
976 if (CanOptimizeFunction() && 979 if (CanOptimizeFunction() &&
977 function.IsOptimizable() && 980 function.IsOptimizable() &&
978 (!is_optimizing() || may_reoptimize())) { 981 (!is_optimizing() || may_reoptimize())) {
979 const Register function_reg = R6; 982 const Register function_reg = R6;
983 const Register saved_pp = R7;
980 new_pp = R13; 984 new_pp = R13;
985 // The pool pointer is not setup before entering the Dart frame.
986 // Preserve PP of caller.
987 __ mov(saved_pp, PP);
981 988
982 // Set up pool pointer in new_pp. 989 // Temporarily setup pool pointer for this dart function.
983 __ LoadPoolPointer(new_pp); 990 __ LoadPoolPointer();
984 991
985 // Load function object using the callee's pool pointer. 992 // Load function object using the callee's pool pointer.
986 __ LoadObject(function_reg, function, new_pp); 993 __ LoadObject(function_reg, function);
994 // Preserve new PP and restore PP of caller.
995 __ mov(new_pp, PP);
996 __ mov(PP, saved_pp);
997 __ set_constant_pool_allowed(false);
987 998
988 // Patch point is after the eventually inlined function object. 999 // Patch point is after the eventually inlined function object.
989 entry_patch_pc_offset_ = assembler()->CodeSize(); 1000 entry_patch_pc_offset_ = assembler()->CodeSize();
990 1001
991 __ LoadFieldFromOffset( 1002 __ LoadFieldFromOffset(
992 R7, function_reg, Function::usage_counter_offset(), new_pp, kWord); 1003 R7, function_reg, Function::usage_counter_offset(), kWord);
993 // Reoptimization of an optimized function is triggered by counting in 1004 // Reoptimization of an optimized function is triggered by counting in
994 // IC stubs, but not at the entry of the function. 1005 // IC stubs, but not at the entry of the function.
995 if (!is_optimizing()) { 1006 if (!is_optimizing()) {
996 __ add(R7, R7, Operand(1)); 1007 __ add(R7, R7, Operand(1));
997 __ StoreFieldToOffset( 1008 __ StoreFieldToOffset(
998 R7, function_reg, Function::usage_counter_offset(), new_pp, kWord); 1009 R7, function_reg, Function::usage_counter_offset(), kWord);
999 } 1010 }
1000 __ CompareImmediate(R7, GetOptimizationThreshold(), new_pp); 1011 __ CompareImmediate(R7, GetOptimizationThreshold());
1001 ASSERT(function_reg == R6); 1012 ASSERT(function_reg == R6);
1002 Label dont_optimize; 1013 Label dont_optimize;
1003 __ b(&dont_optimize, LT); 1014 __ b(&dont_optimize, LT);
1004 __ Branch(&StubCode::OptimizeFunctionLabel(), new_pp); 1015 __ Branch(&StubCode::OptimizeFunctionLabel());
1005 __ Bind(&dont_optimize); 1016 __ Bind(&dont_optimize);
1006 } else if (!flow_graph().IsCompiledForOsr()) { 1017 } else if (!flow_graph().IsCompiledForOsr()) {
1007 // We have to load the PP here too because a load of an external label
1008 // may be patched at the AddCurrentDescriptor below.
1009 new_pp = R13;
1010
1011 // Set up pool pointer in new_pp.
1012 __ LoadPoolPointer(new_pp);
1013
1014 entry_patch_pc_offset_ = assembler()->CodeSize(); 1018 entry_patch_pc_offset_ = assembler()->CodeSize();
1015 } 1019 }
1016 __ Comment("Enter frame"); 1020 __ Comment("Enter frame");
1017 if (flow_graph().IsCompiledForOsr()) { 1021 if (flow_graph().IsCompiledForOsr()) {
1018 intptr_t extra_slots = StackSize() 1022 intptr_t extra_slots = StackSize()
1019 - flow_graph().num_stack_locals() 1023 - flow_graph().num_stack_locals()
1020 - flow_graph().num_copied_params(); 1024 - flow_graph().num_copied_params();
1021 ASSERT(extra_slots >= 0); 1025 ASSERT(extra_slots >= 0);
1022 __ EnterOsrFrame(extra_slots * kWordSize, new_pp); 1026 __ EnterOsrFrame(extra_slots * kWordSize, new_pp);
1023 } else { 1027 } else {
1024 ASSERT(StackSize() >= 0); 1028 ASSERT(StackSize() >= 0);
1025 __ EnterDartFrameWithInfo(StackSize() * kWordSize, new_pp); 1029 __ EnterDartFrameWithInfo(StackSize() * kWordSize, new_pp);
1026 } 1030 }
1027 } 1031 }
1028 1032
1029 1033
1030 // Input parameters: 1034 // Input parameters:
1031 // LR: return address. 1035 // LR: return address.
1032 // SP: address of last argument. 1036 // SP: address of last argument.
1033 // FP: caller's frame pointer. 1037 // FP: caller's frame pointer.
1034 // PP: caller's pool pointer. 1038 // PP: caller's pool pointer.
1035 // R5: ic-data. 1039 // R5: ic-data.
1036 // R4: arguments descriptor array. 1040 // R4: arguments descriptor array.
1037 void FlowGraphCompiler::CompileGraph() { 1041 void FlowGraphCompiler::CompileGraph() {
1038 InitCompiler(); 1042 InitCompiler();
1039 1043
1040 TryIntrinsify(); 1044 TryIntrinsify();
1041 1045
1042 EmitFrameEntry(); 1046 EmitFrameEntry();
1047 ASSERT(assembler()->constant_pool_allowed());
1043 1048
1044 const Function& function = parsed_function().function(); 1049 const Function& function = parsed_function().function();
1045 1050
1046 const int num_fixed_params = function.num_fixed_parameters(); 1051 const int num_fixed_params = function.num_fixed_parameters();
1047 const int num_copied_params = parsed_function().num_copied_params(); 1052 const int num_copied_params = parsed_function().num_copied_params();
1048 const int num_locals = parsed_function().num_stack_locals(); 1053 const int num_locals = parsed_function().num_stack_locals();
1049 1054
1050 // We check the number of passed arguments when we have to copy them due to 1055 // We check the number of passed arguments when we have to copy them due to
1051 // the presence of optional parameters. 1056 // the presence of optional parameters.
1052 // No such checking code is generated if only fixed parameters are declared, 1057 // No such checking code is generated if only fixed parameters are declared,
1053 // unless we are in debug mode or unless we are compiling a closure. 1058 // unless we are in debug mode or unless we are compiling a closure.
1054 if (num_copied_params == 0) { 1059 if (num_copied_params == 0) {
1055 #ifdef DEBUG 1060 #ifdef DEBUG
1056 ASSERT(!parsed_function().function().HasOptionalParameters()); 1061 ASSERT(!parsed_function().function().HasOptionalParameters());
1057 const bool check_arguments = !flow_graph().IsCompiledForOsr(); 1062 const bool check_arguments = !flow_graph().IsCompiledForOsr();
1058 #else 1063 #else
1059 const bool check_arguments = 1064 const bool check_arguments =
1060 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); 1065 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
1061 #endif 1066 #endif
1062 if (check_arguments) { 1067 if (check_arguments) {
1063 __ Comment("Check argument count"); 1068 __ Comment("Check argument count");
1064 // Check that exactly num_fixed arguments are passed in. 1069 // Check that exactly num_fixed arguments are passed in.
1065 Label correct_num_arguments, wrong_num_arguments; 1070 Label correct_num_arguments, wrong_num_arguments;
1066 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset(), PP); 1071 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset());
1067 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params), PP); 1072 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params));
1068 __ b(&wrong_num_arguments, NE); 1073 __ b(&wrong_num_arguments, NE);
1069 __ LoadFieldFromOffset(R1, R4, 1074 __ LoadFieldFromOffset(R1, R4,
1070 ArgumentsDescriptor::positional_count_offset(), PP); 1075 ArgumentsDescriptor::positional_count_offset());
1071 __ CompareRegisters(R0, R1); 1076 __ CompareRegisters(R0, R1);
1072 __ b(&correct_num_arguments, EQ); 1077 __ b(&correct_num_arguments, EQ);
1073 __ Bind(&wrong_num_arguments); 1078 __ Bind(&wrong_num_arguments);
1074 if (function.IsClosureFunction()) { 1079 if (function.IsClosureFunction()) {
1080 ASSERT(assembler()->constant_pool_allowed());
1075 __ LeaveDartFrame(); // The arguments are still on the stack. 1081 __ LeaveDartFrame(); // The arguments are still on the stack.
1082 // Do not use caller's pool ptr in branch.
1083 ASSERT(!assembler()->constant_pool_allowed());
1076 __ BranchPatchable(&StubCode::CallClosureNoSuchMethodLabel()); 1084 __ BranchPatchable(&StubCode::CallClosureNoSuchMethodLabel());
1085 __ set_constant_pool_allowed(true);
1077 // The noSuchMethod call may return to the caller, but not here. 1086 // The noSuchMethod call may return to the caller, but not here.
1078 } else { 1087 } else {
1079 __ Stop("Wrong number of arguments"); 1088 __ Stop("Wrong number of arguments");
1080 } 1089 }
1081 __ Bind(&correct_num_arguments); 1090 __ Bind(&correct_num_arguments);
1082 } 1091 }
1083 } else if (!flow_graph().IsCompiledForOsr()) { 1092 } else if (!flow_graph().IsCompiledForOsr()) {
1084 CopyParameters(); 1093 CopyParameters();
1085 } 1094 }
1086 1095
1087 if (function.IsClosureFunction() && !flow_graph().IsCompiledForOsr()) { 1096 if (function.IsClosureFunction() && !flow_graph().IsCompiledForOsr()) {
1088 // Load context from the closure object (first argument). 1097 // Load context from the closure object (first argument).
1089 LocalScope* scope = parsed_function().node_sequence()->scope(); 1098 LocalScope* scope = parsed_function().node_sequence()->scope();
1090 LocalVariable* closure_parameter = scope->VariableAt(0); 1099 LocalVariable* closure_parameter = scope->VariableAt(0);
1091 __ ldr(CTX, Address(FP, closure_parameter->index() * kWordSize)); 1100 __ ldr(CTX, Address(FP, closure_parameter->index() * kWordSize));
1092 __ ldr(CTX, FieldAddress(CTX, Closure::context_offset())); 1101 __ ldr(CTX, FieldAddress(CTX, Closure::context_offset()));
1093 } 1102 }
1094 1103
1095 // In unoptimized code, initialize (non-argument) stack allocated slots to 1104 // In unoptimized code, initialize (non-argument) stack allocated slots to
1096 // null. 1105 // null.
1097 if (!is_optimizing()) { 1106 if (!is_optimizing()) {
1098 ASSERT(num_locals > 0); // There is always at least context_var. 1107 ASSERT(num_locals > 0); // There is always at least context_var.
1099 __ Comment("Initialize spill slots"); 1108 __ Comment("Initialize spill slots");
1100 const intptr_t slot_base = parsed_function().first_stack_local_index(); 1109 const intptr_t slot_base = parsed_function().first_stack_local_index();
1101 const intptr_t context_index = 1110 const intptr_t context_index =
1102 parsed_function().current_context_var()->index(); 1111 parsed_function().current_context_var()->index();
1103 if (num_locals > 1) { 1112 if (num_locals > 1) {
1104 __ LoadObject(R0, Object::null_object(), PP); 1113 __ LoadObject(R0, Object::null_object());
1105 } 1114 }
1106 for (intptr_t i = 0; i < num_locals; ++i) { 1115 for (intptr_t i = 0; i < num_locals; ++i) {
1107 // Subtract index i (locals lie at lower addresses than FP). 1116 // Subtract index i (locals lie at lower addresses than FP).
1108 if (((slot_base - i) == context_index)) { 1117 if (((slot_base - i) == context_index)) {
1109 if (function.IsClosureFunction()) { 1118 if (function.IsClosureFunction()) {
1110 __ StoreToOffset(CTX, FP, (slot_base - i) * kWordSize, PP); 1119 __ StoreToOffset(CTX, FP, (slot_base - i) * kWordSize);
1111 } else { 1120 } else {
1112 const Context& empty_context = Context::ZoneHandle( 1121 const Context& empty_context = Context::ZoneHandle(
1113 zone(), isolate()->object_store()->empty_context()); 1122 zone(), isolate()->object_store()->empty_context());
1114 __ LoadObject(R1, empty_context, PP); 1123 __ LoadObject(R1, empty_context);
1115 __ StoreToOffset(R1, FP, (slot_base - i) * kWordSize, PP); 1124 __ StoreToOffset(R1, FP, (slot_base - i) * kWordSize);
1116 } 1125 }
1117 } else { 1126 } else {
1118 ASSERT(num_locals > 1); 1127 ASSERT(num_locals > 1);
1119 __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize, PP); 1128 __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize);
1120 } 1129 }
1121 } 1130 }
1122 } 1131 }
1123 1132
1124 VisitBlocks(); 1133 VisitBlocks();
1125 1134
1126 __ brk(0); 1135 __ brk(0);
1136 ASSERT(assembler()->constant_pool_allowed());
1127 GenerateDeferredCode(); 1137 GenerateDeferredCode();
1128 1138
1129 // Emit function patching code. This will be swapped with the first 3 1139 // Emit function patching code. This will be swapped with the first 3
1130 // instructions at entry point. 1140 // instructions at entry point.
1131 patch_code_pc_offset_ = assembler()->CodeSize(); 1141 patch_code_pc_offset_ = assembler()->CodeSize();
1132 __ BranchPatchable(&StubCode::FixCallersTargetLabel()); 1142 __ BranchPatchable(&StubCode::FixCallersTargetLabel());
1133 1143
1134 if (is_optimizing()) { 1144 if (is_optimizing()) {
1135 lazy_deopt_pc_offset_ = assembler()->CodeSize(); 1145 lazy_deopt_pc_offset_ = assembler()->CodeSize();
1136 __ BranchPatchable(&StubCode::DeoptimizeLazyLabel()); 1146 __ BranchPatchable(&StubCode::DeoptimizeLazyLabel());
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1191 } 1201 }
1192 } 1202 }
1193 1203
1194 1204
1195 void FlowGraphCompiler::EmitEdgeCounter() { 1205 void FlowGraphCompiler::EmitEdgeCounter() {
1196 // We do not check for overflow when incrementing the edge counter. The 1206 // We do not check for overflow when incrementing the edge counter. The
1197 // function should normally be optimized long before the counter can 1207 // function should normally be optimized long before the counter can
1198 // overflow; and though we do not reset the counters when we optimize or 1208 // overflow; and though we do not reset the counters when we optimize or
1199 // deoptimize, there is a bound on the number of 1209 // deoptimize, there is a bound on the number of
1200 // optimization/deoptimization cycles we will attempt. 1210 // optimization/deoptimization cycles we will attempt.
1211 ASSERT(assembler_->constant_pool_allowed());
1201 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); 1212 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
1202 counter.SetAt(0, Smi::Handle(Smi::New(0))); 1213 counter.SetAt(0, Smi::Handle(Smi::New(0)));
1203 __ Comment("Edge counter"); 1214 __ Comment("Edge counter");
1204 __ LoadUniqueObject(R0, counter, PP); 1215 __ LoadUniqueObject(R0, counter);
1205 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0), PP); 1216 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0));
1206 __ add(TMP, TMP, Operand(Smi::RawValue(1))); 1217 __ add(TMP, TMP, Operand(Smi::RawValue(1)));
1207 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0), PP); 1218 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0));
1208 } 1219 }
1209 1220
1210 1221
1211 void FlowGraphCompiler::EmitOptimizedInstanceCall( 1222 void FlowGraphCompiler::EmitOptimizedInstanceCall(
1212 ExternalLabel* target_label, 1223 ExternalLabel* target_label,
1213 const ICData& ic_data, 1224 const ICData& ic_data,
1214 intptr_t argument_count, 1225 intptr_t argument_count,
1215 intptr_t deopt_id, 1226 intptr_t deopt_id,
1216 intptr_t token_pos, 1227 intptr_t token_pos,
1217 LocationSummary* locs) { 1228 LocationSummary* locs) {
1218 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); 1229 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
1219 // Each ICData propagated from unoptimized to optimized code contains the 1230 // Each ICData propagated from unoptimized to optimized code contains the
1220 // function that corresponds to the Dart function of that IC call. Due 1231 // function that corresponds to the Dart function of that IC call. Due
1221 // to inlining in optimized code, that function may not correspond to the 1232 // to inlining in optimized code, that function may not correspond to the
1222 // top-level function (parsed_function().function()) which could be 1233 // top-level function (parsed_function().function()) which could be
1223 // reoptimized and which counter needs to be incremented. 1234 // reoptimized and which counter needs to be incremented.
1224 // Pass the function explicitly, it is used in IC stub. 1235 // Pass the function explicitly, it is used in IC stub.
1225 1236
1226 __ LoadObject(R6, parsed_function().function(), PP); 1237 __ LoadObject(R6, parsed_function().function());
1227 __ LoadUniqueObject(R5, ic_data, PP); 1238 __ LoadUniqueObject(R5, ic_data);
1228 GenerateDartCall(deopt_id, 1239 GenerateDartCall(deopt_id,
1229 token_pos, 1240 token_pos,
1230 target_label, 1241 target_label,
1231 RawPcDescriptors::kIcCall, 1242 RawPcDescriptors::kIcCall,
1232 locs); 1243 locs);
1233 __ Drop(argument_count); 1244 __ Drop(argument_count);
1234 } 1245 }
1235 1246
1236 1247
1237 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, 1248 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
1238 const ICData& ic_data, 1249 const ICData& ic_data,
1239 intptr_t argument_count, 1250 intptr_t argument_count,
1240 intptr_t deopt_id, 1251 intptr_t deopt_id,
1241 intptr_t token_pos, 1252 intptr_t token_pos,
1242 LocationSummary* locs) { 1253 LocationSummary* locs) {
1243 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); 1254 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
1244 __ LoadUniqueObject(R5, ic_data, PP); 1255 __ LoadUniqueObject(R5, ic_data);
1245 GenerateDartCall(deopt_id, 1256 GenerateDartCall(deopt_id,
1246 token_pos, 1257 token_pos,
1247 target_label, 1258 target_label,
1248 RawPcDescriptors::kIcCall, 1259 RawPcDescriptors::kIcCall,
1249 locs); 1260 locs);
1250 __ Drop(argument_count); 1261 __ Drop(argument_count);
1251 } 1262 }
1252 1263
1253 1264
1254 void FlowGraphCompiler::EmitMegamorphicInstanceCall( 1265 void FlowGraphCompiler::EmitMegamorphicInstanceCall(
1255 const ICData& ic_data, 1266 const ICData& ic_data,
1256 intptr_t argument_count, 1267 intptr_t argument_count,
1257 intptr_t deopt_id, 1268 intptr_t deopt_id,
1258 intptr_t token_pos, 1269 intptr_t token_pos,
1259 LocationSummary* locs) { 1270 LocationSummary* locs) {
1260 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); 1271 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
1261 const String& name = String::Handle(ic_data.target_name()); 1272 const String& name = String::Handle(ic_data.target_name());
1262 const Array& arguments_descriptor = 1273 const Array& arguments_descriptor =
1263 Array::ZoneHandle(ic_data.arguments_descriptor()); 1274 Array::ZoneHandle(ic_data.arguments_descriptor());
1264 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); 1275 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
1265 const MegamorphicCache& cache = 1276 const MegamorphicCache& cache =
1266 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); 1277 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
1267 const Register receiverR = R0; 1278 const Register receiverR = R0;
1268 const Register cacheR = R1; 1279 const Register cacheR = R1;
1269 const Register targetR = R1; 1280 const Register targetR = R1;
1270 __ LoadFromOffset(receiverR, SP, (argument_count - 1) * kWordSize, PP); 1281 __ LoadFromOffset(receiverR, SP, (argument_count - 1) * kWordSize);
1271 __ LoadObject(cacheR, cache, PP); 1282 __ LoadObject(cacheR, cache);
1272 1283
1273 if (FLAG_use_megamorphic_stub) { 1284 if (FLAG_use_megamorphic_stub) {
1274 __ BranchLink(&StubCode::MegamorphicLookupLabel(), PP); 1285 __ BranchLink(&StubCode::MegamorphicLookupLabel());
1275 } else { 1286 } else {
1276 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); 1287 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR);
1277 } 1288 }
1278 __ LoadObject(R5, ic_data, PP); 1289 __ LoadObject(R5, ic_data);
1279 __ LoadObject(R4, arguments_descriptor, PP); 1290 __ LoadObject(R4, arguments_descriptor);
1280 __ blr(targetR); 1291 __ blr(targetR);
1281 AddCurrentDescriptor(RawPcDescriptors::kOther, 1292 AddCurrentDescriptor(RawPcDescriptors::kOther,
1282 Isolate::kNoDeoptId, token_pos); 1293 Isolate::kNoDeoptId, token_pos);
1283 RecordSafepoint(locs); 1294 RecordSafepoint(locs);
1284 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); 1295 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id);
1285 if (is_optimizing()) { 1296 if (is_optimizing()) {
1286 AddDeoptIndexAtCall(deopt_id_after, token_pos); 1297 AddDeoptIndexAtCall(deopt_id_after, token_pos);
1287 } else { 1298 } else {
1288 // Add deoptimization continuation point after the call and before the 1299 // Add deoptimization continuation point after the call and before the
1289 // arguments are removed. 1300 // arguments are removed.
1290 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); 1301 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
1291 } 1302 }
1292 __ Drop(argument_count); 1303 __ Drop(argument_count);
1293 } 1304 }
1294 1305
1295 1306
1296 void FlowGraphCompiler::EmitUnoptimizedStaticCall( 1307 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
1297 intptr_t argument_count, 1308 intptr_t argument_count,
1298 intptr_t deopt_id, 1309 intptr_t deopt_id,
1299 intptr_t token_pos, 1310 intptr_t token_pos,
1300 LocationSummary* locs, 1311 LocationSummary* locs,
1301 const ICData& ic_data) { 1312 const ICData& ic_data) {
1302 const uword label_address = 1313 const uword label_address =
1303 StubCode::UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested()); 1314 StubCode::UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested());
1304 ExternalLabel target_label(label_address); 1315 ExternalLabel target_label(label_address);
1305 __ LoadObject(R5, ic_data, PP); 1316 __ LoadObject(R5, ic_data);
1306 GenerateDartCall(deopt_id, 1317 GenerateDartCall(deopt_id,
1307 token_pos, 1318 token_pos,
1308 &target_label, 1319 &target_label,
1309 RawPcDescriptors::kUnoptStaticCall, 1320 RawPcDescriptors::kUnoptStaticCall,
1310 locs); 1321 locs);
1311 __ Drop(argument_count); 1322 __ Drop(argument_count);
1312 } 1323 }
1313 1324
1314 1325
1315 void FlowGraphCompiler::EmitOptimizedStaticCall( 1326 void FlowGraphCompiler::EmitOptimizedStaticCall(
1316 const Function& function, 1327 const Function& function,
1317 const Array& arguments_descriptor, 1328 const Array& arguments_descriptor,
1318 intptr_t argument_count, 1329 intptr_t argument_count,
1319 intptr_t deopt_id, 1330 intptr_t deopt_id,
1320 intptr_t token_pos, 1331 intptr_t token_pos,
1321 LocationSummary* locs) { 1332 LocationSummary* locs) {
1322 __ LoadObject(R4, arguments_descriptor, PP); 1333 __ LoadObject(R4, arguments_descriptor);
1323 // Do not use the code from the function, but let the code be patched so that 1334 // Do not use the code from the function, but let the code be patched so that
1324 // we can record the outgoing edges to other code. 1335 // we can record the outgoing edges to other code.
1325 GenerateDartCall(deopt_id, 1336 GenerateDartCall(deopt_id,
1326 token_pos, 1337 token_pos,
1327 &StubCode::CallStaticFunctionLabel(), 1338 &StubCode::CallStaticFunctionLabel(),
1328 RawPcDescriptors::kOther, 1339 RawPcDescriptors::kOther,
1329 locs); 1340 locs);
1330 AddStaticCallTarget(function); 1341 AddStaticCallTarget(function);
1331 __ Drop(argument_count); 1342 __ Drop(argument_count);
1332 } 1343 }
1333 1344
1334 1345
1335 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( 1346 Condition FlowGraphCompiler::EmitEqualityRegConstCompare(
1336 Register reg, 1347 Register reg,
1337 const Object& obj, 1348 const Object& obj,
1338 bool needs_number_check, 1349 bool needs_number_check,
1339 intptr_t token_pos) { 1350 intptr_t token_pos) {
1340 if (needs_number_check) { 1351 if (needs_number_check) {
1341 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); 1352 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint());
1342 __ Push(reg); 1353 __ Push(reg);
1343 __ PushObject(obj, PP); 1354 __ PushObject(obj);
1344 if (is_optimizing()) { 1355 if (is_optimizing()) {
1345 __ BranchLinkPatchable( 1356 __ BranchLinkPatchable(
1346 &StubCode::OptimizedIdenticalWithNumberCheckLabel()); 1357 &StubCode::OptimizedIdenticalWithNumberCheckLabel());
1347 } else { 1358 } else {
1348 __ BranchLinkPatchable( 1359 __ BranchLinkPatchable(
1349 &StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); 1360 &StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
1350 } 1361 }
1351 if (token_pos != Scanner::kNoSourcePos) { 1362 if (token_pos != Scanner::kNoSourcePos) {
1352 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, 1363 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
1353 Isolate::kNoDeoptId, 1364 Isolate::kNoDeoptId,
1354 token_pos); 1365 token_pos);
1355 } 1366 }
1356 // Stub returns result in flags (result of a cmp, we need Z computed). 1367 // Stub returns result in flags (result of a cmp, we need Z computed).
1357 __ Drop(1); // Discard constant. 1368 __ Drop(1); // Discard constant.
1358 __ Pop(reg); // Restore 'reg'. 1369 __ Pop(reg); // Restore 'reg'.
1359 } else { 1370 } else {
1360 __ CompareObject(reg, obj, PP); 1371 __ CompareObject(reg, obj);
1361 } 1372 }
1362 return EQ; 1373 return EQ;
1363 } 1374 }
1364 1375
1365 1376
1366 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, 1377 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
1367 Register right, 1378 Register right,
1368 bool needs_number_check, 1379 bool needs_number_check,
1369 intptr_t token_pos) { 1380 intptr_t token_pos) {
1370 if (needs_number_check) { 1381 if (needs_number_check) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1473 intptr_t token_index, 1484 intptr_t token_index,
1474 LocationSummary* locs) { 1485 LocationSummary* locs) {
1475 ASSERT(is_optimizing()); 1486 ASSERT(is_optimizing());
1476 1487
1477 __ Comment("EmitTestAndCall"); 1488 __ Comment("EmitTestAndCall");
1478 const Array& arguments_descriptor = 1489 const Array& arguments_descriptor =
1479 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, 1490 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
1480 argument_names)); 1491 argument_names));
1481 1492
1482 // Load receiver into R0. 1493 // Load receiver into R0.
1483 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize, PP); 1494 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
1484 __ LoadObject(R4, arguments_descriptor, PP); 1495 __ LoadObject(R4, arguments_descriptor);
1485 1496
1486 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; 1497 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid;
1487 const intptr_t kNumChecks = ic_data.NumberOfChecks(); 1498 const intptr_t kNumChecks = ic_data.NumberOfChecks();
1488 1499
1489 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); 1500 ASSERT(!ic_data.IsNull() && (kNumChecks > 0));
1490 1501
1491 Label after_smi_test; 1502 Label after_smi_test;
1492 __ tsti(R0, Immediate(kSmiTagMask)); 1503 __ tsti(R0, Immediate(kSmiTagMask));
1493 if (kFirstCheckIsSmi) { 1504 if (kFirstCheckIsSmi) {
1494 // Jump if receiver is not Smi. 1505 // Jump if receiver is not Smi.
(...skipping 25 matching lines...) Expand all
1520 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); 1531 ASSERT(!ic_data.IsNull() && (kNumChecks > 0));
1521 GrowableArray<CidTarget> sorted(kNumChecks); 1532 GrowableArray<CidTarget> sorted(kNumChecks);
1522 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); 1533 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true);
1523 1534
1524 // Value is not Smi, 1535 // Value is not Smi,
1525 const intptr_t kSortedLen = sorted.length(); 1536 const intptr_t kSortedLen = sorted.length();
1526 // If kSortedLen is 0 then only a Smi check was needed; the Smi check above 1537 // If kSortedLen is 0 then only a Smi check was needed; the Smi check above
1527 // will fail if there was only one check and receiver is not Smi. 1538 // will fail if there was only one check and receiver is not Smi.
1528 if (kSortedLen == 0) return; 1539 if (kSortedLen == 0) return;
1529 1540
1530 __ LoadClassId(R2, R0, PP); 1541 __ LoadClassId(R2, R0);
1531 for (intptr_t i = 0; i < kSortedLen; i++) { 1542 for (intptr_t i = 0; i < kSortedLen; i++) {
1532 const bool kIsLastCheck = (i == (kSortedLen - 1)); 1543 const bool kIsLastCheck = (i == (kSortedLen - 1));
1533 ASSERT(sorted[i].cid != kSmiCid); 1544 ASSERT(sorted[i].cid != kSmiCid);
1534 Label next_test; 1545 Label next_test;
1535 __ CompareImmediate(R2, sorted[i].cid, PP); 1546 __ CompareImmediate(R2, sorted[i].cid);
1536 if (kIsLastCheck) { 1547 if (kIsLastCheck) {
1537 __ b(failed, NE); 1548 __ b(failed, NE);
1538 } else { 1549 } else {
1539 __ b(&next_test, NE); 1550 __ b(&next_test, NE);
1540 } 1551 }
1541 // Do not use the code from the function, but let the code be patched so 1552 // Do not use the code from the function, but let the code be patched so
1542 // that we can record the outgoing edges to other code. 1553 // that we can record the outgoing edges to other code.
1543 GenerateDartCall(deopt_id, 1554 GenerateDartCall(deopt_id,
1544 token_index, 1555 token_index,
1545 &StubCode::CallStaticFunctionLabel(), 1556 &StubCode::CallStaticFunctionLabel(),
(...skipping 18 matching lines...) Expand all
1564 MoveOperands* move = moves_[index]; 1575 MoveOperands* move = moves_[index];
1565 const Location source = move->src(); 1576 const Location source = move->src();
1566 const Location destination = move->dest(); 1577 const Location destination = move->dest();
1567 1578
1568 if (source.IsRegister()) { 1579 if (source.IsRegister()) {
1569 if (destination.IsRegister()) { 1580 if (destination.IsRegister()) {
1570 __ mov(destination.reg(), source.reg()); 1581 __ mov(destination.reg(), source.reg());
1571 } else { 1582 } else {
1572 ASSERT(destination.IsStackSlot()); 1583 ASSERT(destination.IsStackSlot());
1573 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1584 const intptr_t dest_offset = destination.ToStackSlotOffset();
1574 __ StoreToOffset(source.reg(), destination.base_reg(), dest_offset, PP); 1585 __ StoreToOffset(source.reg(), destination.base_reg(), dest_offset);
1575 } 1586 }
1576 } else if (source.IsStackSlot()) { 1587 } else if (source.IsStackSlot()) {
1577 if (destination.IsRegister()) { 1588 if (destination.IsRegister()) {
1578 const intptr_t source_offset = source.ToStackSlotOffset(); 1589 const intptr_t source_offset = source.ToStackSlotOffset();
1579 __ LoadFromOffset( 1590 __ LoadFromOffset(
1580 destination.reg(), source.base_reg(), source_offset, PP); 1591 destination.reg(), source.base_reg(), source_offset);
1581 } else { 1592 } else {
1582 ASSERT(destination.IsStackSlot()); 1593 ASSERT(destination.IsStackSlot());
1583 const intptr_t source_offset = source.ToStackSlotOffset(); 1594 const intptr_t source_offset = source.ToStackSlotOffset();
1584 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1595 const intptr_t dest_offset = destination.ToStackSlotOffset();
1585 ScratchRegisterScope tmp(this, kNoRegister); 1596 ScratchRegisterScope tmp(this, kNoRegister);
1586 __ LoadFromOffset(tmp.reg(), source.base_reg(), source_offset, PP); 1597 __ LoadFromOffset(tmp.reg(), source.base_reg(), source_offset);
1587 __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset, PP); 1598 __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset);
1588 } 1599 }
1589 } else if (source.IsFpuRegister()) { 1600 } else if (source.IsFpuRegister()) {
1590 if (destination.IsFpuRegister()) { 1601 if (destination.IsFpuRegister()) {
1591 __ vmov(destination.fpu_reg(), source.fpu_reg()); 1602 __ vmov(destination.fpu_reg(), source.fpu_reg());
1592 } else { 1603 } else {
1593 if (destination.IsDoubleStackSlot()) { 1604 if (destination.IsDoubleStackSlot()) {
1594 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1605 const intptr_t dest_offset = destination.ToStackSlotOffset();
1595 VRegister src = source.fpu_reg(); 1606 VRegister src = source.fpu_reg();
1596 __ StoreDToOffset(src, destination.base_reg(), dest_offset, PP); 1607 __ StoreDToOffset(src, destination.base_reg(), dest_offset);
1597 } else { 1608 } else {
1598 ASSERT(destination.IsQuadStackSlot()); 1609 ASSERT(destination.IsQuadStackSlot());
1599 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1610 const intptr_t dest_offset = destination.ToStackSlotOffset();
1600 __ StoreQToOffset( 1611 __ StoreQToOffset(
1601 source.fpu_reg(), destination.base_reg(), dest_offset, PP); 1612 source.fpu_reg(), destination.base_reg(), dest_offset);
1602 } 1613 }
1603 } 1614 }
1604 } else if (source.IsDoubleStackSlot()) { 1615 } else if (source.IsDoubleStackSlot()) {
1605 if (destination.IsFpuRegister()) { 1616 if (destination.IsFpuRegister()) {
1606 const intptr_t source_offset = source.ToStackSlotOffset(); 1617 const intptr_t source_offset = source.ToStackSlotOffset();
1607 const VRegister dst = destination.fpu_reg(); 1618 const VRegister dst = destination.fpu_reg();
1608 __ LoadDFromOffset(dst, source.base_reg(), source_offset, PP); 1619 __ LoadDFromOffset(dst, source.base_reg(), source_offset);
1609 } else { 1620 } else {
1610 ASSERT(destination.IsDoubleStackSlot()); 1621 ASSERT(destination.IsDoubleStackSlot());
1611 const intptr_t source_offset = source.ToStackSlotOffset(); 1622 const intptr_t source_offset = source.ToStackSlotOffset();
1612 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1623 const intptr_t dest_offset = destination.ToStackSlotOffset();
1613 __ LoadDFromOffset(VTMP, source.base_reg(), source_offset, PP); 1624 __ LoadDFromOffset(VTMP, source.base_reg(), source_offset);
1614 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset, PP); 1625 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset);
1615 } 1626 }
1616 } else if (source.IsQuadStackSlot()) { 1627 } else if (source.IsQuadStackSlot()) {
1617 if (destination.IsFpuRegister()) { 1628 if (destination.IsFpuRegister()) {
1618 const intptr_t source_offset = source.ToStackSlotOffset(); 1629 const intptr_t source_offset = source.ToStackSlotOffset();
1619 __ LoadQFromOffset( 1630 __ LoadQFromOffset(
1620 destination.fpu_reg(), source.base_reg(), source_offset, PP); 1631 destination.fpu_reg(), source.base_reg(), source_offset);
1621 } else { 1632 } else {
1622 ASSERT(destination.IsQuadStackSlot()); 1633 ASSERT(destination.IsQuadStackSlot());
1623 const intptr_t source_offset = source.ToStackSlotOffset(); 1634 const intptr_t source_offset = source.ToStackSlotOffset();
1624 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1635 const intptr_t dest_offset = destination.ToStackSlotOffset();
1625 __ LoadQFromOffset(VTMP, source.base_reg(), source_offset, PP); 1636 __ LoadQFromOffset(VTMP, source.base_reg(), source_offset);
1626 __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset, PP); 1637 __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset);
1627 } 1638 }
1628 } else { 1639 } else {
1629 ASSERT(source.IsConstant()); 1640 ASSERT(source.IsConstant());
1630 const Object& constant = source.constant(); 1641 const Object& constant = source.constant();
1631 if (destination.IsRegister()) { 1642 if (destination.IsRegister()) {
1632 if (constant.IsSmi() && 1643 if (constant.IsSmi() &&
1633 (source.constant_instruction()->representation() == kUnboxedInt32)) { 1644 (source.constant_instruction()->representation() == kUnboxedInt32)) {
1634 __ LoadImmediate(destination.reg(), 1645 __ LoadImmediate(destination.reg(),
1635 static_cast<int32_t>(Smi::Cast(constant).Value()), 1646 static_cast<int32_t>(Smi::Cast(constant).Value()));
1636 PP);
1637 } else { 1647 } else {
1638 __ LoadObject(destination.reg(), constant, PP); 1648 __ LoadObject(destination.reg(), constant);
1639 } 1649 }
1640 } else if (destination.IsFpuRegister()) { 1650 } else if (destination.IsFpuRegister()) {
1641 const VRegister dst = destination.fpu_reg(); 1651 const VRegister dst = destination.fpu_reg();
1642 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { 1652 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) {
1643 __ veor(dst, dst, dst); 1653 __ veor(dst, dst, dst);
1644 } else { 1654 } else {
1645 ScratchRegisterScope tmp(this, kNoRegister); 1655 ScratchRegisterScope tmp(this, kNoRegister);
1646 __ LoadObject(tmp.reg(), constant, PP); 1656 __ LoadObject(tmp.reg(), constant);
1647 __ LoadDFieldFromOffset(dst, tmp.reg(), Double::value_offset(), PP); 1657 __ LoadDFieldFromOffset(dst, tmp.reg(), Double::value_offset());
1648 } 1658 }
1649 } else if (destination.IsDoubleStackSlot()) { 1659 } else if (destination.IsDoubleStackSlot()) {
1650 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { 1660 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) {
1651 __ veor(VTMP, VTMP, VTMP); 1661 __ veor(VTMP, VTMP, VTMP);
1652 } else { 1662 } else {
1653 ScratchRegisterScope tmp(this, kNoRegister); 1663 ScratchRegisterScope tmp(this, kNoRegister);
1654 __ LoadObject(tmp.reg(), constant, PP); 1664 __ LoadObject(tmp.reg(), constant);
1655 __ LoadDFieldFromOffset(VTMP, tmp.reg(), Double::value_offset(), PP); 1665 __ LoadDFieldFromOffset(VTMP, tmp.reg(), Double::value_offset());
1656 } 1666 }
1657 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1667 const intptr_t dest_offset = destination.ToStackSlotOffset();
1658 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset, PP); 1668 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset);
1659 } else { 1669 } else {
1660 ASSERT(destination.IsStackSlot()); 1670 ASSERT(destination.IsStackSlot());
1661 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1671 const intptr_t dest_offset = destination.ToStackSlotOffset();
1662 ScratchRegisterScope tmp(this, kNoRegister); 1672 ScratchRegisterScope tmp(this, kNoRegister);
1663 if (constant.IsSmi() && 1673 if (constant.IsSmi() &&
1664 (source.constant_instruction()->representation() == kUnboxedInt32)) { 1674 (source.constant_instruction()->representation() == kUnboxedInt32)) {
1665 __ LoadImmediate(tmp.reg(), 1675 __ LoadImmediate(tmp.reg(),
1666 static_cast<int32_t>(Smi::Cast(constant).Value()), 1676 static_cast<int32_t>(Smi::Cast(constant).Value()));
1667 PP);
1668 } else { 1677 } else {
1669 __ LoadObject(tmp.reg(), constant, PP); 1678 __ LoadObject(tmp.reg(), constant);
1670 } 1679 }
1671 __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset, PP); 1680 __ StoreToOffset(tmp.reg(), destination.base_reg(), dest_offset);
1672 } 1681 }
1673 } 1682 }
1674 1683
1675 move->Eliminate(); 1684 move->Eliminate();
1676 } 1685 }
1677 1686
1678 1687
1679 void ParallelMoveResolver::EmitSwap(int index) { 1688 void ParallelMoveResolver::EmitSwap(int index) {
1680 MoveOperands* move = moves_[index]; 1689 MoveOperands* move = moves_[index];
1681 const Location source = move->src(); 1690 const Location source = move->src();
(...skipping 30 matching lines...) Expand all
1712 VRegister reg = source.IsFpuRegister() ? source.fpu_reg() 1721 VRegister reg = source.IsFpuRegister() ? source.fpu_reg()
1713 : destination.fpu_reg(); 1722 : destination.fpu_reg();
1714 Register base_reg = source.IsFpuRegister() 1723 Register base_reg = source.IsFpuRegister()
1715 ? destination.base_reg() 1724 ? destination.base_reg()
1716 : source.base_reg(); 1725 : source.base_reg();
1717 const intptr_t slot_offset = source.IsFpuRegister() 1726 const intptr_t slot_offset = source.IsFpuRegister()
1718 ? destination.ToStackSlotOffset() 1727 ? destination.ToStackSlotOffset()
1719 : source.ToStackSlotOffset(); 1728 : source.ToStackSlotOffset();
1720 1729
1721 if (double_width) { 1730 if (double_width) {
1722 __ LoadDFromOffset(VTMP, base_reg, slot_offset, PP); 1731 __ LoadDFromOffset(VTMP, base_reg, slot_offset);
1723 __ StoreDToOffset(reg, base_reg, slot_offset, PP); 1732 __ StoreDToOffset(reg, base_reg, slot_offset);
1724 __ fmovdd(reg, VTMP); 1733 __ fmovdd(reg, VTMP);
1725 } else { 1734 } else {
1726 __ LoadQFromOffset(VTMP, base_reg, slot_offset, PP); 1735 __ LoadQFromOffset(VTMP, base_reg, slot_offset);
1727 __ StoreQToOffset(reg, base_reg, slot_offset, PP); 1736 __ StoreQToOffset(reg, base_reg, slot_offset);
1728 __ vmov(reg, VTMP); 1737 __ vmov(reg, VTMP);
1729 } 1738 }
1730 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { 1739 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1731 const intptr_t source_offset = source.ToStackSlotOffset(); 1740 const intptr_t source_offset = source.ToStackSlotOffset();
1732 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1741 const intptr_t dest_offset = destination.ToStackSlotOffset();
1733 1742
1734 ScratchFpuRegisterScope ensure_scratch(this, kNoFpuRegister); 1743 ScratchFpuRegisterScope ensure_scratch(this, kNoFpuRegister);
1735 VRegister scratch = ensure_scratch.reg(); 1744 VRegister scratch = ensure_scratch.reg();
1736 __ LoadDFromOffset(VTMP, source.base_reg(), source_offset, PP); 1745 __ LoadDFromOffset(VTMP, source.base_reg(), source_offset);
1737 __ LoadDFromOffset(scratch, destination.base_reg(), dest_offset, PP); 1746 __ LoadDFromOffset(scratch, destination.base_reg(), dest_offset);
1738 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset, PP); 1747 __ StoreDToOffset(VTMP, destination.base_reg(), dest_offset);
1739 __ StoreDToOffset(scratch, source.base_reg(), source_offset, PP); 1748 __ StoreDToOffset(scratch, source.base_reg(), source_offset);
1740 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { 1749 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) {
1741 const intptr_t source_offset = source.ToStackSlotOffset(); 1750 const intptr_t source_offset = source.ToStackSlotOffset();
1742 const intptr_t dest_offset = destination.ToStackSlotOffset(); 1751 const intptr_t dest_offset = destination.ToStackSlotOffset();
1743 1752
1744 ScratchFpuRegisterScope ensure_scratch(this, kNoFpuRegister); 1753 ScratchFpuRegisterScope ensure_scratch(this, kNoFpuRegister);
1745 VRegister scratch = ensure_scratch.reg(); 1754 VRegister scratch = ensure_scratch.reg();
1746 __ LoadQFromOffset(VTMP, source.base_reg(), source_offset, PP); 1755 __ LoadQFromOffset(VTMP, source.base_reg(), source_offset);
1747 __ LoadQFromOffset(scratch, destination.base_reg(), dest_offset, PP); 1756 __ LoadQFromOffset(scratch, destination.base_reg(), dest_offset);
1748 __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset, PP); 1757 __ StoreQToOffset(VTMP, destination.base_reg(), dest_offset);
1749 __ StoreQToOffset(scratch, source.base_reg(), source_offset, PP); 1758 __ StoreQToOffset(scratch, source.base_reg(), source_offset);
1750 } else { 1759 } else {
1751 UNREACHABLE(); 1760 UNREACHABLE();
1752 } 1761 }
1753 1762
1754 // The swap of source and destination has executed a move from source to 1763 // The swap of source and destination has executed a move from source to
1755 // destination. 1764 // destination.
1756 move->Eliminate(); 1765 move->Eliminate();
1757 1766
1758 // Any unperformed (including pending) move with a source of either 1767 // Any unperformed (including pending) move with a source of either
1759 // this move's source or destination needs to have their source 1768 // this move's source or destination needs to have their source
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1792 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { 1801 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
1793 UNREACHABLE(); 1802 UNREACHABLE();
1794 } 1803 }
1795 1804
1796 1805
1797 void ParallelMoveResolver::Exchange(Register reg, 1806 void ParallelMoveResolver::Exchange(Register reg,
1798 Register base_reg, 1807 Register base_reg,
1799 intptr_t stack_offset) { 1808 intptr_t stack_offset) {
1800 ScratchRegisterScope tmp(this, reg); 1809 ScratchRegisterScope tmp(this, reg);
1801 __ mov(tmp.reg(), reg); 1810 __ mov(tmp.reg(), reg);
1802 __ LoadFromOffset(reg, base_reg, stack_offset, PP); 1811 __ LoadFromOffset(reg, base_reg, stack_offset);
1803 __ StoreToOffset(tmp.reg(), base_reg, stack_offset, PP); 1812 __ StoreToOffset(tmp.reg(), base_reg, stack_offset);
1804 } 1813 }
1805 1814
1806 1815
1807 void ParallelMoveResolver::Exchange(Register base_reg1, 1816 void ParallelMoveResolver::Exchange(Register base_reg1,
1808 intptr_t stack_offset1, 1817 intptr_t stack_offset1,
1809 Register base_reg2, 1818 Register base_reg2,
1810 intptr_t stack_offset2) { 1819 intptr_t stack_offset2) {
1811 ScratchRegisterScope tmp1(this, kNoRegister); 1820 ScratchRegisterScope tmp1(this, kNoRegister);
1812 ScratchRegisterScope tmp2(this, tmp1.reg()); 1821 ScratchRegisterScope tmp2(this, tmp1.reg());
1813 __ LoadFromOffset(tmp1.reg(), base_reg1, stack_offset1, PP); 1822 __ LoadFromOffset(tmp1.reg(), base_reg1, stack_offset1);
1814 __ LoadFromOffset(tmp2.reg(), base_reg2, stack_offset2, PP); 1823 __ LoadFromOffset(tmp2.reg(), base_reg2, stack_offset2);
1815 __ StoreToOffset(tmp1.reg(), base_reg2, stack_offset2, PP); 1824 __ StoreToOffset(tmp1.reg(), base_reg2, stack_offset2);
1816 __ StoreToOffset(tmp2.reg(), base_reg1, stack_offset1, PP); 1825 __ StoreToOffset(tmp2.reg(), base_reg1, stack_offset1);
1817 } 1826 }
1818 1827
1819 1828
1820 void ParallelMoveResolver::SpillScratch(Register reg) { 1829 void ParallelMoveResolver::SpillScratch(Register reg) {
1821 __ Push(reg); 1830 __ Push(reg);
1822 } 1831 }
1823 1832
1824 1833
1825 void ParallelMoveResolver::RestoreScratch(Register reg) { 1834 void ParallelMoveResolver::RestoreScratch(Register reg) {
1826 __ Pop(reg); 1835 __ Pop(reg);
1827 } 1836 }
1828 1837
1829 1838
1830 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { 1839 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
1831 __ PushDouble(reg); 1840 __ PushDouble(reg);
1832 } 1841 }
1833 1842
1834 1843
1835 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { 1844 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
1836 __ PopDouble(reg); 1845 __ PopDouble(reg);
1837 } 1846 }
1838 1847
1839 1848
1840 #undef __ 1849 #undef __
1841 1850
1842 } // namespace dart 1851 } // namespace dart
1843 1852
1844 #endif // defined TARGET_ARCH_ARM64 1853 #endif // defined TARGET_ARCH_ARM64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698