| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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->AddPcMarker(Function::Handle(), slot_ix++); | 105 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
| 104 builder->AddCallerFp(slot_ix++); | 106 builder->AddCallerFp(slot_ix++); |
| 105 builder->AddReturnAddress(Function::Handle(current->code().function()), | 107 builder->AddReturnAddress(Function::Handle(zone, current->code().function()), |
| 106 deopt_id(), | 108 deopt_id(), |
| 107 slot_ix++); | 109 slot_ix++); |
| 108 | 110 |
| 109 // Emit all values that are needed for materialization as a part of the | 111 // Emit all values that are needed for materialization as a part of the |
| 110 // expression stack for the bottom-most frame. This guarantees that GC | 112 // expression stack for the bottom-most frame. This guarantees that GC |
| 111 // will be able to find them during materialization. | 113 // will be able to find them during materialization. |
| 112 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 114 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 113 | 115 |
| 114 // For the innermost environment, set outgoing arguments and the locals. | 116 // For the innermost environment, set outgoing arguments and the locals. |
| 115 for (intptr_t i = current->Length() - 1; | 117 for (intptr_t i = current->Length() - 1; |
| 116 i >= current->fixed_parameter_count(); | 118 i >= current->fixed_parameter_count(); |
| 117 i--) { | 119 i--) { |
| 118 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 120 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 119 } | 121 } |
| 120 | 122 |
| 121 Environment* previous = current; | 123 Environment* previous = current; |
| 122 current = current->outer(); | 124 current = current->outer(); |
| 123 while (current != NULL) { | 125 while (current != NULL) { |
| 124 // PP, FP, and PC. | 126 // PP, FP, and PC. |
| 125 builder->AddPp(Function::Handle(current->code().function()), slot_ix++); | 127 builder->AddPp(Function::Handle(zone, current->code().function()), |
| 126 builder->AddPcMarker(Function::Handle(previous->code().function()), | 128 slot_ix++); |
| 129 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 127 slot_ix++); | 130 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 // 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 |
| 144 // Set the locals, note that outgoing arguments are not in the environment. | 148 // Set the locals, note that outgoing arguments are not in the environment. |
| 145 for (intptr_t i = current->Length() - 1; | 149 for (intptr_t i = current->Length() - 1; |
| 146 i >= current->fixed_parameter_count(); | 150 i >= current->fixed_parameter_count(); |
| 147 i--) { | 151 i--) { |
| 148 builder->AddCopy(current->ValueAt(i), | 152 builder->AddCopy(current->ValueAt(i), |
| 149 current->LocationAt(i), | 153 current->LocationAt(i), |
| 150 slot_ix++); | 154 slot_ix++); |
| 151 } | 155 } |
| 152 | 156 |
| 153 // Iterate on the outer environment. | 157 // Iterate on the outer environment. |
| 154 previous = current; | 158 previous = current; |
| 155 current = current->outer(); | 159 current = current->outer(); |
| 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 // PC marker. | 166 // PC marker. |
| 163 builder->AddPcMarker(Function::Handle(previous->code().function()), | 167 builder->AddPcMarker(Function::Handle(zone, previous->code().function()), |
| 164 slot_ix++); | 168 slot_ix++); |
| 165 builder->AddCallerFp(slot_ix++); | 169 builder->AddCallerFp(slot_ix++); |
| 166 builder->AddCallerPc(slot_ix++); | 170 builder->AddCallerPc(slot_ix++); |
| 167 | 171 |
| 168 // For the outermost environment, set the incoming arguments. | 172 // For the outermost environment, set the incoming arguments. |
| 169 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 173 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 170 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 174 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
| 171 } | 175 } |
| 172 | 176 |
| 173 return builder->CreateDeoptInfo(deopt_table); | 177 return builder->CreateDeoptInfo(deopt_table); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 | 218 |
| 215 // Clobbers RCX. | 219 // Clobbers RCX. |
| 216 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 220 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 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 const SubtypeTestCache& type_test_cache = | 227 const SubtypeTestCache& type_test_cache = |
| 224 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 228 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 225 __ LoadUniqueObject(temp_reg, type_test_cache); | 229 __ LoadUniqueObject(temp_reg, type_test_cache); |
| 226 __ pushq(temp_reg); // Subtype test cache. | 230 __ pushq(temp_reg); // Subtype test cache. |
| 227 __ pushq(instance_reg); // Instance. | 231 __ pushq(instance_reg); // Instance. |
| 228 if (test_kind == kTestTypeOneArg) { | 232 if (test_kind == kTestTypeOneArg) { |
| 229 ASSERT(type_arguments_reg == kNoRegister); | 233 ASSERT(type_arguments_reg == kNoRegister); |
| 230 __ PushObject(Object::null_object()); | 234 __ PushObject(Object::null_object()); |
| 231 __ Call(&StubCode::Subtype1TestCacheLabel()); | 235 __ Call(&StubCode::Subtype1TestCacheLabel()); |
| 232 } else if (test_kind == kTestTypeTwoArgs) { | 236 } else if (test_kind == kTestTypeTwoArgs) { |
| 233 ASSERT(type_arguments_reg == kNoRegister); | 237 ASSERT(type_arguments_reg == kNoRegister); |
| 234 __ PushObject(Object::null_object()); | 238 __ PushObject(Object::null_object()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 256 // RAX: instance (must survive). | 260 // RAX: instance (must survive). |
| 257 // Clobbers R10. | 261 // Clobbers R10. |
| 258 RawSubtypeTestCache* | 262 RawSubtypeTestCache* |
| 259 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 263 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 260 intptr_t token_pos, | 264 intptr_t token_pos, |
| 261 const AbstractType& type, | 265 const AbstractType& type, |
| 262 Label* is_instance_lbl, | 266 Label* is_instance_lbl, |
| 263 Label* is_not_instance_lbl) { | 267 Label* is_not_instance_lbl) { |
| 264 __ Comment("InstantiatedTypeWithArgumentsTest"); | 268 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 265 ASSERT(type.IsInstantiated()); | 269 ASSERT(type.IsInstantiated()); |
| 266 const Class& type_class = Class::ZoneHandle(type.type_class()); | 270 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 267 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); | 271 ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass()); |
| 268 const Register kInstanceReg = RAX; | 272 const Register kInstanceReg = RAX; |
| 269 Error& malformed_error = Error::Handle(); | 273 Error& malformed_error = Error::Handle(zone()); |
| 270 const Type& int_type = Type::Handle(Type::IntType()); | 274 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
| 271 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); | 275 const bool smi_is_ok = int_type.IsSubtypeOf(type, &malformed_error); |
| 272 // Malformed type should have been handled at graph construction time. | 276 // Malformed type should have been handled at graph construction time. |
| 273 ASSERT(smi_is_ok || malformed_error.IsNull()); | 277 ASSERT(smi_is_ok || malformed_error.IsNull()); |
| 274 __ testq(kInstanceReg, Immediate(kSmiTagMask)); | 278 __ testq(kInstanceReg, Immediate(kSmiTagMask)); |
| 275 if (smi_is_ok) { | 279 if (smi_is_ok) { |
| 276 __ j(ZERO, is_instance_lbl); | 280 __ j(ZERO, is_instance_lbl); |
| 277 } else { | 281 } else { |
| 278 __ j(ZERO, is_not_instance_lbl); | 282 __ j(ZERO, is_not_instance_lbl); |
| 279 } | 283 } |
| 280 const intptr_t num_type_args = type_class.NumTypeArguments(); | 284 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 281 const intptr_t num_type_params = type_class.NumTypeParameters(); | 285 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 282 const intptr_t from_index = num_type_args - num_type_params; | 286 const intptr_t from_index = num_type_args - num_type_params; |
| 283 const TypeArguments& type_arguments = | 287 const TypeArguments& type_arguments = |
| 284 TypeArguments::ZoneHandle(type.arguments()); | 288 TypeArguments::ZoneHandle(zone(), type.arguments()); |
| 285 const bool is_raw_type = type_arguments.IsNull() || | 289 const bool is_raw_type = type_arguments.IsNull() || |
| 286 type_arguments.IsRaw(from_index, num_type_params); | 290 type_arguments.IsRaw(from_index, num_type_params); |
| 287 // Signature class is an instantiated parameterized type. | 291 // Signature class is an instantiated parameterized type. |
| 288 if (!type_class.IsSignatureClass()) { | 292 if (!type_class.IsSignatureClass()) { |
| 289 if (is_raw_type) { | 293 if (is_raw_type) { |
| 290 const Register kClassIdReg = R10; | 294 const Register kClassIdReg = R10; |
| 291 // dynamic type argument, check only classes. | 295 // dynamic type argument, check only classes. |
| 292 __ LoadClassId(kClassIdReg, kInstanceReg); | 296 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 293 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 297 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 294 __ j(EQUAL, is_instance_lbl); | 298 __ j(EQUAL, is_instance_lbl); |
| 295 // List is a very common case. | 299 // List is a very common case. |
| 296 if (IsListClass(type_class)) { | 300 if (IsListClass(type_class)) { |
| 297 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 301 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 298 } | 302 } |
| 299 return GenerateSubtype1TestCacheLookup( | 303 return GenerateSubtype1TestCacheLookup( |
| 300 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 304 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 301 } | 305 } |
| 302 // If one type argument only, check if type argument is Object or dynamic. | 306 // If one type argument only, check if type argument is Object or dynamic. |
| 303 if (type_arguments.Length() == 1) { | 307 if (type_arguments.Length() == 1) { |
| 304 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 308 const AbstractType& tp_argument = AbstractType::ZoneHandle(zone(), |
| 305 type_arguments.TypeAt(0)); | 309 type_arguments.TypeAt(0)); |
| 306 ASSERT(!tp_argument.IsMalformed()); | 310 ASSERT(!tp_argument.IsMalformed()); |
| 307 if (tp_argument.IsType()) { | 311 if (tp_argument.IsType()) { |
| 308 ASSERT(tp_argument.HasResolvedTypeClass()); | 312 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 309 // Check if type argument is dynamic or Object. | 313 // Check if type argument is dynamic or Object. |
| 310 const Type& object_type = Type::Handle(Type::ObjectType()); | 314 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 311 if (object_type.IsSubtypeOf(tp_argument, NULL)) { | 315 if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
| 312 // Instance class test only necessary. | 316 // Instance class test only necessary. |
| 313 return GenerateSubtype1TestCacheLookup( | 317 return GenerateSubtype1TestCacheLookup( |
| 314 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 318 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 315 } | 319 } |
| 316 } | 320 } |
| 317 } | 321 } |
| 318 } | 322 } |
| 319 // Regular subtype test cache involving instance's type arguments. | 323 // Regular subtype test cache involving instance's type arguments. |
| 320 const Register kTypeArgumentsReg = kNoRegister; | 324 const Register kTypeArgumentsReg = kNoRegister; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 345 // RAX: instance to test against (preserved). | 349 // RAX: instance to test against (preserved). |
| 346 // Clobbers R10, R13. | 350 // Clobbers R10, R13. |
| 347 // Returns true if there is a fallthrough. | 351 // Returns true if there is a fallthrough. |
| 348 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 352 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 349 intptr_t token_pos, | 353 intptr_t token_pos, |
| 350 const AbstractType& type, | 354 const AbstractType& type, |
| 351 Label* is_instance_lbl, | 355 Label* is_instance_lbl, |
| 352 Label* is_not_instance_lbl) { | 356 Label* is_not_instance_lbl) { |
| 353 __ Comment("InstantiatedTypeNoArgumentsTest"); | 357 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 354 ASSERT(type.IsInstantiated()); | 358 ASSERT(type.IsInstantiated()); |
| 355 const Class& type_class = Class::Handle(type.type_class()); | 359 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| 356 ASSERT(type_class.NumTypeArguments() == 0); | 360 ASSERT(type_class.NumTypeArguments() == 0); |
| 357 | 361 |
| 358 const Register kInstanceReg = RAX; | 362 const Register kInstanceReg = RAX; |
| 359 __ testq(kInstanceReg, Immediate(kSmiTagMask)); | 363 __ testq(kInstanceReg, Immediate(kSmiTagMask)); |
| 360 // If instance is Smi, check directly. | 364 // If instance is Smi, check directly. |
| 361 const Class& smi_class = Class::Handle(Smi::Class()); | 365 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
| 362 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 366 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), |
| 363 type_class, | 367 type_class, |
| 364 TypeArguments::Handle(), | 368 TypeArguments::Handle(zone()), |
| 365 NULL)) { | 369 NULL)) { |
| 366 __ j(ZERO, is_instance_lbl); | 370 __ j(ZERO, is_instance_lbl); |
| 367 } else { | 371 } else { |
| 368 __ j(ZERO, is_not_instance_lbl); | 372 __ j(ZERO, is_not_instance_lbl); |
| 369 } | 373 } |
| 370 // Compare if the classes are equal. | 374 // Compare if the classes are equal. |
| 371 const Register kClassIdReg = R10; | 375 const Register kClassIdReg = R10; |
| 372 __ LoadClassId(kClassIdReg, kInstanceReg); | 376 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 373 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 377 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 374 __ j(EQUAL, is_instance_lbl); | 378 __ j(EQUAL, is_instance_lbl); |
| 375 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 379 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 376 // interfaces. | 380 // interfaces. |
| 377 // Bool interface can be implemented only by core class Bool. | 381 // Bool interface can be implemented only by core class Bool. |
| 378 if (type.IsBoolType()) { | 382 if (type.IsBoolType()) { |
| 379 __ cmpl(kClassIdReg, Immediate(kBoolCid)); | 383 __ cmpl(kClassIdReg, Immediate(kBoolCid)); |
| 380 __ j(EQUAL, is_instance_lbl); | 384 __ j(EQUAL, is_instance_lbl); |
| 381 __ jmp(is_not_instance_lbl); | 385 __ jmp(is_not_instance_lbl); |
| 382 return false; | 386 return false; |
| 383 } | 387 } |
| 384 if (type.IsFunctionType()) { | 388 if (type.IsFunctionType()) { |
| 385 // Check if instance is a closure. | 389 // Check if instance is a closure. |
| 386 __ LoadClassById(R13, kClassIdReg); | 390 __ LoadClassById(R13, kClassIdReg); |
| 387 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); | 391 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); |
| 388 __ CompareObject(R13, Object::null_object()); | 392 __ CompareObject(R13, Object::null_object()); |
| 389 __ j(NOT_EQUAL, is_instance_lbl); | 393 __ j(NOT_EQUAL, is_instance_lbl); |
| 390 } | 394 } |
| 391 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 395 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 392 // Note that instance is not Smi (checked above). | 396 // Note that instance is not Smi (checked above). |
| 393 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 397 if (type.IsSubtypeOf(Type::Handle(zone(), Type::Number()), NULL)) { |
| 394 GenerateNumberTypeCheck( | 398 GenerateNumberTypeCheck( |
| 395 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 399 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 396 return false; | 400 return false; |
| 397 } | 401 } |
| 398 if (type.IsStringType()) { | 402 if (type.IsStringType()) { |
| 399 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 403 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 400 return false; | 404 return false; |
| 401 } | 405 } |
| 402 // Otherwise fallthrough. | 406 // Otherwise fallthrough. |
| 403 return true; | 407 return true; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 // Load instantiator (or null) and instantiator type arguments on stack. | 457 // Load instantiator (or null) and instantiator type arguments on stack. |
| 454 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 458 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 455 // RDX: instantiator type arguments. | 459 // RDX: instantiator type arguments. |
| 456 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 460 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 457 __ CompareObject(RDX, Object::null_object()); | 461 __ CompareObject(RDX, Object::null_object()); |
| 458 __ j(EQUAL, is_instance_lbl); | 462 __ j(EQUAL, is_instance_lbl); |
| 459 __ movq(RDI, | 463 __ movq(RDI, |
| 460 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); | 464 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); |
| 461 // RDI: Concrete type of type. | 465 // RDI: Concrete type of type. |
| 462 // Check if type argument is dynamic. | 466 // Check if type argument is dynamic. |
| 463 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); | 467 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::DynamicType())); |
| 464 __ j(EQUAL, is_instance_lbl); | 468 __ j(EQUAL, is_instance_lbl); |
| 465 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | 469 const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType()); |
| 466 __ CompareObject(RDI, object_type); | 470 __ CompareObject(RDI, object_type); |
| 467 __ j(EQUAL, is_instance_lbl); | 471 __ j(EQUAL, is_instance_lbl); |
| 468 | 472 |
| 469 // For Smi check quickly against int and num interfaces. | 473 // For Smi check quickly against int and num interfaces. |
| 470 Label not_smi; | 474 Label not_smi; |
| 471 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? | 475 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 472 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 476 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 473 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType())); | 477 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType())); |
| 474 __ j(EQUAL, is_instance_lbl); | 478 __ j(EQUAL, is_instance_lbl); |
| 475 __ CompareObject(RDI, Type::ZoneHandle(Type::Number())); | 479 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number())); |
| 476 __ j(EQUAL, is_instance_lbl); | 480 __ j(EQUAL, is_instance_lbl); |
| 477 // Smi must be handled in runtime. | 481 // Smi must be handled in runtime. |
| 478 Label fall_through; | 482 Label fall_through; |
| 479 __ jmp(&fall_through); | 483 __ jmp(&fall_through); |
| 480 | 484 |
| 481 __ Bind(¬_smi); | 485 __ Bind(¬_smi); |
| 482 // RDX: instantiator type arguments. | 486 // RDX: instantiator type arguments. |
| 483 // RAX: instance. | 487 // RAX: instance. |
| 484 const Register kInstanceReg = RAX; | 488 const Register kInstanceReg = RAX; |
| 485 const Register kTypeArgumentsReg = RDX; | 489 const Register kTypeArgumentsReg = RDX; |
| 486 const Register kTempReg = R10; | 490 const Register kTempReg = R10; |
| 487 const SubtypeTestCache& type_test_cache = | 491 const SubtypeTestCache& type_test_cache = |
| 488 SubtypeTestCache::ZoneHandle( | 492 SubtypeTestCache::ZoneHandle(zone(), |
| 489 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 493 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 490 kInstanceReg, | 494 kInstanceReg, |
| 491 kTypeArgumentsReg, | 495 kTypeArgumentsReg, |
| 492 kTempReg, | 496 kTempReg, |
| 493 is_instance_lbl, | 497 is_instance_lbl, |
| 494 is_not_instance_lbl)); | 498 is_not_instance_lbl)); |
| 495 __ Bind(&fall_through); | 499 __ Bind(&fall_through); |
| 496 return type_test_cache.raw(); | 500 return type_test_cache.raw(); |
| 497 } | 501 } |
| 498 if (type.IsType()) { | 502 if (type.IsType()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 529 const AbstractType& type, | 533 const AbstractType& type, |
| 530 Label* is_instance_lbl, | 534 Label* is_instance_lbl, |
| 531 Label* is_not_instance_lbl) { | 535 Label* is_not_instance_lbl) { |
| 532 __ Comment("InlineInstanceof"); | 536 __ Comment("InlineInstanceof"); |
| 533 if (type.IsVoidType()) { | 537 if (type.IsVoidType()) { |
| 534 // A non-null value is returned from a void function, which will result in a | 538 // A non-null value is returned from a void function, which will result in a |
| 535 // type error. A null value is handled prior to executing this inline code. | 539 // type error. A null value is handled prior to executing this inline code. |
| 536 return SubtypeTestCache::null(); | 540 return SubtypeTestCache::null(); |
| 537 } | 541 } |
| 538 if (type.IsInstantiated()) { | 542 if (type.IsInstantiated()) { |
| 539 const Class& type_class = Class::ZoneHandle(type.type_class()); | 543 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 540 // A class equality check is only applicable with a dst type of a | 544 // A class equality check is only applicable with a dst type of a |
| 541 // non-parameterized class, non-signature class, or with a raw dst type of | 545 // non-parameterized class, non-signature class, or with a raw dst type of |
| 542 // a parameterized class. | 546 // a parameterized class. |
| 543 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { | 547 if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) { |
| 544 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 548 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, |
| 545 type, | 549 type, |
| 546 is_instance_lbl, | 550 is_instance_lbl, |
| 547 is_not_instance_lbl); | 551 is_not_instance_lbl); |
| 548 // Fall through to runtime call. | 552 // Fall through to runtime call. |
| 549 } | 553 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 // return false here if the instance is null (and if the type is | 602 // return false here if the instance is null (and if the type is |
| 599 // instantiated). | 603 // instantiated). |
| 600 // We can only inline this null check if the type is instantiated at compile | 604 // We can only inline this null check if the type is instantiated at compile |
| 601 // time, since an uninstantiated type at compile time could be Object or | 605 // time, since an uninstantiated type at compile time could be Object or |
| 602 // dynamic at run time. | 606 // dynamic at run time. |
| 603 __ CompareObject(RAX, Object::null_object()); | 607 __ CompareObject(RAX, Object::null_object()); |
| 604 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 608 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
| 605 } | 609 } |
| 606 | 610 |
| 607 // Generate inline instanceof test. | 611 // Generate inline instanceof test. |
| 608 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 612 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 609 test_cache = GenerateInlineInstanceof(token_pos, type, | 613 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 610 &is_instance, &is_not_instance); | 614 &is_instance, &is_not_instance); |
| 611 | 615 |
| 612 // test_cache is null if there is no fall-through. | 616 // test_cache is null if there is no fall-through. |
| 613 Label done; | 617 Label done; |
| 614 if (!test_cache.IsNull()) { | 618 if (!test_cache.IsNull()) { |
| 615 // Generate runtime call. | 619 // Generate runtime call. |
| 616 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 620 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 617 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 621 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 618 __ PushObject(Object::null_object()); // Make room for the result. | 622 __ PushObject(Object::null_object()); // Make room for the result. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 // We should never return here. | 701 // We should never return here. |
| 698 __ int3(); | 702 __ int3(); |
| 699 | 703 |
| 700 __ Bind(&is_assignable); // For a null object. | 704 __ Bind(&is_assignable); // For a null object. |
| 701 __ popq(RDX); // Remove pushed instantiator type arguments. | 705 __ popq(RDX); // Remove pushed instantiator type arguments. |
| 702 __ popq(RCX); // Remove pushed instantiator. | 706 __ popq(RCX); // Remove pushed instantiator. |
| 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 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 716 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 713 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 717 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 714 __ PushObject(Object::null_object()); // Make room for the result. | 718 __ PushObject(Object::null_object()); // Make room for the result. |
| 715 __ pushq(RAX); // Push the source object. | 719 __ pushq(RAX); // 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 __ pushq(RCX); // Instantiator. | 721 __ pushq(RCX); // Instantiator. |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 // RAX is arg_pos as Smi. | 866 // RAX is arg_pos as Smi. |
| 863 // Point to next named entry. | 867 // Point to next named entry. |
| 864 __ AddImmediate( | 868 __ AddImmediate( |
| 865 RDI, Immediate(ArgumentsDescriptor::named_entry_size())); | 869 RDI, Immediate(ArgumentsDescriptor::named_entry_size())); |
| 866 __ negq(RAX); | 870 __ negq(RAX); |
| 867 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. | 871 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
| 868 __ movq(RAX, argument_addr); | 872 __ movq(RAX, argument_addr); |
| 869 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 873 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 870 __ Bind(&load_default_value); | 874 __ Bind(&load_default_value); |
| 871 // Load RAX with default argument. | 875 // Load RAX with default argument. |
| 872 const Object& value = Object::ZoneHandle( | 876 const Object& value = Object::ZoneHandle(zone(), |
| 873 parsed_function().default_parameter_values().At( | 877 parsed_function().default_parameter_values().At( |
| 874 param_pos - num_fixed_params)); | 878 param_pos - num_fixed_params)); |
| 875 __ LoadObject(RAX, value); | 879 __ LoadObject(RAX, value); |
| 876 __ Bind(&assign_optional_parameter); | 880 __ Bind(&assign_optional_parameter); |
| 877 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. | 881 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| 878 // We do not use the final allocation index of the variable here, i.e. | 882 // We do not use the final allocation index of the variable here, i.e. |
| 879 // scope->VariableAt(i)->index(), because captured variables still need | 883 // scope->VariableAt(i)->index(), because captured variables still need |
| 880 // to be copied to the context that is not yet allocated. | 884 // to be copied to the context that is not yet allocated. |
| 881 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 885 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 882 const Address param_addr(RBP, computed_param_pos * kWordSize); | 886 const Address param_addr(RBP, computed_param_pos * kWordSize); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 898 __ SmiUntag(RCX); | 902 __ SmiUntag(RCX); |
| 899 for (int i = 0; i < num_opt_pos_params; i++) { | 903 for (int i = 0; i < num_opt_pos_params; i++) { |
| 900 Label next_parameter; | 904 Label next_parameter; |
| 901 // Handle this optional positional parameter only if k or fewer positional | 905 // Handle this optional positional parameter only if k or fewer positional |
| 902 // arguments have been passed, where k is param_pos, the position of this | 906 // arguments have been passed, where k is param_pos, the position of this |
| 903 // optional parameter in the formal parameter list. | 907 // optional parameter in the formal parameter list. |
| 904 const int param_pos = num_fixed_params + i; | 908 const int param_pos = num_fixed_params + i; |
| 905 __ CompareImmediate(RCX, Immediate(param_pos)); | 909 __ CompareImmediate(RCX, Immediate(param_pos)); |
| 906 __ j(GREATER, &next_parameter, Assembler::kNearJump); | 910 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 907 // Load RAX with default argument. | 911 // Load RAX with default argument. |
| 908 const Object& value = Object::ZoneHandle( | 912 const Object& value = Object::ZoneHandle(zone(), |
| 909 parsed_function().default_parameter_values().At(i)); | 913 parsed_function().default_parameter_values().At(i)); |
| 910 __ LoadObject(RAX, value); | 914 __ LoadObject(RAX, value); |
| 911 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. | 915 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| 912 // We do not use the final allocation index of the variable here, i.e. | 916 // We do not use the final allocation index of the variable here, i.e. |
| 913 // scope->VariableAt(i)->index(), because captured variables still need | 917 // scope->VariableAt(i)->index(), because captured variables still need |
| 914 // to be copied to the context that is not yet allocated. | 918 // to be copied to the context that is not yet allocated. |
| 915 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 919 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 916 const Address param_addr(RBP, computed_param_pos * kWordSize); | 920 const Address param_addr(RBP, computed_param_pos * kWordSize); |
| 917 __ movq(param_addr, RAX); | 921 __ movq(param_addr, RAX); |
| 918 __ Bind(&next_parameter); | 922 __ Bind(&next_parameter); |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1238 } | 1242 } |
| 1239 | 1243 |
| 1240 | 1244 |
| 1241 void FlowGraphCompiler::EmitEdgeCounter() { | 1245 void FlowGraphCompiler::EmitEdgeCounter() { |
| 1242 // We do not check for overflow when incrementing the edge counter. The | 1246 // We do not check for overflow when incrementing the edge counter. The |
| 1243 // function should normally be optimized long before the counter can | 1247 // function should normally be optimized long before the counter can |
| 1244 // overflow; and though we do not reset the counters when we optimize or | 1248 // overflow; and though we do not reset the counters when we optimize or |
| 1245 // deoptimize, there is a bound on the number of | 1249 // deoptimize, there is a bound on the number of |
| 1246 // optimization/deoptimization cycles we will attempt. | 1250 // optimization/deoptimization cycles we will attempt. |
| 1247 ASSERT(assembler_->constant_pool_allowed()); | 1251 ASSERT(assembler_->constant_pool_allowed()); |
| 1248 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1252 const Array& counter = Array::ZoneHandle(zone(), Array::New(1, Heap::kOld)); |
| 1249 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1253 counter.SetAt(0, Smi::Handle(zone(), Smi::New(0))); |
| 1250 __ Comment("Edge counter"); | 1254 __ Comment("Edge counter"); |
| 1251 __ LoadUniqueObject(RAX, counter); | 1255 __ LoadUniqueObject(RAX, counter); |
| 1252 intptr_t increment_start = assembler_->CodeSize(); | 1256 intptr_t increment_start = assembler_->CodeSize(); |
| 1253 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(0)), 1); | 1257 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(0)), 1); |
| 1254 int32_t size = assembler_->CodeSize() - increment_start; | 1258 int32_t size = assembler_->CodeSize() - increment_start; |
| 1255 if (isolate()->edge_counter_increment_size() == -1) { | 1259 if (isolate()->edge_counter_increment_size() == -1) { |
| 1256 isolate()->set_edge_counter_increment_size(size); | 1260 isolate()->set_edge_counter_increment_size(size); |
| 1257 } else { | 1261 } else { |
| 1258 ASSERT(size == isolate()->edge_counter_increment_size()); | 1262 ASSERT(size == isolate()->edge_counter_increment_size()); |
| 1259 } | 1263 } |
| 1260 } | 1264 } |
| 1261 | 1265 |
| 1262 | 1266 |
| 1263 int32_t FlowGraphCompiler::EdgeCounterIncrementSizeInBytes() { | 1267 int32_t FlowGraphCompiler::EdgeCounterIncrementSizeInBytes() { |
| 1264 const int32_t size = Isolate::Current()->edge_counter_increment_size(); | 1268 const int32_t size = Isolate::Current()->edge_counter_increment_size(); |
| 1265 ASSERT(size != -1); | 1269 ASSERT(size != -1); |
| 1266 return size; | 1270 return size; |
| 1267 } | 1271 } |
| 1268 | 1272 |
| 1269 | 1273 |
| 1270 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1274 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1271 ExternalLabel* target_label, | 1275 ExternalLabel* target_label, |
| 1272 const ICData& ic_data, | 1276 const ICData& ic_data, |
| 1273 intptr_t argument_count, | 1277 intptr_t argument_count, |
| 1274 intptr_t deopt_id, | 1278 intptr_t deopt_id, |
| 1275 intptr_t token_pos, | 1279 intptr_t token_pos, |
| 1276 LocationSummary* locs) { | 1280 LocationSummary* locs) { |
| 1277 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1281 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1278 // Each ICData propagated from unoptimized to optimized code contains the | 1282 // Each ICData propagated from unoptimized to optimized code contains the |
| 1279 // function that corresponds to the Dart function of that IC call. Due | 1283 // function that corresponds to the Dart function of that IC call. Due |
| 1280 // to inlining in optimized code, that function may not correspond to the | 1284 // to inlining in optimized code, that function may not correspond to the |
| 1281 // top-level function (parsed_function().function()) which could be | 1285 // top-level function (parsed_function().function()) which could be |
| 1282 // reoptimized and which counter needs to be incremented. | 1286 // reoptimized and which counter needs to be incremented. |
| 1283 // Pass the function explicitly, it is used in IC stub. | 1287 // Pass the function explicitly, it is used in IC stub. |
| 1284 __ LoadObject(RDI, parsed_function().function()); | 1288 __ LoadObject(RDI, parsed_function().function()); |
| 1285 __ LoadUniqueObject(RBX, ic_data); | 1289 __ LoadUniqueObject(RBX, ic_data); |
| 1286 GenerateDartCall(deopt_id, | 1290 GenerateDartCall(deopt_id, |
| 1287 token_pos, | 1291 token_pos, |
| 1288 target_label, | 1292 target_label, |
| 1289 RawPcDescriptors::kIcCall, | 1293 RawPcDescriptors::kIcCall, |
| 1290 locs); | 1294 locs); |
| 1291 __ Drop(argument_count, RCX); | 1295 __ Drop(argument_count, RCX); |
| 1292 } | 1296 } |
| 1293 | 1297 |
| 1294 | 1298 |
| 1295 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1299 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 1296 const ICData& ic_data, | 1300 const ICData& ic_data, |
| 1297 intptr_t argument_count, | 1301 intptr_t argument_count, |
| 1298 intptr_t deopt_id, | 1302 intptr_t deopt_id, |
| 1299 intptr_t token_pos, | 1303 intptr_t token_pos, |
| 1300 LocationSummary* locs) { | 1304 LocationSummary* locs) { |
| 1301 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1305 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1302 __ LoadUniqueObject(RBX, ic_data); | 1306 __ LoadUniqueObject(RBX, ic_data); |
| 1303 GenerateDartCall(deopt_id, | 1307 GenerateDartCall(deopt_id, |
| 1304 token_pos, | 1308 token_pos, |
| 1305 target_label, | 1309 target_label, |
| 1306 RawPcDescriptors::kIcCall, | 1310 RawPcDescriptors::kIcCall, |
| 1307 locs); | 1311 locs); |
| 1308 __ Drop(argument_count, RCX); | 1312 __ Drop(argument_count, RCX); |
| 1309 } | 1313 } |
| 1310 | 1314 |
| 1311 | 1315 |
| 1312 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1316 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1313 const ICData& ic_data, | 1317 const ICData& ic_data, |
| 1314 intptr_t argument_count, | 1318 intptr_t argument_count, |
| 1315 intptr_t deopt_id, | 1319 intptr_t deopt_id, |
| 1316 intptr_t token_pos, | 1320 intptr_t token_pos, |
| 1317 LocationSummary* locs) { | 1321 LocationSummary* locs) { |
| 1318 MegamorphicCacheTable* table = isolate()->megamorphic_cache_table(); | 1322 MegamorphicCacheTable* table = isolate()->megamorphic_cache_table(); |
| 1319 const String& name = String::Handle(ic_data.target_name()); | 1323 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1320 const Array& arguments_descriptor = | 1324 const Array& arguments_descriptor = |
| 1321 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1325 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1322 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1326 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1323 const MegamorphicCache& cache = | 1327 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1324 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1328 zone(), table->Lookup(name, arguments_descriptor)); |
| 1325 const Register receiverR = RDI; | 1329 const Register receiverR = RDI; |
| 1326 const Register cacheR = RBX; | 1330 const Register cacheR = RBX; |
| 1327 const Register targetR = RCX; | 1331 const Register targetR = RCX; |
| 1328 __ movq(receiverR, Address(RSP, (argument_count - 1) * kWordSize)); | 1332 __ movq(receiverR, Address(RSP, (argument_count - 1) * kWordSize)); |
| 1329 __ LoadObject(cacheR, cache); | 1333 __ LoadObject(cacheR, cache); |
| 1330 | 1334 |
| 1331 if (FLAG_use_megamorphic_stub) { | 1335 if (FLAG_use_megamorphic_stub) { |
| 1332 __ call(&StubCode::MegamorphicLookupLabel()); | 1336 __ call(&StubCode::MegamorphicLookupLabel()); |
| 1333 } else { | 1337 } else { |
| 1334 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); | 1338 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1475 const Array& argument_names, | 1479 const Array& argument_names, |
| 1476 Label* failed, | 1480 Label* failed, |
| 1477 Label* match_found, | 1481 Label* match_found, |
| 1478 intptr_t deopt_id, | 1482 intptr_t deopt_id, |
| 1479 intptr_t token_index, | 1483 intptr_t token_index, |
| 1480 LocationSummary* locs) { | 1484 LocationSummary* locs) { |
| 1481 ASSERT(is_optimizing()); | 1485 ASSERT(is_optimizing()); |
| 1482 | 1486 |
| 1483 __ Comment("EmitTestAndCall"); | 1487 __ Comment("EmitTestAndCall"); |
| 1484 const Array& arguments_descriptor = | 1488 const Array& arguments_descriptor = |
| 1485 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1489 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
| 1486 argument_names)); | 1490 argument_names)); |
| 1487 // Load receiver into RAX. | 1491 // Load receiver into RAX. |
| 1488 __ movq(RAX, | 1492 __ movq(RAX, |
| 1489 Address(RSP, (argument_count - 1) * kWordSize)); | 1493 Address(RSP, (argument_count - 1) * kWordSize)); |
| 1490 __ LoadObject(R10, arguments_descriptor); | 1494 __ LoadObject(R10, arguments_descriptor); |
| 1491 | 1495 |
| 1492 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1496 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
| 1493 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1497 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
| 1494 | 1498 |
| 1495 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1499 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
| 1496 | 1500 |
| 1497 Label after_smi_test; | 1501 Label after_smi_test; |
| 1498 __ testq(RAX, Immediate(kSmiTagMask)); | 1502 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1499 if (kFirstCheckIsSmi) { | 1503 if (kFirstCheckIsSmi) { |
| 1500 // Jump if receiver is not Smi. | 1504 // Jump if receiver is not Smi. |
| 1501 if (kNumChecks == 1) { | 1505 if (kNumChecks == 1) { |
| 1502 __ j(NOT_ZERO, failed); | 1506 __ j(NOT_ZERO, failed); |
| 1503 } else { | 1507 } else { |
| 1504 __ j(NOT_ZERO, &after_smi_test); | 1508 __ j(NOT_ZERO, &after_smi_test); |
| 1505 } | 1509 } |
| 1506 // Do not use the code from the function, but let the code be patched so | 1510 // Do not use the code from the function, but let the code be patched so |
| 1507 // that we can record the outgoing edges to other code. | 1511 // that we can record the outgoing edges to other code. |
| 1508 GenerateDartCall(deopt_id, | 1512 GenerateDartCall(deopt_id, |
| 1509 token_index, | 1513 token_index, |
| 1510 &StubCode::CallStaticFunctionLabel(), | 1514 &StubCode::CallStaticFunctionLabel(), |
| 1511 RawPcDescriptors::kOther, | 1515 RawPcDescriptors::kOther, |
| 1512 locs); | 1516 locs); |
| 1513 const Function& function = Function::Handle(ic_data.GetTargetAt(0)); | 1517 const Function& function = Function::Handle(zone(), ic_data.GetTargetAt(0)); |
| 1514 AddStaticCallTarget(function); | 1518 AddStaticCallTarget(function); |
| 1515 __ Drop(argument_count, RCX); | 1519 __ Drop(argument_count, RCX); |
| 1516 if (kNumChecks > 1) { | 1520 if (kNumChecks > 1) { |
| 1517 __ jmp(match_found); | 1521 __ jmp(match_found); |
| 1518 } | 1522 } |
| 1519 } else { | 1523 } else { |
| 1520 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1524 // Receiver is Smi, but Smi is not a valid class therefore fail. |
| 1521 // (Smi class must be first in the list). | 1525 // (Smi class must be first in the list). |
| 1522 __ j(ZERO, failed); | 1526 __ j(ZERO, failed); |
| 1523 } | 1527 } |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1793 __ movups(reg, Address(RSP, 0)); | 1797 __ movups(reg, Address(RSP, 0)); |
| 1794 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); | 1798 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); |
| 1795 } | 1799 } |
| 1796 | 1800 |
| 1797 | 1801 |
| 1798 #undef __ | 1802 #undef __ |
| 1799 | 1803 |
| 1800 } // namespace dart | 1804 } // namespace dart |
| 1801 | 1805 |
| 1802 #endif // defined TARGET_ARCH_X64 | 1806 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |