| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 intptr_t slot_ix = 0; | 88 intptr_t slot_ix = 0; |
| 89 Environment* current = deopt_env_; | 89 Environment* current = deopt_env_; |
| 90 | 90 |
| 91 // Emit all kMaterializeObject instructions describing objects to be | 91 // Emit all kMaterializeObject instructions describing objects to be |
| 92 // materialized on the deoptimization as a prefix to the deoptimization info. | 92 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 93 EmitMaterializations(deopt_env_, builder); | 93 EmitMaterializations(deopt_env_, builder); |
| 94 | 94 |
| 95 // The real frame starts here. | 95 // The real frame starts here. |
| 96 builder->MarkFrameStart(); | 96 builder->MarkFrameStart(); |
| 97 | 97 |
| 98 Zone* zone = compiler->zone(); |
| 99 |
| 98 // Current PP, FP, and PC. | 100 // Current PP, FP, and PC. |
| 99 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 101 builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++); |
| 100 builder->AddPcMarker(Function::Handle(), slot_ix++); | 102 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
| 101 builder->AddCallerFp(slot_ix++); | 103 builder->AddCallerFp(slot_ix++); |
| 102 builder->AddReturnAddress(Function::Handle(current->code().function()), | 104 builder->AddReturnAddress(Function::Handle(zone, current->code().function()), |
| 103 deopt_id(), | 105 deopt_id(), |
| 104 slot_ix++); | 106 slot_ix++); |
| 105 | 107 |
| 106 // Emit all values that are needed for materialization as a part of the | 108 // Emit all values that are needed for materialization as a part of the |
| 107 // expression stack for the bottom-most frame. This guarantees that GC | 109 // expression stack for the bottom-most frame. This guarantees that GC |
| 108 // will be able to find them during materialization. | 110 // will be able to find them during materialization. |
| 109 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 111 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 110 | 112 |
| 111 // For the innermost environment, set outgoing arguments and the locals. | 113 // For the innermost environment, set outgoing arguments and the locals. |
| 112 for (intptr_t i = current->Length() - 1; | 114 for (intptr_t i = current->Length() - 1; |
| 113 i >= current->fixed_parameter_count(); | 115 i >= current->fixed_parameter_count(); |
| 114 i--) { | 116 i--) { |
| 115 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 117 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 116 } | 118 } |
| 117 | 119 |
| 118 Environment* previous = current; | 120 Environment* previous = current; |
| 119 current = current->outer(); | 121 current = current->outer(); |
| 120 while (current != NULL) { | 122 while (current != NULL) { |
| 121 // PP, FP, and PC. | 123 // PP, FP, and PC. |
| 122 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 124 builder->AddPp(Function::Handle( |
| 123 builder->AddPcMarker(Function::Handle(previous->code().function()), | 125 zone, current->code().function()), slot_ix++); |
| 126 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 124 slot_ix++); | 127 slot_ix++); |
| 125 builder->AddCallerFp(slot_ix++); | 128 builder->AddCallerFp(slot_ix++); |
| 126 | 129 |
| 127 // For any outer environment the deopt id is that of the call instruction | 130 // For any outer environment the deopt id is that of the call instruction |
| 128 // which is recorded in the outer environment. | 131 // which is recorded in the outer environment. |
| 129 builder->AddReturnAddress(Function::Handle(current->code().function()), | 132 builder->AddReturnAddress( |
| 130 Isolate::ToDeoptAfter(current->deopt_id()), | 133 Function::Handle(zone, current->code().function()), |
| 131 slot_ix++); | 134 Isolate::ToDeoptAfter(current->deopt_id()), |
| 135 slot_ix++); |
| 132 | 136 |
| 133 // The values of outgoing arguments can be changed from the inlined call so | 137 // The values of outgoing arguments can be changed from the inlined call so |
| 134 // we must read them from the previous environment. | 138 // we must read them from the previous environment. |
| 135 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 139 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 136 builder->AddCopy(previous->ValueAt(i), | 140 builder->AddCopy(previous->ValueAt(i), |
| 137 previous->LocationAt(i), | 141 previous->LocationAt(i), |
| 138 slot_ix++); | 142 slot_ix++); |
| 139 } | 143 } |
| 140 | 144 |
| 141 // Set the locals, note that outgoing arguments are not in the environment. | 145 // Set the locals, note that outgoing arguments are not in the environment. |
| 142 for (intptr_t i = current->Length() - 1; | 146 for (intptr_t i = current->Length() - 1; |
| 143 i >= current->fixed_parameter_count(); | 147 i >= current->fixed_parameter_count(); |
| 144 i--) { | 148 i--) { |
| 145 builder->AddCopy(current->ValueAt(i), | 149 builder->AddCopy(current->ValueAt(i), |
| 146 current->LocationAt(i), | 150 current->LocationAt(i), |
| 147 slot_ix++); | 151 slot_ix++); |
| 148 } | 152 } |
| 149 | 153 |
| 150 // Iterate on the outer environment. | 154 // Iterate on the outer environment. |
| 151 previous = current; | 155 previous = current; |
| 152 current = current->outer(); | 156 current = current->outer(); |
| 153 } | 157 } |
| 154 // The previous pointer is now the outermost environment. | 158 // The previous pointer is now the outermost environment. |
| 155 ASSERT(previous != NULL); | 159 ASSERT(previous != NULL); |
| 156 | 160 |
| 157 // For the outermost environment, set caller PC, caller PP, and caller FP. | 161 // For the outermost environment, set caller PC, caller PP, and caller FP. |
| 158 builder->AddCallerPp(slot_ix++); | 162 builder->AddCallerPp(slot_ix++); |
| 159 // PC marker. | 163 // PC marker. |
| 160 builder->AddPcMarker(Function::Handle(previous->code().function()), | 164 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 161 slot_ix++); | 165 slot_ix++); |
| 162 builder->AddCallerFp(slot_ix++); | 166 builder->AddCallerFp(slot_ix++); |
| 163 builder->AddCallerPc(slot_ix++); | 167 builder->AddCallerPc(slot_ix++); |
| 164 | 168 |
| 165 // For the outermost environment, set the incoming arguments. | 169 // For the outermost environment, set the incoming arguments. |
| 166 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 170 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 167 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 171 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
| 168 } | 172 } |
| 169 | 173 |
| 170 return builder->CreateDeoptInfo(deopt_table); | 174 return builder->CreateDeoptInfo(deopt_table); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 217 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 214 TypeTestStubKind test_kind, | 218 TypeTestStubKind test_kind, |
| 215 Register instance_reg, | 219 Register instance_reg, |
| 216 Register type_arguments_reg, | 220 Register type_arguments_reg, |
| 217 Register temp_reg, | 221 Register temp_reg, |
| 218 Label* is_instance_lbl, | 222 Label* is_instance_lbl, |
| 219 Label* is_not_instance_lbl) { | 223 Label* is_not_instance_lbl) { |
| 220 ASSERT(instance_reg == R0); | 224 ASSERT(instance_reg == R0); |
| 221 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 225 ASSERT(temp_reg == kNoRegister); // Unused on ARM. |
| 222 const SubtypeTestCache& type_test_cache = | 226 const SubtypeTestCache& type_test_cache = |
| 223 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 227 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 224 __ LoadUniqueObject(R2, type_test_cache); | 228 __ LoadUniqueObject(R2, type_test_cache); |
| 225 if (test_kind == kTestTypeOneArg) { | 229 if (test_kind == kTestTypeOneArg) { |
| 226 ASSERT(type_arguments_reg == kNoRegister); | 230 ASSERT(type_arguments_reg == kNoRegister); |
| 227 __ LoadObject(R1, Object::null_object()); | 231 __ LoadObject(R1, Object::null_object()); |
| 228 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 232 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 229 } else if (test_kind == kTestTypeTwoArgs) { | 233 } else if (test_kind == kTestTypeTwoArgs) { |
| 230 ASSERT(type_arguments_reg == kNoRegister); | 234 ASSERT(type_arguments_reg == kNoRegister); |
| 231 __ LoadObject(R1, Object::null_object()); | 235 __ LoadObject(R1, Object::null_object()); |
| 232 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); | 236 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); |
| 233 } else if (test_kind == kTestTypeThreeArgs) { | 237 } else if (test_kind == kTestTypeThreeArgs) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 248 // R0: instance being type checked (preserved). | 252 // R0: instance being type checked (preserved). |
| 249 // Clobbers R2. | 253 // Clobbers R2. |
| 250 RawSubtypeTestCache* | 254 RawSubtypeTestCache* |
| 251 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 255 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 252 intptr_t token_pos, | 256 intptr_t token_pos, |
| 253 const AbstractType& type, | 257 const AbstractType& type, |
| 254 Label* is_instance_lbl, | 258 Label* is_instance_lbl, |
| 255 Label* is_not_instance_lbl) { | 259 Label* is_not_instance_lbl) { |
| 256 __ Comment("InstantiatedTypeWithArgumentsTest"); | 260 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 257 ASSERT(type.IsInstantiated()); | 261 ASSERT(type.IsInstantiated()); |
| 258 const Class& type_class = Class::ZoneHandle(type.type_class()); | 262 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 259 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); | 263 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); |
| 260 const Register kInstanceReg = R0; | 264 const Register kInstanceReg = R0; |
| 261 Error& malformed_error = Error::Handle(); | 265 Error& malformed_error = Error::Handle(zone()); |
| 262 const Type& int_type = Type::Handle(Type::IntType()); | 266 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
| 263 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); | 267 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); |
| 264 // Malformed type should have been handled at graph construction time. | 268 // Malformed type should have been handled at graph construction time. |
| 265 ASSERT(smi_is_ok || malformed_error.IsNull()); | 269 ASSERT(smi_is_ok || malformed_error.IsNull()); |
| 266 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); | 270 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); |
| 267 if (smi_is_ok) { | 271 if (smi_is_ok) { |
| 268 __ b(is_instance_lbl, EQ); | 272 __ b(is_instance_lbl, EQ); |
| 269 } else { | 273 } else { |
| 270 __ b(is_not_instance_lbl, EQ); | 274 __ b(is_not_instance_lbl, EQ); |
| 271 } | 275 } |
| 272 const intptr_t num_type_args = type_class.NumTypeArguments(); | 276 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 273 const intptr_t num_type_params = type_class.NumTypeParameters(); | 277 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 274 const intptr_t from_index = num_type_args - num_type_params; | 278 const intptr_t from_index = num_type_args - num_type_params; |
| 275 const TypeArguments& type_arguments = | 279 const TypeArguments& type_arguments = |
| 276 TypeArguments::ZoneHandle(type.arguments()); | 280 TypeArguments::ZoneHandle(zone(), type.arguments()); |
| 277 const bool is_raw_type = type_arguments.IsNull() || | 281 const bool is_raw_type = type_arguments.IsNull() || |
| 278 type_arguments.IsRaw(from_index, num_type_params); | 282 type_arguments.IsRaw(from_index, num_type_params); |
| 279 // Signature class is an instantiated parameterized type. | 283 // Signature class is an instantiated parameterized type. |
| 280 if (!type_class.IsSignatureClass()) { | 284 if (!type_class.IsSignatureClass()) { |
| 281 if (is_raw_type) { | 285 if (is_raw_type) { |
| 282 const Register kClassIdReg = R2; | 286 const Register kClassIdReg = R2; |
| 283 // dynamic type argument, check only classes. | 287 // dynamic type argument, check only classes. |
| 284 __ LoadClassId(kClassIdReg, kInstanceReg); | 288 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 285 __ CompareImmediate(kClassIdReg, type_class.id()); | 289 __ CompareImmediate(kClassIdReg, type_class.id()); |
| 286 __ b(is_instance_lbl, EQ); | 290 __ b(is_instance_lbl, EQ); |
| 287 // List is a very common case. | 291 // List is a very common case. |
| 288 if (IsListClass(type_class)) { | 292 if (IsListClass(type_class)) { |
| 289 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 293 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 290 } | 294 } |
| 291 return GenerateSubtype1TestCacheLookup( | 295 return GenerateSubtype1TestCacheLookup( |
| 292 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 296 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 293 } | 297 } |
| 294 // If one type argument only, check if type argument is Object or dynamic. | 298 // If one type argument only, check if type argument is Object or dynamic. |
| 295 if (type_arguments.Length() == 1) { | 299 if (type_arguments.Length() == 1) { |
| 296 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 300 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 297 type_arguments.TypeAt(0)); | 301 zone(), type_arguments.TypeAt(0)); |
| 298 ASSERT(!tp_argument.IsMalformed()); | 302 ASSERT(!tp_argument.IsMalformed()); |
| 299 if (tp_argument.IsType()) { | 303 if (tp_argument.IsType()) { |
| 300 ASSERT(tp_argument.HasResolvedTypeClass()); | 304 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 301 // Check if type argument is dynamic or Object. | 305 // Check if type argument is dynamic or Object. |
| 302 const Type& object_type = Type::Handle(Type::ObjectType()); | 306 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 303 if (object_type.IsSubtypeOf(tp_argument, NULL)) { | 307 if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
| 304 // Instance class test only necessary. | 308 // Instance class test only necessary. |
| 305 return GenerateSubtype1TestCacheLookup( | 309 return GenerateSubtype1TestCacheLookup( |
| 306 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 310 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 307 } | 311 } |
| 308 } | 312 } |
| 309 } | 313 } |
| 310 } | 314 } |
| 311 // Regular subtype test cache involving instance's type arguments. | 315 // Regular subtype test cache involving instance's type arguments. |
| 312 const Register kTypeArgumentsReg = kNoRegister; | 316 const Register kTypeArgumentsReg = kNoRegister; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 338 // R0: instance being type checked (preserved). | 342 // R0: instance being type checked (preserved). |
| 339 // Clobbers R2, R3. | 343 // Clobbers R2, R3. |
| 340 // Returns true if there is a fallthrough. | 344 // Returns true if there is a fallthrough. |
| 341 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 345 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 342 intptr_t token_pos, | 346 intptr_t token_pos, |
| 343 const AbstractType& type, | 347 const AbstractType& type, |
| 344 Label* is_instance_lbl, | 348 Label* is_instance_lbl, |
| 345 Label* is_not_instance_lbl) { | 349 Label* is_not_instance_lbl) { |
| 346 __ Comment("InstantiatedTypeNoArgumentsTest"); | 350 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 347 ASSERT(type.IsInstantiated()); | 351 ASSERT(type.IsInstantiated()); |
| 348 const Class& type_class = Class::Handle(type.type_class()); | 352 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| 349 ASSERT(type_class.NumTypeArguments() == 0); | 353 ASSERT(type_class.NumTypeArguments() == 0); |
| 350 | 354 |
| 351 const Register kInstanceReg = R0; | 355 const Register kInstanceReg = R0; |
| 352 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); | 356 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); |
| 353 // If instance is Smi, check directly. | 357 // If instance is Smi, check directly. |
| 354 const Class& smi_class = Class::Handle(Smi::Class()); | 358 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
| 355 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 359 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), |
| 356 type_class, | 360 type_class, |
| 357 TypeArguments::Handle(), | 361 TypeArguments::Handle(zone()), |
| 358 NULL)) { | 362 NULL)) { |
| 359 __ b(is_instance_lbl, EQ); | 363 __ b(is_instance_lbl, EQ); |
| 360 } else { | 364 } else { |
| 361 __ b(is_not_instance_lbl, EQ); | 365 __ b(is_not_instance_lbl, EQ); |
| 362 } | 366 } |
| 363 // Compare if the classes are equal. | 367 // Compare if the classes are equal. |
| 364 const Register kClassIdReg = R2; | 368 const Register kClassIdReg = R2; |
| 365 __ LoadClassId(kClassIdReg, kInstanceReg); | 369 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 366 __ CompareImmediate(kClassIdReg, type_class.id()); | 370 __ CompareImmediate(kClassIdReg, type_class.id()); |
| 367 __ b(is_instance_lbl, EQ); | 371 __ b(is_instance_lbl, EQ); |
| 368 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 372 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 369 // interfaces. | 373 // interfaces. |
| 370 // Bool interface can be implemented only by core class Bool. | 374 // Bool interface can be implemented only by core class Bool. |
| 371 if (type.IsBoolType()) { | 375 if (type.IsBoolType()) { |
| 372 __ CompareImmediate(kClassIdReg, kBoolCid); | 376 __ CompareImmediate(kClassIdReg, kBoolCid); |
| 373 __ b(is_instance_lbl, EQ); | 377 __ b(is_instance_lbl, EQ); |
| 374 __ b(is_not_instance_lbl); | 378 __ b(is_not_instance_lbl); |
| 375 return false; | 379 return false; |
| 376 } | 380 } |
| 377 if (type.IsFunctionType()) { | 381 if (type.IsFunctionType()) { |
| 378 // Check if instance is a closure. | 382 // Check if instance is a closure. |
| 379 __ LoadClassById(R3, kClassIdReg); | 383 __ LoadClassById(R3, kClassIdReg); |
| 380 __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset()); | 384 __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset()); |
| 381 __ CompareObject(R3, Object::null_object()); | 385 __ CompareObject(R3, Object::null_object()); |
| 382 __ b(is_instance_lbl, NE); | 386 __ b(is_instance_lbl, NE); |
| 383 } | 387 } |
| 384 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 388 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 385 // Note that instance is not Smi (checked above). | 389 // Note that instance is not Smi (checked above). |
| 386 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 390 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { |
| 387 GenerateNumberTypeCheck( | 391 GenerateNumberTypeCheck( |
| 388 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 392 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 389 return false; | 393 return false; |
| 390 } | 394 } |
| 391 if (type.IsStringType()) { | 395 if (type.IsStringType()) { |
| 392 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 396 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 393 return false; | 397 return false; |
| 394 } | 398 } |
| 395 // Otherwise fallthrough. | 399 // Otherwise fallthrough. |
| 396 return true; | 400 return true; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 // Load instantiator (or null) and instantiator type arguments on stack. | 449 // Load instantiator (or null) and instantiator type arguments on stack. |
| 446 __ ldr(R1, Address(SP)); // Get instantiator type arguments. | 450 __ ldr(R1, Address(SP)); // Get instantiator type arguments. |
| 447 // R1: instantiator type arguments. | 451 // R1: instantiator type arguments. |
| 448 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 452 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 449 __ CompareObject(R1, Object::null_object()); | 453 __ CompareObject(R1, Object::null_object()); |
| 450 __ b(is_instance_lbl, EQ); | 454 __ b(is_instance_lbl, EQ); |
| 451 __ LoadFieldFromOffset( | 455 __ LoadFieldFromOffset( |
| 452 R2, R1, TypeArguments::type_at_offset(type_param.index())); | 456 R2, R1, TypeArguments::type_at_offset(type_param.index())); |
| 453 // R2: concrete type of type. | 457 // R2: concrete type of type. |
| 454 // Check if type argument is dynamic. | 458 // Check if type argument is dynamic. |
| 455 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType())); | 459 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::DynamicType())); |
| 456 __ b(is_instance_lbl, EQ); | 460 __ b(is_instance_lbl, EQ); |
| 457 __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType())); | 461 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); |
| 458 __ b(is_instance_lbl, EQ); | 462 __ b(is_instance_lbl, EQ); |
| 459 | 463 |
| 460 // For Smi check quickly against int and num interfaces. | 464 // For Smi check quickly against int and num interfaces. |
| 461 Label not_smi; | 465 Label not_smi; |
| 462 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? | 466 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? |
| 463 __ b(¬_smi, NE); | 467 __ b(¬_smi, NE); |
| 464 __ CompareObject(R2, Type::ZoneHandle(Type::IntType())); | 468 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); |
| 465 __ b(is_instance_lbl, EQ); | 469 __ b(is_instance_lbl, EQ); |
| 466 __ CompareObject(R2, Type::ZoneHandle(Type::Number())); | 470 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); |
| 467 __ b(is_instance_lbl, EQ); | 471 __ b(is_instance_lbl, EQ); |
| 468 // Smi must be handled in runtime. | 472 // Smi must be handled in runtime. |
| 469 Label fall_through; | 473 Label fall_through; |
| 470 __ b(&fall_through); | 474 __ b(&fall_through); |
| 471 | 475 |
| 472 __ Bind(¬_smi); | 476 __ Bind(¬_smi); |
| 473 // R1: instantiator type arguments. | 477 // R1: instantiator type arguments. |
| 474 // R0: instance. | 478 // R0: instance. |
| 475 const Register kInstanceReg = R0; | 479 const Register kInstanceReg = R0; |
| 476 const Register kTypeArgumentsReg = R1; | 480 const Register kTypeArgumentsReg = R1; |
| 477 const Register kTempReg = kNoRegister; | 481 const Register kTempReg = kNoRegister; |
| 478 const SubtypeTestCache& type_test_cache = | 482 const SubtypeTestCache& type_test_cache = |
| 479 SubtypeTestCache::ZoneHandle( | 483 SubtypeTestCache::ZoneHandle(zone(), |
| 480 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 484 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 481 kInstanceReg, | 485 kInstanceReg, |
| 482 kTypeArgumentsReg, | 486 kTypeArgumentsReg, |
| 483 kTempReg, | 487 kTempReg, |
| 484 is_instance_lbl, | 488 is_instance_lbl, |
| 485 is_not_instance_lbl)); | 489 is_not_instance_lbl)); |
| 486 __ Bind(&fall_through); | 490 __ Bind(&fall_through); |
| 487 return type_test_cache.raw(); | 491 return type_test_cache.raw(); |
| 488 } | 492 } |
| 489 if (type.IsType()) { | 493 if (type.IsType()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 520 const AbstractType& type, | 524 const AbstractType& type, |
| 521 Label* is_instance_lbl, | 525 Label* is_instance_lbl, |
| 522 Label* is_not_instance_lbl) { | 526 Label* is_not_instance_lbl) { |
| 523 __ Comment("InlineInstanceof"); | 527 __ Comment("InlineInstanceof"); |
| 524 if (type.IsVoidType()) { | 528 if (type.IsVoidType()) { |
| 525 // A non-null value is returned from a void function, which will result in a | 529 // A non-null value is returned from a void function, which will result in a |
| 526 // type error. A null value is handled prior to executing this inline code. | 530 // type error. A null value is handled prior to executing this inline code. |
| 527 return SubtypeTestCache::null(); | 531 return SubtypeTestCache::null(); |
| 528 } | 532 } |
| 529 if (type.IsInstantiated()) { | 533 if (type.IsInstantiated()) { |
| 530 const Class& type_class = Class::ZoneHandle(type.type_class()); | 534 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 531 // A class equality check is only applicable with a dst type of a | 535 // A class equality check is only applicable with a dst type of a |
| 532 // non-parameterized class, non-signature class, or with a raw dst type of | 536 // non-parameterized class, non-signature class, or with a raw dst type of |
| 533 // a parameterized class. | 537 // a parameterized class. |
| 534 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { | 538 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { |
| 535 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 539 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, |
| 536 type, | 540 type, |
| 537 is_instance_lbl, | 541 is_instance_lbl, |
| 538 is_not_instance_lbl); | 542 is_not_instance_lbl); |
| 539 // Fall through to runtime call. | 543 // Fall through to runtime call. |
| 540 } | 544 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 // return false here if the instance is null (and if the type is | 594 // return false here if the instance is null (and if the type is |
| 591 // instantiated). | 595 // instantiated). |
| 592 // We can only inline this null check if the type is instantiated at compile | 596 // We can only inline this null check if the type is instantiated at compile |
| 593 // time, since an uninstantiated type at compile time could be Object or | 597 // time, since an uninstantiated type at compile time could be Object or |
| 594 // dynamic at run time. | 598 // dynamic at run time. |
| 595 __ CompareObject(R0, Object::null_object()); | 599 __ CompareObject(R0, Object::null_object()); |
| 596 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 600 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
| 597 } | 601 } |
| 598 | 602 |
| 599 // Generate inline instanceof test. | 603 // Generate inline instanceof test. |
| 600 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 604 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 601 test_cache = GenerateInlineInstanceof(token_pos, type, | 605 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 602 &is_instance, &is_not_instance); | 606 &is_instance, &is_not_instance); |
| 603 | 607 |
| 604 // test_cache is null if there is no fall-through. | 608 // test_cache is null if there is no fall-through. |
| 605 Label done; | 609 Label done; |
| 606 if (!test_cache.IsNull()) { | 610 if (!test_cache.IsNull()) { |
| 607 // Generate runtime call. | 611 // Generate runtime call. |
| 608 // Load instantiator (R2) and its type arguments (R1). | 612 // Load instantiator (R2) and its type arguments (R1). |
| 609 __ ldr(R1, Address(SP, 0 * kWordSize)); | 613 __ ldr(R1, Address(SP, 0 * kWordSize)); |
| 610 __ ldr(R2, Address(SP, 1 * kWordSize)); | 614 __ ldr(R2, Address(SP, 1 * kWordSize)); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 __ brk(0); | 693 __ brk(0); |
| 690 | 694 |
| 691 __ Bind(&is_assignable); // For a null object. | 695 __ Bind(&is_assignable); // For a null object. |
| 692 // Restore instantiator (R2) and its type arguments (R1). | 696 // Restore instantiator (R2) and its type arguments (R1). |
| 693 __ Pop(R1); | 697 __ Pop(R1); |
| 694 __ Pop(R2); | 698 __ Pop(R2); |
| 695 return; | 699 return; |
| 696 } | 700 } |
| 697 | 701 |
| 698 // Generate inline type check, linking to runtime call if not assignable. | 702 // Generate inline type check, linking to runtime call if not assignable. |
| 699 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 703 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 700 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 704 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 701 &is_assignable, &runtime_call); | 705 &is_assignable, &runtime_call); |
| 702 | 706 |
| 703 __ Bind(&runtime_call); | 707 __ Bind(&runtime_call); |
| 704 // Load instantiator (R2) and its type arguments (R1). | 708 // Load instantiator (R2) and its type arguments (R1). |
| 705 __ ldr(R1, Address(SP)); | 709 __ ldr(R1, Address(SP)); |
| 706 __ ldr(R2, Address(SP, 1 * kWordSize)); | 710 __ ldr(R2, Address(SP, 1 * kWordSize)); |
| 707 __ PushObject(Object::null_object()); // Make room for the result. | 711 __ PushObject(Object::null_object()); // Make room for the result. |
| 708 __ Push(R0); // Push the source object. | 712 __ Push(R0); // Push the source object. |
| 709 __ PushObject(dst_type); // Push the type of the destination. | 713 __ PushObject(dst_type); // Push the type of the destination. |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 // Point to next named entry. | 855 // Point to next named entry. |
| 852 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); | 856 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); |
| 853 // Negate and untag R5 so we can use in scaled address mode. | 857 // Negate and untag R5 so we can use in scaled address mode. |
| 854 __ subs(R5, ZR, Operand(R5, ASR, 1)); | 858 __ subs(R5, ZR, Operand(R5, ASR, 1)); |
| 855 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged. | 859 Address argument_addr(R7, R5, UXTX, Address::Scaled); // R5 is untagged. |
| 856 __ ldr(R5, argument_addr); | 860 __ ldr(R5, argument_addr); |
| 857 __ b(&assign_optional_parameter); | 861 __ b(&assign_optional_parameter); |
| 858 __ Bind(&load_default_value); | 862 __ Bind(&load_default_value); |
| 859 // Load R5 with default argument. | 863 // Load R5 with default argument. |
| 860 const Object& value = Object::ZoneHandle( | 864 const Object& value = Object::ZoneHandle( |
| 861 parsed_function().default_parameter_values().At( | 865 zone(), parsed_function().default_parameter_values().At( |
| 862 param_pos - num_fixed_params)); | 866 param_pos - num_fixed_params)); |
| 863 __ LoadObject(R5, value); | 867 __ LoadObject(R5, value); |
| 864 __ Bind(&assign_optional_parameter); | 868 __ Bind(&assign_optional_parameter); |
| 865 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. | 869 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 866 // We do not use the final allocation index of the variable here, i.e. | 870 // We do not use the final allocation index of the variable here, i.e. |
| 867 // scope->VariableAt(i)->index(), because captured variables still need | 871 // scope->VariableAt(i)->index(), because captured variables still need |
| 868 // to be copied to the context that is not yet allocated. | 872 // to be copied to the context that is not yet allocated. |
| 869 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 873 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 870 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); | 874 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); |
| 871 } | 875 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 886 for (int i = 0; i < num_opt_pos_params; i++) { | 890 for (int i = 0; i < num_opt_pos_params; i++) { |
| 887 Label next_parameter; | 891 Label next_parameter; |
| 888 // Handle this optional positional parameter only if k or fewer positional | 892 // Handle this optional positional parameter only if k or fewer positional |
| 889 // arguments have been passed, where k is param_pos, the position of this | 893 // arguments have been passed, where k is param_pos, the position of this |
| 890 // optional parameter in the formal parameter list. | 894 // optional parameter in the formal parameter list. |
| 891 const int param_pos = num_fixed_params + i; | 895 const int param_pos = num_fixed_params + i; |
| 892 __ CompareImmediate(R8, param_pos); | 896 __ CompareImmediate(R8, param_pos); |
| 893 __ b(&next_parameter, GT); | 897 __ b(&next_parameter, GT); |
| 894 // Load R5 with default argument. | 898 // Load R5 with default argument. |
| 895 const Object& value = Object::ZoneHandle( | 899 const Object& value = Object::ZoneHandle( |
| 896 parsed_function().default_parameter_values().At(i)); | 900 zone(), parsed_function().default_parameter_values().At(i)); |
| 897 __ LoadObject(R5, value); | 901 __ LoadObject(R5, value); |
| 898 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. | 902 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 899 // We do not use the final allocation index of the variable here, i.e. | 903 // We do not use the final allocation index of the variable here, i.e. |
| 900 // scope->VariableAt(i)->index(), because captured variables still need | 904 // scope->VariableAt(i)->index(), because captured variables still need |
| 901 // to be copied to the context that is not yet allocated. | 905 // to be copied to the context that is not yet allocated. |
| 902 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 906 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 903 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); | 907 __ StoreToOffset(R5, FP, computed_param_pos * kWordSize); |
| 904 __ Bind(&next_parameter); | 908 __ Bind(&next_parameter); |
| 905 } | 909 } |
| 906 if (check_correct_named_args) { | 910 if (check_correct_named_args) { |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 } | 1198 } |
| 1195 | 1199 |
| 1196 | 1200 |
| 1197 void FlowGraphCompiler::EmitEdgeCounter() { | 1201 void FlowGraphCompiler::EmitEdgeCounter() { |
| 1198 // We do not check for overflow when incrementing the edge counter. The | 1202 // We do not check for overflow when incrementing the edge counter. The |
| 1199 // function should normally be optimized long before the counter can | 1203 // function should normally be optimized long before the counter can |
| 1200 // overflow; and though we do not reset the counters when we optimize or | 1204 // overflow; and though we do not reset the counters when we optimize or |
| 1201 // deoptimize, there is a bound on the number of | 1205 // deoptimize, there is a bound on the number of |
| 1202 // optimization/deoptimization cycles we will attempt. | 1206 // optimization/deoptimization cycles we will attempt. |
| 1203 ASSERT(assembler_->constant_pool_allowed()); | 1207 ASSERT(assembler_->constant_pool_allowed()); |
| 1204 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1208 const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld)); |
| 1205 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1209 counter.SetAt(0, Smi::Handle(zone(), Smi::New(0))); |
| 1206 __ Comment("Edge counter"); | 1210 __ Comment("Edge counter"); |
| 1207 __ LoadUniqueObject(R0, counter); | 1211 __ LoadUniqueObject(R0, counter); |
| 1208 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0)); | 1212 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0)); |
| 1209 __ add(TMP, TMP, Operand(Smi::RawValue(1))); | 1213 __ add(TMP, TMP, Operand(Smi::RawValue(1))); |
| 1210 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0)); | 1214 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0)); |
| 1211 } | 1215 } |
| 1212 | 1216 |
| 1213 | 1217 |
| 1214 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1218 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1215 ExternalLabel* target_label, | 1219 ExternalLabel* target_label, |
| 1216 const ICData& ic_data, | 1220 const ICData& ic_data, |
| 1217 intptr_t argument_count, | 1221 intptr_t argument_count, |
| 1218 intptr_t deopt_id, | 1222 intptr_t deopt_id, |
| 1219 intptr_t token_pos, | 1223 intptr_t token_pos, |
| 1220 LocationSummary* locs) { | 1224 LocationSummary* locs) { |
| 1221 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1225 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1222 // Each ICData propagated from unoptimized to optimized code contains the | 1226 // Each ICData propagated from unoptimized to optimized code contains the |
| 1223 // function that corresponds to the Dart function of that IC call. Due | 1227 // function that corresponds to the Dart function of that IC call. Due |
| 1224 // to inlining in optimized code, that function may not correspond to the | 1228 // to inlining in optimized code, that function may not correspond to the |
| 1225 // top-level function (parsed_function().function()) which could be | 1229 // top-level function (parsed_function().function()) which could be |
| 1226 // reoptimized and which counter needs to be incremented. | 1230 // reoptimized and which counter needs to be incremented. |
| 1227 // Pass the function explicitly, it is used in IC stub. | 1231 // Pass the function explicitly, it is used in IC stub. |
| 1228 | 1232 |
| 1229 __ LoadObject(R6, parsed_function().function()); | 1233 __ LoadObject(R6, parsed_function().function()); |
| 1230 __ LoadUniqueObject(R5, ic_data); | 1234 __ LoadUniqueObject(R5, ic_data); |
| 1231 GenerateDartCall(deopt_id, | 1235 GenerateDartCall(deopt_id, |
| 1232 token_pos, | 1236 token_pos, |
| 1233 target_label, | 1237 target_label, |
| 1234 RawPcDescriptors::kIcCall, | 1238 RawPcDescriptors::kIcCall, |
| 1235 locs); | 1239 locs); |
| 1236 __ Drop(argument_count); | 1240 __ Drop(argument_count); |
| 1237 } | 1241 } |
| 1238 | 1242 |
| 1239 | 1243 |
| 1240 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1244 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 1241 const ICData& ic_data, | 1245 const ICData& ic_data, |
| 1242 intptr_t argument_count, | 1246 intptr_t argument_count, |
| 1243 intptr_t deopt_id, | 1247 intptr_t deopt_id, |
| 1244 intptr_t token_pos, | 1248 intptr_t token_pos, |
| 1245 LocationSummary* locs) { | 1249 LocationSummary* locs) { |
| 1246 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1250 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1247 __ LoadUniqueObject(R5, ic_data); | 1251 __ LoadUniqueObject(R5, ic_data); |
| 1248 GenerateDartCall(deopt_id, | 1252 GenerateDartCall(deopt_id, |
| 1249 token_pos, | 1253 token_pos, |
| 1250 target_label, | 1254 target_label, |
| 1251 RawPcDescriptors::kIcCall, | 1255 RawPcDescriptors::kIcCall, |
| 1252 locs); | 1256 locs); |
| 1253 __ Drop(argument_count); | 1257 __ Drop(argument_count); |
| 1254 } | 1258 } |
| 1255 | 1259 |
| 1256 | 1260 |
| 1257 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1261 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1258 const ICData& ic_data, | 1262 const ICData& ic_data, |
| 1259 intptr_t argument_count, | 1263 intptr_t argument_count, |
| 1260 intptr_t deopt_id, | 1264 intptr_t deopt_id, |
| 1261 intptr_t token_pos, | 1265 intptr_t token_pos, |
| 1262 LocationSummary* locs) { | 1266 LocationSummary* locs) { |
| 1263 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); | 1267 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); |
| 1264 const String& name = String::Handle(ic_data.target_name()); | 1268 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1265 const Array& arguments_descriptor = | 1269 const Array& arguments_descriptor = |
| 1266 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1270 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1267 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1271 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1268 const MegamorphicCache& cache = | 1272 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1269 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1273 zone(), table->Lookup(name, arguments_descriptor)); |
| 1270 const Register receiverR = R0; | 1274 const Register receiverR = R0; |
| 1271 const Register cacheR = R1; | 1275 const Register cacheR = R1; |
| 1272 const Register targetR = R1; | 1276 const Register targetR = R1; |
| 1273 __ LoadFromOffset(receiverR, SP, (argument_count - 1) * kWordSize); | 1277 __ LoadFromOffset(receiverR, SP, (argument_count - 1) * kWordSize); |
| 1274 __ LoadObject(cacheR, cache); | 1278 __ LoadObject(cacheR, cache); |
| 1275 | 1279 |
| 1276 if (FLAG_use_megamorphic_stub) { | 1280 if (FLAG_use_megamorphic_stub) { |
| 1277 __ BranchLink(&StubCode::MegamorphicLookupLabel()); | 1281 __ BranchLink(&StubCode::MegamorphicLookupLabel()); |
| 1278 } else { | 1282 } else { |
| 1279 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); | 1283 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1472 const Array& argument_names, | 1476 const Array& argument_names, |
| 1473 Label* failed, | 1477 Label* failed, |
| 1474 Label* match_found, | 1478 Label* match_found, |
| 1475 intptr_t deopt_id, | 1479 intptr_t deopt_id, |
| 1476 intptr_t token_index, | 1480 intptr_t token_index, |
| 1477 LocationSummary* locs) { | 1481 LocationSummary* locs) { |
| 1478 ASSERT(is_optimizing()); | 1482 ASSERT(is_optimizing()); |
| 1479 | 1483 |
| 1480 __ Comment("EmitTestAndCall"); | 1484 __ Comment("EmitTestAndCall"); |
| 1481 const Array& arguments_descriptor = | 1485 const Array& arguments_descriptor = |
| 1482 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1486 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
| 1483 argument_names)); | 1487 argument_names)); |
| 1484 | 1488 |
| 1485 // Load receiver into R0. | 1489 // Load receiver into R0. |
| 1486 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1490 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); |
| 1487 __ LoadObject(R4, arguments_descriptor); | 1491 __ LoadObject(R4, arguments_descriptor); |
| 1488 | 1492 |
| 1489 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1493 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
| 1490 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1494 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
| 1491 | 1495 |
| 1492 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1496 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
| 1493 | 1497 |
| 1494 Label after_smi_test; | 1498 Label after_smi_test; |
| 1495 __ tsti(R0, Immediate(kSmiTagMask)); | 1499 __ tsti(R0, Immediate(kSmiTagMask)); |
| 1496 if (kFirstCheckIsSmi) { | 1500 if (kFirstCheckIsSmi) { |
| 1497 // Jump if receiver is not Smi. | 1501 // Jump if receiver is not Smi. |
| 1498 if (kNumChecks == 1) { | 1502 if (kNumChecks == 1) { |
| 1499 __ b(failed, NE); | 1503 __ b(failed, NE); |
| 1500 } else { | 1504 } else { |
| 1501 __ b(&after_smi_test, NE); | 1505 __ b(&after_smi_test, NE); |
| 1502 } | 1506 } |
| 1503 // Do not use the code from the function, but let the code be patched so | 1507 // Do not use the code from the function, but let the code be patched so |
| 1504 // that we can record the outgoing edges to other code. | 1508 // that we can record the outgoing edges to other code. |
| 1505 GenerateDartCall(deopt_id, | 1509 GenerateDartCall(deopt_id, |
| 1506 token_index, | 1510 token_index, |
| 1507 &StubCode::CallStaticFunctionLabel(), | 1511 &StubCode::CallStaticFunctionLabel(), |
| 1508 RawPcDescriptors::kOther, | 1512 RawPcDescriptors::kOther, |
| 1509 locs); | 1513 locs); |
| 1510 const Function& function = Function::Handle(ic_data.GetTargetAt(0)); | 1514 const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0)); |
| 1511 AddStaticCallTarget(function); | 1515 AddStaticCallTarget(function); |
| 1512 __ Drop(argument_count); | 1516 __ Drop(argument_count); |
| 1513 if (kNumChecks > 1) { | 1517 if (kNumChecks > 1) { |
| 1514 __ b(match_found); | 1518 __ b(match_found); |
| 1515 } | 1519 } |
| 1516 } else { | 1520 } else { |
| 1517 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1521 // Receiver is Smi, but Smi is not a valid class therefore fail. |
| 1518 // (Smi class must be first in the list). | 1522 // (Smi class must be first in the list). |
| 1519 __ b(failed, EQ); | 1523 __ b(failed, EQ); |
| 1520 } | 1524 } |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1836 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1840 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1837 __ PopDouble(reg); | 1841 __ PopDouble(reg); |
| 1838 } | 1842 } |
| 1839 | 1843 |
| 1840 | 1844 |
| 1841 #undef __ | 1845 #undef __ |
| 1842 | 1846 |
| 1843 } // namespace dart | 1847 } // namespace dart |
| 1844 | 1848 |
| 1845 #endif // defined TARGET_ARCH_ARM64 | 1849 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |