| 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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 intptr_t slot_ix = 0; | 87 intptr_t slot_ix = 0; |
| 88 Environment* current = deopt_env_; | 88 Environment* current = deopt_env_; |
| 89 | 89 |
| 90 // Emit all kMaterializeObject instructions describing objects to be | 90 // Emit all kMaterializeObject instructions describing objects to be |
| 91 // materialized on the deoptimization as a prefix to the deoptimization info. | 91 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 92 EmitMaterializations(deopt_env_, builder); | 92 EmitMaterializations(deopt_env_, builder); |
| 93 | 93 |
| 94 // The real frame starts here. | 94 // The real frame starts here. |
| 95 builder->MarkFrameStart(); | 95 builder->MarkFrameStart(); |
| 96 | 96 |
| 97 Zone* zone = compiler->zone(); |
| 98 |
| 97 // Current PP, FP, and PC. | 99 // Current PP, FP, and PC. |
| 98 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 100 builder->AddPp(Function::Handle(zone, current->code().function()), slot_ix++); |
| 99 builder->AddCallerFp(slot_ix++); | 101 builder->AddCallerFp(slot_ix++); |
| 100 builder->AddReturnAddress(Function::Handle(current->code().function()), | 102 builder->AddReturnAddress(Function::Handle(zone, current->code().function()), |
| 101 deopt_id(), | 103 deopt_id(), |
| 102 slot_ix++); | 104 slot_ix++); |
| 103 | 105 |
| 104 // Callee's PC marker is not used anymore. Pass Code::null() to set to 0. | 106 // Callee's PC marker is not used anymore. Pass Code::null() to set to 0. |
| 105 builder->AddPcMarker(Function::Handle(), slot_ix++); | 107 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
| 106 | 108 |
| 107 // Emit all values that are needed for materialization as a part of the | 109 // Emit all values that are needed for materialization as a part of the |
| 108 // expression stack for the bottom-most frame. This guarantees that GC | 110 // expression stack for the bottom-most frame. This guarantees that GC |
| 109 // will be able to find them during materialization. | 111 // will be able to find them during materialization. |
| 110 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 112 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 111 | 113 |
| 112 // For the innermost environment, set outgoing arguments and the locals. | 114 // For the innermost environment, set outgoing arguments and the locals. |
| 113 for (intptr_t i = current->Length() - 1; | 115 for (intptr_t i = current->Length() - 1; |
| 114 i >= current->fixed_parameter_count(); | 116 i >= current->fixed_parameter_count(); |
| 115 i--) { | 117 i--) { |
| 116 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 118 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 117 } | 119 } |
| 118 | 120 |
| 119 Environment* previous = current; | 121 Environment* previous = current; |
| 120 current = current->outer(); | 122 current = current->outer(); |
| 121 while (current != NULL) { | 123 while (current != NULL) { |
| 122 // PP, FP, and PC. | 124 // PP, FP, and PC. |
| 123 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 125 builder->AddPp( |
| 126 Function::Handle(zone, current->code().function()), slot_ix++); |
| 124 builder->AddCallerFp(slot_ix++); | 127 builder->AddCallerFp(slot_ix++); |
| 125 | 128 |
| 126 // For any outer environment the deopt id is that of the call instruction | 129 // For any outer environment the deopt id is that of the call instruction |
| 127 // which is recorded in the outer environment. | 130 // which is recorded in the outer environment. |
| 128 builder->AddReturnAddress(Function::Handle(current->code().function()), | 131 builder->AddReturnAddress( |
| 129 Isolate::ToDeoptAfter(current->deopt_id()), | 132 Function::Handle(zone, current->code().function()), |
| 130 slot_ix++); | 133 Isolate::ToDeoptAfter(current->deopt_id()), |
| 134 slot_ix++); |
| 131 | 135 |
| 132 // PC marker. | 136 // PC marker. |
| 133 builder->AddPcMarker(Function::Handle(previous->code().function()), | 137 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 134 slot_ix++); | 138 slot_ix++); |
| 135 | 139 |
| 136 // The values of outgoing arguments can be changed from the inlined call so | 140 // The values of outgoing arguments can be changed from the inlined call so |
| 137 // we must read them from the previous environment. | 141 // we must read them from the previous environment. |
| 138 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 142 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 139 builder->AddCopy(previous->ValueAt(i), | 143 builder->AddCopy(previous->ValueAt(i), |
| 140 previous->LocationAt(i), | 144 previous->LocationAt(i), |
| 141 slot_ix++); | 145 slot_ix++); |
| 142 } | 146 } |
| 143 | 147 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 156 } | 160 } |
| 157 // The previous pointer is now the outermost environment. | 161 // The previous pointer is now the outermost environment. |
| 158 ASSERT(previous != NULL); | 162 ASSERT(previous != NULL); |
| 159 | 163 |
| 160 // For the outermost environment, set caller PC, caller PP, and caller FP. | 164 // For the outermost environment, set caller PC, caller PP, and caller FP. |
| 161 builder->AddCallerPp(slot_ix++); | 165 builder->AddCallerPp(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 // PC marker. | 169 // PC marker. |
| 166 builder->AddPcMarker(Function::Handle(previous->code().function()), | 170 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 167 slot_ix++); | 171 slot_ix++); |
| 168 | 172 |
| 169 // For the outermost environment, set the incoming arguments. | 173 // For the outermost environment, set the incoming arguments. |
| 170 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 174 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 171 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 175 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
| 172 } | 176 } |
| 173 | 177 |
| 174 return builder->CreateDeoptInfo(deopt_table); | 178 return builder->CreateDeoptInfo(deopt_table); |
| 175 } | 179 } |
| 176 | 180 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 TypeTestStubKind test_kind, | 221 TypeTestStubKind test_kind, |
| 218 Register instance_reg, | 222 Register instance_reg, |
| 219 Register type_arguments_reg, | 223 Register type_arguments_reg, |
| 220 Register temp_reg, | 224 Register temp_reg, |
| 221 Label* is_instance_lbl, | 225 Label* is_instance_lbl, |
| 222 Label* is_not_instance_lbl) { | 226 Label* is_not_instance_lbl) { |
| 223 __ Comment("CallSubtypeTestStub"); | 227 __ Comment("CallSubtypeTestStub"); |
| 224 ASSERT(instance_reg == A0); | 228 ASSERT(instance_reg == A0); |
| 225 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. | 229 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
| 226 const SubtypeTestCache& type_test_cache = | 230 const SubtypeTestCache& type_test_cache = |
| 227 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 231 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 228 __ LoadUniqueObject(A2, type_test_cache); | 232 __ LoadUniqueObject(A2, type_test_cache); |
| 229 if (test_kind == kTestTypeOneArg) { | 233 if (test_kind == kTestTypeOneArg) { |
| 230 ASSERT(type_arguments_reg == kNoRegister); | 234 ASSERT(type_arguments_reg == kNoRegister); |
| 231 __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null())); | 235 __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null())); |
| 232 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 236 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 233 } else if (test_kind == kTestTypeTwoArgs) { | 237 } else if (test_kind == kTestTypeTwoArgs) { |
| 234 ASSERT(type_arguments_reg == kNoRegister); | 238 ASSERT(type_arguments_reg == kNoRegister); |
| 235 __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null())); | 239 __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null())); |
| 236 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); | 240 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); |
| 237 } else if (test_kind == kTestTypeThreeArgs) { | 241 } else if (test_kind == kTestTypeThreeArgs) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 252 // A0: instance being type checked (preserved). | 256 // A0: instance being type checked (preserved). |
| 253 // Clobbers T0. | 257 // Clobbers T0. |
| 254 RawSubtypeTestCache* | 258 RawSubtypeTestCache* |
| 255 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 259 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 256 intptr_t token_pos, | 260 intptr_t token_pos, |
| 257 const AbstractType& type, | 261 const AbstractType& type, |
| 258 Label* is_instance_lbl, | 262 Label* is_instance_lbl, |
| 259 Label* is_not_instance_lbl) { | 263 Label* is_not_instance_lbl) { |
| 260 __ Comment("InstantiatedTypeWithArgumentsTest"); | 264 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 261 ASSERT(type.IsInstantiated()); | 265 ASSERT(type.IsInstantiated()); |
| 262 const Class& type_class = Class::ZoneHandle(type.type_class()); | 266 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 263 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); | 267 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); |
| 264 const Register kInstanceReg = A0; | 268 const Register kInstanceReg = A0; |
| 265 Error& malformed_error = Error::Handle(); | 269 Error& malformed_error = Error::Handle(zone()); |
| 266 const Type& int_type = Type::Handle(Type::IntType()); | 270 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
| 267 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); | 271 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); |
| 268 // Malformed type should have been handled at graph construction time. | 272 // Malformed type should have been handled at graph construction time. |
| 269 ASSERT(smi_is_ok || malformed_error.IsNull()); | 273 ASSERT(smi_is_ok || malformed_error.IsNull()); |
| 270 __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask)); | 274 __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask)); |
| 271 if (smi_is_ok) { | 275 if (smi_is_ok) { |
| 272 __ beq(CMPRES1, ZR, is_instance_lbl); | 276 __ beq(CMPRES1, ZR, is_instance_lbl); |
| 273 } else { | 277 } else { |
| 274 __ beq(CMPRES1, ZR, is_not_instance_lbl); | 278 __ beq(CMPRES1, ZR, is_not_instance_lbl); |
| 275 } | 279 } |
| 276 const intptr_t num_type_args = type_class.NumTypeArguments(); | 280 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 277 const intptr_t num_type_params = type_class.NumTypeParameters(); | 281 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 278 const intptr_t from_index = num_type_args - num_type_params; | 282 const intptr_t from_index = num_type_args - num_type_params; |
| 279 const TypeArguments& type_arguments = | 283 const TypeArguments& type_arguments = |
| 280 TypeArguments::ZoneHandle(type.arguments()); | 284 TypeArguments::ZoneHandle(zone(), type.arguments()); |
| 281 const bool is_raw_type = type_arguments.IsNull() || | 285 const bool is_raw_type = type_arguments.IsNull() || |
| 282 type_arguments.IsRaw(from_index, num_type_params); | 286 type_arguments.IsRaw(from_index, num_type_params); |
| 283 // Signature class is an instantiated parameterized type. | 287 // Signature class is an instantiated parameterized type. |
| 284 if (!type_class.IsSignatureClass()) { | 288 if (!type_class.IsSignatureClass()) { |
| 285 if (is_raw_type) { | 289 if (is_raw_type) { |
| 286 const Register kClassIdReg = T0; | 290 const Register kClassIdReg = T0; |
| 287 // dynamic type argument, check only classes. | 291 // dynamic type argument, check only classes. |
| 288 __ LoadClassId(kClassIdReg, kInstanceReg); | 292 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 289 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); | 293 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); |
| 290 // List is a very common case. | 294 // List is a very common case. |
| 291 if (IsListClass(type_class)) { | 295 if (IsListClass(type_class)) { |
| 292 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 296 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 293 } | 297 } |
| 294 return GenerateSubtype1TestCacheLookup( | 298 return GenerateSubtype1TestCacheLookup( |
| 295 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 299 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 296 } | 300 } |
| 297 // If one type argument only, check if type argument is Object or dynamic. | 301 // If one type argument only, check if type argument is Object or dynamic. |
| 298 if (type_arguments.Length() == 1) { | 302 if (type_arguments.Length() == 1) { |
| 299 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 303 const AbstractType& tp_argument = AbstractType::ZoneHandle(zone(), |
| 300 type_arguments.TypeAt(0)); | 304 type_arguments.TypeAt(0)); |
| 301 ASSERT(!tp_argument.IsMalformed()); | 305 ASSERT(!tp_argument.IsMalformed()); |
| 302 if (tp_argument.IsType()) { | 306 if (tp_argument.IsType()) { |
| 303 ASSERT(tp_argument.HasResolvedTypeClass()); | 307 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 304 // Check if type argument is dynamic or Object. | 308 // Check if type argument is dynamic or Object. |
| 305 const Type& object_type = Type::Handle(Type::ObjectType()); | 309 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 306 if (object_type.IsSubtypeOf(tp_argument, NULL)) { | 310 if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
| 307 // Instance class test only necessary. | 311 // Instance class test only necessary. |
| 308 return GenerateSubtype1TestCacheLookup( | 312 return GenerateSubtype1TestCacheLookup( |
| 309 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 313 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 310 } | 314 } |
| 311 } | 315 } |
| 312 } | 316 } |
| 313 } | 317 } |
| 314 // Regular subtype test cache involving instance's type arguments. | 318 // Regular subtype test cache involving instance's type arguments. |
| 315 const Register kTypeArgumentsReg = kNoRegister; | 319 const Register kTypeArgumentsReg = kNoRegister; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 341 // A0: instance being type checked (preserved). | 345 // A0: instance being type checked (preserved). |
| 342 // Clobbers: T0, T1, T2 | 346 // Clobbers: T0, T1, T2 |
| 343 // Returns true if there is a fallthrough. | 347 // Returns true if there is a fallthrough. |
| 344 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 348 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 345 intptr_t token_pos, | 349 intptr_t token_pos, |
| 346 const AbstractType& type, | 350 const AbstractType& type, |
| 347 Label* is_instance_lbl, | 351 Label* is_instance_lbl, |
| 348 Label* is_not_instance_lbl) { | 352 Label* is_not_instance_lbl) { |
| 349 __ Comment("InstantiatedTypeNoArgumentsTest"); | 353 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 350 ASSERT(type.IsInstantiated()); | 354 ASSERT(type.IsInstantiated()); |
| 351 const Class& type_class = Class::Handle(type.type_class()); | 355 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| 352 ASSERT(type_class.NumTypeArguments() == 0); | 356 ASSERT(type_class.NumTypeArguments() == 0); |
| 353 | 357 |
| 354 const Register kInstanceReg = A0; | 358 const Register kInstanceReg = A0; |
| 355 __ andi(T0, A0, Immediate(kSmiTagMask)); | 359 __ andi(T0, A0, Immediate(kSmiTagMask)); |
| 356 // If instance is Smi, check directly. | 360 // If instance is Smi, check directly. |
| 357 const Class& smi_class = Class::Handle(Smi::Class()); | 361 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
| 358 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 362 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), |
| 359 type_class, | 363 type_class, |
| 360 TypeArguments::Handle(), | 364 TypeArguments::Handle(zone()), |
| 361 NULL)) { | 365 NULL)) { |
| 362 __ beq(T0, ZR, is_instance_lbl); | 366 __ beq(T0, ZR, is_instance_lbl); |
| 363 } else { | 367 } else { |
| 364 __ beq(T0, ZR, is_not_instance_lbl); | 368 __ beq(T0, ZR, is_not_instance_lbl); |
| 365 } | 369 } |
| 366 // Compare if the classes are equal. | 370 // Compare if the classes are equal. |
| 367 const Register kClassIdReg = T0; | 371 const Register kClassIdReg = T0; |
| 368 __ LoadClassId(kClassIdReg, kInstanceReg); | 372 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 369 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); | 373 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); |
| 370 | 374 |
| 371 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 375 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 372 // interfaces. | 376 // interfaces. |
| 373 // Bool interface can be implemented only by core class Bool. | 377 // Bool interface can be implemented only by core class Bool. |
| 374 if (type.IsBoolType()) { | 378 if (type.IsBoolType()) { |
| 375 __ BranchEqual(kClassIdReg, Immediate(kBoolCid), is_instance_lbl); | 379 __ BranchEqual(kClassIdReg, Immediate(kBoolCid), is_instance_lbl); |
| 376 __ b(is_not_instance_lbl); | 380 __ b(is_not_instance_lbl); |
| 377 return false; | 381 return false; |
| 378 } | 382 } |
| 379 if (type.IsFunctionType()) { | 383 if (type.IsFunctionType()) { |
| 380 // Check if instance is a closure. | 384 // Check if instance is a closure. |
| 381 __ LoadClassById(T1, kClassIdReg); | 385 __ LoadClassById(T1, kClassIdReg); |
| 382 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); | 386 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); |
| 383 __ BranchNotEqual(T1, Object::null_object(), is_instance_lbl); | 387 __ BranchNotEqual(T1, Object::null_object(), is_instance_lbl); |
| 384 } | 388 } |
| 385 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 389 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 386 // Note that instance is not Smi (checked above). | 390 // Note that instance is not Smi (checked above). |
| 387 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 391 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { |
| 388 GenerateNumberTypeCheck( | 392 GenerateNumberTypeCheck( |
| 389 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 393 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 390 return false; | 394 return false; |
| 391 } | 395 } |
| 392 if (type.IsStringType()) { | 396 if (type.IsStringType()) { |
| 393 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 397 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 394 return false; | 398 return false; |
| 395 } | 399 } |
| 396 // Otherwise fallthrough. | 400 // Otherwise fallthrough. |
| 397 return true; | 401 return true; |
| (...skipping 47 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 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. | 450 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. |
| 447 // A1: instantiator type arguments. | 451 // A1: 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 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null())); | 453 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null())); |
| 450 __ beq(A1, T7, is_instance_lbl); | 454 __ beq(A1, T7, is_instance_lbl); |
| 451 __ lw(T2, | 455 __ lw(T2, |
| 452 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); | 456 FieldAddress(A1, 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 __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl); | 459 __ BranchEqual(T2, |
| 456 __ BranchEqual(T2, Type::ZoneHandle(Type::ObjectType()), is_instance_lbl); | 460 Type::ZoneHandle(zone(), Type::DynamicType()), is_instance_lbl); |
| 461 __ BranchEqual(T2, |
| 462 Type::ZoneHandle(zone(), Type::ObjectType()), is_instance_lbl); |
| 457 | 463 |
| 458 // For Smi check quickly against int and num interfaces. | 464 // For Smi check quickly against int and num interfaces. |
| 459 Label not_smi; | 465 Label not_smi; |
| 460 __ andi(CMPRES1, A0, Immediate(kSmiTagMask)); | 466 __ andi(CMPRES1, A0, Immediate(kSmiTagMask)); |
| 461 __ bne(CMPRES1, ZR, ¬_smi); // Value is Smi? | 467 __ bne(CMPRES1, ZR, ¬_smi); // Value is Smi? |
| 462 __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl); | 468 __ BranchEqual(T2, |
| 463 __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl); | 469 Type::ZoneHandle(zone(), Type::IntType()), is_instance_lbl); |
| 470 __ BranchEqual(T2, |
| 471 Type::ZoneHandle(zone(), Type::Number()), is_instance_lbl); |
| 464 // Smi must be handled in runtime. | 472 // Smi must be handled in runtime. |
| 465 Label fall_through; | 473 Label fall_through; |
| 466 __ b(&fall_through); | 474 __ b(&fall_through); |
| 467 | 475 |
| 468 __ Bind(¬_smi); | 476 __ Bind(¬_smi); |
| 469 // T1: instantiator type arguments. | 477 // T1: instantiator type arguments. |
| 470 // A0: instance. | 478 // A0: instance. |
| 471 const Register kInstanceReg = A0; | 479 const Register kInstanceReg = A0; |
| 472 const Register kTypeArgumentsReg = A1; | 480 const Register kTypeArgumentsReg = A1; |
| 473 const Register kTempReg = kNoRegister; | 481 const Register kTempReg = kNoRegister; |
| 474 const SubtypeTestCache& type_test_cache = | 482 const SubtypeTestCache& type_test_cache = |
| 475 SubtypeTestCache::ZoneHandle( | 483 SubtypeTestCache::ZoneHandle(zone(), |
| 476 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 484 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 477 kInstanceReg, | 485 kInstanceReg, |
| 478 kTypeArgumentsReg, | 486 kTypeArgumentsReg, |
| 479 kTempReg, | 487 kTempReg, |
| 480 is_instance_lbl, | 488 is_instance_lbl, |
| 481 is_not_instance_lbl)); | 489 is_not_instance_lbl)); |
| 482 __ Bind(&fall_through); | 490 __ Bind(&fall_through); |
| 483 return type_test_cache.raw(); | 491 return type_test_cache.raw(); |
| 484 } | 492 } |
| 485 if (type.IsType()) { | 493 if (type.IsType()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 516 const AbstractType& type, | 524 const AbstractType& type, |
| 517 Label* is_instance_lbl, | 525 Label* is_instance_lbl, |
| 518 Label* is_not_instance_lbl) { | 526 Label* is_not_instance_lbl) { |
| 519 __ Comment("InlineInstanceof"); | 527 __ Comment("InlineInstanceof"); |
| 520 if (type.IsVoidType()) { | 528 if (type.IsVoidType()) { |
| 521 // 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 |
| 522 // 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. |
| 523 return SubtypeTestCache::null(); | 531 return SubtypeTestCache::null(); |
| 524 } | 532 } |
| 525 if (type.IsInstantiated()) { | 533 if (type.IsInstantiated()) { |
| 526 const Class& type_class = Class::ZoneHandle(type.type_class()); | 534 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 527 // 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 |
| 528 // 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 |
| 529 // a parameterized class. | 537 // a parameterized class. |
| 530 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { | 538 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { |
| 531 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 539 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, |
| 532 type, | 540 type, |
| 533 is_instance_lbl, | 541 is_instance_lbl, |
| 534 is_not_instance_lbl); | 542 is_not_instance_lbl); |
| 535 // Fall through to runtime call. | 543 // Fall through to runtime call. |
| 536 } | 544 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 // return false here if the instance is null (and if the type is | 595 // return false here if the instance is null (and if the type is |
| 588 // instantiated). | 596 // instantiated). |
| 589 // We can only inline this null check if the type is instantiated at compile | 597 // We can only inline this null check if the type is instantiated at compile |
| 590 // time, since an uninstantiated type at compile time could be Object or | 598 // time, since an uninstantiated type at compile time could be Object or |
| 591 // dynamic at run time. | 599 // dynamic at run time. |
| 592 __ BranchEqual(A0, Object::null_object(), | 600 __ BranchEqual(A0, Object::null_object(), |
| 593 type.IsNullType() ? &is_instance : &is_not_instance); | 601 type.IsNullType() ? &is_instance : &is_not_instance); |
| 594 } | 602 } |
| 595 | 603 |
| 596 // Generate inline instanceof test. | 604 // Generate inline instanceof test. |
| 597 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 605 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 598 test_cache = GenerateInlineInstanceof(token_pos, type, | 606 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 599 &is_instance, &is_not_instance); | 607 &is_instance, &is_not_instance); |
| 600 | 608 |
| 601 // test_cache is null if there is no fall-through. | 609 // test_cache is null if there is no fall-through. |
| 602 Label done; | 610 Label done; |
| 603 if (!test_cache.IsNull()) { | 611 if (!test_cache.IsNull()) { |
| 604 // Generate runtime call. | 612 // Generate runtime call. |
| 605 // Load instantiator (A2) and its type arguments (A1). | 613 // Load instantiator (A2) and its type arguments (A1). |
| 606 __ lw(A1, Address(SP, 0 * kWordSize)); | 614 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 607 __ lw(A2, Address(SP, 1 * kWordSize)); | 615 __ lw(A2, Address(SP, 1 * kWordSize)); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 | 706 |
| 699 __ Bind(&is_assignable); // For a null object. | 707 __ Bind(&is_assignable); // For a null object. |
| 700 // Restore instantiator and its type arguments. | 708 // Restore instantiator and its type arguments. |
| 701 __ lw(A1, Address(SP, 0 * kWordSize)); | 709 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 702 __ lw(A2, Address(SP, 1 * kWordSize)); | 710 __ lw(A2, Address(SP, 1 * kWordSize)); |
| 703 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 711 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 704 return; | 712 return; |
| 705 } | 713 } |
| 706 | 714 |
| 707 // Generate inline type check, linking to runtime call if not assignable. | 715 // Generate inline type check, linking to runtime call if not assignable. |
| 708 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 716 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 709 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 717 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 710 &is_assignable, &runtime_call); | 718 &is_assignable, &runtime_call); |
| 711 | 719 |
| 712 __ Bind(&runtime_call); | 720 __ Bind(&runtime_call); |
| 713 // Load instantiator (A2) and its type arguments (A1). | 721 // Load instantiator (A2) and its type arguments (A1). |
| 714 __ lw(A1, Address(SP, 0 * kWordSize)); | 722 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 715 __ lw(A2, Address(SP, 1 * kWordSize)); | 723 __ lw(A2, Address(SP, 1 * kWordSize)); |
| 716 | 724 |
| 717 __ addiu(SP, SP, Immediate(-7 * kWordSize)); | 725 __ addiu(SP, SP, Immediate(-7 * kWordSize)); |
| 718 __ LoadObject(TMP, Object::null_object()); | 726 __ LoadObject(TMP, Object::null_object()); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 // Point to next named entry. | 873 // Point to next named entry. |
| 866 __ AddImmediate(T0, ArgumentsDescriptor::named_entry_size()); | 874 __ AddImmediate(T0, ArgumentsDescriptor::named_entry_size()); |
| 867 __ subu(T3, ZR, T3); | 875 __ subu(T3, ZR, T3); |
| 868 __ sll(T3, T3, 1); | 876 __ sll(T3, T3, 1); |
| 869 __ addu(T3, T1, T3); | 877 __ addu(T3, T1, T3); |
| 870 __ b(&assign_optional_parameter); | 878 __ b(&assign_optional_parameter); |
| 871 __ delay_slot()->lw(T3, Address(T3)); | 879 __ delay_slot()->lw(T3, Address(T3)); |
| 872 | 880 |
| 873 __ Bind(&load_default_value); | 881 __ Bind(&load_default_value); |
| 874 // Load T3 with default argument. | 882 // Load T3 with default argument. |
| 875 const Object& value = Object::ZoneHandle( | 883 const Object& value = Object::ZoneHandle(zone(), |
| 876 parsed_function().default_parameter_values().At( | 884 parsed_function().default_parameter_values().At( |
| 877 param_pos - num_fixed_params)); | 885 param_pos - num_fixed_params)); |
| 878 __ LoadObject(T3, value); | 886 __ LoadObject(T3, value); |
| 879 __ Bind(&assign_optional_parameter); | 887 __ Bind(&assign_optional_parameter); |
| 880 // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos]. | 888 // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 881 // We do not use the final allocation index of the variable here, i.e. | 889 // We do not use the final allocation index of the variable here, i.e. |
| 882 // scope->VariableAt(i)->index(), because captured variables still need | 890 // scope->VariableAt(i)->index(), because captured variables still need |
| 883 // to be copied to the context that is not yet allocated. | 891 // to be copied to the context that is not yet allocated. |
| 884 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 892 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 885 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 893 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 899 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 907 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 900 __ SmiUntag(T2); | 908 __ SmiUntag(T2); |
| 901 for (int i = 0; i < num_opt_pos_params; i++) { | 909 for (int i = 0; i < num_opt_pos_params; i++) { |
| 902 Label next_parameter; | 910 Label next_parameter; |
| 903 // Handle this optional positional parameter only if k or fewer positional | 911 // Handle this optional positional parameter only if k or fewer positional |
| 904 // arguments have been passed, where k is param_pos, the position of this | 912 // arguments have been passed, where k is param_pos, the position of this |
| 905 // optional parameter in the formal parameter list. | 913 // optional parameter in the formal parameter list. |
| 906 const int param_pos = num_fixed_params + i; | 914 const int param_pos = num_fixed_params + i; |
| 907 __ BranchSignedGreater(T2, Immediate(param_pos), &next_parameter); | 915 __ BranchSignedGreater(T2, Immediate(param_pos), &next_parameter); |
| 908 // Load T3 with default argument. | 916 // Load T3 with default argument. |
| 909 const Object& value = Object::ZoneHandle( | 917 const Object& value = Object::ZoneHandle(zone(), |
| 910 parsed_function().default_parameter_values().At(i)); | 918 parsed_function().default_parameter_values().At(i)); |
| 911 __ LoadObject(T3, value); | 919 __ LoadObject(T3, value); |
| 912 // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos]. | 920 // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos]. |
| 913 // We do not use the final allocation index of the variable here, i.e. | 921 // We do not use the final allocation index of the variable here, i.e. |
| 914 // scope->VariableAt(i)->index(), because captured variables still need | 922 // scope->VariableAt(i)->index(), because captured variables still need |
| 915 // to be copied to the context that is not yet allocated. | 923 // to be copied to the context that is not yet allocated. |
| 916 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 924 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 917 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 925 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| 918 __ Bind(&next_parameter); | 926 __ Bind(&next_parameter); |
| 919 } | 927 } |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 } | 1221 } |
| 1214 } | 1222 } |
| 1215 | 1223 |
| 1216 | 1224 |
| 1217 void FlowGraphCompiler::EmitEdgeCounter() { | 1225 void FlowGraphCompiler::EmitEdgeCounter() { |
| 1218 // We do not check for overflow when incrementing the edge counter. The | 1226 // We do not check for overflow when incrementing the edge counter. The |
| 1219 // function should normally be optimized long before the counter can | 1227 // function should normally be optimized long before the counter can |
| 1220 // overflow; and though we do not reset the counters when we optimize or | 1228 // overflow; and though we do not reset the counters when we optimize or |
| 1221 // deoptimize, there is a bound on the number of | 1229 // deoptimize, there is a bound on the number of |
| 1222 // optimization/deoptimization cycles we will attempt. | 1230 // optimization/deoptimization cycles we will attempt. |
| 1223 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1231 const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld)); |
| 1224 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1232 counter.SetAt(0, Smi::Handle(zone(), Smi::New(0))); |
| 1225 __ Comment("Edge counter"); | 1233 __ Comment("Edge counter"); |
| 1226 __ LoadUniqueObject(T0, counter); | 1234 __ LoadUniqueObject(T0, counter); |
| 1227 __ lw(T1, FieldAddress(T0, Array::element_offset(0))); | 1235 __ lw(T1, FieldAddress(T0, Array::element_offset(0))); |
| 1228 __ AddImmediate(T1, T1, Smi::RawValue(1)); | 1236 __ AddImmediate(T1, T1, Smi::RawValue(1)); |
| 1229 __ sw(T1, FieldAddress(T0, Array::element_offset(0))); | 1237 __ sw(T1, FieldAddress(T0, Array::element_offset(0))); |
| 1230 } | 1238 } |
| 1231 | 1239 |
| 1232 | 1240 |
| 1233 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1241 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1234 ExternalLabel* target_label, | 1242 ExternalLabel* target_label, |
| 1235 const ICData& ic_data, | 1243 const ICData& ic_data, |
| 1236 intptr_t argument_count, | 1244 intptr_t argument_count, |
| 1237 intptr_t deopt_id, | 1245 intptr_t deopt_id, |
| 1238 intptr_t token_pos, | 1246 intptr_t token_pos, |
| 1239 LocationSummary* locs) { | 1247 LocationSummary* locs) { |
| 1240 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1248 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1241 // Each ICData propagated from unoptimized to optimized code contains the | 1249 // Each ICData propagated from unoptimized to optimized code contains the |
| 1242 // function that corresponds to the Dart function of that IC call. Due | 1250 // function that corresponds to the Dart function of that IC call. Due |
| 1243 // to inlining in optimized code, that function may not correspond to the | 1251 // to inlining in optimized code, that function may not correspond to the |
| 1244 // top-level function (parsed_function().function()) which could be | 1252 // top-level function (parsed_function().function()) which could be |
| 1245 // reoptimized and which counter needs to be incremented. | 1253 // reoptimized and which counter needs to be incremented. |
| 1246 // Pass the function explicitly, it is used in IC stub. | 1254 // Pass the function explicitly, it is used in IC stub. |
| 1247 __ Comment("OptimizedInstanceCall"); | 1255 __ Comment("OptimizedInstanceCall"); |
| 1248 __ LoadObject(T0, parsed_function().function()); | 1256 __ LoadObject(T0, parsed_function().function()); |
| 1249 __ LoadUniqueObject(S5, ic_data); | 1257 __ LoadUniqueObject(S5, ic_data); |
| 1250 GenerateDartCall(deopt_id, | 1258 GenerateDartCall(deopt_id, |
| 1251 token_pos, | 1259 token_pos, |
| 1252 target_label, | 1260 target_label, |
| 1253 RawPcDescriptors::kIcCall, | 1261 RawPcDescriptors::kIcCall, |
| 1254 locs); | 1262 locs); |
| 1255 __ Drop(argument_count); | 1263 __ Drop(argument_count); |
| 1256 } | 1264 } |
| 1257 | 1265 |
| 1258 | 1266 |
| 1259 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1267 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 1260 const ICData& ic_data, | 1268 const ICData& ic_data, |
| 1261 intptr_t argument_count, | 1269 intptr_t argument_count, |
| 1262 intptr_t deopt_id, | 1270 intptr_t deopt_id, |
| 1263 intptr_t token_pos, | 1271 intptr_t token_pos, |
| 1264 LocationSummary* locs) { | 1272 LocationSummary* locs) { |
| 1265 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1273 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1266 __ Comment("InstanceCall"); | 1274 __ Comment("InstanceCall"); |
| 1267 __ LoadUniqueObject(S5, ic_data); | 1275 __ LoadUniqueObject(S5, ic_data); |
| 1268 GenerateDartCall(deopt_id, | 1276 GenerateDartCall(deopt_id, |
| 1269 token_pos, | 1277 token_pos, |
| 1270 target_label, | 1278 target_label, |
| 1271 RawPcDescriptors::kIcCall, | 1279 RawPcDescriptors::kIcCall, |
| 1272 locs); | 1280 locs); |
| 1273 __ Comment("InstanceCall return"); | 1281 __ Comment("InstanceCall return"); |
| 1274 __ Drop(argument_count); | 1282 __ Drop(argument_count); |
| 1275 } | 1283 } |
| 1276 | 1284 |
| 1277 | 1285 |
| 1278 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1286 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1279 const ICData& ic_data, | 1287 const ICData& ic_data, |
| 1280 intptr_t argument_count, | 1288 intptr_t argument_count, |
| 1281 intptr_t deopt_id, | 1289 intptr_t deopt_id, |
| 1282 intptr_t token_pos, | 1290 intptr_t token_pos, |
| 1283 LocationSummary* locs) { | 1291 LocationSummary* locs) { |
| 1284 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); | 1292 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); |
| 1285 const String& name = String::Handle(ic_data.target_name()); | 1293 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1286 const Array& arguments_descriptor = | 1294 const Array& arguments_descriptor = |
| 1287 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1295 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1288 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1296 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1289 const MegamorphicCache& cache = | 1297 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1290 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1298 zone(), table->Lookup(name, arguments_descriptor)); |
| 1291 __ Comment("MegamorphicInstanceCall"); | 1299 __ Comment("MegamorphicInstanceCall"); |
| 1292 const Register receiverR = T0; | 1300 const Register receiverR = T0; |
| 1293 const Register cacheR = T1; | 1301 const Register cacheR = T1; |
| 1294 const Register targetR = T1; | 1302 const Register targetR = T1; |
| 1295 __ lw(receiverR, Address(SP, (argument_count - 1) * kWordSize)); | 1303 __ lw(receiverR, Address(SP, (argument_count - 1) * kWordSize)); |
| 1296 __ LoadObject(cacheR, cache); | 1304 __ LoadObject(cacheR, cache); |
| 1297 | 1305 |
| 1298 if (FLAG_use_megamorphic_stub) { | 1306 if (FLAG_use_megamorphic_stub) { |
| 1299 __ BranchLink(&StubCode::MegamorphicLookupLabel()); | 1307 __ BranchLink(&StubCode::MegamorphicLookupLabel()); |
| 1300 } else { | 1308 } else { |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1534 intptr_t argument_count, | 1542 intptr_t argument_count, |
| 1535 const Array& argument_names, | 1543 const Array& argument_names, |
| 1536 Label* failed, | 1544 Label* failed, |
| 1537 Label* match_found, | 1545 Label* match_found, |
| 1538 intptr_t deopt_id, | 1546 intptr_t deopt_id, |
| 1539 intptr_t token_index, | 1547 intptr_t token_index, |
| 1540 LocationSummary* locs) { | 1548 LocationSummary* locs) { |
| 1541 ASSERT(is_optimizing()); | 1549 ASSERT(is_optimizing()); |
| 1542 __ Comment("EmitTestAndCall"); | 1550 __ Comment("EmitTestAndCall"); |
| 1543 const Array& arguments_descriptor = | 1551 const Array& arguments_descriptor = |
| 1544 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1552 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
| 1545 argument_names)); | 1553 argument_names)); |
| 1546 | 1554 |
| 1547 // Load receiver into T0. | 1555 // Load receiver into T0. |
| 1548 __ LoadFromOffset(T0, SP, (argument_count - 1) * kWordSize); | 1556 __ LoadFromOffset(T0, SP, (argument_count - 1) * kWordSize); |
| 1549 __ LoadObject(S4, arguments_descriptor); | 1557 __ LoadObject(S4, arguments_descriptor); |
| 1550 | 1558 |
| 1551 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1559 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
| 1552 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1560 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
| 1553 | 1561 |
| 1554 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1562 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
| 1555 | 1563 |
| 1556 Label after_smi_test; | 1564 Label after_smi_test; |
| 1557 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 1565 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
| 1558 if (kFirstCheckIsSmi) { | 1566 if (kFirstCheckIsSmi) { |
| 1559 // Jump if receiver is not Smi. | 1567 // Jump if receiver is not Smi. |
| 1560 if (kNumChecks == 1) { | 1568 if (kNumChecks == 1) { |
| 1561 __ bne(CMPRES1, ZR, failed); | 1569 __ bne(CMPRES1, ZR, failed); |
| 1562 } else { | 1570 } else { |
| 1563 __ bne(CMPRES1, ZR, &after_smi_test); | 1571 __ bne(CMPRES1, ZR, &after_smi_test); |
| 1564 } | 1572 } |
| 1565 // Do not use the code from the function, but let the code be patched so | 1573 // Do not use the code from the function, but let the code be patched so |
| 1566 // that we can record the outgoing edges to other code. | 1574 // that we can record the outgoing edges to other code. |
| 1567 GenerateDartCall(deopt_id, | 1575 GenerateDartCall(deopt_id, |
| 1568 token_index, | 1576 token_index, |
| 1569 &StubCode::CallStaticFunctionLabel(), | 1577 &StubCode::CallStaticFunctionLabel(), |
| 1570 RawPcDescriptors::kOther, | 1578 RawPcDescriptors::kOther, |
| 1571 locs); | 1579 locs); |
| 1572 const Function& function = Function::Handle(ic_data.GetTargetAt(0)); | 1580 const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0)); |
| 1573 AddStaticCallTarget(function); | 1581 AddStaticCallTarget(function); |
| 1574 __ Drop(argument_count); | 1582 __ Drop(argument_count); |
| 1575 if (kNumChecks > 1) { | 1583 if (kNumChecks > 1) { |
| 1576 __ b(match_found); | 1584 __ b(match_found); |
| 1577 } | 1585 } |
| 1578 } else { | 1586 } else { |
| 1579 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1587 // Receiver is Smi, but Smi is not a valid class therefore fail. |
| 1580 // (Smi class must be first in the list). | 1588 // (Smi class must be first in the list). |
| 1581 __ beq(CMPRES1, ZR, failed); | 1589 __ beq(CMPRES1, ZR, failed); |
| 1582 } | 1590 } |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1858 __ AddImmediate(SP, kDoubleSize); | 1866 __ AddImmediate(SP, kDoubleSize); |
| 1859 } | 1867 } |
| 1860 | 1868 |
| 1861 | 1869 |
| 1862 #undef __ | 1870 #undef __ |
| 1863 | 1871 |
| 1864 | 1872 |
| 1865 } // namespace dart | 1873 } // namespace dart |
| 1866 | 1874 |
| 1867 #endif // defined TARGET_ARCH_MIPS | 1875 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |