| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 intptr_t slot_ix = 0; | 91 intptr_t slot_ix = 0; |
| 92 Environment* current = deopt_env_; | 92 Environment* current = deopt_env_; |
| 93 | 93 |
| 94 // Emit all kMaterializeObject instructions describing objects to be | 94 // Emit all kMaterializeObject instructions describing objects to be |
| 95 // materialized on the deoptimization as a prefix to the deoptimization info. | 95 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 96 EmitMaterializations(deopt_env_, builder); | 96 EmitMaterializations(deopt_env_, builder); |
| 97 | 97 |
| 98 // The real frame starts here. | 98 // The real frame starts here. |
| 99 builder->MarkFrameStart(); | 99 builder->MarkFrameStart(); |
| 100 | 100 |
| 101 Zone* zone = compiler->zone(); |
| 102 |
| 101 // Current PP, FP, and PC. | 103 // Current PP, FP, and PC. |
| 102 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 104 builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++); |
| 103 builder->AddCallerFp(slot_ix++); | 105 builder->AddCallerFp(slot_ix++); |
| 104 builder->AddReturnAddress(Function::Handle(current->code().function()), | 106 builder->AddReturnAddress(Function::Handle(zone, current->code().function()), |
| 105 deopt_id(), | 107 deopt_id(), |
| 106 slot_ix++); | 108 slot_ix++); |
| 107 | 109 |
| 108 // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. | 110 // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. |
| 109 builder->AddPcMarker(Function::Handle(), slot_ix++); | 111 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
| 110 | 112 |
| 111 // Emit all values that are needed for materialization as a part of the | 113 // Emit all values that are needed for materialization as a part of the |
| 112 // expression stack for the bottom-most frame. This guarantees that GC | 114 // expression stack for the bottom-most frame. This guarantees that GC |
| 113 // will be able to find them during materialization. | 115 // will be able to find them during materialization. |
| 114 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 116 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 115 | 117 |
| 116 // For the innermost environment, set outgoing arguments and the locals. | 118 // For the innermost environment, set outgoing arguments and the locals. |
| 117 for (intptr_t i = current->Length() - 1; | 119 for (intptr_t i = current->Length() - 1; |
| 118 i >= current->fixed_parameter_count(); | 120 i >= current->fixed_parameter_count(); |
| 119 i--) { | 121 i--) { |
| 120 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 122 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 121 } | 123 } |
| 122 | 124 |
| 123 Environment* previous = current; | 125 Environment* previous = current; |
| 124 current = current->outer(); | 126 current = current->outer(); |
| 125 while (current != NULL) { | 127 while (current != NULL) { |
| 126 // PP, FP, and PC. | 128 // PP, FP, and PC. |
| 127 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 129 builder->AddPp( |
| 130 Function::Handle(zone, current->code().function()), slot_ix++); |
| 128 builder->AddCallerFp(slot_ix++); | 131 builder->AddCallerFp(slot_ix++); |
| 129 | 132 |
| 130 // For any outer environment the deopt id is that of the call instruction | 133 // For any outer environment the deopt id is that of the call instruction |
| 131 // which is recorded in the outer environment. | 134 // which is recorded in the outer environment. |
| 132 builder->AddReturnAddress(Function::Handle(current->code().function()), | 135 builder->AddReturnAddress( |
| 133 Isolate::ToDeoptAfter(current->deopt_id()), | 136 Function::Handle(zone, current->code().function()), |
| 134 slot_ix++); | 137 Isolate::ToDeoptAfter(current->deopt_id()), |
| 138 slot_ix++); |
| 135 | 139 |
| 136 // PC marker. | 140 // PC marker. |
| 137 builder->AddPcMarker(Function::Handle(previous->code().function()), | 141 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 138 slot_ix++); | 142 slot_ix++); |
| 139 | 143 |
| 140 // The values of outgoing arguments can be changed from the inlined call so | 144 // The values of outgoing arguments can be changed from the inlined call so |
| 141 // we must read them from the previous environment. | 145 // we must read them from the previous environment. |
| 142 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 146 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 143 builder->AddCopy(previous->ValueAt(i), | 147 builder->AddCopy(previous->ValueAt(i), |
| 144 previous->LocationAt(i), | 148 previous->LocationAt(i), |
| 145 slot_ix++); | 149 slot_ix++); |
| 146 } | 150 } |
| 147 | 151 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 160 } | 164 } |
| 161 // The previous pointer is now the outermost environment. | 165 // The previous pointer is now the outermost environment. |
| 162 ASSERT(previous != NULL); | 166 ASSERT(previous != NULL); |
| 163 | 167 |
| 164 // For the outermost environment, set caller PC, caller PP, and caller FP. | 168 // For the outermost environment, set caller PC, caller PP, and caller FP. |
| 165 builder->AddCallerPp(slot_ix++); | 169 builder->AddCallerPp(slot_ix++); |
| 166 builder->AddCallerFp(slot_ix++); | 170 builder->AddCallerFp(slot_ix++); |
| 167 builder->AddCallerPc(slot_ix++); | 171 builder->AddCallerPc(slot_ix++); |
| 168 | 172 |
| 169 // PC marker. | 173 // PC marker. |
| 170 builder->AddPcMarker(Function::Handle(previous->code().function()), | 174 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 171 slot_ix++); | 175 slot_ix++); |
| 172 | 176 |
| 173 // For the outermost environment, set the incoming arguments. | 177 // For the outermost environment, set the incoming arguments. |
| 174 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 178 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 175 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 179 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
| 176 } | 180 } |
| 177 | 181 |
| 178 return builder->CreateDeoptInfo(deopt_table); | 182 return builder->CreateDeoptInfo(deopt_table); |
| 179 } | 183 } |
| 180 | 184 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 230 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 227 TypeTestStubKind test_kind, | 231 TypeTestStubKind test_kind, |
| 228 Register instance_reg, | 232 Register instance_reg, |
| 229 Register type_arguments_reg, | 233 Register type_arguments_reg, |
| 230 Register temp_reg, | 234 Register temp_reg, |
| 231 Label* is_instance_lbl, | 235 Label* is_instance_lbl, |
| 232 Label* is_not_instance_lbl) { | 236 Label* is_not_instance_lbl) { |
| 233 ASSERT(instance_reg == R0); | 237 ASSERT(instance_reg == R0); |
| 234 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 238 ASSERT(temp_reg == kNoRegister); // Unused on ARM. |
| 235 const SubtypeTestCache& type_test_cache = | 239 const SubtypeTestCache& type_test_cache = |
| 236 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 240 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 237 __ LoadUniqueObject(R2, type_test_cache); | 241 __ LoadUniqueObject(R2, type_test_cache); |
| 238 if (test_kind == kTestTypeOneArg) { | 242 if (test_kind == kTestTypeOneArg) { |
| 239 ASSERT(type_arguments_reg == kNoRegister); | 243 ASSERT(type_arguments_reg == kNoRegister); |
| 240 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 244 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); |
| 241 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 245 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 242 } else if (test_kind == kTestTypeTwoArgs) { | 246 } else if (test_kind == kTestTypeTwoArgs) { |
| 243 ASSERT(type_arguments_reg == kNoRegister); | 247 ASSERT(type_arguments_reg == kNoRegister); |
| 244 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 248 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); |
| 245 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); | 249 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); |
| 246 } else if (test_kind == kTestTypeThreeArgs) { | 250 } else if (test_kind == kTestTypeThreeArgs) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 261 // R0: instance being type checked (preserved). | 265 // R0: instance being type checked (preserved). |
| 262 // Clobbers R2. | 266 // Clobbers R2. |
| 263 RawSubtypeTestCache* | 267 RawSubtypeTestCache* |
| 264 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 268 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 265 intptr_t token_pos, | 269 intptr_t token_pos, |
| 266 const AbstractType& type, | 270 const AbstractType& type, |
| 267 Label* is_instance_lbl, | 271 Label* is_instance_lbl, |
| 268 Label* is_not_instance_lbl) { | 272 Label* is_not_instance_lbl) { |
| 269 __ Comment("InstantiatedTypeWithArgumentsTest"); | 273 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 270 ASSERT(type.IsInstantiated()); | 274 ASSERT(type.IsInstantiated()); |
| 271 const Class& type_class = Class::ZoneHandle(type.type_class()); | 275 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 272 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); | 276 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); |
| 273 const Register kInstanceReg = R0; | 277 const Register kInstanceReg = R0; |
| 274 Error& malformed_error = Error::Handle(); | 278 Error& malformed_error = Error::Handle(zone()); |
| 275 const Type& int_type = Type::Handle(Type::IntType()); | 279 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
| 276 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); | 280 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); |
| 277 // Malformed type should have been handled at graph construction time. | 281 // Malformed type should have been handled at graph construction time. |
| 278 ASSERT(smi_is_ok || malformed_error.IsNull()); | 282 ASSERT(smi_is_ok || malformed_error.IsNull()); |
| 279 __ tst(kInstanceReg, Operand(kSmiTagMask)); | 283 __ tst(kInstanceReg, Operand(kSmiTagMask)); |
| 280 if (smi_is_ok) { | 284 if (smi_is_ok) { |
| 281 __ b(is_instance_lbl, EQ); | 285 __ b(is_instance_lbl, EQ); |
| 282 } else { | 286 } else { |
| 283 __ b(is_not_instance_lbl, EQ); | 287 __ b(is_not_instance_lbl, EQ); |
| 284 } | 288 } |
| 285 const intptr_t num_type_args = type_class.NumTypeArguments(); | 289 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 286 const intptr_t num_type_params = type_class.NumTypeParameters(); | 290 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 287 const intptr_t from_index = num_type_args - num_type_params; | 291 const intptr_t from_index = num_type_args - num_type_params; |
| 288 const TypeArguments& type_arguments = | 292 const TypeArguments& type_arguments = |
| 289 TypeArguments::ZoneHandle(type.arguments()); | 293 TypeArguments::ZoneHandle(zone(), type.arguments()); |
| 290 const bool is_raw_type = type_arguments.IsNull() || | 294 const bool is_raw_type = type_arguments.IsNull() || |
| 291 type_arguments.IsRaw(from_index, num_type_params); | 295 type_arguments.IsRaw(from_index, num_type_params); |
| 292 // Signature class is an instantiated parameterized type. | 296 // Signature class is an instantiated parameterized type. |
| 293 if (!type_class.IsSignatureClass()) { | 297 if (!type_class.IsSignatureClass()) { |
| 294 if (is_raw_type) { | 298 if (is_raw_type) { |
| 295 const Register kClassIdReg = R2; | 299 const Register kClassIdReg = R2; |
| 296 // dynamic type argument, check only classes. | 300 // dynamic type argument, check only classes. |
| 297 __ LoadClassId(kClassIdReg, kInstanceReg); | 301 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 298 __ CompareImmediate(kClassIdReg, type_class.id()); | 302 __ CompareImmediate(kClassIdReg, type_class.id()); |
| 299 __ b(is_instance_lbl, EQ); | 303 __ b(is_instance_lbl, EQ); |
| 300 // List is a very common case. | 304 // List is a very common case. |
| 301 if (IsListClass(type_class)) { | 305 if (IsListClass(type_class)) { |
| 302 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 306 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 303 } | 307 } |
| 304 return GenerateSubtype1TestCacheLookup( | 308 return GenerateSubtype1TestCacheLookup( |
| 305 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 309 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 306 } | 310 } |
| 307 // If one type argument only, check if type argument is Object or dynamic. | 311 // If one type argument only, check if type argument is Object or dynamic. |
| 308 if (type_arguments.Length() == 1) { | 312 if (type_arguments.Length() == 1) { |
| 309 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 313 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 310 type_arguments.TypeAt(0)); | 314 zone(), type_arguments.TypeAt(0)); |
| 311 ASSERT(!tp_argument.IsMalformed()); | 315 ASSERT(!tp_argument.IsMalformed()); |
| 312 if (tp_argument.IsType()) { | 316 if (tp_argument.IsType()) { |
| 313 ASSERT(tp_argument.HasResolvedTypeClass()); | 317 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 314 // Check if type argument is dynamic or Object. | 318 // Check if type argument is dynamic or Object. |
| 315 const Type& object_type = Type::Handle(Type::ObjectType()); | 319 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 316 if (object_type.IsSubtypeOf(tp_argument, NULL)) { | 320 if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
| 317 // Instance class test only necessary. | 321 // Instance class test only necessary. |
| 318 return GenerateSubtype1TestCacheLookup( | 322 return GenerateSubtype1TestCacheLookup( |
| 319 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 323 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 320 } | 324 } |
| 321 } | 325 } |
| 322 } | 326 } |
| 323 } | 327 } |
| 324 // Regular subtype test cache involving instance's type arguments. | 328 // Regular subtype test cache involving instance's type arguments. |
| 325 const Register kTypeArgumentsReg = kNoRegister; | 329 const Register kTypeArgumentsReg = kNoRegister; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 351 // R0: instance being type checked (preserved). | 355 // R0: instance being type checked (preserved). |
| 352 // Clobbers R2, R3. | 356 // Clobbers R2, R3. |
| 353 // Returns true if there is a fallthrough. | 357 // Returns true if there is a fallthrough. |
| 354 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 358 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 355 intptr_t token_pos, | 359 intptr_t token_pos, |
| 356 const AbstractType& type, | 360 const AbstractType& type, |
| 357 Label* is_instance_lbl, | 361 Label* is_instance_lbl, |
| 358 Label* is_not_instance_lbl) { | 362 Label* is_not_instance_lbl) { |
| 359 __ Comment("InstantiatedTypeNoArgumentsTest"); | 363 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 360 ASSERT(type.IsInstantiated()); | 364 ASSERT(type.IsInstantiated()); |
| 361 const Class& type_class = Class::Handle(type.type_class()); | 365 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| 362 ASSERT(type_class.NumTypeArguments() == 0); | 366 ASSERT(type_class.NumTypeArguments() == 0); |
| 363 | 367 |
| 364 const Register kInstanceReg = R0; | 368 const Register kInstanceReg = R0; |
| 365 __ tst(kInstanceReg, Operand(kSmiTagMask)); | 369 __ tst(kInstanceReg, Operand(kSmiTagMask)); |
| 366 // If instance is Smi, check directly. | 370 // If instance is Smi, check directly. |
| 367 const Class& smi_class = Class::Handle(Smi::Class()); | 371 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
| 368 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 372 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), |
| 369 type_class, | 373 type_class, |
| 370 TypeArguments::Handle(), | 374 TypeArguments::Handle(zone()), |
| 371 NULL)) { | 375 NULL)) { |
| 372 __ b(is_instance_lbl, EQ); | 376 __ b(is_instance_lbl, EQ); |
| 373 } else { | 377 } else { |
| 374 __ b(is_not_instance_lbl, EQ); | 378 __ b(is_not_instance_lbl, EQ); |
| 375 } | 379 } |
| 376 // Compare if the classes are equal. | 380 // Compare if the classes are equal. |
| 377 const Register kClassIdReg = R2; | 381 const Register kClassIdReg = R2; |
| 378 __ LoadClassId(kClassIdReg, kInstanceReg); | 382 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 379 __ CompareImmediate(kClassIdReg, type_class.id()); | 383 __ CompareImmediate(kClassIdReg, type_class.id()); |
| 380 __ b(is_instance_lbl, EQ); | 384 __ b(is_instance_lbl, EQ); |
| 381 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 385 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 382 // interfaces. | 386 // interfaces. |
| 383 // Bool interface can be implemented only by core class Bool. | 387 // Bool interface can be implemented only by core class Bool. |
| 384 if (type.IsBoolType()) { | 388 if (type.IsBoolType()) { |
| 385 __ CompareImmediate(kClassIdReg, kBoolCid); | 389 __ CompareImmediate(kClassIdReg, kBoolCid); |
| 386 __ b(is_instance_lbl, EQ); | 390 __ b(is_instance_lbl, EQ); |
| 387 __ b(is_not_instance_lbl); | 391 __ b(is_not_instance_lbl); |
| 388 return false; | 392 return false; |
| 389 } | 393 } |
| 390 if (type.IsFunctionType()) { | 394 if (type.IsFunctionType()) { |
| 391 // Check if instance is a closure. | 395 // Check if instance is a closure. |
| 392 __ LoadClassById(R3, kClassIdReg); | 396 __ LoadClassById(R3, kClassIdReg); |
| 393 __ ldr(R3, FieldAddress(R3, Class::signature_function_offset())); | 397 __ ldr(R3, FieldAddress(R3, Class::signature_function_offset())); |
| 394 __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null())); | 398 __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null())); |
| 395 __ b(is_instance_lbl, NE); | 399 __ b(is_instance_lbl, NE); |
| 396 } | 400 } |
| 397 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 401 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 398 // Note that instance is not Smi (checked above). | 402 // Note that instance is not Smi (checked above). |
| 399 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 403 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { |
| 400 GenerateNumberTypeCheck( | 404 GenerateNumberTypeCheck( |
| 401 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 405 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 402 return false; | 406 return false; |
| 403 } | 407 } |
| 404 if (type.IsStringType()) { | 408 if (type.IsStringType()) { |
| 405 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 409 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 406 return false; | 410 return false; |
| 407 } | 411 } |
| 408 // Otherwise fallthrough. | 412 // Otherwise fallthrough. |
| 409 return true; | 413 return true; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 // Load instantiator (or null) and instantiator type arguments on stack. | 462 // Load instantiator (or null) and instantiator type arguments on stack. |
| 459 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | 463 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. |
| 460 // R1: instantiator type arguments. | 464 // R1: instantiator type arguments. |
| 461 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 465 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 462 __ CompareImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 466 __ CompareImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); |
| 463 __ b(is_instance_lbl, EQ); | 467 __ b(is_instance_lbl, EQ); |
| 464 __ ldr(R2, | 468 __ ldr(R2, |
| 465 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); | 469 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); |
| 466 // R2: concrete type of type. | 470 // R2: concrete type of type. |
| 467 // Check if type argument is dynamic. | 471 // Check if type argument is dynamic. |
| 468 __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType())); | 472 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::DynamicType())); |
| 469 __ b(is_instance_lbl, EQ); | 473 __ b(is_instance_lbl, EQ); |
| 470 __ CompareObject(R2, Type::ZoneHandle(Type::ObjectType())); | 474 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); |
| 471 __ b(is_instance_lbl, EQ); | 475 __ b(is_instance_lbl, EQ); |
| 472 | 476 |
| 473 // For Smi check quickly against int and num interfaces. | 477 // For Smi check quickly against int and num interfaces. |
| 474 Label not_smi; | 478 Label not_smi; |
| 475 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? | 479 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? |
| 476 __ b(¬_smi, NE); | 480 __ b(¬_smi, NE); |
| 477 __ CompareObject(R2, Type::ZoneHandle(Type::IntType())); | 481 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); |
| 478 __ b(is_instance_lbl, EQ); | 482 __ b(is_instance_lbl, EQ); |
| 479 __ CompareObject(R2, Type::ZoneHandle(Type::Number())); | 483 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); |
| 480 __ b(is_instance_lbl, EQ); | 484 __ b(is_instance_lbl, EQ); |
| 481 // Smi must be handled in runtime. | 485 // Smi must be handled in runtime. |
| 482 Label fall_through; | 486 Label fall_through; |
| 483 __ b(&fall_through); | 487 __ b(&fall_through); |
| 484 | 488 |
| 485 __ Bind(¬_smi); | 489 __ Bind(¬_smi); |
| 486 // R1: instantiator type arguments. | 490 // R1: instantiator type arguments. |
| 487 // R0: instance. | 491 // R0: instance. |
| 488 const Register kInstanceReg = R0; | 492 const Register kInstanceReg = R0; |
| 489 const Register kTypeArgumentsReg = R1; | 493 const Register kTypeArgumentsReg = R1; |
| 490 const Register kTempReg = kNoRegister; | 494 const Register kTempReg = kNoRegister; |
| 491 const SubtypeTestCache& type_test_cache = | 495 const SubtypeTestCache& type_test_cache = |
| 492 SubtypeTestCache::ZoneHandle( | 496 SubtypeTestCache::ZoneHandle(zone(), |
| 493 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 497 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 494 kInstanceReg, | 498 kInstanceReg, |
| 495 kTypeArgumentsReg, | 499 kTypeArgumentsReg, |
| 496 kTempReg, | 500 kTempReg, |
| 497 is_instance_lbl, | 501 is_instance_lbl, |
| 498 is_not_instance_lbl)); | 502 is_not_instance_lbl)); |
| 499 __ Bind(&fall_through); | 503 __ Bind(&fall_through); |
| 500 return type_test_cache.raw(); | 504 return type_test_cache.raw(); |
| 501 } | 505 } |
| 502 if (type.IsType()) { | 506 if (type.IsType()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 533 const AbstractType& type, | 537 const AbstractType& type, |
| 534 Label* is_instance_lbl, | 538 Label* is_instance_lbl, |
| 535 Label* is_not_instance_lbl) { | 539 Label* is_not_instance_lbl) { |
| 536 __ Comment("InlineInstanceof"); | 540 __ Comment("InlineInstanceof"); |
| 537 if (type.IsVoidType()) { | 541 if (type.IsVoidType()) { |
| 538 // A non-null value is returned from a void function, which will result in a | 542 // A non-null value is returned from a void function, which will result in a |
| 539 // type error. A null value is handled prior to executing this inline code. | 543 // type error. A null value is handled prior to executing this inline code. |
| 540 return SubtypeTestCache::null(); | 544 return SubtypeTestCache::null(); |
| 541 } | 545 } |
| 542 if (type.IsInstantiated()) { | 546 if (type.IsInstantiated()) { |
| 543 const Class& type_class = Class::ZoneHandle(type.type_class()); | 547 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 544 // A class equality check is only applicable with a dst type of a | 548 // A class equality check is only applicable with a dst type of a |
| 545 // non-parameterized class, non-signature class, or with a raw dst type of | 549 // non-parameterized class, non-signature class, or with a raw dst type of |
| 546 // a parameterized class. | 550 // a parameterized class. |
| 547 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { | 551 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { |
| 548 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 552 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, |
| 549 type, | 553 type, |
| 550 is_instance_lbl, | 554 is_instance_lbl, |
| 551 is_not_instance_lbl); | 555 is_not_instance_lbl); |
| 552 // Fall through to runtime call. | 556 // Fall through to runtime call. |
| 553 } | 557 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 // return false here if the instance is null (and if the type is | 606 // return false here if the instance is null (and if the type is |
| 603 // instantiated). | 607 // instantiated). |
| 604 // We can only inline this null check if the type is instantiated at compile | 608 // We can only inline this null check if the type is instantiated at compile |
| 605 // time, since an uninstantiated type at compile time could be Object or | 609 // time, since an uninstantiated type at compile time could be Object or |
| 606 // dynamic at run time. | 610 // dynamic at run time. |
| 607 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); | 611 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); |
| 608 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 612 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
| 609 } | 613 } |
| 610 | 614 |
| 611 // Generate inline instanceof test. | 615 // Generate inline instanceof test. |
| 612 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 616 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 613 test_cache = GenerateInlineInstanceof(token_pos, type, | 617 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 614 &is_instance, &is_not_instance); | 618 &is_instance, &is_not_instance); |
| 615 | 619 |
| 616 // test_cache is null if there is no fall-through. | 620 // test_cache is null if there is no fall-through. |
| 617 Label done; | 621 Label done; |
| 618 if (!test_cache.IsNull()) { | 622 if (!test_cache.IsNull()) { |
| 619 // Generate runtime call. | 623 // Generate runtime call. |
| 620 // Load instantiator (R2) and its type arguments (R1). | 624 // Load instantiator (R2) and its type arguments (R1). |
| 621 __ ldm(IA, SP, (1 << R1) | (1 << R2)); | 625 __ ldm(IA, SP, (1 << R1) | (1 << R2)); |
| 622 __ PushObject(Object::null_object()); // Make room for the result. | 626 __ PushObject(Object::null_object()); // Make room for the result. |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 // We should never return here. | 701 // We should never return here. |
| 698 __ bkpt(0); | 702 __ bkpt(0); |
| 699 | 703 |
| 700 __ Bind(&is_assignable); // For a null object. | 704 __ Bind(&is_assignable); // For a null object. |
| 701 // Restore instantiator (R2) and its type arguments (R1). | 705 // Restore instantiator (R2) and its type arguments (R1). |
| 702 __ PopList((1 << R1) | (1 << R2)); | 706 __ PopList((1 << R1) | (1 << R2)); |
| 703 return; | 707 return; |
| 704 } | 708 } |
| 705 | 709 |
| 706 // Generate inline type check, linking to runtime call if not assignable. | 710 // Generate inline type check, linking to runtime call if not assignable. |
| 707 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 711 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 708 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 712 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 709 &is_assignable, &runtime_call); | 713 &is_assignable, &runtime_call); |
| 710 | 714 |
| 711 __ Bind(&runtime_call); | 715 __ Bind(&runtime_call); |
| 712 // Load instantiator (R2) and its type arguments (R1). | 716 // Load instantiator (R2) and its type arguments (R1). |
| 713 __ ldm(IA, SP, (1 << R1) | (1 << R2)); | 717 __ ldm(IA, SP, (1 << R1) | (1 << R2)); |
| 714 __ PushObject(Object::null_object()); // Make room for the result. | 718 __ PushObject(Object::null_object()); // Make room for the result. |
| 715 __ Push(R0); // Push the source object. | 719 __ Push(R0); // Push the source object. |
| 716 __ PushObject(dst_type); // Push the type of the destination. | 720 __ PushObject(dst_type); // Push the type of the destination. |
| 717 // Push instantiator (R2) and its type arguments (R1). | 721 // Push instantiator (R2) and its type arguments (R1). |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 // R5 is arg_pos as Smi. | 858 // R5 is arg_pos as Smi. |
| 855 // Point to next named entry. | 859 // Point to next named entry. |
| 856 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); | 860 __ add(R6, R6, Operand(ArgumentsDescriptor::named_entry_size())); |
| 857 __ rsb(R5, R5, Operand(0)); | 861 __ rsb(R5, R5, Operand(0)); |
| 858 Address argument_addr(R7, R5, LSL, 1); // R5 is a negative Smi. | 862 Address argument_addr(R7, R5, LSL, 1); // R5 is a negative Smi. |
| 859 __ ldr(R5, argument_addr); | 863 __ ldr(R5, argument_addr); |
| 860 __ b(&assign_optional_parameter); | 864 __ b(&assign_optional_parameter); |
| 861 __ Bind(&load_default_value); | 865 __ Bind(&load_default_value); |
| 862 // Load R5 with default argument. | 866 // Load R5 with default argument. |
| 863 const Object& value = Object::ZoneHandle( | 867 const Object& value = Object::ZoneHandle( |
| 864 parsed_function().default_parameter_values().At( | 868 zone(), parsed_function().default_parameter_values().At( |
| 865 param_pos - num_fixed_params)); | 869 param_pos - num_fixed_params)); |
| 866 __ LoadObject(R5, value); | 870 __ LoadObject(R5, value); |
| 867 __ Bind(&assign_optional_parameter); | 871 __ Bind(&assign_optional_parameter); |
| 868 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. | 872 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 869 // We do not use the final allocation index of the variable here, i.e. | 873 // We do not use the final allocation index of the variable here, i.e. |
| 870 // scope->VariableAt(i)->index(), because captured variables still need | 874 // scope->VariableAt(i)->index(), because captured variables still need |
| 871 // to be copied to the context that is not yet allocated. | 875 // to be copied to the context that is not yet allocated. |
| 872 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 876 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 873 const Address param_addr(FP, computed_param_pos * kWordSize); | 877 const Address param_addr(FP, computed_param_pos * kWordSize); |
| 874 __ str(R5, param_addr); | 878 __ str(R5, param_addr); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 890 for (int i = 0; i < num_opt_pos_params; i++) { | 894 for (int i = 0; i < num_opt_pos_params; i++) { |
| 891 Label next_parameter; | 895 Label next_parameter; |
| 892 // Handle this optional positional parameter only if k or fewer positional | 896 // Handle this optional positional parameter only if k or fewer positional |
| 893 // arguments have been passed, where k is param_pos, the position of this | 897 // arguments have been passed, where k is param_pos, the position of this |
| 894 // optional parameter in the formal parameter list. | 898 // optional parameter in the formal parameter list. |
| 895 const int param_pos = num_fixed_params + i; | 899 const int param_pos = num_fixed_params + i; |
| 896 __ CompareImmediate(R9, param_pos); | 900 __ CompareImmediate(R9, param_pos); |
| 897 __ b(&next_parameter, GT); | 901 __ b(&next_parameter, GT); |
| 898 // Load R5 with default argument. | 902 // Load R5 with default argument. |
| 899 const Object& value = Object::ZoneHandle( | 903 const Object& value = Object::ZoneHandle( |
| 900 parsed_function().default_parameter_values().At(i)); | 904 zone(), parsed_function().default_parameter_values().At(i)); |
| 901 __ LoadObject(R5, value); | 905 __ LoadObject(R5, value); |
| 902 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. | 906 // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 903 // We do not use the final allocation index of the variable here, i.e. | 907 // We do not use the final allocation index of the variable here, i.e. |
| 904 // scope->VariableAt(i)->index(), because captured variables still need | 908 // scope->VariableAt(i)->index(), because captured variables still need |
| 905 // to be copied to the context that is not yet allocated. | 909 // to be copied to the context that is not yet allocated. |
| 906 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 910 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 907 const Address param_addr(FP, computed_param_pos * kWordSize); | 911 const Address param_addr(FP, computed_param_pos * kWordSize); |
| 908 __ str(R5, param_addr); | 912 __ str(R5, param_addr); |
| 909 __ Bind(&next_parameter); | 913 __ Bind(&next_parameter); |
| 910 } | 914 } |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1201 } | 1205 } |
| 1202 | 1206 |
| 1203 | 1207 |
| 1204 void FlowGraphCompiler::EmitEdgeCounter() { | 1208 void FlowGraphCompiler::EmitEdgeCounter() { |
| 1205 // We do not check for overflow when incrementing the edge counter. The | 1209 // We do not check for overflow when incrementing the edge counter. The |
| 1206 // function should normally be optimized long before the counter can | 1210 // function should normally be optimized long before the counter can |
| 1207 // overflow; and though we do not reset the counters when we optimize or | 1211 // overflow; and though we do not reset the counters when we optimize or |
| 1208 // deoptimize, there is a bound on the number of | 1212 // deoptimize, there is a bound on the number of |
| 1209 // optimization/deoptimization cycles we will attempt. | 1213 // optimization/deoptimization cycles we will attempt. |
| 1210 ASSERT(assembler_->constant_pool_allowed()); | 1214 ASSERT(assembler_->constant_pool_allowed()); |
| 1211 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1215 const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld)); |
| 1212 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1216 counter.SetAt(0, Smi::Handle(zone(), Smi::New(0))); |
| 1213 __ Comment("Edge counter"); | 1217 __ Comment("Edge counter"); |
| 1214 __ LoadUniqueObject(R0, counter); | 1218 __ LoadUniqueObject(R0, counter); |
| 1215 intptr_t increment_start = assembler_->CodeSize(); | 1219 intptr_t increment_start = assembler_->CodeSize(); |
| 1216 #if defined(DEBUG) | 1220 #if defined(DEBUG) |
| 1217 bool old_use_far_branches = assembler_->use_far_branches(); | 1221 bool old_use_far_branches = assembler_->use_far_branches(); |
| 1218 assembler_->set_use_far_branches(true); | 1222 assembler_->set_use_far_branches(true); |
| 1219 #endif // DEBUG | 1223 #endif // DEBUG |
| 1220 __ ldr(IP, FieldAddress(R0, Array::element_offset(0))); | 1224 __ ldr(IP, FieldAddress(R0, Array::element_offset(0))); |
| 1221 __ add(IP, IP, Operand(Smi::RawValue(1))); | 1225 __ add(IP, IP, Operand(Smi::RawValue(1))); |
| 1222 __ StoreIntoSmiField(FieldAddress(R0, Array::element_offset(0)), IP); | 1226 __ StoreIntoSmiField(FieldAddress(R0, Array::element_offset(0)), IP); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1239 } | 1243 } |
| 1240 | 1244 |
| 1241 | 1245 |
| 1242 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1246 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1243 ExternalLabel* target_label, | 1247 ExternalLabel* target_label, |
| 1244 const ICData& ic_data, | 1248 const ICData& ic_data, |
| 1245 intptr_t argument_count, | 1249 intptr_t argument_count, |
| 1246 intptr_t deopt_id, | 1250 intptr_t deopt_id, |
| 1247 intptr_t token_pos, | 1251 intptr_t token_pos, |
| 1248 LocationSummary* locs) { | 1252 LocationSummary* locs) { |
| 1249 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1253 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1250 // Each ICData propagated from unoptimized to optimized code contains the | 1254 // Each ICData propagated from unoptimized to optimized code contains the |
| 1251 // function that corresponds to the Dart function of that IC call. Due | 1255 // function that corresponds to the Dart function of that IC call. Due |
| 1252 // to inlining in optimized code, that function may not correspond to the | 1256 // to inlining in optimized code, that function may not correspond to the |
| 1253 // top-level function (parsed_function().function()) which could be | 1257 // top-level function (parsed_function().function()) which could be |
| 1254 // reoptimized and which counter needs to be incremented. | 1258 // reoptimized and which counter needs to be incremented. |
| 1255 // Pass the function explicitly, it is used in IC stub. | 1259 // Pass the function explicitly, it is used in IC stub. |
| 1256 | 1260 |
| 1257 __ LoadObject(R6, parsed_function().function()); | 1261 __ LoadObject(R6, parsed_function().function()); |
| 1258 __ LoadUniqueObject(R5, ic_data); | 1262 __ LoadUniqueObject(R5, ic_data); |
| 1259 GenerateDartCall(deopt_id, | 1263 GenerateDartCall(deopt_id, |
| 1260 token_pos, | 1264 token_pos, |
| 1261 target_label, | 1265 target_label, |
| 1262 RawPcDescriptors::kIcCall, | 1266 RawPcDescriptors::kIcCall, |
| 1263 locs); | 1267 locs); |
| 1264 __ Drop(argument_count); | 1268 __ Drop(argument_count); |
| 1265 } | 1269 } |
| 1266 | 1270 |
| 1267 | 1271 |
| 1268 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1272 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 1269 const ICData& ic_data, | 1273 const ICData& ic_data, |
| 1270 intptr_t argument_count, | 1274 intptr_t argument_count, |
| 1271 intptr_t deopt_id, | 1275 intptr_t deopt_id, |
| 1272 intptr_t token_pos, | 1276 intptr_t token_pos, |
| 1273 LocationSummary* locs) { | 1277 LocationSummary* locs) { |
| 1274 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1278 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1275 __ LoadUniqueObject(R5, ic_data); | 1279 __ LoadUniqueObject(R5, ic_data); |
| 1276 GenerateDartCall(deopt_id, | 1280 GenerateDartCall(deopt_id, |
| 1277 token_pos, | 1281 token_pos, |
| 1278 target_label, | 1282 target_label, |
| 1279 RawPcDescriptors::kIcCall, | 1283 RawPcDescriptors::kIcCall, |
| 1280 locs); | 1284 locs); |
| 1281 __ Drop(argument_count); | 1285 __ Drop(argument_count); |
| 1282 } | 1286 } |
| 1283 | 1287 |
| 1284 | 1288 |
| 1285 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1289 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1286 const ICData& ic_data, | 1290 const ICData& ic_data, |
| 1287 intptr_t argument_count, | 1291 intptr_t argument_count, |
| 1288 intptr_t deopt_id, | 1292 intptr_t deopt_id, |
| 1289 intptr_t token_pos, | 1293 intptr_t token_pos, |
| 1290 LocationSummary* locs) { | 1294 LocationSummary* locs) { |
| 1291 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); | 1295 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); |
| 1292 const String& name = String::Handle(ic_data.target_name()); | 1296 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1293 const Array& arguments_descriptor = | 1297 const Array& arguments_descriptor = |
| 1294 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1298 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1295 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1299 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1296 const MegamorphicCache& cache = | 1300 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1297 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1301 zone(), table->Lookup(name, arguments_descriptor)); |
| 1298 const Register receiverR = R0; | 1302 const Register receiverR = R0; |
| 1299 const Register cacheR = R1; | 1303 const Register cacheR = R1; |
| 1300 const Register targetR = R1; | 1304 const Register targetR = R1; |
| 1301 __ LoadFromOffset(kWord, receiverR, SP, (argument_count - 1) * kWordSize); | 1305 __ LoadFromOffset(kWord, receiverR, SP, (argument_count - 1) * kWordSize); |
| 1302 __ LoadObject(cacheR, cache); | 1306 __ LoadObject(cacheR, cache); |
| 1303 | 1307 |
| 1304 if (FLAG_use_megamorphic_stub) { | 1308 if (FLAG_use_megamorphic_stub) { |
| 1305 __ BranchLink(&StubCode::MegamorphicLookupLabel()); | 1309 __ BranchLink(&StubCode::MegamorphicLookupLabel()); |
| 1306 } else { | 1310 } else { |
| 1307 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); | 1311 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1517 intptr_t argument_count, | 1521 intptr_t argument_count, |
| 1518 const Array& argument_names, | 1522 const Array& argument_names, |
| 1519 Label* failed, | 1523 Label* failed, |
| 1520 Label* match_found, | 1524 Label* match_found, |
| 1521 intptr_t deopt_id, | 1525 intptr_t deopt_id, |
| 1522 intptr_t token_index, | 1526 intptr_t token_index, |
| 1523 LocationSummary* locs) { | 1527 LocationSummary* locs) { |
| 1524 ASSERT(is_optimizing()); | 1528 ASSERT(is_optimizing()); |
| 1525 __ Comment("EmitTestAndCall"); | 1529 __ Comment("EmitTestAndCall"); |
| 1526 const Array& arguments_descriptor = | 1530 const Array& arguments_descriptor = |
| 1527 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1531 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
| 1528 argument_names)); | 1532 argument_names)); |
| 1529 | 1533 |
| 1530 // Load receiver into R0. | 1534 // Load receiver into R0. |
| 1531 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1535 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
| 1532 __ LoadObject(R4, arguments_descriptor); | 1536 __ LoadObject(R4, arguments_descriptor); |
| 1533 | 1537 |
| 1534 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1538 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
| 1535 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1539 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
| 1536 | 1540 |
| 1537 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1541 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
| 1538 | 1542 |
| 1539 Label after_smi_test; | 1543 Label after_smi_test; |
| 1540 __ tst(R0, Operand(kSmiTagMask)); | 1544 __ tst(R0, Operand(kSmiTagMask)); |
| 1541 if (kFirstCheckIsSmi) { | 1545 if (kFirstCheckIsSmi) { |
| 1542 // Jump if receiver is not Smi. | 1546 // Jump if receiver is not Smi. |
| 1543 if (kNumChecks == 1) { | 1547 if (kNumChecks == 1) { |
| 1544 __ b(failed, NE); | 1548 __ b(failed, NE); |
| 1545 } else { | 1549 } else { |
| 1546 __ b(&after_smi_test, NE); | 1550 __ b(&after_smi_test, NE); |
| 1547 } | 1551 } |
| 1548 // 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 |
| 1549 // that we can record the outgoing edges to other code. | 1553 // that we can record the outgoing edges to other code. |
| 1550 GenerateDartCall(deopt_id, | 1554 GenerateDartCall(deopt_id, |
| 1551 token_index, | 1555 token_index, |
| 1552 &StubCode::CallStaticFunctionLabel(), | 1556 &StubCode::CallStaticFunctionLabel(), |
| 1553 RawPcDescriptors::kOther, | 1557 RawPcDescriptors::kOther, |
| 1554 locs); | 1558 locs); |
| 1555 const Function& function = Function::Handle(ic_data.GetTargetAt(0)); | 1559 const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0)); |
| 1556 AddStaticCallTarget(function); | 1560 AddStaticCallTarget(function); |
| 1557 __ Drop(argument_count); | 1561 __ Drop(argument_count); |
| 1558 if (kNumChecks > 1) { | 1562 if (kNumChecks > 1) { |
| 1559 __ b(match_found); | 1563 __ b(match_found); |
| 1560 } | 1564 } |
| 1561 } else { | 1565 } else { |
| 1562 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1566 // Receiver is Smi, but Smi is not a valid class therefore fail. |
| 1563 // (Smi class must be first in the list). | 1567 // (Smi class must be first in the list). |
| 1564 __ b(failed, EQ); | 1568 __ b(failed, EQ); |
| 1565 } | 1569 } |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1900 DRegister dreg = EvenDRegisterOf(reg); | 1904 DRegister dreg = EvenDRegisterOf(reg); |
| 1901 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1905 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
| 1902 } | 1906 } |
| 1903 | 1907 |
| 1904 | 1908 |
| 1905 #undef __ | 1909 #undef __ |
| 1906 | 1910 |
| 1907 } // namespace dart | 1911 } // namespace dart |
| 1908 | 1912 |
| 1909 #endif // defined TARGET_ARCH_ARM | 1913 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |