| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 bool FlowGraphCompiler::SupportsUnboxedMints() { | 45 bool FlowGraphCompiler::SupportsUnboxedMints() { |
| 46 return FLAG_unbox_mints; | 46 return FLAG_unbox_mints; |
| 47 } | 47 } |
| 48 | 48 |
| 49 | 49 |
| 50 bool FlowGraphCompiler::SupportsUnboxedSimd128() { | 50 bool FlowGraphCompiler::SupportsUnboxedSimd128() { |
| 51 return FLAG_enable_simd_inline; | 51 return FLAG_enable_simd_inline; |
| 52 } | 52 } |
| 53 | 53 |
| 54 | 54 |
| 55 | |
| 56 bool FlowGraphCompiler::SupportsSinCos() { | 55 bool FlowGraphCompiler::SupportsSinCos() { |
| 57 return true; | 56 return true; |
| 58 } | 57 } |
| 59 | 58 |
| 60 | 59 |
| 61 bool FlowGraphCompiler::SupportsHardwareDivision() { | 60 bool FlowGraphCompiler::SupportsHardwareDivision() { |
| 62 return true; | 61 return true; |
| 63 } | 62 } |
| 64 | 63 |
| 65 | 64 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 builder->AddCallerFp(slot_ix++); | 108 builder->AddCallerFp(slot_ix++); |
| 110 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 109 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
| 111 | 110 |
| 112 // 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 |
| 113 // expression stack for the bottom-most frame. This guarantees that GC | 112 // expression stack for the bottom-most frame. This guarantees that GC |
| 114 // will be able to find them during materialization. | 113 // will be able to find them during materialization. |
| 115 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 114 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 116 | 115 |
| 117 // For the innermost environment, set outgoing arguments and the locals. | 116 // For the innermost environment, set outgoing arguments and the locals. |
| 118 for (intptr_t i = current->Length() - 1; | 117 for (intptr_t i = current->Length() - 1; |
| 119 i >= current->fixed_parameter_count(); | 118 i >= current->fixed_parameter_count(); i--) { |
| 120 i--) { | |
| 121 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 119 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 122 } | 120 } |
| 123 | 121 |
| 124 Environment* previous = current; | 122 Environment* previous = current; |
| 125 current = current->outer(); | 123 current = current->outer(); |
| 126 while (current != NULL) { | 124 while (current != NULL) { |
| 127 builder->AddPp(current->function(), slot_ix++); | 125 builder->AddPp(current->function(), slot_ix++); |
| 128 builder->AddPcMarker(previous->function(), slot_ix++); | 126 builder->AddPcMarker(previous->function(), slot_ix++); |
| 129 builder->AddCallerFp(slot_ix++); | 127 builder->AddCallerFp(slot_ix++); |
| 130 | 128 |
| 131 // 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 |
| 132 // which is recorded in the outer environment. | 130 // which is recorded in the outer environment. |
| 133 builder->AddReturnAddress( | 131 builder->AddReturnAddress(current->function(), |
| 134 current->function(), | 132 Thread::ToDeoptAfter(current->deopt_id()), |
| 135 Thread::ToDeoptAfter(current->deopt_id()), | 133 slot_ix++); |
| 136 slot_ix++); | |
| 137 | 134 |
| 138 // The values of outgoing arguments can be changed from the inlined call so | 135 // The values of outgoing arguments can be changed from the inlined call so |
| 139 // we must read them from the previous environment. | 136 // we must read them from the previous environment. |
| 140 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 137 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 141 builder->AddCopy(previous->ValueAt(i), | 138 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), |
| 142 previous->LocationAt(i), | |
| 143 slot_ix++); | 139 slot_ix++); |
| 144 } | 140 } |
| 145 | 141 |
| 146 // Set the locals, note that outgoing arguments are not in the environment. | 142 // Set the locals, note that outgoing arguments are not in the environment. |
| 147 for (intptr_t i = current->Length() - 1; | 143 for (intptr_t i = current->Length() - 1; |
| 148 i >= current->fixed_parameter_count(); | 144 i >= current->fixed_parameter_count(); i--) { |
| 149 i--) { | 145 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 150 builder->AddCopy(current->ValueAt(i), | |
| 151 current->LocationAt(i), | |
| 152 slot_ix++); | |
| 153 } | 146 } |
| 154 | 147 |
| 155 // Iterate on the outer environment. | 148 // Iterate on the outer environment. |
| 156 previous = current; | 149 previous = current; |
| 157 current = current->outer(); | 150 current = current->outer(); |
| 158 } | 151 } |
| 159 // The previous pointer is now the outermost environment. | 152 // The previous pointer is now the outermost environment. |
| 160 ASSERT(previous != NULL); | 153 ASSERT(previous != NULL); |
| 161 | 154 |
| 162 // Set slots for the outermost environment. | 155 // Set slots for the outermost environment. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 210 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 218 TypeTestStubKind test_kind, | 211 TypeTestStubKind test_kind, |
| 219 Register instance_reg, | 212 Register instance_reg, |
| 220 Register type_arguments_reg, | 213 Register type_arguments_reg, |
| 221 Register temp_reg, | 214 Register temp_reg, |
| 222 Label* is_instance_lbl, | 215 Label* is_instance_lbl, |
| 223 Label* is_not_instance_lbl) { | 216 Label* is_not_instance_lbl) { |
| 224 const SubtypeTestCache& type_test_cache = | 217 const SubtypeTestCache& type_test_cache = |
| 225 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 218 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 226 __ LoadUniqueObject(temp_reg, type_test_cache); | 219 __ LoadUniqueObject(temp_reg, type_test_cache); |
| 227 __ pushq(temp_reg); // Subtype test cache. | 220 __ pushq(temp_reg); // Subtype test cache. |
| 228 __ pushq(instance_reg); // Instance. | 221 __ pushq(instance_reg); // Instance. |
| 229 if (test_kind == kTestTypeOneArg) { | 222 if (test_kind == kTestTypeOneArg) { |
| 230 ASSERT(type_arguments_reg == kNoRegister); | 223 ASSERT(type_arguments_reg == kNoRegister); |
| 231 __ PushObject(Object::null_object()); | 224 __ PushObject(Object::null_object()); |
| 232 __ Call(*StubCode::Subtype1TestCache_entry()); | 225 __ Call(*StubCode::Subtype1TestCache_entry()); |
| 233 } else if (test_kind == kTestTypeTwoArgs) { | 226 } else if (test_kind == kTestTypeTwoArgs) { |
| 234 ASSERT(type_arguments_reg == kNoRegister); | 227 ASSERT(type_arguments_reg == kNoRegister); |
| 235 __ PushObject(Object::null_object()); | 228 __ PushObject(Object::null_object()); |
| 236 __ Call(*StubCode::Subtype2TestCache_entry()); | 229 __ Call(*StubCode::Subtype2TestCache_entry()); |
| 237 } else if (test_kind == kTestTypeThreeArgs) { | 230 } else if (test_kind == kTestTypeThreeArgs) { |
| 238 __ pushq(type_arguments_reg); | 231 __ pushq(type_arguments_reg); |
| 239 __ Call(*StubCode::Subtype3TestCache_entry()); | 232 __ Call(*StubCode::Subtype3TestCache_entry()); |
| 240 } else { | 233 } else { |
| 241 UNREACHABLE(); | 234 UNREACHABLE(); |
| 242 } | 235 } |
| 243 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. | 236 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
| 244 ASSERT(instance_reg != RCX); | 237 ASSERT(instance_reg != RCX); |
| 245 ASSERT(temp_reg != RCX); | 238 ASSERT(temp_reg != RCX); |
| 246 __ popq(instance_reg); // Discard. | 239 __ popq(instance_reg); // Discard. |
| 247 __ popq(instance_reg); // Restore receiver. | 240 __ popq(instance_reg); // Restore receiver. |
| 248 __ popq(temp_reg); // Discard. | 241 __ popq(temp_reg); // Discard. |
| 249 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); | 242 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); |
| 250 return type_test_cache.raw(); | 243 return type_test_cache.raw(); |
| 251 } | 244 } |
| 252 | 245 |
| 253 | 246 |
| 254 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 247 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 255 // type test is conclusive, otherwise fallthrough if a type test could not | 248 // type test is conclusive, otherwise fallthrough if a type test could not |
| 256 // be completed. | 249 // be completed. |
| 257 // RAX: instance (must survive). | 250 // RAX: instance (must survive). |
| 258 // Clobbers R10. | 251 // Clobbers R10. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 280 __ j(ZERO, is_not_instance_lbl); | 273 __ j(ZERO, is_not_instance_lbl); |
| 281 } | 274 } |
| 282 // A function type test requires checking the function signature. | 275 // A function type test requires checking the function signature. |
| 283 if (!type.IsFunctionType()) { | 276 if (!type.IsFunctionType()) { |
| 284 const intptr_t num_type_args = type_class.NumTypeArguments(); | 277 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 285 const intptr_t num_type_params = type_class.NumTypeParameters(); | 278 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 286 const intptr_t from_index = num_type_args - num_type_params; | 279 const intptr_t from_index = num_type_args - num_type_params; |
| 287 const TypeArguments& type_arguments = | 280 const TypeArguments& type_arguments = |
| 288 TypeArguments::ZoneHandle(zone(), type.arguments()); | 281 TypeArguments::ZoneHandle(zone(), type.arguments()); |
| 289 const bool is_raw_type = type_arguments.IsNull() || | 282 const bool is_raw_type = type_arguments.IsNull() || |
| 290 type_arguments.IsRaw(from_index, num_type_params); | 283 type_arguments.IsRaw(from_index, num_type_params); |
| 291 if (is_raw_type) { | 284 if (is_raw_type) { |
| 292 const Register kClassIdReg = R10; | 285 const Register kClassIdReg = R10; |
| 293 // dynamic type argument, check only classes. | 286 // dynamic type argument, check only classes. |
| 294 __ LoadClassId(kClassIdReg, kInstanceReg); | 287 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 295 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 288 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 296 __ j(EQUAL, is_instance_lbl); | 289 __ j(EQUAL, is_instance_lbl); |
| 297 // List is a very common case. | 290 // List is a very common case. |
| 298 if (IsListClass(type_class)) { | 291 if (IsListClass(type_class)) { |
| 299 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 292 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 300 } | 293 } |
| 301 return GenerateSubtype1TestCacheLookup( | 294 return GenerateSubtype1TestCacheLookup( |
| 302 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 295 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 303 } | 296 } |
| 304 // If one type argument only, check if type argument is Object or dynamic. | 297 // If one type argument only, check if type argument is Object or dynamic. |
| 305 if (type_arguments.Length() == 1) { | 298 if (type_arguments.Length() == 1) { |
| 306 const AbstractType& tp_argument = AbstractType::ZoneHandle(zone(), | 299 const AbstractType& tp_argument = |
| 307 type_arguments.TypeAt(0)); | 300 AbstractType::ZoneHandle(zone(), type_arguments.TypeAt(0)); |
| 308 ASSERT(!tp_argument.IsMalformed()); | 301 ASSERT(!tp_argument.IsMalformed()); |
| 309 if (tp_argument.IsType()) { | 302 if (tp_argument.IsType()) { |
| 310 ASSERT(tp_argument.HasResolvedTypeClass()); | 303 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 311 // Check if type argument is dynamic or Object. | 304 // Check if type argument is dynamic or Object. |
| 312 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 305 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 313 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 306 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
| 314 // Instance class test only necessary. | 307 // Instance class test only necessary. |
| 315 return GenerateSubtype1TestCacheLookup( | 308 return GenerateSubtype1TestCacheLookup( |
| 316 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 309 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 317 } | 310 } |
| 318 } | 311 } |
| 319 } | 312 } |
| 320 } | 313 } |
| 321 // Regular subtype test cache involving instance's type arguments. | 314 // Regular subtype test cache involving instance's type arguments. |
| 322 const Register kTypeArgumentsReg = kNoRegister; | 315 const Register kTypeArgumentsReg = kNoRegister; |
| 323 const Register kTempReg = R10; | 316 const Register kTempReg = R10; |
| 324 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, | 317 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
| 325 kInstanceReg, | 318 kTypeArgumentsReg, kTempReg, |
| 326 kTypeArgumentsReg, | 319 is_instance_lbl, is_not_instance_lbl); |
| 327 kTempReg, | |
| 328 is_instance_lbl, | |
| 329 is_not_instance_lbl); | |
| 330 } | 320 } |
| 331 | 321 |
| 332 | 322 |
| 333 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 323 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 334 const GrowableArray<intptr_t>& class_ids, | 324 const GrowableArray<intptr_t>& class_ids, |
| 335 Label* is_equal_lbl, | 325 Label* is_equal_lbl, |
| 336 Label* is_not_equal_lbl) { | 326 Label* is_not_equal_lbl) { |
| 337 for (intptr_t i = 0; i < class_ids.length(); i++) { | 327 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 338 __ cmpl(class_id_reg, Immediate(class_ids[i])); | 328 __ cmpl(class_id_reg, Immediate(class_ids[i])); |
| 339 __ j(EQUAL, is_equal_lbl); | 329 __ j(EQUAL, is_equal_lbl); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 358 // Fallthrough. | 348 // Fallthrough. |
| 359 return true; | 349 return true; |
| 360 } | 350 } |
| 361 const Class& type_class = Class::Handle(zone(), type.type_class()); | 351 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| 362 ASSERT(type_class.NumTypeArguments() == 0); | 352 ASSERT(type_class.NumTypeArguments() == 0); |
| 363 | 353 |
| 364 const Register kInstanceReg = RAX; | 354 const Register kInstanceReg = RAX; |
| 365 __ testq(kInstanceReg, Immediate(kSmiTagMask)); | 355 __ testq(kInstanceReg, Immediate(kSmiTagMask)); |
| 366 // If instance is Smi, check directly. | 356 // If instance is Smi, check directly. |
| 367 const Class& smi_class = Class::Handle(zone(), Smi::Class()); | 357 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
| 368 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), | 358 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), type_class, |
| 369 type_class, | 359 TypeArguments::Handle(zone()), NULL, NULL, |
| 370 TypeArguments::Handle(zone()), | |
| 371 NULL, | |
| 372 NULL, | |
| 373 Heap::kOld)) { | 360 Heap::kOld)) { |
| 374 __ j(ZERO, is_instance_lbl); | 361 __ j(ZERO, is_instance_lbl); |
| 375 } else { | 362 } else { |
| 376 __ j(ZERO, is_not_instance_lbl); | 363 __ j(ZERO, is_not_instance_lbl); |
| 377 } | 364 } |
| 378 const Register kClassIdReg = R10; | 365 const Register kClassIdReg = R10; |
| 379 __ LoadClassId(kClassIdReg, kInstanceReg); | 366 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 380 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 367 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
| 381 // interfaces. | 368 // interfaces. |
| 382 // Bool interface can be implemented only by core class Bool. | 369 // Bool interface can be implemented only by core class Bool. |
| 383 if (type.IsBoolType()) { | 370 if (type.IsBoolType()) { |
| 384 __ cmpl(kClassIdReg, Immediate(kBoolCid)); | 371 __ cmpl(kClassIdReg, Immediate(kBoolCid)); |
| 385 __ j(EQUAL, is_instance_lbl); | 372 __ j(EQUAL, is_instance_lbl); |
| 386 __ jmp(is_not_instance_lbl); | 373 __ jmp(is_not_instance_lbl); |
| 387 return false; | 374 return false; |
| 388 } | 375 } |
| 389 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 376 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 390 // Note that instance is not Smi (checked above). | 377 // Note that instance is not Smi (checked above). |
| 391 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { | 378 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { |
| 392 GenerateNumberTypeCheck( | 379 GenerateNumberTypeCheck(kClassIdReg, type, is_instance_lbl, |
| 393 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 380 is_not_instance_lbl); |
| 394 return false; | 381 return false; |
| 395 } | 382 } |
| 396 if (type.IsStringType()) { | 383 if (type.IsStringType()) { |
| 397 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 384 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 398 return false; | 385 return false; |
| 399 } | 386 } |
| 400 if (type.IsDartFunctionType()) { | 387 if (type.IsDartFunctionType()) { |
| 401 // Check if instance is a closure. | 388 // Check if instance is a closure. |
| 402 __ cmpq(kClassIdReg, Immediate(kClosureCid)); | 389 __ cmpq(kClassIdReg, Immediate(kClosureCid)); |
| 403 __ j(EQUAL, is_instance_lbl); | 390 __ j(EQUAL, is_instance_lbl); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 430 __ LoadClass(R10, kInstanceReg); | 417 __ LoadClass(R10, kInstanceReg); |
| 431 // R10: instance class. | 418 // R10: instance class. |
| 432 // Check immediate superclass equality. | 419 // Check immediate superclass equality. |
| 433 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); | 420 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); |
| 434 __ movq(R13, FieldAddress(R13, Type::type_class_id_offset())); | 421 __ movq(R13, FieldAddress(R13, Type::type_class_id_offset())); |
| 435 __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id()))); | 422 __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id()))); |
| 436 __ j(EQUAL, is_instance_lbl); | 423 __ j(EQUAL, is_instance_lbl); |
| 437 | 424 |
| 438 const Register kTypeArgumentsReg = kNoRegister; | 425 const Register kTypeArgumentsReg = kNoRegister; |
| 439 const Register kTempReg = R10; | 426 const Register kTempReg = R10; |
| 440 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 427 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
| 441 kInstanceReg, | 428 kTypeArgumentsReg, kTempReg, |
| 442 kTypeArgumentsReg, | 429 is_instance_lbl, is_not_instance_lbl); |
| 443 kTempReg, | |
| 444 is_instance_lbl, | |
| 445 is_not_instance_lbl); | |
| 446 } | 430 } |
| 447 | 431 |
| 448 | 432 |
| 449 // Generates inlined check if 'type' is a type parameter or type itself | 433 // Generates inlined check if 'type' is a type parameter or type itself |
| 450 // RAX: instance (preserved). | 434 // RAX: instance (preserved). |
| 451 // Clobbers RDI, RDX, R10. | 435 // Clobbers RDI, RDX, R10. |
| 452 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 436 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 453 TokenPosition token_pos, | 437 TokenPosition token_pos, |
| 454 const AbstractType& type, | 438 const AbstractType& type, |
| 455 Label* is_instance_lbl, | 439 Label* is_instance_lbl, |
| 456 Label* is_not_instance_lbl) { | 440 Label* is_not_instance_lbl) { |
| 457 __ Comment("UninstantiatedTypeTest"); | 441 __ Comment("UninstantiatedTypeTest"); |
| 458 ASSERT(!type.IsInstantiated()); | 442 ASSERT(!type.IsInstantiated()); |
| 459 // Skip check if destination is a dynamic type. | 443 // Skip check if destination is a dynamic type. |
| 460 if (type.IsTypeParameter()) { | 444 if (type.IsTypeParameter()) { |
| 461 const TypeParameter& type_param = TypeParameter::Cast(type); | 445 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 462 // Load instantiator type arguments on stack. | 446 // Load instantiator type arguments on stack. |
| 463 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 447 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 464 // RDX: instantiator type arguments. | 448 // RDX: instantiator type arguments. |
| 465 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 449 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 466 __ CompareObject(RDX, Object::null_object()); | 450 __ CompareObject(RDX, Object::null_object()); |
| 467 __ j(EQUAL, is_instance_lbl); | 451 __ j(EQUAL, is_instance_lbl); |
| 468 __ movq(RDI, | 452 __ movq(RDI, FieldAddress( |
| 469 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); | 453 RDX, TypeArguments::type_at_offset(type_param.index()))); |
| 470 // RDI: Concrete type of type. | 454 // RDI: Concrete type of type. |
| 471 // Check if type argument is dynamic. | 455 // Check if type argument is dynamic. |
| 472 __ CompareObject(RDI, Object::dynamic_type()); | 456 __ CompareObject(RDI, Object::dynamic_type()); |
| 473 __ j(EQUAL, is_instance_lbl); | 457 __ j(EQUAL, is_instance_lbl); |
| 474 const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType()); | 458 const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType()); |
| 475 __ CompareObject(RDI, object_type); | 459 __ CompareObject(RDI, object_type); |
| 476 __ j(EQUAL, is_instance_lbl); | 460 __ j(EQUAL, is_instance_lbl); |
| 477 | 461 |
| 478 // For Smi check quickly against int and num interfaces. | 462 // For Smi check quickly against int and num interfaces. |
| 479 Label not_smi; | 463 Label not_smi; |
| 480 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? | 464 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 481 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 465 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 482 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType())); | 466 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType())); |
| 483 __ j(EQUAL, is_instance_lbl); | 467 __ j(EQUAL, is_instance_lbl); |
| 484 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number())); | 468 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number())); |
| 485 __ j(EQUAL, is_instance_lbl); | 469 __ j(EQUAL, is_instance_lbl); |
| 486 // Smi must be handled in runtime. | 470 // Smi must be handled in runtime. |
| 487 Label fall_through; | 471 Label fall_through; |
| 488 __ jmp(&fall_through); | 472 __ jmp(&fall_through); |
| 489 | 473 |
| 490 __ Bind(¬_smi); | 474 __ Bind(¬_smi); |
| 491 // RDX: instantiator type arguments. | 475 // RDX: instantiator type arguments. |
| 492 // RAX: instance. | 476 // RAX: instance. |
| 493 const Register kInstanceReg = RAX; | 477 const Register kInstanceReg = RAX; |
| 494 const Register kTypeArgumentsReg = RDX; | 478 const Register kTypeArgumentsReg = RDX; |
| 495 const Register kTempReg = R10; | 479 const Register kTempReg = R10; |
| 496 const SubtypeTestCache& type_test_cache = | 480 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
| 497 SubtypeTestCache::ZoneHandle(zone(), | 481 zone(), GenerateCallSubtypeTestStub( |
| 498 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 482 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, |
| 499 kInstanceReg, | 483 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
| 500 kTypeArgumentsReg, | |
| 501 kTempReg, | |
| 502 is_instance_lbl, | |
| 503 is_not_instance_lbl)); | |
| 504 __ Bind(&fall_through); | 484 __ Bind(&fall_through); |
| 505 return type_test_cache.raw(); | 485 return type_test_cache.raw(); |
| 506 } | 486 } |
| 507 if (type.IsType()) { | 487 if (type.IsType()) { |
| 508 const Register kInstanceReg = RAX; | 488 const Register kInstanceReg = RAX; |
| 509 const Register kTypeArgumentsReg = RDX; | 489 const Register kTypeArgumentsReg = RDX; |
| 510 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? | 490 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
| 511 __ j(ZERO, is_not_instance_lbl); | 491 __ j(ZERO, is_not_instance_lbl); |
| 512 __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args. | 492 __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args. |
| 513 // Uninstantiated type class is known at compile time, but the type | 493 // Uninstantiated type class is known at compile time, but the type |
| 514 // arguments are determined at runtime by the instantiator. | 494 // arguments are determined at runtime by the instantiator. |
| 515 const Register kTempReg = R10; | 495 const Register kTempReg = R10; |
| 516 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 496 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, |
| 517 kInstanceReg, | 497 kTypeArgumentsReg, kTempReg, |
| 518 kTypeArgumentsReg, | 498 is_instance_lbl, is_not_instance_lbl); |
| 519 kTempReg, | |
| 520 is_instance_lbl, | |
| 521 is_not_instance_lbl); | |
| 522 } | 499 } |
| 523 return SubtypeTestCache::null(); | 500 return SubtypeTestCache::null(); |
| 524 } | 501 } |
| 525 | 502 |
| 526 | 503 |
| 527 // Inputs: | 504 // Inputs: |
| 528 // - RAX: instance to test against (preserved). | 505 // - RAX: instance to test against (preserved). |
| 529 // - RDX: optional instantiator type arguments (preserved). | 506 // - RDX: optional instantiator type arguments (preserved). |
| 530 // Clobbers R10, R13. | 507 // Clobbers R10, R13. |
| 531 // Returns: | 508 // Returns: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 543 // A non-null value is returned from a void function, which will result in a | 520 // A non-null value is returned from a void function, which will result in a |
| 544 // type error. A null value is handled prior to executing this inline code. | 521 // type error. A null value is handled prior to executing this inline code. |
| 545 return SubtypeTestCache::null(); | 522 return SubtypeTestCache::null(); |
| 546 } | 523 } |
| 547 if (type.IsInstantiated()) { | 524 if (type.IsInstantiated()) { |
| 548 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 525 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 549 // A class equality check is only applicable with a dst type (not a | 526 // A class equality check is only applicable with a dst type (not a |
| 550 // function type) of a non-parameterized class or with a raw dst type of | 527 // function type) of a non-parameterized class or with a raw dst type of |
| 551 // a parameterized class. | 528 // a parameterized class. |
| 552 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { | 529 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { |
| 553 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 530 return GenerateInstantiatedTypeWithArgumentsTest( |
| 554 type, | 531 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
| 555 is_instance_lbl, | |
| 556 is_not_instance_lbl); | |
| 557 // Fall through to runtime call. | 532 // Fall through to runtime call. |
| 558 } | 533 } |
| 559 const bool has_fall_through = | 534 const bool has_fall_through = GenerateInstantiatedTypeNoArgumentsTest( |
| 560 GenerateInstantiatedTypeNoArgumentsTest(token_pos, | 535 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
| 561 type, | |
| 562 is_instance_lbl, | |
| 563 is_not_instance_lbl); | |
| 564 if (has_fall_through) { | 536 if (has_fall_through) { |
| 565 // If test non-conclusive so far, try the inlined type-test cache. | 537 // If test non-conclusive so far, try the inlined type-test cache. |
| 566 // 'type' is known at compile time. | 538 // 'type' is known at compile time. |
| 567 return GenerateSubtype1TestCacheLookup( | 539 return GenerateSubtype1TestCacheLookup( |
| 568 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 540 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 569 } else { | 541 } else { |
| 570 return SubtypeTestCache::null(); | 542 return SubtypeTestCache::null(); |
| 571 } | 543 } |
| 572 } | 544 } |
| 573 return GenerateUninstantiatedTypeTest(token_pos, | 545 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, |
| 574 type, | |
| 575 is_instance_lbl, | |
| 576 is_not_instance_lbl); | 546 is_not_instance_lbl); |
| 577 } | 547 } |
| 578 | 548 |
| 579 | 549 |
| 580 // If instanceof type test cannot be performed successfully at compile time and | 550 // If instanceof type test cannot be performed successfully at compile time and |
| 581 // therefore eliminated, optimize it by adding inlined tests for: | 551 // therefore eliminated, optimize it by adding inlined tests for: |
| 582 // - NULL -> return false. | 552 // - NULL -> return false. |
| 583 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 553 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 584 // - Class equality (only if class is not parameterized). | 554 // - Class equality (only if class is not parameterized). |
| 585 // Inputs: | 555 // Inputs: |
| (...skipping 20 matching lines...) Expand all Loading... |
| 606 // instantiated). | 576 // instantiated). |
| 607 // We can only inline this null check if the type is instantiated at compile | 577 // We can only inline this null check if the type is instantiated at compile |
| 608 // time, since an uninstantiated type at compile time could be Object or | 578 // time, since an uninstantiated type at compile time could be Object or |
| 609 // dynamic at run time. | 579 // dynamic at run time. |
| 610 __ CompareObject(RAX, Object::null_object()); | 580 __ CompareObject(RAX, Object::null_object()); |
| 611 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 581 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
| 612 } | 582 } |
| 613 | 583 |
| 614 // Generate inline instanceof test. | 584 // Generate inline instanceof test. |
| 615 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 585 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 616 test_cache = GenerateInlineInstanceof(token_pos, type, | 586 test_cache = |
| 617 &is_instance, &is_not_instance); | 587 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
| 618 | 588 |
| 619 // test_cache is null if there is no fall-through. | 589 // test_cache is null if there is no fall-through. |
| 620 Label done; | 590 Label done; |
| 621 if (!test_cache.IsNull()) { | 591 if (!test_cache.IsNull()) { |
| 622 // Generate runtime call. | 592 // Generate runtime call. |
| 623 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 593 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 624 __ PushObject(Object::null_object()); // Make room for the result. | 594 __ PushObject(Object::null_object()); // Make room for the result. |
| 625 __ pushq(RAX); // Push the instance. | 595 __ pushq(RAX); // Push the instance. |
| 626 __ PushObject(type); // Push the type. | 596 __ PushObject(type); // Push the type. |
| 627 __ pushq(RDX); // Instantiator type arguments. | 597 __ pushq(RDX); // Instantiator type arguments. |
| 628 __ LoadUniqueObject(RAX, test_cache); | 598 __ LoadUniqueObject(RAX, test_cache); |
| 629 __ pushq(RAX); | 599 __ pushq(RAX); |
| 630 GenerateRuntimeCall(token_pos, | 600 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
| 631 deopt_id, | |
| 632 kInstanceofRuntimeEntry, | |
| 633 4, | |
| 634 locs); | |
| 635 // Pop the parameters supplied to the runtime entry. The result of the | 601 // Pop the parameters supplied to the runtime entry. The result of the |
| 636 // instanceof runtime call will be left as the result of the operation. | 602 // instanceof runtime call will be left as the result of the operation. |
| 637 __ Drop(4); | 603 __ Drop(4); |
| 638 if (negate_result) { | 604 if (negate_result) { |
| 639 __ popq(RDX); | 605 __ popq(RDX); |
| 640 __ LoadObject(RAX, Bool::True()); | 606 __ LoadObject(RAX, Bool::True()); |
| 641 __ cmpq(RDX, RAX); | 607 __ cmpq(RDX, RAX); |
| 642 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 608 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 643 __ LoadObject(RAX, Bool::False()); | 609 __ LoadObject(RAX, Bool::False()); |
| 644 } else { | 610 } else { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 647 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 682 __ pushq(RDX); // Store instantiator type arguments. | 648 __ pushq(RDX); // Store instantiator type arguments. |
| 683 // A null object is always assignable and is returned as result. | 649 // A null object is always assignable and is returned as result. |
| 684 Label is_assignable, runtime_call; | 650 Label is_assignable, runtime_call; |
| 685 __ CompareObject(RAX, Object::null_object()); | 651 __ CompareObject(RAX, Object::null_object()); |
| 686 __ j(EQUAL, &is_assignable); | 652 __ j(EQUAL, &is_assignable); |
| 687 | 653 |
| 688 // Generate throw new TypeError() if the type is malformed or malbounded. | 654 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 689 if (dst_type.IsMalformedOrMalbounded()) { | 655 if (dst_type.IsMalformedOrMalbounded()) { |
| 690 __ PushObject(Object::null_object()); // Make room for the result. | 656 __ PushObject(Object::null_object()); // Make room for the result. |
| 691 __ pushq(RAX); // Push the source object. | 657 __ pushq(RAX); // Push the source object. |
| 692 __ PushObject(dst_name); // Push the name of the destination. | 658 __ PushObject(dst_name); // Push the name of the destination. |
| 693 __ PushObject(dst_type); // Push the type of the destination. | 659 __ PushObject(dst_type); // Push the type of the destination. |
| 694 GenerateRuntimeCall(token_pos, | 660 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
| 695 deopt_id, | |
| 696 kBadTypeErrorRuntimeEntry, | |
| 697 3, | |
| 698 locs); | 661 locs); |
| 699 // We should never return here. | 662 // We should never return here. |
| 700 __ int3(); | 663 __ int3(); |
| 701 | 664 |
| 702 __ Bind(&is_assignable); // For a null object. | 665 __ Bind(&is_assignable); // For a null object. |
| 703 __ popq(RDX); // Remove pushed instantiator type arguments. | 666 __ popq(RDX); // Remove pushed instantiator type arguments. |
| 704 return; | 667 return; |
| 705 } | 668 } |
| 706 | 669 |
| 707 // Generate inline type check, linking to runtime call if not assignable. | 670 // Generate inline type check, linking to runtime call if not assignable. |
| 708 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 671 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 709 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 672 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
| 710 &is_assignable, &runtime_call); | 673 &runtime_call); |
| 711 | 674 |
| 712 __ Bind(&runtime_call); | 675 __ Bind(&runtime_call); |
| 713 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 676 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 714 __ PushObject(Object::null_object()); // Make room for the result. | 677 __ PushObject(Object::null_object()); // Make room for the result. |
| 715 __ pushq(RAX); // Push the source object. | 678 __ pushq(RAX); // Push the source object. |
| 716 __ PushObject(dst_type); // Push the type of the destination. | 679 __ PushObject(dst_type); // Push the type of the destination. |
| 717 __ pushq(RDX); // Instantiator type arguments. | 680 __ pushq(RDX); // Instantiator type arguments. |
| 718 __ PushObject(dst_name); // Push the name of the destination. | 681 __ PushObject(dst_name); // Push the name of the destination. |
| 719 __ LoadUniqueObject(RAX, test_cache); | 682 __ LoadUniqueObject(RAX, test_cache); |
| 720 __ pushq(RAX); | 683 __ pushq(RAX); |
| 721 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 684 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
| 722 // Pop the parameters supplied to the runtime entry. The result of the | 685 // Pop the parameters supplied to the runtime entry. The result of the |
| 723 // type check runtime call is the checked value. | 686 // type check runtime call is the checked value. |
| 724 __ Drop(5); | 687 __ Drop(5); |
| 725 __ popq(RAX); | 688 __ popq(RAX); |
| 726 | 689 |
| 727 __ Bind(&is_assignable); | 690 __ Bind(&is_assignable); |
| 728 __ popq(RDX); // Remove pushed instantiator type arguments. | 691 __ popq(RDX); // Remove pushed instantiator type arguments. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 | 740 |
| 778 // Copy positional arguments. | 741 // Copy positional arguments. |
| 779 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 742 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
| 780 // to fp[kFirstLocalSlotFromFp - i]. | 743 // to fp[kFirstLocalSlotFromFp - i]. |
| 781 | 744 |
| 782 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 745 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 783 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. | 746 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. |
| 784 // Let RBX point to the last passed positional argument, i.e. to | 747 // Let RBX point to the last passed positional argument, i.e. to |
| 785 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 748 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
| 786 __ subq(RBX, RCX); | 749 __ subq(RBX, RCX); |
| 787 __ leaq(RBX, Address(RBP, RBX, TIMES_4, | 750 __ leaq(RBX, |
| 788 (kParamEndSlotFromFp + 1) * kWordSize)); | 751 Address(RBP, RBX, TIMES_4, (kParamEndSlotFromFp + 1) * kWordSize)); |
| 789 | 752 |
| 790 // Let RDI point to the last copied positional argument, i.e. to | 753 // Let RDI point to the last copied positional argument, i.e. to |
| 791 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. | 754 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. |
| 792 __ SmiUntag(RCX); | 755 __ SmiUntag(RCX); |
| 793 __ movq(RAX, RCX); | 756 __ movq(RAX, RCX); |
| 794 __ negq(RAX); | 757 __ negq(RAX); |
| 795 // -num_pos_args is in RAX. | 758 // -num_pos_args is in RAX. |
| 796 __ leaq(RDI, | 759 __ leaq(RDI, |
| 797 Address(RBP, RAX, TIMES_8, (kFirstLocalSlotFromFp + 1) * kWordSize)); | 760 Address(RBP, RAX, TIMES_8, (kFirstLocalSlotFromFp + 1) * kWordSize)); |
| 798 Label loop, loop_condition; | 761 Label loop, loop_condition; |
| 799 __ jmp(&loop_condition, Assembler::kNearJump); | 762 __ jmp(&loop_condition, Assembler::kNearJump); |
| 800 // We do not use the final allocation index of the variable here, i.e. | 763 // We do not use the final allocation index of the variable here, i.e. |
| 801 // scope->VariableAt(i)->index(), because captured variables still need | 764 // scope->VariableAt(i)->index(), because captured variables still need |
| 802 // to be copied to the context that is not yet allocated. | 765 // to be copied to the context that is not yet allocated. |
| 803 const Address argument_addr(RBX, RCX, TIMES_8, 0); | 766 const Address argument_addr(RBX, RCX, TIMES_8, 0); |
| 804 const Address copy_addr(RDI, RCX, TIMES_8, 0); | 767 const Address copy_addr(RDI, RCX, TIMES_8, 0); |
| 805 __ Bind(&loop); | 768 __ Bind(&loop); |
| 806 __ movq(RAX, argument_addr); | 769 __ movq(RAX, argument_addr); |
| 807 __ movq(copy_addr, RAX); | 770 __ movq(copy_addr, RAX); |
| 808 __ Bind(&loop_condition); | 771 __ Bind(&loop_condition); |
| 809 __ decq(RCX); | 772 __ decq(RCX); |
| 810 __ j(POSITIVE, &loop, Assembler::kNearJump); | 773 __ j(POSITIVE, &loop, Assembler::kNearJump); |
| 811 | 774 |
| 812 // Copy or initialize optional named arguments. | 775 // Copy or initialize optional named arguments. |
| 813 Label all_arguments_processed; | 776 Label all_arguments_processed; |
| 814 #ifdef DEBUG | 777 #ifdef DEBUG |
| 815 const bool check_correct_named_args = true; | 778 const bool check_correct_named_args = true; |
| 816 #else | 779 #else |
| 817 const bool check_correct_named_args = function.IsClosureFunction(); | 780 const bool check_correct_named_args = function.IsClosureFunction(); |
| 818 #endif | 781 #endif |
| 819 if (num_opt_named_params > 0) { | 782 if (num_opt_named_params > 0) { |
| 820 // Start by alphabetically sorting the names of the optional parameters. | 783 // Start by alphabetically sorting the names of the optional parameters. |
| 821 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | 784 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
| 822 int* opt_param_position = new int[num_opt_named_params]; | 785 int* opt_param_position = new int[num_opt_named_params]; |
| 823 for (int pos = num_fixed_params; pos < num_params; pos++) { | 786 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 824 LocalVariable* parameter = scope->VariableAt(pos); | 787 LocalVariable* parameter = scope->VariableAt(pos); |
| 825 const String& opt_param_name = parameter->name(); | 788 const String& opt_param_name = parameter->name(); |
| 826 int i = pos - num_fixed_params; | 789 int i = pos - num_fixed_params; |
| 827 while (--i >= 0) { | 790 while (--i >= 0) { |
| 828 LocalVariable* param_i = opt_param[i]; | 791 LocalVariable* param_i = opt_param[i]; |
| 829 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 792 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 830 ASSERT(result != 0); | 793 ASSERT(result != 0); |
| 831 if (result > 0) break; | 794 if (result > 0) break; |
| 832 opt_param[i + 1] = opt_param[i]; | 795 opt_param[i + 1] = opt_param[i]; |
| 833 opt_param_position[i + 1] = opt_param_position[i]; | 796 opt_param_position[i + 1] = opt_param_position[i]; |
| 834 } | 797 } |
| 835 opt_param[i + 1] = parameter; | 798 opt_param[i + 1] = parameter; |
| 836 opt_param_position[i + 1] = pos; | 799 opt_param_position[i + 1] = pos; |
| 837 } | 800 } |
| 838 // Generate code handling each optional parameter in alphabetical order. | 801 // Generate code handling each optional parameter in alphabetical order. |
| 839 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 802 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 840 __ movq(RCX, | 803 __ movq(RCX, |
| 841 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); | 804 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 842 __ SmiUntag(RCX); | 805 __ SmiUntag(RCX); |
| 843 // Let RBX point to the first passed argument, i.e. to | 806 // Let RBX point to the first passed argument, i.e. to |
| 844 // fp[kParamEndSlotFromFp + num_args]; num_args (RBX) is Smi. | 807 // fp[kParamEndSlotFromFp + num_args]; num_args (RBX) is Smi. |
| 845 __ leaq(RBX, | 808 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kParamEndSlotFromFp * kWordSize)); |
| 846 Address(RBP, RBX, TIMES_4, kParamEndSlotFromFp * kWordSize)); | |
| 847 // Let RDI point to the entry of the first named argument. | 809 // Let RDI point to the entry of the first named argument. |
| 848 __ leaq(RDI, | 810 __ leaq(RDI, |
| 849 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); | 811 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); |
| 850 for (int i = 0; i < num_opt_named_params; i++) { | 812 for (int i = 0; i < num_opt_named_params; i++) { |
| 851 Label load_default_value, assign_optional_parameter; | 813 Label load_default_value, assign_optional_parameter; |
| 852 const int param_pos = opt_param_position[i]; | 814 const int param_pos = opt_param_position[i]; |
| 853 // Check if this named parameter was passed in. | 815 // Check if this named parameter was passed in. |
| 854 // Load RAX with the name of the argument. | 816 // Load RAX with the name of the argument. |
| 855 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); | 817 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); |
| 856 ASSERT(opt_param[i]->name().IsSymbol()); | 818 ASSERT(opt_param[i]->name().IsSymbol()); |
| 857 __ CompareObject(RAX, opt_param[i]->name()); | 819 __ CompareObject(RAX, opt_param[i]->name()); |
| 858 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | 820 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 859 // Load RAX with passed-in argument at provided arg_pos, i.e. at | 821 // Load RAX with passed-in argument at provided arg_pos, i.e. at |
| 860 // fp[kParamEndSlotFromFp + num_args - arg_pos]. | 822 // fp[kParamEndSlotFromFp + num_args - arg_pos]. |
| 861 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); | 823 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); |
| 862 // RAX is arg_pos as Smi. | 824 // RAX is arg_pos as Smi. |
| 863 // Point to next named entry. | 825 // Point to next named entry. |
| 864 __ AddImmediate( | 826 __ AddImmediate(RDI, Immediate(ArgumentsDescriptor::named_entry_size())); |
| 865 RDI, Immediate(ArgumentsDescriptor::named_entry_size())); | |
| 866 __ negq(RAX); | 827 __ negq(RAX); |
| 867 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. | 828 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
| 868 __ movq(RAX, argument_addr); | 829 __ movq(RAX, argument_addr); |
| 869 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 830 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 870 __ Bind(&load_default_value); | 831 __ Bind(&load_default_value); |
| 871 // Load RAX with default argument. | 832 // Load RAX with default argument. |
| 872 const Instance& value = parsed_function().DefaultParameterValueAt( | 833 const Instance& value = parsed_function().DefaultParameterValueAt( |
| 873 param_pos - num_fixed_params); | 834 param_pos - num_fixed_params); |
| 874 __ LoadObject(RAX, value); | 835 __ LoadObject(RAX, value); |
| 875 __ Bind(&assign_optional_parameter); | 836 __ Bind(&assign_optional_parameter); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 939 // This step can be skipped in case we decide that formal parameters are | 900 // This step can be skipped in case we decide that formal parameters are |
| 940 // implicitly final, since garbage collecting the unmodified value is not | 901 // implicitly final, since garbage collecting the unmodified value is not |
| 941 // an issue anymore. | 902 // an issue anymore. |
| 942 | 903 |
| 943 // R10 : arguments descriptor array. | 904 // R10 : arguments descriptor array. |
| 944 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 905 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 945 __ SmiUntag(RCX); | 906 __ SmiUntag(RCX); |
| 946 __ LoadObject(R12, Object::null_object()); | 907 __ LoadObject(R12, Object::null_object()); |
| 947 Label null_args_loop, null_args_loop_condition; | 908 Label null_args_loop, null_args_loop_condition; |
| 948 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 909 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 949 const Address original_argument_addr( | 910 const Address original_argument_addr(RBP, RCX, TIMES_8, |
| 950 RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize); | 911 (kParamEndSlotFromFp + 1) * kWordSize); |
| 951 __ Bind(&null_args_loop); | 912 __ Bind(&null_args_loop); |
| 952 __ movq(original_argument_addr, R12); | 913 __ movq(original_argument_addr, R12); |
| 953 __ Bind(&null_args_loop_condition); | 914 __ Bind(&null_args_loop_condition); |
| 954 __ decq(RCX); | 915 __ decq(RCX); |
| 955 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 916 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 956 } | 917 } |
| 957 | 918 |
| 958 | 919 |
| 959 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 920 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 960 // TOS: return address. | 921 // TOS: return address. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 978 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); | 939 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); |
| 979 __ LoadObject(RAX, Object::null_object()); | 940 __ LoadObject(RAX, Object::null_object()); |
| 980 __ ret(); | 941 __ ret(); |
| 981 } | 942 } |
| 982 | 943 |
| 983 | 944 |
| 984 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc | 945 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc |
| 985 // needs to be updated to match. | 946 // needs to be updated to match. |
| 986 void FlowGraphCompiler::EmitFrameEntry() { | 947 void FlowGraphCompiler::EmitFrameEntry() { |
| 987 if (flow_graph().IsCompiledForOsr()) { | 948 if (flow_graph().IsCompiledForOsr()) { |
| 988 intptr_t extra_slots = StackSize() | 949 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - |
| 989 - flow_graph().num_stack_locals() | 950 flow_graph().num_copied_params(); |
| 990 - flow_graph().num_copied_params(); | |
| 991 ASSERT(extra_slots >= 0); | 951 ASSERT(extra_slots >= 0); |
| 992 __ EnterOsrFrame(extra_slots * kWordSize); | 952 __ EnterOsrFrame(extra_slots * kWordSize); |
| 993 } else { | 953 } else { |
| 994 const Register new_pp = R13; | 954 const Register new_pp = R13; |
| 995 __ LoadPoolPointer(new_pp); | 955 __ LoadPoolPointer(new_pp); |
| 996 | 956 |
| 997 const Function& function = parsed_function().function(); | 957 const Function& function = parsed_function().function(); |
| 998 if (CanOptimizeFunction() && | 958 if (CanOptimizeFunction() && function.IsOptimizable() && |
| 999 function.IsOptimizable() && | |
| 1000 (!is_optimizing() || may_reoptimize())) { | 959 (!is_optimizing() || may_reoptimize())) { |
| 1001 __ Comment("Invocation Count Check"); | 960 __ Comment("Invocation Count Check"); |
| 1002 const Register function_reg = RDI; | 961 const Register function_reg = RDI; |
| 1003 // Load function object using the callee's pool pointer. | 962 // Load function object using the callee's pool pointer. |
| 1004 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); | 963 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); |
| 1005 | 964 |
| 1006 // Reoptimization of an optimized function is triggered by counting in | 965 // Reoptimization of an optimized function is triggered by counting in |
| 1007 // IC stubs, but not at the entry of the function. | 966 // IC stubs, but not at the entry of the function. |
| 1008 if (!is_optimizing()) { | 967 if (!is_optimizing()) { |
| 1009 __ incl(FieldAddress(function_reg, Function::usage_counter_offset())); | 968 __ incl(FieldAddress(function_reg, Function::usage_counter_offset())); |
| 1010 } | 969 } |
| 1011 __ cmpl( | 970 __ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()), |
| 1012 FieldAddress(function_reg, Function::usage_counter_offset()), | 971 Immediate(GetOptimizationThreshold())); |
| 1013 Immediate(GetOptimizationThreshold())); | |
| 1014 ASSERT(function_reg == RDI); | 972 ASSERT(function_reg == RDI); |
| 1015 __ J(GREATER_EQUAL, | 973 __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry(), new_pp); |
| 1016 *StubCode::OptimizeFunction_entry(), | |
| 1017 new_pp); | |
| 1018 } | 974 } |
| 1019 ASSERT(StackSize() >= 0); | 975 ASSERT(StackSize() >= 0); |
| 1020 __ Comment("Enter frame"); | 976 __ Comment("Enter frame"); |
| 1021 __ EnterDartFrame(StackSize() * kWordSize, new_pp); | 977 __ EnterDartFrame(StackSize() * kWordSize, new_pp); |
| 1022 } | 978 } |
| 1023 } | 979 } |
| 1024 | 980 |
| 1025 | 981 |
| 1026 void FlowGraphCompiler::CompileGraph() { | 982 void FlowGraphCompiler::CompileGraph() { |
| 1027 InitCompiler(); | 983 InitCompiler(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1052 if (num_copied_params == 0) { | 1008 if (num_copied_params == 0) { |
| 1053 const bool check_arguments = | 1009 const bool check_arguments = |
| 1054 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1010 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
| 1055 if (check_arguments) { | 1011 if (check_arguments) { |
| 1056 __ Comment("Check argument count"); | 1012 __ Comment("Check argument count"); |
| 1057 // Check that exactly num_fixed arguments are passed in. | 1013 // Check that exactly num_fixed arguments are passed in. |
| 1058 Label correct_num_arguments, wrong_num_arguments; | 1014 Label correct_num_arguments, wrong_num_arguments; |
| 1059 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1015 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1060 __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params))); | 1016 __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params))); |
| 1061 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); | 1017 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); |
| 1062 __ cmpq(RAX, | 1018 __ cmpq(RAX, FieldAddress( |
| 1063 FieldAddress(R10, | 1019 R10, ArgumentsDescriptor::positional_count_offset())); |
| 1064 ArgumentsDescriptor::positional_count_offset())); | |
| 1065 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); | 1020 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); |
| 1066 | 1021 |
| 1067 __ Bind(&wrong_num_arguments); | 1022 __ Bind(&wrong_num_arguments); |
| 1068 __ LeaveDartFrame(kKeepCalleePP); // Leave arguments on the stack. | 1023 __ LeaveDartFrame(kKeepCalleePP); // Leave arguments on the stack. |
| 1069 __ Jmp(*StubCode::CallClosureNoSuchMethod_entry()); | 1024 __ Jmp(*StubCode::CallClosureNoSuchMethod_entry()); |
| 1070 // The noSuchMethod call may return to the caller, but not here. | 1025 // The noSuchMethod call may return to the caller, but not here. |
| 1071 __ Bind(&correct_num_arguments); | 1026 __ Bind(&correct_num_arguments); |
| 1072 } | 1027 } |
| 1073 } else if (!flow_graph().IsCompiledForOsr()) { | 1028 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1074 CopyParameters(); | 1029 CopyParameters(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1102 __ LoadObject(RAX, Object::null_object()); | 1057 __ LoadObject(RAX, Object::null_object()); |
| 1103 } | 1058 } |
| 1104 for (intptr_t i = 0; i < num_locals; ++i) { | 1059 for (intptr_t i = 0; i < num_locals; ++i) { |
| 1105 // Subtract index i (locals lie at lower addresses than RBP). | 1060 // Subtract index i (locals lie at lower addresses than RBP). |
| 1106 if (((slot_base - i) == context_index)) { | 1061 if (((slot_base - i) == context_index)) { |
| 1107 if (function.IsClosureFunction()) { | 1062 if (function.IsClosureFunction()) { |
| 1108 __ movq(Address(RBP, (slot_base - i) * kWordSize), CTX); | 1063 __ movq(Address(RBP, (slot_base - i) * kWordSize), CTX); |
| 1109 } else { | 1064 } else { |
| 1110 const Context& empty_context = Context::ZoneHandle( | 1065 const Context& empty_context = Context::ZoneHandle( |
| 1111 zone(), isolate()->object_store()->empty_context()); | 1066 zone(), isolate()->object_store()->empty_context()); |
| 1112 __ StoreObject( | 1067 __ StoreObject(Address(RBP, (slot_base - i) * kWordSize), |
| 1113 Address(RBP, (slot_base - i) * kWordSize), empty_context); | 1068 empty_context); |
| 1114 } | 1069 } |
| 1115 } else { | 1070 } else { |
| 1116 ASSERT(num_locals > 1); | 1071 ASSERT(num_locals > 1); |
| 1117 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); | 1072 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); |
| 1118 } | 1073 } |
| 1119 } | 1074 } |
| 1120 } | 1075 } |
| 1121 | 1076 |
| 1122 EndCodeSourceRange(TokenPosition::kDartCodePrologue); | 1077 EndCodeSourceRange(TokenPosition::kDartCodePrologue); |
| 1123 ASSERT(!block_order().is_empty()); | 1078 ASSERT(!block_order().is_empty()); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 AddDeoptIndexAtCall(deopt_id_after); | 1159 AddDeoptIndexAtCall(deopt_id_after); |
| 1205 } else { | 1160 } else { |
| 1206 // Add deoptimization continuation point after the call and before the | 1161 // Add deoptimization continuation point after the call and before the |
| 1207 // arguments are removed. | 1162 // arguments are removed. |
| 1208 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1163 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
| 1209 } | 1164 } |
| 1210 } | 1165 } |
| 1211 } | 1166 } |
| 1212 | 1167 |
| 1213 | 1168 |
| 1214 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1169 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, |
| 1215 intptr_t argument_count, | 1170 intptr_t deopt_id, |
| 1216 intptr_t deopt_id, | 1171 TokenPosition token_pos, |
| 1217 TokenPosition token_pos, | 1172 LocationSummary* locs, |
| 1218 LocationSummary* locs, | 1173 const ICData& ic_data) { |
| 1219 const ICData& ic_data) { | |
| 1220 const StubEntry* stub_entry = | 1174 const StubEntry* stub_entry = |
| 1221 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1175 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
| 1222 __ LoadObject(RBX, ic_data); | 1176 __ LoadObject(RBX, ic_data); |
| 1223 GenerateDartCall(deopt_id, | 1177 GenerateDartCall(deopt_id, token_pos, *stub_entry, |
| 1224 token_pos, | 1178 RawPcDescriptors::kUnoptStaticCall, locs); |
| 1225 *stub_entry, | |
| 1226 RawPcDescriptors::kUnoptStaticCall, | |
| 1227 locs); | |
| 1228 __ Drop(argument_count, RCX); | 1179 __ Drop(argument_count, RCX); |
| 1229 } | 1180 } |
| 1230 | 1181 |
| 1231 | 1182 |
| 1232 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { | 1183 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { |
| 1233 // We do not check for overflow when incrementing the edge counter. The | 1184 // We do not check for overflow when incrementing the edge counter. The |
| 1234 // function should normally be optimized long before the counter can | 1185 // function should normally be optimized long before the counter can |
| 1235 // overflow; and though we do not reset the counters when we optimize or | 1186 // overflow; and though we do not reset the counters when we optimize or |
| 1236 // deoptimize, there is a bound on the number of | 1187 // deoptimize, there is a bound on the number of |
| 1237 // optimization/deoptimization cycles we will attempt. | 1188 // optimization/deoptimization cycles we will attempt. |
| 1238 ASSERT(!edge_counters_array_.IsNull()); | 1189 ASSERT(!edge_counters_array_.IsNull()); |
| 1239 ASSERT(assembler_->constant_pool_allowed()); | 1190 ASSERT(assembler_->constant_pool_allowed()); |
| 1240 __ Comment("Edge counter"); | 1191 __ Comment("Edge counter"); |
| 1241 __ LoadObject(RAX, edge_counters_array_); | 1192 __ LoadObject(RAX, edge_counters_array_); |
| 1242 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(edge_id)), 1); | 1193 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(edge_id)), 1); |
| 1243 } | 1194 } |
| 1244 | 1195 |
| 1245 | 1196 |
| 1246 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1197 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, |
| 1247 const StubEntry& stub_entry, | 1198 const ICData& ic_data, |
| 1248 const ICData& ic_data, | 1199 intptr_t argument_count, |
| 1249 intptr_t argument_count, | 1200 intptr_t deopt_id, |
| 1250 intptr_t deopt_id, | 1201 TokenPosition token_pos, |
| 1251 TokenPosition token_pos, | 1202 LocationSummary* locs) { |
| 1252 LocationSummary* locs) { | |
| 1253 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1203 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1254 // Each ICData propagated from unoptimized to optimized code contains the | 1204 // Each ICData propagated from unoptimized to optimized code contains the |
| 1255 // function that corresponds to the Dart function of that IC call. Due | 1205 // function that corresponds to the Dart function of that IC call. Due |
| 1256 // to inlining in optimized code, that function may not correspond to the | 1206 // to inlining in optimized code, that function may not correspond to the |
| 1257 // top-level function (parsed_function().function()) which could be | 1207 // top-level function (parsed_function().function()) which could be |
| 1258 // reoptimized and which counter needs to be incremented. | 1208 // reoptimized and which counter needs to be incremented. |
| 1259 // Pass the function explicitly, it is used in IC stub. | 1209 // Pass the function explicitly, it is used in IC stub. |
| 1260 __ LoadObject(RDI, parsed_function().function()); | 1210 __ LoadObject(RDI, parsed_function().function()); |
| 1261 __ LoadUniqueObject(RBX, ic_data); | 1211 __ LoadUniqueObject(RBX, ic_data); |
| 1262 GenerateDartCall(deopt_id, | 1212 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
| 1263 token_pos, | |
| 1264 stub_entry, | |
| 1265 RawPcDescriptors::kIcCall, | |
| 1266 locs); | 1213 locs); |
| 1267 __ Drop(argument_count, RCX); | 1214 __ Drop(argument_count, RCX); |
| 1268 } | 1215 } |
| 1269 | 1216 |
| 1270 | 1217 |
| 1271 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1218 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
| 1272 const ICData& ic_data, | 1219 const ICData& ic_data, |
| 1273 intptr_t argument_count, | 1220 intptr_t argument_count, |
| 1274 intptr_t deopt_id, | 1221 intptr_t deopt_id, |
| 1275 TokenPosition token_pos, | 1222 TokenPosition token_pos, |
| 1276 LocationSummary* locs) { | 1223 LocationSummary* locs) { |
| 1277 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1224 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1278 __ LoadUniqueObject(RBX, ic_data); | 1225 __ LoadUniqueObject(RBX, ic_data); |
| 1279 GenerateDartCall(deopt_id, | 1226 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
| 1280 token_pos, | |
| 1281 stub_entry, | |
| 1282 RawPcDescriptors::kIcCall, | |
| 1283 locs); | 1227 locs); |
| 1284 __ Drop(argument_count, RCX); | 1228 __ Drop(argument_count, RCX); |
| 1285 } | 1229 } |
| 1286 | 1230 |
| 1287 | 1231 |
| 1288 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1232 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1289 const ICData& ic_data, | 1233 const ICData& ic_data, |
| 1290 intptr_t argument_count, | 1234 intptr_t argument_count, |
| 1291 intptr_t deopt_id, | 1235 intptr_t deopt_id, |
| 1292 TokenPosition token_pos, | 1236 TokenPosition token_pos, |
| 1293 LocationSummary* locs, | 1237 LocationSummary* locs, |
| 1294 intptr_t try_index, | 1238 intptr_t try_index, |
| 1295 intptr_t slow_path_argument_count) { | 1239 intptr_t slow_path_argument_count) { |
| 1296 const String& name = String::Handle(zone(), ic_data.target_name()); | 1240 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1297 const Array& arguments_descriptor = | 1241 const Array& arguments_descriptor = |
| 1298 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1242 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1299 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1243 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1300 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), | 1244 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1245 zone(), |
| 1301 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1246 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
| 1302 __ Comment("MegamorphicCall"); | 1247 __ Comment("MegamorphicCall"); |
| 1303 // Load receiver into RDI. | 1248 // Load receiver into RDI. |
| 1304 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); | 1249 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); |
| 1305 Label done; | 1250 Label done; |
| 1306 if (ShouldInlineSmiStringHashCode(ic_data)) { | 1251 if (ShouldInlineSmiStringHashCode(ic_data)) { |
| 1307 Label megamorphic_call; | 1252 Label megamorphic_call; |
| 1308 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | 1253 __ Comment("Inlined get:hashCode for Smi and OneByteString"); |
| 1309 __ movq(RAX, RDI); // Move Smi hashcode to RAX. | 1254 __ movq(RAX, RDI); // Move Smi hashcode to RAX. |
| 1310 __ testq(RDI, Immediate(kSmiTagMask)); | 1255 __ testq(RDI, Immediate(kSmiTagMask)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1324 | 1269 |
| 1325 __ Bind(&done); | 1270 __ Bind(&done); |
| 1326 RecordSafepoint(locs, slow_path_argument_count); | 1271 RecordSafepoint(locs, slow_path_argument_count); |
| 1327 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1272 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
| 1328 if (FLAG_precompiled_mode) { | 1273 if (FLAG_precompiled_mode) { |
| 1329 // Megamorphic calls may occur in slow path stubs. | 1274 // Megamorphic calls may occur in slow path stubs. |
| 1330 // If valid use try_index argument. | 1275 // If valid use try_index argument. |
| 1331 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1276 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
| 1332 try_index = CurrentTryIndex(); | 1277 try_index = CurrentTryIndex(); |
| 1333 } | 1278 } |
| 1334 pc_descriptors_list()->AddDescriptor(RawPcDescriptors::kOther, | 1279 pc_descriptors_list()->AddDescriptor( |
| 1335 assembler()->CodeSize(), | 1280 RawPcDescriptors::kOther, assembler()->CodeSize(), Thread::kNoDeoptId, |
| 1336 Thread::kNoDeoptId, | 1281 token_pos, try_index); |
| 1337 token_pos, | |
| 1338 try_index); | |
| 1339 } else if (is_optimizing()) { | 1282 } else if (is_optimizing()) { |
| 1340 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1283 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1341 Thread::kNoDeoptId, token_pos); | 1284 token_pos); |
| 1342 AddDeoptIndexAtCall(deopt_id_after); | 1285 AddDeoptIndexAtCall(deopt_id_after); |
| 1343 } else { | 1286 } else { |
| 1344 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1287 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
| 1345 Thread::kNoDeoptId, token_pos); | 1288 token_pos); |
| 1346 // Add deoptimization continuation point after the call and before the | 1289 // Add deoptimization continuation point after the call and before the |
| 1347 // arguments are removed. | 1290 // arguments are removed. |
| 1348 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1291 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
| 1349 } | 1292 } |
| 1350 __ Drop(argument_count, RCX); | 1293 __ Drop(argument_count, RCX); |
| 1351 } | 1294 } |
| 1352 | 1295 |
| 1353 | 1296 |
| 1354 void FlowGraphCompiler::EmitSwitchableInstanceCall( | 1297 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, |
| 1355 const ICData& ic_data, | 1298 intptr_t argument_count, |
| 1356 intptr_t argument_count, | 1299 intptr_t deopt_id, |
| 1357 intptr_t deopt_id, | 1300 TokenPosition token_pos, |
| 1358 TokenPosition token_pos, | 1301 LocationSummary* locs) { |
| 1359 LocationSummary* locs) { | |
| 1360 ASSERT(ic_data.NumArgsTested() == 1); | 1302 ASSERT(ic_data.NumArgsTested() == 1); |
| 1361 const Code& initial_stub = Code::ZoneHandle( | 1303 const Code& initial_stub = |
| 1362 StubCode::ICCallThroughFunction_entry()->code()); | 1304 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code()); |
| 1363 | 1305 |
| 1364 __ Comment("SwitchableCall"); | 1306 __ Comment("SwitchableCall"); |
| 1365 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); | 1307 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); |
| 1366 __ LoadUniqueObject(CODE_REG, initial_stub); | 1308 __ LoadUniqueObject(CODE_REG, initial_stub); |
| 1367 __ movq(RCX, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); | 1309 __ movq(RCX, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); |
| 1368 __ LoadUniqueObject(RBX, ic_data); | 1310 __ LoadUniqueObject(RBX, ic_data); |
| 1369 __ call(RCX); | 1311 __ call(RCX); |
| 1370 | 1312 |
| 1371 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1313 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos); |
| 1372 Thread::kNoDeoptId, token_pos); | |
| 1373 RecordSafepoint(locs); | 1314 RecordSafepoint(locs); |
| 1374 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1315 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
| 1375 if (is_optimizing()) { | 1316 if (is_optimizing()) { |
| 1376 AddDeoptIndexAtCall(deopt_id_after); | 1317 AddDeoptIndexAtCall(deopt_id_after); |
| 1377 } else { | 1318 } else { |
| 1378 // Add deoptimization continuation point after the call and before the | 1319 // Add deoptimization continuation point after the call and before the |
| 1379 // arguments are removed. | 1320 // arguments are removed. |
| 1380 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1321 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
| 1381 } | 1322 } |
| 1382 __ Drop(argument_count, RCX); | 1323 __ Drop(argument_count, RCX); |
| 1383 } | 1324 } |
| 1384 | 1325 |
| 1385 | 1326 |
| 1386 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1327 void FlowGraphCompiler::EmitOptimizedStaticCall( |
| 1387 const Function& function, | 1328 const Function& function, |
| 1388 const Array& arguments_descriptor, | 1329 const Array& arguments_descriptor, |
| 1389 intptr_t argument_count, | 1330 intptr_t argument_count, |
| 1390 intptr_t deopt_id, | 1331 intptr_t deopt_id, |
| 1391 TokenPosition token_pos, | 1332 TokenPosition token_pos, |
| 1392 LocationSummary* locs) { | 1333 LocationSummary* locs) { |
| 1393 ASSERT(!function.IsClosureFunction()); | 1334 ASSERT(!function.IsClosureFunction()); |
| 1394 if (function.HasOptionalParameters()) { | 1335 if (function.HasOptionalParameters()) { |
| 1395 __ LoadObject(R10, arguments_descriptor); | 1336 __ LoadObject(R10, arguments_descriptor); |
| 1396 } else { | 1337 } else { |
| 1397 __ xorq(R10, R10); // GC safe smi zero because of stub. | 1338 __ xorq(R10, R10); // GC safe smi zero because of stub. |
| 1398 } | 1339 } |
| 1399 // Do not use the code from the function, but let the code be patched so that | 1340 // Do not use the code from the function, but let the code be patched so that |
| 1400 // we can record the outgoing edges to other code. | 1341 // we can record the outgoing edges to other code. |
| 1401 GenerateStaticDartCall(deopt_id, | 1342 GenerateStaticDartCall(deopt_id, token_pos, |
| 1402 token_pos, | |
| 1403 *StubCode::CallStaticFunction_entry(), | 1343 *StubCode::CallStaticFunction_entry(), |
| 1404 RawPcDescriptors::kOther, | 1344 RawPcDescriptors::kOther, locs, function); |
| 1405 locs, | |
| 1406 function); | |
| 1407 __ Drop(argument_count, RCX); | 1345 __ Drop(argument_count, RCX); |
| 1408 } | 1346 } |
| 1409 | 1347 |
| 1410 | 1348 |
| 1411 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1349 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
| 1412 Register reg, | 1350 Register reg, |
| 1413 const Object& obj, | 1351 const Object& obj, |
| 1414 bool needs_number_check, | 1352 bool needs_number_check, |
| 1415 TokenPosition token_pos) { | 1353 TokenPosition token_pos) { |
| 1416 ASSERT(!needs_number_check || | 1354 ASSERT(!needs_number_check || |
| 1417 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); | 1355 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); |
| 1418 | 1356 |
| 1419 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { | 1357 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { |
| 1420 ASSERT(!needs_number_check); | 1358 ASSERT(!needs_number_check); |
| 1421 __ testq(reg, reg); | 1359 __ testq(reg, reg); |
| 1422 return EQUAL; | 1360 return EQUAL; |
| 1423 } | 1361 } |
| 1424 | 1362 |
| 1425 if (needs_number_check) { | 1363 if (needs_number_check) { |
| 1426 __ pushq(reg); | 1364 __ pushq(reg); |
| 1427 __ PushObject(obj); | 1365 __ PushObject(obj); |
| 1428 if (is_optimizing()) { | 1366 if (is_optimizing()) { |
| 1429 __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1367 __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
| 1430 } else { | 1368 } else { |
| 1431 __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1369 __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
| 1432 } | 1370 } |
| 1433 if (token_pos.IsReal()) { | 1371 if (token_pos.IsReal()) { |
| 1434 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1372 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
| 1435 Thread::kNoDeoptId, | |
| 1436 token_pos); | 1373 token_pos); |
| 1437 } | 1374 } |
| 1438 // Stub returns result in flags (result of a cmpq, we need ZF computed). | 1375 // Stub returns result in flags (result of a cmpq, we need ZF computed). |
| 1439 __ popq(reg); // Discard constant. | 1376 __ popq(reg); // Discard constant. |
| 1440 __ popq(reg); // Restore 'reg'. | 1377 __ popq(reg); // Restore 'reg'. |
| 1441 } else { | 1378 } else { |
| 1442 __ CompareObject(reg, obj); | 1379 __ CompareObject(reg, obj); |
| 1443 } | 1380 } |
| 1444 return EQUAL; | 1381 return EQUAL; |
| 1445 } | 1382 } |
| 1446 | 1383 |
| 1447 | 1384 |
| 1448 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( | 1385 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( |
| 1449 Register left, | 1386 Register left, |
| 1450 Register right, | 1387 Register right, |
| 1451 bool needs_number_check, | 1388 bool needs_number_check, |
| 1452 TokenPosition token_pos) { | 1389 TokenPosition token_pos) { |
| 1453 if (needs_number_check) { | 1390 if (needs_number_check) { |
| 1454 __ pushq(left); | 1391 __ pushq(left); |
| 1455 __ pushq(right); | 1392 __ pushq(right); |
| 1456 if (is_optimizing()) { | 1393 if (is_optimizing()) { |
| 1457 __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1394 __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
| 1458 } else { | 1395 } else { |
| 1459 __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1396 __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
| 1460 } | 1397 } |
| 1461 if (token_pos.IsReal()) { | 1398 if (token_pos.IsReal()) { |
| 1462 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1399 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
| 1463 Thread::kNoDeoptId, | |
| 1464 token_pos); | 1400 token_pos); |
| 1465 } | 1401 } |
| 1466 // Stub returns result in flags (result of a cmpq, we need ZF computed). | 1402 // Stub returns result in flags (result of a cmpq, we need ZF computed). |
| 1467 __ popq(right); | 1403 __ popq(right); |
| 1468 __ popq(left); | 1404 __ popq(left); |
| 1469 } else { | 1405 } else { |
| 1470 __ CompareRegisters(left, right); | 1406 __ CompareRegisters(left, right); |
| 1471 } | 1407 } |
| 1472 return EQUAL; | 1408 return EQUAL; |
| 1473 } | 1409 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1513 const Array& argument_names, | 1449 const Array& argument_names, |
| 1514 Label* failed, | 1450 Label* failed, |
| 1515 Label* match_found, | 1451 Label* match_found, |
| 1516 intptr_t deopt_id, | 1452 intptr_t deopt_id, |
| 1517 TokenPosition token_index, | 1453 TokenPosition token_index, |
| 1518 LocationSummary* locs, | 1454 LocationSummary* locs, |
| 1519 bool complete) { | 1455 bool complete) { |
| 1520 ASSERT(is_optimizing()); | 1456 ASSERT(is_optimizing()); |
| 1521 | 1457 |
| 1522 __ Comment("EmitTestAndCall"); | 1458 __ Comment("EmitTestAndCall"); |
| 1523 const Array& arguments_descriptor = | 1459 const Array& arguments_descriptor = Array::ZoneHandle( |
| 1524 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, | 1460 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
| 1525 argument_names)); | |
| 1526 // Load receiver into RAX. | 1461 // Load receiver into RAX. |
| 1527 __ movq(RAX, | 1462 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize)); |
| 1528 Address(RSP, (argument_count - 1) * kWordSize)); | |
| 1529 __ LoadObject(R10, arguments_descriptor); | 1463 __ LoadObject(R10, arguments_descriptor); |
| 1530 | 1464 |
| 1531 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1465 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
| 1532 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1466 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
| 1533 | 1467 |
| 1534 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1468 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
| 1535 | 1469 |
| 1536 Label after_smi_test; | 1470 Label after_smi_test; |
| 1537 if (kFirstCheckIsSmi) { | 1471 if (kFirstCheckIsSmi) { |
| 1538 __ testq(RAX, Immediate(kSmiTagMask)); | 1472 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1539 // Jump if receiver is not Smi. | 1473 // Jump if receiver is not Smi. |
| 1540 if (kNumChecks == 1) { | 1474 if (kNumChecks == 1) { |
| 1541 __ j(NOT_ZERO, failed); | 1475 __ j(NOT_ZERO, failed); |
| 1542 } else { | 1476 } else { |
| 1543 __ j(NOT_ZERO, &after_smi_test); | 1477 __ j(NOT_ZERO, &after_smi_test); |
| 1544 } | 1478 } |
| 1545 // Do not use the code from the function, but let the code be patched so | 1479 // Do not use the code from the function, but let the code be patched so |
| 1546 // that we can record the outgoing edges to other code. | 1480 // that we can record the outgoing edges to other code. |
| 1547 const Function& function = Function::ZoneHandle( | 1481 const Function& function = |
| 1548 zone(), ic_data.GetTargetAt(0)); | 1482 Function::ZoneHandle(zone(), ic_data.GetTargetAt(0)); |
| 1549 GenerateStaticDartCall(deopt_id, | 1483 GenerateStaticDartCall(deopt_id, token_index, |
| 1550 token_index, | |
| 1551 *StubCode::CallStaticFunction_entry(), | 1484 *StubCode::CallStaticFunction_entry(), |
| 1552 RawPcDescriptors::kOther, | 1485 RawPcDescriptors::kOther, locs, function); |
| 1553 locs, | |
| 1554 function); | |
| 1555 __ Drop(argument_count, RCX); | 1486 __ Drop(argument_count, RCX); |
| 1556 if (kNumChecks > 1) { | 1487 if (kNumChecks > 1) { |
| 1557 __ jmp(match_found); | 1488 __ jmp(match_found); |
| 1558 } | 1489 } |
| 1559 } else { | 1490 } else { |
| 1560 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1491 // Receiver is Smi, but Smi is not a valid class therefore fail. |
| 1561 // (Smi class must be first in the list). | 1492 // (Smi class must be first in the list). |
| 1562 if (!complete) { | 1493 if (!complete) { |
| 1563 __ testq(RAX, Immediate(kSmiTagMask)); | 1494 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1564 __ j(ZERO, failed); | 1495 __ j(ZERO, failed); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1590 } | 1521 } |
| 1591 } else { | 1522 } else { |
| 1592 if (!kIsLastCheck) { | 1523 if (!kIsLastCheck) { |
| 1593 __ cmpl(RDI, Immediate(sorted[i].cid)); | 1524 __ cmpl(RDI, Immediate(sorted[i].cid)); |
| 1594 __ j(NOT_EQUAL, &next_test); | 1525 __ j(NOT_EQUAL, &next_test); |
| 1595 } | 1526 } |
| 1596 } | 1527 } |
| 1597 // Do not use the code from the function, but let the code be patched so | 1528 // Do not use the code from the function, but let the code be patched so |
| 1598 // that we can record the outgoing edges to other code. | 1529 // that we can record the outgoing edges to other code. |
| 1599 const Function& function = *sorted[i].target; | 1530 const Function& function = *sorted[i].target; |
| 1600 GenerateStaticDartCall(deopt_id, | 1531 GenerateStaticDartCall(deopt_id, token_index, |
| 1601 token_index, | |
| 1602 *StubCode::CallStaticFunction_entry(), | 1532 *StubCode::CallStaticFunction_entry(), |
| 1603 RawPcDescriptors::kOther, | 1533 RawPcDescriptors::kOther, locs, function); |
| 1604 locs, | |
| 1605 function); | |
| 1606 __ Drop(argument_count, RCX); | 1534 __ Drop(argument_count, RCX); |
| 1607 if (!kIsLastCheck) { | 1535 if (!kIsLastCheck) { |
| 1608 __ jmp(match_found); | 1536 __ jmp(match_found); |
| 1609 } | 1537 } |
| 1610 __ Bind(&next_test); | 1538 __ Bind(&next_test); |
| 1611 } | 1539 } |
| 1612 } | 1540 } |
| 1613 | 1541 |
| 1614 | 1542 |
| 1615 #undef __ | 1543 #undef __ |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1665 __ movups(XMM0, source.ToStackSlotAddress()); | 1593 __ movups(XMM0, source.ToStackSlotAddress()); |
| 1666 __ movups(destination.ToStackSlotAddress(), XMM0); | 1594 __ movups(destination.ToStackSlotAddress(), XMM0); |
| 1667 } | 1595 } |
| 1668 } else { | 1596 } else { |
| 1669 ASSERT(source.IsConstant()); | 1597 ASSERT(source.IsConstant()); |
| 1670 const Object& constant = source.constant(); | 1598 const Object& constant = source.constant(); |
| 1671 if (destination.IsRegister()) { | 1599 if (destination.IsRegister()) { |
| 1672 if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { | 1600 if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { |
| 1673 __ xorq(destination.reg(), destination.reg()); | 1601 __ xorq(destination.reg(), destination.reg()); |
| 1674 } else if (constant.IsSmi() && | 1602 } else if (constant.IsSmi() && |
| 1675 (source.constant_instruction()->representation() == kUnboxedInt32)) { | 1603 (source.constant_instruction()->representation() == |
| 1604 kUnboxedInt32)) { |
| 1676 __ movl(destination.reg(), Immediate(Smi::Cast(constant).Value())); | 1605 __ movl(destination.reg(), Immediate(Smi::Cast(constant).Value())); |
| 1677 } else { | 1606 } else { |
| 1678 __ LoadObject(destination.reg(), constant); | 1607 __ LoadObject(destination.reg(), constant); |
| 1679 } | 1608 } |
| 1680 } else if (destination.IsFpuRegister()) { | 1609 } else if (destination.IsFpuRegister()) { |
| 1681 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { | 1610 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { |
| 1682 __ xorps(destination.fpu_reg(), destination.fpu_reg()); | 1611 __ xorps(destination.fpu_reg(), destination.fpu_reg()); |
| 1683 } else { | 1612 } else { |
| 1684 __ LoadObject(TMP, constant); | 1613 __ LoadObject(TMP, constant); |
| 1685 __ movsd(destination.fpu_reg(), | 1614 __ movsd(destination.fpu_reg(), |
| 1686 FieldAddress(TMP, Double::value_offset())); | 1615 FieldAddress(TMP, Double::value_offset())); |
| 1687 } | 1616 } |
| 1688 } else if (destination.IsDoubleStackSlot()) { | 1617 } else if (destination.IsDoubleStackSlot()) { |
| 1689 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { | 1618 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { |
| 1690 __ xorps(XMM0, XMM0); | 1619 __ xorps(XMM0, XMM0); |
| 1691 } else { | 1620 } else { |
| 1692 __ LoadObject(TMP, constant); | 1621 __ LoadObject(TMP, constant); |
| 1693 __ movsd(XMM0, FieldAddress(TMP, Double::value_offset())); | 1622 __ movsd(XMM0, FieldAddress(TMP, Double::value_offset())); |
| 1694 } | 1623 } |
| 1695 __ movsd(destination.ToStackSlotAddress(), XMM0); | 1624 __ movsd(destination.ToStackSlotAddress(), XMM0); |
| 1696 } else { | 1625 } else { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1720 Exchange(source.reg(), destination.ToStackSlotAddress()); | 1649 Exchange(source.reg(), destination.ToStackSlotAddress()); |
| 1721 } else if (source.IsStackSlot() && destination.IsRegister()) { | 1650 } else if (source.IsStackSlot() && destination.IsRegister()) { |
| 1722 Exchange(destination.reg(), source.ToStackSlotAddress()); | 1651 Exchange(destination.reg(), source.ToStackSlotAddress()); |
| 1723 } else if (source.IsStackSlot() && destination.IsStackSlot()) { | 1652 } else if (source.IsStackSlot() && destination.IsStackSlot()) { |
| 1724 Exchange(destination.ToStackSlotAddress(), source.ToStackSlotAddress()); | 1653 Exchange(destination.ToStackSlotAddress(), source.ToStackSlotAddress()); |
| 1725 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { | 1654 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { |
| 1726 __ movaps(XMM0, source.fpu_reg()); | 1655 __ movaps(XMM0, source.fpu_reg()); |
| 1727 __ movaps(source.fpu_reg(), destination.fpu_reg()); | 1656 __ movaps(source.fpu_reg(), destination.fpu_reg()); |
| 1728 __ movaps(destination.fpu_reg(), XMM0); | 1657 __ movaps(destination.fpu_reg(), XMM0); |
| 1729 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { | 1658 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { |
| 1730 ASSERT(destination.IsDoubleStackSlot() || | 1659 ASSERT(destination.IsDoubleStackSlot() || destination.IsQuadStackSlot() || |
| 1731 destination.IsQuadStackSlot() || | 1660 source.IsDoubleStackSlot() || source.IsQuadStackSlot()); |
| 1732 source.IsDoubleStackSlot() || | 1661 bool double_width = |
| 1733 source.IsQuadStackSlot()); | 1662 destination.IsDoubleStackSlot() || source.IsDoubleStackSlot(); |
| 1734 bool double_width = destination.IsDoubleStackSlot() || | 1663 XmmRegister reg = |
| 1735 source.IsDoubleStackSlot(); | 1664 source.IsFpuRegister() ? source.fpu_reg() : destination.fpu_reg(); |
| 1736 XmmRegister reg = source.IsFpuRegister() ? source.fpu_reg() | |
| 1737 : destination.fpu_reg(); | |
| 1738 Address slot_address = source.IsFpuRegister() | 1665 Address slot_address = source.IsFpuRegister() |
| 1739 ? destination.ToStackSlotAddress() | 1666 ? destination.ToStackSlotAddress() |
| 1740 : source.ToStackSlotAddress(); | 1667 : source.ToStackSlotAddress(); |
| 1741 | 1668 |
| 1742 if (double_width) { | 1669 if (double_width) { |
| 1743 __ movsd(XMM0, slot_address); | 1670 __ movsd(XMM0, slot_address); |
| 1744 __ movsd(slot_address, reg); | 1671 __ movsd(slot_address, reg); |
| 1745 } else { | 1672 } else { |
| 1746 __ movups(XMM0, slot_address); | 1673 __ movups(XMM0, slot_address); |
| 1747 __ movups(slot_address, reg); | 1674 __ movups(slot_address, reg); |
| 1748 } | 1675 } |
| 1749 __ movaps(reg, XMM0); | 1676 __ movaps(reg, XMM0); |
| 1750 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { | 1677 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1843 __ movups(reg, Address(RSP, 0)); | 1770 __ movups(reg, Address(RSP, 0)); |
| 1844 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); | 1771 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); |
| 1845 } | 1772 } |
| 1846 | 1773 |
| 1847 | 1774 |
| 1848 #undef __ | 1775 #undef __ |
| 1849 | 1776 |
| 1850 } // namespace dart | 1777 } // namespace dart |
| 1851 | 1778 |
| 1852 #endif // defined TARGET_ARCH_X64 | 1779 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |