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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
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 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 builder->AddCallerFp(slot_ix++); | 110 builder->AddCallerFp(slot_ix++); |
111 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 111 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
112 | 112 |
113 // Emit all values that are needed for materialization as a part of the | 113 // Emit all values that are needed for materialization as a part of the |
114 // expression stack for the bottom-most frame. This guarantees that GC | 114 // expression stack for the bottom-most frame. This guarantees that GC |
115 // will be able to find them during materialization. | 115 // will be able to find them during materialization. |
116 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 116 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
117 | 117 |
118 // For the innermost environment, set outgoing arguments and the locals. | 118 // For the innermost environment, set outgoing arguments and the locals. |
119 for (intptr_t i = current->Length() - 1; | 119 for (intptr_t i = current->Length() - 1; |
120 i >= current->fixed_parameter_count(); | 120 i >= current->fixed_parameter_count(); i--) { |
121 i--) { | |
122 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 121 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
123 } | 122 } |
124 | 123 |
125 builder->AddPcMarker(current->function(), slot_ix++); | 124 builder->AddPcMarker(current->function(), slot_ix++); |
126 builder->AddCallerFp(slot_ix++); | 125 builder->AddCallerFp(slot_ix++); |
127 | 126 |
128 Environment* previous = current; | 127 Environment* previous = current; |
129 current = current->outer(); | 128 current = current->outer(); |
130 while (current != NULL) { | 129 while (current != NULL) { |
131 // For any outer environment the deopt id is that of the call instruction | 130 // For any outer environment the deopt id is that of the call instruction |
132 // which is recorded in the outer environment. | 131 // which is recorded in the outer environment. |
133 builder->AddReturnAddress( | 132 builder->AddReturnAddress(current->function(), |
134 current->function(), | 133 Thread::ToDeoptAfter(current->deopt_id()), |
135 Thread::ToDeoptAfter(current->deopt_id()), | 134 slot_ix++); |
136 slot_ix++); | |
137 | 135 |
138 // The values of outgoing arguments can be changed from the inlined call so | 136 // The values of outgoing arguments can be changed from the inlined call so |
139 // we must read them from the previous environment. | 137 // we must read them from the previous environment. |
140 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 138 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
141 builder->AddCopy(previous->ValueAt(i), | 139 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), |
142 previous->LocationAt(i), | |
143 slot_ix++); | 140 slot_ix++); |
144 } | 141 } |
145 | 142 |
146 // Set the locals, note that outgoing arguments are not in the environment. | 143 // Set the locals, note that outgoing arguments are not in the environment. |
147 for (intptr_t i = current->Length() - 1; | 144 for (intptr_t i = current->Length() - 1; |
148 i >= current->fixed_parameter_count(); | 145 i >= current->fixed_parameter_count(); i--) { |
149 i--) { | 146 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
150 builder->AddCopy(current->ValueAt(i), | |
151 current->LocationAt(i), | |
152 slot_ix++); | |
153 } | 147 } |
154 | 148 |
155 builder->AddPcMarker(current->function(), slot_ix++); | 149 builder->AddPcMarker(current->function(), slot_ix++); |
156 builder->AddCallerFp(slot_ix++); | 150 builder->AddCallerFp(slot_ix++); |
157 | 151 |
158 // Iterate on the outer environment. | 152 // Iterate on the outer environment. |
159 previous = current; | 153 previous = current; |
160 current = current->outer(); | 154 current = current->outer(); |
161 } | 155 } |
162 // The previous pointer is now the outermost environment. | 156 // The previous pointer is now the outermost environment. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 Register instance_reg, | 214 Register instance_reg, |
221 Register type_arguments_reg, | 215 Register type_arguments_reg, |
222 Register temp_reg, | 216 Register temp_reg, |
223 Label* is_instance_lbl, | 217 Label* is_instance_lbl, |
224 Label* is_not_instance_lbl) { | 218 Label* is_not_instance_lbl) { |
225 const SubtypeTestCache& type_test_cache = | 219 const SubtypeTestCache& type_test_cache = |
226 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 220 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
227 const Immediate& raw_null = | 221 const Immediate& raw_null = |
228 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 222 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
229 __ LoadObject(temp_reg, type_test_cache); | 223 __ LoadObject(temp_reg, type_test_cache); |
230 __ pushl(temp_reg); // Subtype test cache. | 224 __ pushl(temp_reg); // Subtype test cache. |
231 __ pushl(instance_reg); // Instance. | 225 __ pushl(instance_reg); // Instance. |
232 if (test_kind == kTestTypeOneArg) { | 226 if (test_kind == kTestTypeOneArg) { |
233 ASSERT(type_arguments_reg == kNoRegister); | 227 ASSERT(type_arguments_reg == kNoRegister); |
234 __ pushl(raw_null); | 228 __ pushl(raw_null); |
235 __ Call(*StubCode::Subtype1TestCache_entry()); | 229 __ Call(*StubCode::Subtype1TestCache_entry()); |
236 } else if (test_kind == kTestTypeTwoArgs) { | 230 } else if (test_kind == kTestTypeTwoArgs) { |
237 ASSERT(type_arguments_reg == kNoRegister); | 231 ASSERT(type_arguments_reg == kNoRegister); |
238 __ pushl(raw_null); | 232 __ pushl(raw_null); |
239 __ Call(*StubCode::Subtype2TestCache_entry()); | 233 __ Call(*StubCode::Subtype2TestCache_entry()); |
240 } else if (test_kind == kTestTypeThreeArgs) { | 234 } else if (test_kind == kTestTypeThreeArgs) { |
241 __ pushl(type_arguments_reg); | 235 __ pushl(type_arguments_reg); |
242 __ Call(*StubCode::Subtype3TestCache_entry()); | 236 __ Call(*StubCode::Subtype3TestCache_entry()); |
243 } else { | 237 } else { |
244 UNREACHABLE(); | 238 UNREACHABLE(); |
245 } | 239 } |
246 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 240 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
247 ASSERT(instance_reg != ECX); | 241 ASSERT(instance_reg != ECX); |
248 ASSERT(temp_reg != ECX); | 242 ASSERT(temp_reg != ECX); |
249 __ popl(instance_reg); // Discard. | 243 __ popl(instance_reg); // Discard. |
250 __ popl(instance_reg); // Restore receiver. | 244 __ popl(instance_reg); // Restore receiver. |
251 __ popl(temp_reg); // Discard. | 245 __ popl(temp_reg); // Discard. |
252 GenerateBoolToJump(ECX, is_instance_lbl, is_not_instance_lbl); | 246 GenerateBoolToJump(ECX, is_instance_lbl, is_not_instance_lbl); |
253 return type_test_cache.raw(); | 247 return type_test_cache.raw(); |
254 } | 248 } |
255 | 249 |
256 | 250 |
257 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 251 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
258 // type test is conclusive, otherwise fallthrough if a type test could not | 252 // type test is conclusive, otherwise fallthrough if a type test could not |
259 // be completed. | 253 // be completed. |
260 // EAX: instance (must survive). | 254 // EAX: instance (must survive). |
261 // Clobbers ECX, EDI. | 255 // Clobbers ECX, EDI. |
(...skipping 21 matching lines...) Expand all Loading... |
283 __ j(ZERO, is_not_instance_lbl); | 277 __ j(ZERO, is_not_instance_lbl); |
284 } | 278 } |
285 // A function type test requires checking the function signature. | 279 // A function type test requires checking the function signature. |
286 if (!type.IsFunctionType()) { | 280 if (!type.IsFunctionType()) { |
287 const intptr_t num_type_args = type_class.NumTypeArguments(); | 281 const intptr_t num_type_args = type_class.NumTypeArguments(); |
288 const intptr_t num_type_params = type_class.NumTypeParameters(); | 282 const intptr_t num_type_params = type_class.NumTypeParameters(); |
289 const intptr_t from_index = num_type_args - num_type_params; | 283 const intptr_t from_index = num_type_args - num_type_params; |
290 const TypeArguments& type_arguments = | 284 const TypeArguments& type_arguments = |
291 TypeArguments::ZoneHandle(zone(), type.arguments()); | 285 TypeArguments::ZoneHandle(zone(), type.arguments()); |
292 const bool is_raw_type = type_arguments.IsNull() || | 286 const bool is_raw_type = type_arguments.IsNull() || |
293 type_arguments.IsRaw(from_index, num_type_params); | 287 type_arguments.IsRaw(from_index, num_type_params); |
294 if (is_raw_type) { | 288 if (is_raw_type) { |
295 const Register kClassIdReg = ECX; | 289 const Register kClassIdReg = ECX; |
296 // dynamic type argument, check only classes. | 290 // dynamic type argument, check only classes. |
297 __ LoadClassId(kClassIdReg, kInstanceReg); | 291 __ LoadClassId(kClassIdReg, kInstanceReg); |
298 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 292 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
299 __ j(EQUAL, is_instance_lbl); | 293 __ j(EQUAL, is_instance_lbl); |
300 // List is a very common case. | 294 // List is a very common case. |
301 if (IsListClass(type_class)) { | 295 if (IsListClass(type_class)) { |
302 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 296 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
303 } | 297 } |
304 return GenerateSubtype1TestCacheLookup( | 298 return GenerateSubtype1TestCacheLookup( |
305 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 299 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
306 } | 300 } |
307 // If one type argument only, check if type argument is Object or dynamic. | 301 // If one type argument only, check if type argument is Object or dynamic. |
308 if (type_arguments.Length() == 1) { | 302 if (type_arguments.Length() == 1) { |
309 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 303 const AbstractType& tp_argument = |
310 zone(), type_arguments.TypeAt(0)); | 304 AbstractType::ZoneHandle(zone(), type_arguments.TypeAt(0)); |
311 ASSERT(!tp_argument.IsMalformed()); | 305 ASSERT(!tp_argument.IsMalformed()); |
312 if (tp_argument.IsType()) { | 306 if (tp_argument.IsType()) { |
313 ASSERT(tp_argument.HasResolvedTypeClass()); | 307 ASSERT(tp_argument.HasResolvedTypeClass()); |
314 // Check if type argument is dynamic or Object. | 308 // Check if type argument is dynamic or Object. |
315 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 309 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
316 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 310 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
317 // Instance class test only necessary. | 311 // Instance class test only necessary. |
318 return GenerateSubtype1TestCacheLookup( | 312 return GenerateSubtype1TestCacheLookup( |
319 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 313 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
320 } | 314 } |
321 } | 315 } |
322 } | 316 } |
323 } | 317 } |
324 // Regular subtype test cache involving instance's type arguments. | 318 // Regular subtype test cache involving instance's type arguments. |
325 const Register kTypeArgumentsReg = kNoRegister; | 319 const Register kTypeArgumentsReg = kNoRegister; |
326 const Register kTempReg = EDI; | 320 const Register kTempReg = EDI; |
327 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, | 321 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
328 kInstanceReg, | 322 kTypeArgumentsReg, kTempReg, |
329 kTypeArgumentsReg, | 323 is_instance_lbl, is_not_instance_lbl); |
330 kTempReg, | |
331 is_instance_lbl, | |
332 is_not_instance_lbl); | |
333 } | 324 } |
334 | 325 |
335 | 326 |
336 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 327 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
337 const GrowableArray<intptr_t>& class_ids, | 328 const GrowableArray<intptr_t>& class_ids, |
338 Label* is_equal_lbl, | 329 Label* is_equal_lbl, |
339 Label* is_not_equal_lbl) { | 330 Label* is_not_equal_lbl) { |
340 for (intptr_t i = 0; i < class_ids.length(); i++) { | 331 for (intptr_t i = 0; i < class_ids.length(); i++) { |
341 __ cmpl(class_id_reg, Immediate(class_ids[i])); | 332 __ cmpl(class_id_reg, Immediate(class_ids[i])); |
342 __ j(EQUAL, is_equal_lbl); | 333 __ j(EQUAL, is_equal_lbl); |
(...skipping 18 matching lines...) Expand all Loading... |
361 // Fallthrough. | 352 // Fallthrough. |
362 return true; | 353 return true; |
363 } | 354 } |
364 const Class& type_class = Class::Handle(zone(), type.type_class()); | 355 const Class& type_class = Class::Handle(zone(), type.type_class()); |
365 ASSERT(type_class.NumTypeArguments() == 0); | 356 ASSERT(type_class.NumTypeArguments() == 0); |
366 | 357 |
367 const Register kInstanceReg = EAX; | 358 const Register kInstanceReg = EAX; |
368 __ testl(kInstanceReg, Immediate(kSmiTagMask)); | 359 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
369 // If instance is Smi, check directly. | 360 // If instance is Smi, check directly. |
370 const Class& smi_class = Class::Handle(zone(), Smi::Class()); | 361 const Class& smi_class = Class::Handle(zone(), Smi::Class()); |
371 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), | 362 if (smi_class.IsSubtypeOf(TypeArguments::Handle(zone()), type_class, |
372 type_class, | 363 TypeArguments::Handle(zone()), NULL, NULL, |
373 TypeArguments::Handle(zone()), | |
374 NULL, | |
375 NULL, | |
376 Heap::kOld)) { | 364 Heap::kOld)) { |
377 __ j(ZERO, is_instance_lbl); | 365 __ j(ZERO, is_instance_lbl); |
378 } else { | 366 } else { |
379 __ j(ZERO, is_not_instance_lbl); | 367 __ j(ZERO, is_not_instance_lbl); |
380 } | 368 } |
381 const Register kClassIdReg = ECX; | 369 const Register kClassIdReg = ECX; |
382 __ LoadClassId(kClassIdReg, kInstanceReg); | 370 __ LoadClassId(kClassIdReg, kInstanceReg); |
383 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted | 371 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted |
384 // interfaces. | 372 // interfaces. |
385 // Bool interface can be implemented only by core class Bool. | 373 // Bool interface can be implemented only by core class Bool. |
386 if (type.IsBoolType()) { | 374 if (type.IsBoolType()) { |
387 __ cmpl(kClassIdReg, Immediate(kBoolCid)); | 375 __ cmpl(kClassIdReg, Immediate(kBoolCid)); |
388 __ j(EQUAL, is_instance_lbl); | 376 __ j(EQUAL, is_instance_lbl); |
389 __ jmp(is_not_instance_lbl); | 377 __ jmp(is_not_instance_lbl); |
390 return false; | 378 return false; |
391 } | 379 } |
392 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 380 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
393 // Note that instance is not Smi (checked above). | 381 // Note that instance is not Smi (checked above). |
394 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { | 382 if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) { |
395 GenerateNumberTypeCheck( | 383 GenerateNumberTypeCheck(kClassIdReg, type, is_instance_lbl, |
396 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 384 is_not_instance_lbl); |
397 return false; | 385 return false; |
398 } | 386 } |
399 if (type.IsStringType()) { | 387 if (type.IsStringType()) { |
400 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 388 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
401 return false; | 389 return false; |
402 } | 390 } |
403 if (type.IsDartFunctionType()) { | 391 if (type.IsDartFunctionType()) { |
404 // Check if instance is a closure. | 392 // Check if instance is a closure. |
405 __ cmpl(kClassIdReg, Immediate(kClosureCid)); | 393 __ cmpl(kClassIdReg, Immediate(kClosureCid)); |
406 __ j(EQUAL, is_instance_lbl); | 394 __ j(EQUAL, is_instance_lbl); |
(...skipping 26 matching lines...) Expand all Loading... |
433 __ LoadClass(ECX, kInstanceReg, EDI); | 421 __ LoadClass(ECX, kInstanceReg, EDI); |
434 // ECX: instance class. | 422 // ECX: instance class. |
435 // Check immediate superclass equality. | 423 // Check immediate superclass equality. |
436 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 424 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
437 __ movl(EDI, FieldAddress(EDI, Type::type_class_id_offset())); | 425 __ movl(EDI, FieldAddress(EDI, Type::type_class_id_offset())); |
438 __ cmpl(EDI, Immediate(Smi::RawValue(type_class.id()))); | 426 __ cmpl(EDI, Immediate(Smi::RawValue(type_class.id()))); |
439 __ j(EQUAL, is_instance_lbl); | 427 __ j(EQUAL, is_instance_lbl); |
440 | 428 |
441 const Register kTypeArgumentsReg = kNoRegister; | 429 const Register kTypeArgumentsReg = kNoRegister; |
442 const Register kTempReg = EDI; | 430 const Register kTempReg = EDI; |
443 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 431 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
444 kInstanceReg, | 432 kTypeArgumentsReg, kTempReg, |
445 kTypeArgumentsReg, | 433 is_instance_lbl, is_not_instance_lbl); |
446 kTempReg, | |
447 is_instance_lbl, | |
448 is_not_instance_lbl); | |
449 } | 434 } |
450 | 435 |
451 | 436 |
452 // Generates inlined check if 'type' is a type parameter or type itself | 437 // Generates inlined check if 'type' is a type parameter or type itself |
453 // EAX: instance (preserved). | 438 // EAX: instance (preserved). |
454 // Clobbers EDX, EDI, ECX. | 439 // Clobbers EDX, EDI, ECX. |
455 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 440 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
456 TokenPosition token_pos, | 441 TokenPosition token_pos, |
457 const AbstractType& type, | 442 const AbstractType& type, |
458 Label* is_instance_lbl, | 443 Label* is_instance_lbl, |
459 Label* is_not_instance_lbl) { | 444 Label* is_not_instance_lbl) { |
460 __ Comment("UninstantiatedTypeTest"); | 445 __ Comment("UninstantiatedTypeTest"); |
461 ASSERT(!type.IsInstantiated()); | 446 ASSERT(!type.IsInstantiated()); |
462 // Skip check if destination is a dynamic type. | 447 // Skip check if destination is a dynamic type. |
463 const Immediate& raw_null = | 448 const Immediate& raw_null = |
464 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 449 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
465 if (type.IsTypeParameter()) { | 450 if (type.IsTypeParameter()) { |
466 const TypeParameter& type_param = TypeParameter::Cast(type); | 451 const TypeParameter& type_param = TypeParameter::Cast(type); |
467 // Load instantiator type arguments on stack. | 452 // Load instantiator type arguments on stack. |
468 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 453 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
469 // EDX: instantiator type arguments. | 454 // EDX: instantiator type arguments. |
470 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 455 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
471 __ cmpl(EDX, raw_null); | 456 __ cmpl(EDX, raw_null); |
472 __ j(EQUAL, is_instance_lbl); | 457 __ j(EQUAL, is_instance_lbl); |
473 __ movl(EDI, | 458 __ movl(EDI, FieldAddress( |
474 FieldAddress(EDX, TypeArguments::type_at_offset(type_param.index()))); | 459 EDX, TypeArguments::type_at_offset(type_param.index()))); |
475 // EDI: concrete type of type. | 460 // EDI: concrete type of type. |
476 // Check if type argument is dynamic. | 461 // Check if type argument is dynamic. |
477 __ CompareObject(EDI, Object::dynamic_type()); | 462 __ CompareObject(EDI, Object::dynamic_type()); |
478 __ j(EQUAL, is_instance_lbl); | 463 __ j(EQUAL, is_instance_lbl); |
479 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType())); | 464 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType())); |
480 __ j(EQUAL, is_instance_lbl); | 465 __ j(EQUAL, is_instance_lbl); |
481 | 466 |
482 // For Smi check quickly against int and num interfaces. | 467 // For Smi check quickly against int and num interfaces. |
483 Label not_smi; | 468 Label not_smi; |
484 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? | 469 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? |
485 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 470 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
486 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType())); | 471 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType())); |
487 __ j(EQUAL, is_instance_lbl); | 472 __ j(EQUAL, is_instance_lbl); |
488 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number())); | 473 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number())); |
489 __ j(EQUAL, is_instance_lbl); | 474 __ j(EQUAL, is_instance_lbl); |
490 // Smi must be handled in runtime. | 475 // Smi must be handled in runtime. |
491 Label fall_through; | 476 Label fall_through; |
492 __ jmp(&fall_through); | 477 __ jmp(&fall_through); |
493 | 478 |
494 __ Bind(¬_smi); | 479 __ Bind(¬_smi); |
495 // EDX: instantiator type arguments. | 480 // EDX: instantiator type arguments. |
496 // EAX: instance. | 481 // EAX: instance. |
497 const Register kInstanceReg = EAX; | 482 const Register kInstanceReg = EAX; |
498 const Register kTypeArgumentsReg = EDX; | 483 const Register kTypeArgumentsReg = EDX; |
499 const Register kTempReg = EDI; | 484 const Register kTempReg = EDI; |
500 const SubtypeTestCache& type_test_cache = | 485 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
501 SubtypeTestCache::ZoneHandle(zone(), | 486 zone(), GenerateCallSubtypeTestStub( |
502 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 487 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, |
503 kInstanceReg, | 488 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
504 kTypeArgumentsReg, | |
505 kTempReg, | |
506 is_instance_lbl, | |
507 is_not_instance_lbl)); | |
508 __ Bind(&fall_through); | 489 __ Bind(&fall_through); |
509 return type_test_cache.raw(); | 490 return type_test_cache.raw(); |
510 } | 491 } |
511 if (type.IsType()) { | 492 if (type.IsType()) { |
512 const Register kInstanceReg = EAX; | 493 const Register kInstanceReg = EAX; |
513 const Register kTypeArgumentsReg = EDX; | 494 const Register kTypeArgumentsReg = EDX; |
514 __ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? | 495 __ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
515 __ j(ZERO, is_not_instance_lbl); | 496 __ j(ZERO, is_not_instance_lbl); |
516 __ movl(kTypeArgumentsReg, Address(ESP, 0)); // Instantiator type args. | 497 __ movl(kTypeArgumentsReg, Address(ESP, 0)); // Instantiator type args. |
517 // Uninstantiated type class is known at compile time, but the type | 498 // Uninstantiated type class is known at compile time, but the type |
518 // arguments are determined at runtime by the instantiator. | 499 // arguments are determined at runtime by the instantiator. |
519 const Register kTempReg = EDI; | 500 const Register kTempReg = EDI; |
520 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, | 501 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, |
521 kInstanceReg, | 502 kTypeArgumentsReg, kTempReg, |
522 kTypeArgumentsReg, | 503 is_instance_lbl, is_not_instance_lbl); |
523 kTempReg, | |
524 is_instance_lbl, | |
525 is_not_instance_lbl); | |
526 } | 504 } |
527 return SubtypeTestCache::null(); | 505 return SubtypeTestCache::null(); |
528 } | 506 } |
529 | 507 |
530 | 508 |
531 // Inputs: | 509 // Inputs: |
532 // - EAX: instance to test against (preserved). | 510 // - EAX: instance to test against (preserved). |
533 // - EDX: optional instantiator type arguments (preserved). | 511 // - EDX: optional instantiator type arguments (preserved). |
534 // Clobbers ECX, EDI. | 512 // Clobbers ECX, EDI. |
535 // Returns: | 513 // Returns: |
(...skipping 11 matching lines...) Expand all Loading... |
547 // A non-null value is returned from a void function, which will result in a | 525 // A non-null value is returned from a void function, which will result in a |
548 // type error. A null value is handled prior to executing this inline code. | 526 // type error. A null value is handled prior to executing this inline code. |
549 return SubtypeTestCache::null(); | 527 return SubtypeTestCache::null(); |
550 } | 528 } |
551 if (type.IsInstantiated()) { | 529 if (type.IsInstantiated()) { |
552 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 530 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
553 // A class equality check is only applicable with a dst type (not a | 531 // A class equality check is only applicable with a dst type (not a |
554 // function type) of a non-parameterized class or with a raw dst type of | 532 // function type) of a non-parameterized class or with a raw dst type of |
555 // a parameterized class. | 533 // a parameterized class. |
556 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { | 534 if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) { |
557 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, | 535 return GenerateInstantiatedTypeWithArgumentsTest( |
558 type, | 536 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
559 is_instance_lbl, | |
560 is_not_instance_lbl); | |
561 // Fall through to runtime call. | 537 // Fall through to runtime call. |
562 } | 538 } |
563 const bool has_fall_through = | 539 const bool has_fall_through = GenerateInstantiatedTypeNoArgumentsTest( |
564 GenerateInstantiatedTypeNoArgumentsTest(token_pos, | 540 token_pos, type, is_instance_lbl, is_not_instance_lbl); |
565 type, | |
566 is_instance_lbl, | |
567 is_not_instance_lbl); | |
568 if (has_fall_through) { | 541 if (has_fall_through) { |
569 // If test non-conclusive so far, try the inlined type-test cache. | 542 // If test non-conclusive so far, try the inlined type-test cache. |
570 // 'type' is known at compile time. | 543 // 'type' is known at compile time. |
571 return GenerateSubtype1TestCacheLookup( | 544 return GenerateSubtype1TestCacheLookup( |
572 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 545 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
573 } else { | 546 } else { |
574 return SubtypeTestCache::null(); | 547 return SubtypeTestCache::null(); |
575 } | 548 } |
576 } | 549 } |
577 return GenerateUninstantiatedTypeTest(token_pos, | 550 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, |
578 type, | |
579 is_instance_lbl, | |
580 is_not_instance_lbl); | 551 is_not_instance_lbl); |
581 } | 552 } |
582 | 553 |
583 | 554 |
584 // If instanceof type test cannot be performed successfully at compile time and | 555 // If instanceof type test cannot be performed successfully at compile time and |
585 // therefore eliminated, optimize it by adding inlined tests for: | 556 // therefore eliminated, optimize it by adding inlined tests for: |
586 // - NULL -> return false. | 557 // - NULL -> return false. |
587 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 558 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
588 // - Class equality (only if class is not parameterized). | 559 // - Class equality (only if class is not parameterized). |
589 // Inputs: | 560 // Inputs: |
(...skipping 22 matching lines...) Expand all Loading... |
612 // instantiated). | 583 // instantiated). |
613 // We can only inline this null check if the type is instantiated at compile | 584 // We can only inline this null check if the type is instantiated at compile |
614 // time, since an uninstantiated type at compile time could be Object or | 585 // time, since an uninstantiated type at compile time could be Object or |
615 // dynamic at run time. | 586 // dynamic at run time. |
616 __ cmpl(EAX, raw_null); | 587 __ cmpl(EAX, raw_null); |
617 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 588 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
618 } | 589 } |
619 | 590 |
620 // Generate inline instanceof test. | 591 // Generate inline instanceof test. |
621 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 592 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
622 test_cache = GenerateInlineInstanceof(token_pos, type, | 593 test_cache = |
623 &is_instance, &is_not_instance); | 594 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
624 | 595 |
625 // test_cache is null if there is no fall-through. | 596 // test_cache is null if there is no fall-through. |
626 Label done; | 597 Label done; |
627 if (!test_cache.IsNull()) { | 598 if (!test_cache.IsNull()) { |
628 // Generate runtime call. | 599 // Generate runtime call. |
629 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 600 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
630 __ PushObject(Object::null_object()); // Make room for the result. | 601 __ PushObject(Object::null_object()); // Make room for the result. |
631 __ pushl(EAX); // Push the instance. | 602 __ pushl(EAX); // Push the instance. |
632 __ PushObject(type); // Push the type. | 603 __ PushObject(type); // Push the type. |
633 __ pushl(EDX); // Instantiator type arguments. | 604 __ pushl(EDX); // Instantiator type arguments. |
634 __ LoadObject(EAX, test_cache); | 605 __ LoadObject(EAX, test_cache); |
635 __ pushl(EAX); | 606 __ pushl(EAX); |
636 GenerateRuntimeCall(token_pos, | 607 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
637 deopt_id, | |
638 kInstanceofRuntimeEntry, | |
639 4, | |
640 locs); | |
641 // Pop the parameters supplied to the runtime entry. The result of the | 608 // Pop the parameters supplied to the runtime entry. The result of the |
642 // instanceof runtime call will be left as the result of the operation. | 609 // instanceof runtime call will be left as the result of the operation. |
643 __ Drop(4); | 610 __ Drop(4); |
644 if (negate_result) { | 611 if (negate_result) { |
645 __ popl(EDX); | 612 __ popl(EDX); |
646 __ LoadObject(EAX, Bool::True()); | 613 __ LoadObject(EAX, Bool::True()); |
647 __ cmpl(EDX, EAX); | 614 __ cmpl(EDX, EAX); |
648 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 615 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
649 __ LoadObject(EAX, Bool::False()); | 616 __ LoadObject(EAX, Bool::False()); |
650 } else { | 617 } else { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 // A null object is always assignable and is returned as result. | 656 // A null object is always assignable and is returned as result. |
690 const Immediate& raw_null = | 657 const Immediate& raw_null = |
691 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 658 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
692 Label is_assignable, runtime_call; | 659 Label is_assignable, runtime_call; |
693 __ cmpl(EAX, raw_null); | 660 __ cmpl(EAX, raw_null); |
694 __ j(EQUAL, &is_assignable); | 661 __ j(EQUAL, &is_assignable); |
695 | 662 |
696 // Generate throw new TypeError() if the type is malformed or malbounded. | 663 // Generate throw new TypeError() if the type is malformed or malbounded. |
697 if (dst_type.IsMalformedOrMalbounded()) { | 664 if (dst_type.IsMalformedOrMalbounded()) { |
698 __ PushObject(Object::null_object()); // Make room for the result. | 665 __ PushObject(Object::null_object()); // Make room for the result. |
699 __ pushl(EAX); // Push the source object. | 666 __ pushl(EAX); // Push the source object. |
700 __ PushObject(dst_name); // Push the name of the destination. | 667 __ PushObject(dst_name); // Push the name of the destination. |
701 __ PushObject(dst_type); // Push the type of the destination. | 668 __ PushObject(dst_type); // Push the type of the destination. |
702 GenerateRuntimeCall(token_pos, | 669 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
703 deopt_id, | |
704 kBadTypeErrorRuntimeEntry, | |
705 3, | |
706 locs); | 670 locs); |
707 // We should never return here. | 671 // We should never return here. |
708 __ int3(); | 672 __ int3(); |
709 | 673 |
710 __ Bind(&is_assignable); // For a null object. | 674 __ Bind(&is_assignable); // For a null object. |
711 __ popl(EDX); // Remove pushed instantiator type arguments. | 675 __ popl(EDX); // Remove pushed instantiator type arguments. |
712 return; | 676 return; |
713 } | 677 } |
714 | 678 |
715 // Generate inline type check, linking to runtime call if not assignable. | 679 // Generate inline type check, linking to runtime call if not assignable. |
716 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 680 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
717 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 681 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
718 &is_assignable, &runtime_call); | 682 &runtime_call); |
719 | 683 |
720 __ Bind(&runtime_call); | 684 __ Bind(&runtime_call); |
721 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 685 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
722 __ PushObject(Object::null_object()); // Make room for the result. | 686 __ PushObject(Object::null_object()); // Make room for the result. |
723 __ pushl(EAX); // Push the source object. | 687 __ pushl(EAX); // Push the source object. |
724 __ PushObject(dst_type); // Push the type of the destination. | 688 __ PushObject(dst_type); // Push the type of the destination. |
725 __ pushl(EDX); // Instantiator type arguments. | 689 __ pushl(EDX); // Instantiator type arguments. |
726 __ PushObject(dst_name); // Push the name of the destination. | 690 __ PushObject(dst_name); // Push the name of the destination. |
727 __ LoadObject(EAX, test_cache); | 691 __ LoadObject(EAX, test_cache); |
728 __ pushl(EAX); | 692 __ pushl(EAX); |
729 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 693 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
730 // Pop the parameters supplied to the runtime entry. The result of the | 694 // Pop the parameters supplied to the runtime entry. The result of the |
731 // type check runtime call is the checked value. | 695 // type check runtime call is the checked value. |
732 __ Drop(5); | 696 __ Drop(5); |
733 __ popl(EAX); | 697 __ popl(EAX); |
734 | 698 |
735 __ Bind(&is_assignable); | 699 __ Bind(&is_assignable); |
736 __ popl(EDX); // Remove pushed instantiator type arguments. | 700 __ popl(EDX); // Remove pushed instantiator type arguments. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
785 | 749 |
786 // Copy positional arguments. | 750 // Copy positional arguments. |
787 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 751 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
788 // to fp[kFirstLocalSlotFromFp - i]. | 752 // to fp[kFirstLocalSlotFromFp - i]. |
789 | 753 |
790 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); | 754 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
791 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. | 755 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. |
792 // Let EBX point to the last passed positional argument, i.e. to | 756 // Let EBX point to the last passed positional argument, i.e. to |
793 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 757 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
794 __ subl(EBX, ECX); | 758 __ subl(EBX, ECX); |
795 __ leal(EBX, Address(EBP, EBX, TIMES_2, | 759 __ leal(EBX, |
796 (kParamEndSlotFromFp + 1) * kWordSize)); | 760 Address(EBP, EBX, TIMES_2, (kParamEndSlotFromFp + 1) * kWordSize)); |
797 | 761 |
798 // Let EDI point to the last copied positional argument, i.e. to | 762 // Let EDI point to the last copied positional argument, i.e. to |
799 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. | 763 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. |
800 __ leal(EDI, Address(EBP, (kFirstLocalSlotFromFp + 1) * kWordSize)); | 764 __ leal(EDI, Address(EBP, (kFirstLocalSlotFromFp + 1) * kWordSize)); |
801 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. | 765 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. |
802 __ subl(EDI, ECX); | 766 __ subl(EDI, ECX); |
803 __ SmiUntag(ECX); | 767 __ SmiUntag(ECX); |
804 Label loop, loop_condition; | 768 Label loop, loop_condition; |
805 __ jmp(&loop_condition, Assembler::kNearJump); | 769 __ jmp(&loop_condition, Assembler::kNearJump); |
806 // We do not use the final allocation index of the variable here, i.e. | 770 // We do not use the final allocation index of the variable here, i.e. |
807 // scope->VariableAt(i)->index(), because captured variables still need | 771 // scope->VariableAt(i)->index(), because captured variables still need |
808 // to be copied to the context that is not yet allocated. | 772 // to be copied to the context that is not yet allocated. |
809 const Address argument_addr(EBX, ECX, TIMES_4, 0); | 773 const Address argument_addr(EBX, ECX, TIMES_4, 0); |
810 const Address copy_addr(EDI, ECX, TIMES_4, 0); | 774 const Address copy_addr(EDI, ECX, TIMES_4, 0); |
811 __ Bind(&loop); | 775 __ Bind(&loop); |
812 __ movl(EAX, argument_addr); | 776 __ movl(EAX, argument_addr); |
813 __ movl(copy_addr, EAX); | 777 __ movl(copy_addr, EAX); |
814 __ Bind(&loop_condition); | 778 __ Bind(&loop_condition); |
815 __ decl(ECX); | 779 __ decl(ECX); |
816 __ j(POSITIVE, &loop, Assembler::kNearJump); | 780 __ j(POSITIVE, &loop, Assembler::kNearJump); |
817 | 781 |
818 // Copy or initialize optional named arguments. | 782 // Copy or initialize optional named arguments. |
819 const Immediate& raw_null = | 783 const Immediate& raw_null = |
820 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 784 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
821 Label all_arguments_processed; | 785 Label all_arguments_processed; |
822 #ifdef DEBUG | 786 #ifdef DEBUG |
823 const bool check_correct_named_args = true; | 787 const bool check_correct_named_args = true; |
824 #else | 788 #else |
825 const bool check_correct_named_args = function.IsClosureFunction(); | 789 const bool check_correct_named_args = function.IsClosureFunction(); |
826 #endif | 790 #endif |
827 if (num_opt_named_params > 0) { | 791 if (num_opt_named_params > 0) { |
828 // Start by alphabetically sorting the names of the optional parameters. | 792 // Start by alphabetically sorting the names of the optional parameters. |
829 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | 793 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
830 int* opt_param_position = new int[num_opt_named_params]; | 794 int* opt_param_position = new int[num_opt_named_params]; |
831 for (int pos = num_fixed_params; pos < num_params; pos++) { | 795 for (int pos = num_fixed_params; pos < num_params; pos++) { |
832 LocalVariable* parameter = scope->VariableAt(pos); | 796 LocalVariable* parameter = scope->VariableAt(pos); |
833 const String& opt_param_name = parameter->name(); | 797 const String& opt_param_name = parameter->name(); |
834 int i = pos - num_fixed_params; | 798 int i = pos - num_fixed_params; |
835 while (--i >= 0) { | 799 while (--i >= 0) { |
836 LocalVariable* param_i = opt_param[i]; | 800 LocalVariable* param_i = opt_param[i]; |
837 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 801 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
838 ASSERT(result != 0); | 802 ASSERT(result != 0); |
839 if (result > 0) break; | 803 if (result > 0) break; |
840 opt_param[i + 1] = opt_param[i]; | 804 opt_param[i + 1] = opt_param[i]; |
841 opt_param_position[i + 1] = opt_param_position[i]; | 805 opt_param_position[i + 1] = opt_param_position[i]; |
842 } | 806 } |
843 opt_param[i + 1] = parameter; | 807 opt_param[i + 1] = parameter; |
844 opt_param_position[i + 1] = pos; | 808 opt_param_position[i + 1] = pos; |
845 } | 809 } |
846 // Generate code handling each optional parameter in alphabetical order. | 810 // Generate code handling each optional parameter in alphabetical order. |
847 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); | 811 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
848 __ movl(ECX, | 812 __ movl(ECX, |
849 FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset())); | 813 FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset())); |
850 __ SmiUntag(ECX); | 814 __ SmiUntag(ECX); |
851 // Let EBX point to the first passed argument, i.e. to | 815 // Let EBX point to the first passed argument, i.e. to |
852 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (EBX) is Smi. | 816 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (EBX) is Smi. |
853 __ leal(EBX, | 817 __ leal(EBX, Address(EBP, EBX, TIMES_2, kParamEndSlotFromFp * kWordSize)); |
854 Address(EBP, EBX, TIMES_2, kParamEndSlotFromFp * kWordSize)); | |
855 // Let EDI point to the entry of the first named argument. | 818 // Let EDI point to the entry of the first named argument. |
856 __ leal(EDI, | 819 __ leal(EDI, |
857 FieldAddress(EDX, ArgumentsDescriptor::first_named_entry_offset())); | 820 FieldAddress(EDX, ArgumentsDescriptor::first_named_entry_offset())); |
858 for (int i = 0; i < num_opt_named_params; i++) { | 821 for (int i = 0; i < num_opt_named_params; i++) { |
859 Label load_default_value, assign_optional_parameter; | 822 Label load_default_value, assign_optional_parameter; |
860 const int param_pos = opt_param_position[i]; | 823 const int param_pos = opt_param_position[i]; |
861 // Check if this named parameter was passed in. | 824 // Check if this named parameter was passed in. |
862 // Load EAX with the name of the argument. | 825 // Load EAX with the name of the argument. |
863 __ movl(EAX, Address(EDI, ArgumentsDescriptor::name_offset())); | 826 __ movl(EAX, Address(EDI, ArgumentsDescriptor::name_offset())); |
864 ASSERT(opt_param[i]->name().IsSymbol()); | 827 ASSERT(opt_param[i]->name().IsSymbol()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
944 // checked, otherwise noSuchMethod would not see their original values. | 907 // checked, otherwise noSuchMethod would not see their original values. |
945 // This step can be skipped in case we decide that formal parameters are | 908 // This step can be skipped in case we decide that formal parameters are |
946 // implicitly final, since garbage collecting the unmodified value is not | 909 // implicitly final, since garbage collecting the unmodified value is not |
947 // an issue anymore. | 910 // an issue anymore. |
948 | 911 |
949 // EDX : arguments descriptor array. | 912 // EDX : arguments descriptor array. |
950 __ movl(ECX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); | 913 __ movl(ECX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
951 __ SmiUntag(ECX); | 914 __ SmiUntag(ECX); |
952 Label null_args_loop, null_args_loop_condition; | 915 Label null_args_loop, null_args_loop_condition; |
953 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 916 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
954 const Address original_argument_addr( | 917 const Address original_argument_addr(EBP, ECX, TIMES_4, |
955 EBP, ECX, TIMES_4, (kParamEndSlotFromFp + 1) * kWordSize); | 918 (kParamEndSlotFromFp + 1) * kWordSize); |
956 __ Bind(&null_args_loop); | 919 __ Bind(&null_args_loop); |
957 __ movl(original_argument_addr, raw_null); | 920 __ movl(original_argument_addr, raw_null); |
958 __ Bind(&null_args_loop_condition); | 921 __ Bind(&null_args_loop_condition); |
959 __ decl(ECX); | 922 __ decl(ECX); |
960 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 923 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
961 } | 924 } |
962 | 925 |
963 | 926 |
964 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 927 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
965 // TOS: return address. | 928 // TOS: return address. |
(...skipping 19 matching lines...) Expand all Loading... |
985 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 948 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
986 __ movl(EAX, raw_null); | 949 __ movl(EAX, raw_null); |
987 __ ret(); | 950 __ ret(); |
988 } | 951 } |
989 | 952 |
990 | 953 |
991 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc | 954 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc |
992 // needs to be updated to match. | 955 // needs to be updated to match. |
993 void FlowGraphCompiler::EmitFrameEntry() { | 956 void FlowGraphCompiler::EmitFrameEntry() { |
994 const Function& function = parsed_function().function(); | 957 const Function& function = parsed_function().function(); |
995 if (CanOptimizeFunction() && | 958 if (CanOptimizeFunction() && function.IsOptimizable() && |
996 function.IsOptimizable() && | |
997 (!is_optimizing() || may_reoptimize())) { | 959 (!is_optimizing() || may_reoptimize())) { |
998 __ Comment("Invocation Count Check"); | 960 __ Comment("Invocation Count Check"); |
999 const Register function_reg = EBX; | 961 const Register function_reg = EBX; |
1000 __ LoadObject(function_reg, function); | 962 __ LoadObject(function_reg, function); |
1001 | 963 |
1002 // Reoptimization of an optimized function is triggered by counting in | 964 // Reoptimization of an optimized function is triggered by counting in |
1003 // IC stubs, but not at the entry of the function. | 965 // IC stubs, but not at the entry of the function. |
1004 if (!is_optimizing()) { | 966 if (!is_optimizing()) { |
1005 __ incl(FieldAddress(function_reg, Function::usage_counter_offset())); | 967 __ incl(FieldAddress(function_reg, Function::usage_counter_offset())); |
1006 } | 968 } |
1007 __ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()), | 969 __ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()), |
1008 Immediate(GetOptimizationThreshold())); | 970 Immediate(GetOptimizationThreshold())); |
1009 ASSERT(function_reg == EBX); | 971 ASSERT(function_reg == EBX); |
1010 __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry()); | 972 __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry()); |
1011 } | 973 } |
1012 __ Comment("Enter frame"); | 974 __ Comment("Enter frame"); |
1013 if (flow_graph().IsCompiledForOsr()) { | 975 if (flow_graph().IsCompiledForOsr()) { |
1014 intptr_t extra_slots = StackSize() | 976 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - |
1015 - flow_graph().num_stack_locals() | 977 flow_graph().num_copied_params(); |
1016 - flow_graph().num_copied_params(); | |
1017 ASSERT(extra_slots >= 0); | 978 ASSERT(extra_slots >= 0); |
1018 __ EnterOsrFrame(extra_slots * kWordSize); | 979 __ EnterOsrFrame(extra_slots * kWordSize); |
1019 } else { | 980 } else { |
1020 ASSERT(StackSize() >= 0); | 981 ASSERT(StackSize() >= 0); |
1021 __ EnterDartFrame(StackSize() * kWordSize); | 982 __ EnterDartFrame(StackSize() * kWordSize); |
1022 } | 983 } |
1023 } | 984 } |
1024 | 985 |
1025 | 986 |
1026 void FlowGraphCompiler::CompileGraph() { | 987 void FlowGraphCompiler::CompileGraph() { |
(...skipping 19 matching lines...) Expand all Loading... |
1046 if (num_copied_params == 0) { | 1007 if (num_copied_params == 0) { |
1047 const bool check_arguments = | 1008 const bool check_arguments = |
1048 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1009 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
1049 if (check_arguments) { | 1010 if (check_arguments) { |
1050 __ Comment("Check argument count"); | 1011 __ Comment("Check argument count"); |
1051 // Check that exactly num_fixed arguments are passed in. | 1012 // Check that exactly num_fixed arguments are passed in. |
1052 Label correct_num_arguments, wrong_num_arguments; | 1013 Label correct_num_arguments, wrong_num_arguments; |
1053 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); | 1014 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
1054 __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params))); | 1015 __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params))); |
1055 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); | 1016 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); |
1056 __ cmpl(EAX, | 1017 __ cmpl(EAX, FieldAddress( |
1057 FieldAddress(EDX, | 1018 EDX, ArgumentsDescriptor::positional_count_offset())); |
1058 ArgumentsDescriptor::positional_count_offset())); | |
1059 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); | 1019 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); |
1060 | 1020 |
1061 __ Bind(&wrong_num_arguments); | 1021 __ Bind(&wrong_num_arguments); |
1062 __ LeaveFrame(); // The arguments are still on the stack. | 1022 __ LeaveFrame(); // The arguments are still on the stack. |
1063 __ Jmp(*StubCode::CallClosureNoSuchMethod_entry()); | 1023 __ Jmp(*StubCode::CallClosureNoSuchMethod_entry()); |
1064 // The noSuchMethod call may return to the caller, but not here. | 1024 // The noSuchMethod call may return to the caller, but not here. |
1065 __ Bind(&correct_num_arguments); | 1025 __ Bind(&correct_num_arguments); |
1066 } | 1026 } |
1067 } else if (!flow_graph().IsCompiledForOsr()) { | 1027 } else if (!flow_graph().IsCompiledForOsr()) { |
1068 CopyParameters(); | 1028 CopyParameters(); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1173 AddDeoptIndexAtCall(deopt_id_after); | 1133 AddDeoptIndexAtCall(deopt_id_after); |
1174 } else { | 1134 } else { |
1175 // Add deoptimization continuation point after the call and before the | 1135 // Add deoptimization continuation point after the call and before the |
1176 // arguments are removed. | 1136 // arguments are removed. |
1177 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1137 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1178 } | 1138 } |
1179 } | 1139 } |
1180 } | 1140 } |
1181 | 1141 |
1182 | 1142 |
1183 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1143 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, |
1184 intptr_t argument_count, | 1144 intptr_t deopt_id, |
1185 intptr_t deopt_id, | 1145 TokenPosition token_pos, |
1186 TokenPosition token_pos, | 1146 LocationSummary* locs, |
1187 LocationSummary* locs, | 1147 const ICData& ic_data) { |
1188 const ICData& ic_data) { | |
1189 const StubEntry& stub_entry = | 1148 const StubEntry& stub_entry = |
1190 *StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1149 *StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
1191 __ LoadObject(ECX, ic_data); | 1150 __ LoadObject(ECX, ic_data); |
1192 GenerateDartCall(deopt_id, | 1151 GenerateDartCall(deopt_id, token_pos, stub_entry, |
1193 token_pos, | 1152 RawPcDescriptors::kUnoptStaticCall, locs); |
1194 stub_entry, | |
1195 RawPcDescriptors::kUnoptStaticCall, | |
1196 locs); | |
1197 __ Drop(argument_count); | 1153 __ Drop(argument_count); |
1198 } | 1154 } |
1199 | 1155 |
1200 | 1156 |
1201 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { | 1157 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { |
1202 // We do not check for overflow when incrementing the edge counter. The | 1158 // We do not check for overflow when incrementing the edge counter. The |
1203 // function should normally be optimized long before the counter can | 1159 // function should normally be optimized long before the counter can |
1204 // overflow; and though we do not reset the counters when we optimize or | 1160 // overflow; and though we do not reset the counters when we optimize or |
1205 // deoptimize, there is a bound on the number of | 1161 // deoptimize, there is a bound on the number of |
1206 // optimization/deoptimization cycles we will attempt. | 1162 // optimization/deoptimization cycles we will attempt. |
1207 ASSERT(!edge_counters_array_.IsNull()); | 1163 ASSERT(!edge_counters_array_.IsNull()); |
1208 __ Comment("Edge counter"); | 1164 __ Comment("Edge counter"); |
1209 __ LoadObject(EAX, edge_counters_array_); | 1165 __ LoadObject(EAX, edge_counters_array_); |
1210 __ IncrementSmiField(FieldAddress(EAX, Array::element_offset(edge_id)), 1); | 1166 __ IncrementSmiField(FieldAddress(EAX, Array::element_offset(edge_id)), 1); |
1211 } | 1167 } |
1212 | 1168 |
1213 | 1169 |
1214 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1170 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, |
1215 const StubEntry& stub_entry, | 1171 const ICData& ic_data, |
1216 const ICData& ic_data, | 1172 intptr_t argument_count, |
1217 intptr_t argument_count, | 1173 intptr_t deopt_id, |
1218 intptr_t deopt_id, | 1174 TokenPosition token_pos, |
1219 TokenPosition token_pos, | 1175 LocationSummary* locs) { |
1220 LocationSummary* locs) { | |
1221 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1176 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); |
1222 // Each ICData propagated from unoptimized to optimized code contains the | 1177 // Each ICData propagated from unoptimized to optimized code contains the |
1223 // function that corresponds to the Dart function of that IC call. Due | 1178 // function that corresponds to the Dart function of that IC call. Due |
1224 // to inlining in optimized code, that function may not correspond to the | 1179 // to inlining in optimized code, that function may not correspond to the |
1225 // top-level function (parsed_function().function()) which could be | 1180 // top-level function (parsed_function().function()) which could be |
1226 // reoptimized and which counter needs to be incremented. | 1181 // reoptimized and which counter needs to be incremented. |
1227 // Pass the function explicitly, it is used in IC stub. | 1182 // Pass the function explicitly, it is used in IC stub. |
1228 __ LoadObject(EBX, parsed_function().function()); | 1183 __ LoadObject(EBX, parsed_function().function()); |
1229 __ LoadObject(ECX, ic_data); | 1184 __ LoadObject(ECX, ic_data); |
1230 GenerateDartCall(deopt_id, | 1185 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1231 token_pos, | |
1232 stub_entry, | |
1233 RawPcDescriptors::kIcCall, | |
1234 locs); | 1186 locs); |
1235 __ Drop(argument_count); | 1187 __ Drop(argument_count); |
1236 } | 1188 } |
1237 | 1189 |
1238 | 1190 |
1239 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1191 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
1240 const ICData& ic_data, | 1192 const ICData& ic_data, |
1241 intptr_t argument_count, | 1193 intptr_t argument_count, |
1242 intptr_t deopt_id, | 1194 intptr_t deopt_id, |
1243 TokenPosition token_pos, | 1195 TokenPosition token_pos, |
1244 LocationSummary* locs) { | 1196 LocationSummary* locs) { |
1245 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1197 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); |
1246 __ LoadObject(ECX, ic_data); | 1198 __ LoadObject(ECX, ic_data); |
1247 GenerateDartCall(deopt_id, | 1199 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1248 token_pos, | |
1249 stub_entry, | |
1250 RawPcDescriptors::kIcCall, | |
1251 locs); | 1200 locs); |
1252 __ Drop(argument_count); | 1201 __ Drop(argument_count); |
1253 } | 1202 } |
1254 | 1203 |
1255 | 1204 |
1256 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1205 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
1257 const ICData& ic_data, | 1206 const ICData& ic_data, |
1258 intptr_t argument_count, | 1207 intptr_t argument_count, |
1259 intptr_t deopt_id, | 1208 intptr_t deopt_id, |
1260 TokenPosition token_pos, | 1209 TokenPosition token_pos, |
1261 LocationSummary* locs, | 1210 LocationSummary* locs, |
1262 intptr_t try_index, | 1211 intptr_t try_index, |
1263 intptr_t slow_path_argument_count) { | 1212 intptr_t slow_path_argument_count) { |
1264 const String& name = String::Handle(zone(), ic_data.target_name()); | 1213 const String& name = String::Handle(zone(), ic_data.target_name()); |
1265 const Array& arguments_descriptor = | 1214 const Array& arguments_descriptor = |
1266 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1215 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1267 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1216 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1268 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), | 1217 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
| 1218 zone(), |
1269 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1219 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1270 | 1220 |
1271 __ Comment("MegamorphicCall"); | 1221 __ Comment("MegamorphicCall"); |
1272 // Load receiver into EBX. | 1222 // Load receiver into EBX. |
1273 __ movl(EBX, Address(ESP, (argument_count - 1) * kWordSize)); | 1223 __ movl(EBX, Address(ESP, (argument_count - 1) * kWordSize)); |
1274 Label done; | 1224 Label done; |
1275 if (ShouldInlineSmiStringHashCode(ic_data)) { | 1225 if (ShouldInlineSmiStringHashCode(ic_data)) { |
1276 Label megamorphic_call; | 1226 Label megamorphic_call; |
1277 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | 1227 __ Comment("Inlined get:hashCode for Smi and OneByteString"); |
1278 __ movl(EAX, EBX); // Move Smi hashcode to EAX. | 1228 __ movl(EAX, EBX); // Move Smi hashcode to EAX. |
1279 __ testl(EBX, Immediate(kSmiTagMask)); | 1229 __ testl(EBX, Immediate(kSmiTagMask)); |
1280 __ j(ZERO, &done, Assembler::kNearJump); // It is Smi, we are done. | 1230 __ j(ZERO, &done, Assembler::kNearJump); // It is Smi, we are done. |
1281 | 1231 |
1282 __ CompareClassId(EBX, kOneByteStringCid, EAX); | 1232 __ CompareClassId(EBX, kOneByteStringCid, EAX); |
1283 __ j(NOT_EQUAL, &megamorphic_call, Assembler::kNearJump); | 1233 __ j(NOT_EQUAL, &megamorphic_call, Assembler::kNearJump); |
1284 __ movl(EAX, FieldAddress(EBX, String::hash_offset())); | 1234 __ movl(EAX, FieldAddress(EBX, String::hash_offset())); |
1285 __ cmpl(EAX, Immediate(0)); | 1235 __ cmpl(EAX, Immediate(0)); |
1286 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 1236 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
1287 | 1237 |
1288 __ Bind(&megamorphic_call); | 1238 __ Bind(&megamorphic_call); |
1289 __ Comment("Slow case: megamorphic call"); | 1239 __ Comment("Slow case: megamorphic call"); |
1290 } | 1240 } |
1291 __ LoadObject(ECX, cache); | 1241 __ LoadObject(ECX, cache); |
1292 __ call(Address(THR, Thread::megamorphic_call_checked_entry_offset())); | 1242 __ call(Address(THR, Thread::megamorphic_call_checked_entry_offset())); |
1293 __ call(EBX); | 1243 __ call(EBX); |
1294 | 1244 |
1295 __ Bind(&done); | 1245 __ Bind(&done); |
1296 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1246 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, token_pos); |
1297 Thread::kNoDeoptId, token_pos); | |
1298 RecordSafepoint(locs, slow_path_argument_count); | 1247 RecordSafepoint(locs, slow_path_argument_count); |
1299 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1248 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1300 // Precompilation not implemented on ia32 platform. | 1249 // Precompilation not implemented on ia32 platform. |
1301 ASSERT(!FLAG_precompiled_mode); | 1250 ASSERT(!FLAG_precompiled_mode); |
1302 if (is_optimizing()) { | 1251 if (is_optimizing()) { |
1303 AddDeoptIndexAtCall(deopt_id_after); | 1252 AddDeoptIndexAtCall(deopt_id_after); |
1304 } else { | 1253 } else { |
1305 // Add deoptimization continuation point after the call and before the | 1254 // Add deoptimization continuation point after the call and before the |
1306 // arguments are removed. | 1255 // arguments are removed. |
1307 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1256 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1308 } | 1257 } |
1309 __ Drop(argument_count); | 1258 __ Drop(argument_count); |
1310 } | 1259 } |
1311 | 1260 |
1312 | 1261 |
1313 void FlowGraphCompiler::EmitSwitchableInstanceCall( | 1262 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, |
1314 const ICData& ic_data, | 1263 intptr_t argument_count, |
1315 intptr_t argument_count, | 1264 intptr_t deopt_id, |
1316 intptr_t deopt_id, | 1265 TokenPosition token_pos, |
1317 TokenPosition token_pos, | 1266 LocationSummary* locs) { |
1318 LocationSummary* locs) { | |
1319 // Only generated with precompilation. | 1267 // Only generated with precompilation. |
1320 UNREACHABLE(); | 1268 UNREACHABLE(); |
1321 } | 1269 } |
1322 | 1270 |
1323 | 1271 |
1324 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1272 void FlowGraphCompiler::EmitOptimizedStaticCall( |
1325 const Function& function, | 1273 const Function& function, |
1326 const Array& arguments_descriptor, | 1274 const Array& arguments_descriptor, |
1327 intptr_t argument_count, | 1275 intptr_t argument_count, |
1328 intptr_t deopt_id, | 1276 intptr_t deopt_id, |
1329 TokenPosition token_pos, | 1277 TokenPosition token_pos, |
1330 LocationSummary* locs) { | 1278 LocationSummary* locs) { |
1331 if (function.HasOptionalParameters()) { | 1279 if (function.HasOptionalParameters()) { |
1332 __ LoadObject(EDX, arguments_descriptor); | 1280 __ LoadObject(EDX, arguments_descriptor); |
1333 } else { | 1281 } else { |
1334 __ xorl(EDX, EDX); // GC safe smi zero because of stub. | 1282 __ xorl(EDX, EDX); // GC safe smi zero because of stub. |
1335 } | 1283 } |
1336 // Do not use the code from the function, but let the code be patched so that | 1284 // Do not use the code from the function, but let the code be patched so that |
1337 // we can record the outgoing edges to other code. | 1285 // we can record the outgoing edges to other code. |
1338 GenerateDartCall(deopt_id, | 1286 GenerateDartCall(deopt_id, token_pos, *StubCode::CallStaticFunction_entry(), |
1339 token_pos, | 1287 RawPcDescriptors::kOther, locs); |
1340 *StubCode::CallStaticFunction_entry(), | |
1341 RawPcDescriptors::kOther, | |
1342 locs); | |
1343 AddStaticCallTarget(function); | 1288 AddStaticCallTarget(function); |
1344 __ Drop(argument_count); | 1289 __ Drop(argument_count); |
1345 } | 1290 } |
1346 | 1291 |
1347 | 1292 |
1348 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1293 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
1349 Register reg, | 1294 Register reg, |
1350 const Object& obj, | 1295 const Object& obj, |
1351 bool needs_number_check, | 1296 bool needs_number_check, |
1352 TokenPosition token_pos) { | 1297 TokenPosition token_pos) { |
1353 ASSERT(!needs_number_check || | 1298 ASSERT(!needs_number_check || |
1354 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); | 1299 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); |
1355 | 1300 |
1356 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { | 1301 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { |
1357 ASSERT(!needs_number_check); | 1302 ASSERT(!needs_number_check); |
1358 __ testl(reg, reg); | 1303 __ testl(reg, reg); |
1359 return EQUAL; | 1304 return EQUAL; |
1360 } | 1305 } |
1361 | 1306 |
1362 if (needs_number_check) { | 1307 if (needs_number_check) { |
1363 __ pushl(reg); | 1308 __ pushl(reg); |
1364 __ PushObject(obj); | 1309 __ PushObject(obj); |
1365 if (is_optimizing()) { | 1310 if (is_optimizing()) { |
1366 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1311 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1367 } else { | 1312 } else { |
1368 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1313 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1369 } | 1314 } |
1370 if (token_pos.IsReal()) { | 1315 if (token_pos.IsReal()) { |
1371 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1316 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
1372 Thread::kNoDeoptId, | |
1373 token_pos); | 1317 token_pos); |
1374 } | 1318 } |
1375 // Stub returns result in flags (result of a cmpl, we need ZF computed). | 1319 // Stub returns result in flags (result of a cmpl, we need ZF computed). |
1376 __ popl(reg); // Discard constant. | 1320 __ popl(reg); // Discard constant. |
1377 __ popl(reg); // Restore 'reg'. | 1321 __ popl(reg); // Restore 'reg'. |
1378 } else { | 1322 } else { |
1379 __ CompareObject(reg, obj); | 1323 __ CompareObject(reg, obj); |
1380 } | 1324 } |
1381 return EQUAL; | 1325 return EQUAL; |
1382 } | 1326 } |
1383 | 1327 |
1384 | 1328 |
1385 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( | 1329 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( |
1386 Register left, | 1330 Register left, |
1387 Register right, | 1331 Register right, |
1388 bool needs_number_check, | 1332 bool needs_number_check, |
1389 TokenPosition token_pos) { | 1333 TokenPosition token_pos) { |
1390 if (needs_number_check) { | 1334 if (needs_number_check) { |
1391 __ pushl(left); | 1335 __ pushl(left); |
1392 __ pushl(right); | 1336 __ pushl(right); |
1393 if (is_optimizing()) { | 1337 if (is_optimizing()) { |
1394 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1338 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1395 } else { | 1339 } else { |
1396 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1340 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1397 } | 1341 } |
1398 if (token_pos.IsReal()) { | 1342 if (token_pos.IsReal()) { |
1399 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1343 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, Thread::kNoDeoptId, |
1400 Thread::kNoDeoptId, | |
1401 token_pos); | 1344 token_pos); |
1402 } | 1345 } |
1403 // Stub returns result in flags (result of a cmpl, we need ZF computed). | 1346 // Stub returns result in flags (result of a cmpl, we need ZF computed). |
1404 __ popl(right); | 1347 __ popl(right); |
1405 __ popl(left); | 1348 __ popl(left); |
1406 } else { | 1349 } else { |
1407 __ cmpl(left, right); | 1350 __ cmpl(left, right); |
1408 } | 1351 } |
1409 return EQUAL; | 1352 return EQUAL; |
1410 } | 1353 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1491 const Array& argument_names, | 1434 const Array& argument_names, |
1492 Label* failed, | 1435 Label* failed, |
1493 Label* match_found, | 1436 Label* match_found, |
1494 intptr_t deopt_id, | 1437 intptr_t deopt_id, |
1495 TokenPosition token_index, | 1438 TokenPosition token_index, |
1496 LocationSummary* locs, | 1439 LocationSummary* locs, |
1497 bool complete) { | 1440 bool complete) { |
1498 ASSERT(is_optimizing()); | 1441 ASSERT(is_optimizing()); |
1499 ASSERT(!complete); | 1442 ASSERT(!complete); |
1500 __ Comment("EmitTestAndCall"); | 1443 __ Comment("EmitTestAndCall"); |
1501 const Array& arguments_descriptor = | 1444 const Array& arguments_descriptor = Array::ZoneHandle( |
1502 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, | 1445 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1503 argument_names)); | |
1504 // Load receiver into EAX. | 1446 // Load receiver into EAX. |
1505 __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize)); | 1447 __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize)); |
1506 __ LoadObject(EDX, arguments_descriptor); | 1448 __ LoadObject(EDX, arguments_descriptor); |
1507 | 1449 |
1508 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1450 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
1509 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1451 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
1510 | 1452 |
1511 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1453 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
1512 | 1454 |
1513 Label after_smi_test; | 1455 Label after_smi_test; |
1514 __ testl(EAX, Immediate(kSmiTagMask)); | 1456 __ testl(EAX, Immediate(kSmiTagMask)); |
1515 if (kFirstCheckIsSmi) { | 1457 if (kFirstCheckIsSmi) { |
1516 // Jump if receiver is not Smi. | 1458 // Jump if receiver is not Smi. |
1517 if (kNumChecks == 1) { | 1459 if (kNumChecks == 1) { |
1518 __ j(NOT_ZERO, failed); | 1460 __ j(NOT_ZERO, failed); |
1519 } else { | 1461 } else { |
1520 __ j(NOT_ZERO, &after_smi_test); | 1462 __ j(NOT_ZERO, &after_smi_test); |
1521 } | 1463 } |
1522 // Do not use the code from the function, but let the code be patched so | 1464 // Do not use the code from the function, but let the code be patched so |
1523 // that we can record the outgoing edges to other code. | 1465 // that we can record the outgoing edges to other code. |
1524 GenerateDartCall(deopt_id, | 1466 GenerateDartCall(deopt_id, token_index, |
1525 token_index, | |
1526 *StubCode::CallStaticFunction_entry(), | 1467 *StubCode::CallStaticFunction_entry(), |
1527 RawPcDescriptors::kOther, | 1468 RawPcDescriptors::kOther, locs); |
1528 locs); | 1469 const Function& function = |
1529 const Function& function = Function::ZoneHandle( | 1470 Function::ZoneHandle(zone(), ic_data.GetTargetAt(0)); |
1530 zone(), ic_data.GetTargetAt(0)); | |
1531 AddStaticCallTarget(function); | 1471 AddStaticCallTarget(function); |
1532 __ Drop(argument_count); | 1472 __ Drop(argument_count); |
1533 if (kNumChecks > 1) { | 1473 if (kNumChecks > 1) { |
1534 __ jmp(match_found); | 1474 __ jmp(match_found); |
1535 } | 1475 } |
1536 } else { | 1476 } else { |
1537 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1477 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1538 // (Smi class must be first in the list). | 1478 // (Smi class must be first in the list). |
1539 __ j(ZERO, failed); | 1479 __ j(ZERO, failed); |
1540 } | 1480 } |
(...skipping 16 matching lines...) Expand all Loading... |
1557 ASSERT(sorted[i].cid != kSmiCid); | 1497 ASSERT(sorted[i].cid != kSmiCid); |
1558 Label next_test; | 1498 Label next_test; |
1559 __ cmpl(EDI, Immediate(sorted[i].cid)); | 1499 __ cmpl(EDI, Immediate(sorted[i].cid)); |
1560 if (kIsLastCheck) { | 1500 if (kIsLastCheck) { |
1561 __ j(NOT_EQUAL, failed); | 1501 __ j(NOT_EQUAL, failed); |
1562 } else { | 1502 } else { |
1563 __ j(NOT_EQUAL, &next_test); | 1503 __ j(NOT_EQUAL, &next_test); |
1564 } | 1504 } |
1565 // Do not use the code from the function, but let the code be patched so | 1505 // Do not use the code from the function, but let the code be patched so |
1566 // that we can record the outgoing edges to other code. | 1506 // that we can record the outgoing edges to other code. |
1567 GenerateDartCall(deopt_id, | 1507 GenerateDartCall(deopt_id, token_index, |
1568 token_index, | |
1569 *StubCode::CallStaticFunction_entry(), | 1508 *StubCode::CallStaticFunction_entry(), |
1570 RawPcDescriptors::kOther, | 1509 RawPcDescriptors::kOther, locs); |
1571 locs); | |
1572 const Function& function = *sorted[i].target; | 1510 const Function& function = *sorted[i].target; |
1573 AddStaticCallTarget(function); | 1511 AddStaticCallTarget(function); |
1574 __ Drop(argument_count); | 1512 __ Drop(argument_count); |
1575 if (!kIsLastCheck) { | 1513 if (!kIsLastCheck) { |
1576 __ jmp(match_found); | 1514 __ jmp(match_found); |
1577 } | 1515 } |
1578 __ Bind(&next_test); | 1516 __ Bind(&next_test); |
1579 } | 1517 } |
1580 } | 1518 } |
1581 | 1519 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1633 __ movups(XMM0, source.ToStackSlotAddress()); | 1571 __ movups(XMM0, source.ToStackSlotAddress()); |
1634 __ movups(destination.ToStackSlotAddress(), XMM0); | 1572 __ movups(destination.ToStackSlotAddress(), XMM0); |
1635 } | 1573 } |
1636 } else { | 1574 } else { |
1637 ASSERT(source.IsConstant()); | 1575 ASSERT(source.IsConstant()); |
1638 if (destination.IsRegister()) { | 1576 if (destination.IsRegister()) { |
1639 const Object& constant = source.constant(); | 1577 const Object& constant = source.constant(); |
1640 if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { | 1578 if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { |
1641 __ xorl(destination.reg(), destination.reg()); | 1579 __ xorl(destination.reg(), destination.reg()); |
1642 } else if (constant.IsSmi() && | 1580 } else if (constant.IsSmi() && |
1643 (source.constant_instruction()->representation() == kUnboxedInt32)) { | 1581 (source.constant_instruction()->representation() == |
| 1582 kUnboxedInt32)) { |
1644 __ movl(destination.reg(), Immediate(Smi::Cast(constant).Value())); | 1583 __ movl(destination.reg(), Immediate(Smi::Cast(constant).Value())); |
1645 } else { | 1584 } else { |
1646 __ LoadObjectSafely(destination.reg(), constant); | 1585 __ LoadObjectSafely(destination.reg(), constant); |
1647 } | 1586 } |
1648 } else if (destination.IsFpuRegister()) { | 1587 } else if (destination.IsFpuRegister()) { |
1649 const Double& constant = Double::Cast(source.constant()); | 1588 const Double& constant = Double::Cast(source.constant()); |
1650 uword addr = FlowGraphBuilder::FindDoubleConstant(constant.value()); | 1589 uword addr = FlowGraphBuilder::FindDoubleConstant(constant.value()); |
1651 if (addr == 0) { | 1590 if (addr == 0) { |
1652 __ pushl(EAX); | 1591 __ pushl(EAX); |
1653 __ LoadObject(EAX, constant); | 1592 __ LoadObject(EAX, constant); |
1654 __ movsd(destination.fpu_reg(), | 1593 __ movsd(destination.fpu_reg(), |
1655 FieldAddress(EAX, Double::value_offset())); | 1594 FieldAddress(EAX, Double::value_offset())); |
1656 __ popl(EAX); | 1595 __ popl(EAX); |
1657 } else if (Utils::DoublesBitEqual(constant.value(), 0.0)) { | 1596 } else if (Utils::DoublesBitEqual(constant.value(), 0.0)) { |
1658 __ xorps(destination.fpu_reg(), destination.fpu_reg()); | 1597 __ xorps(destination.fpu_reg(), destination.fpu_reg()); |
1659 } else { | 1598 } else { |
1660 __ movsd(destination.fpu_reg(), Address::Absolute(addr)); | 1599 __ movsd(destination.fpu_reg(), Address::Absolute(addr)); |
1661 } | 1600 } |
1662 } else if (destination.IsDoubleStackSlot()) { | 1601 } else if (destination.IsDoubleStackSlot()) { |
1663 const Double& constant = Double::Cast(source.constant()); | 1602 const Double& constant = Double::Cast(source.constant()); |
1664 uword addr = FlowGraphBuilder::FindDoubleConstant(constant.value()); | 1603 uword addr = FlowGraphBuilder::FindDoubleConstant(constant.value()); |
1665 if (addr == 0) { | 1604 if (addr == 0) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1701 Exchange(source.reg(), destination.ToStackSlotAddress()); | 1640 Exchange(source.reg(), destination.ToStackSlotAddress()); |
1702 } else if (source.IsStackSlot() && destination.IsRegister()) { | 1641 } else if (source.IsStackSlot() && destination.IsRegister()) { |
1703 Exchange(destination.reg(), source.ToStackSlotAddress()); | 1642 Exchange(destination.reg(), source.ToStackSlotAddress()); |
1704 } else if (source.IsStackSlot() && destination.IsStackSlot()) { | 1643 } else if (source.IsStackSlot() && destination.IsStackSlot()) { |
1705 Exchange(destination.ToStackSlotAddress(), source.ToStackSlotAddress()); | 1644 Exchange(destination.ToStackSlotAddress(), source.ToStackSlotAddress()); |
1706 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { | 1645 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { |
1707 __ movaps(XMM0, source.fpu_reg()); | 1646 __ movaps(XMM0, source.fpu_reg()); |
1708 __ movaps(source.fpu_reg(), destination.fpu_reg()); | 1647 __ movaps(source.fpu_reg(), destination.fpu_reg()); |
1709 __ movaps(destination.fpu_reg(), XMM0); | 1648 __ movaps(destination.fpu_reg(), XMM0); |
1710 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { | 1649 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { |
1711 ASSERT(destination.IsDoubleStackSlot() || | 1650 ASSERT(destination.IsDoubleStackSlot() || destination.IsQuadStackSlot() || |
1712 destination.IsQuadStackSlot() || | 1651 source.IsDoubleStackSlot() || source.IsQuadStackSlot()); |
1713 source.IsDoubleStackSlot() || | 1652 bool double_width = |
1714 source.IsQuadStackSlot()); | 1653 destination.IsDoubleStackSlot() || source.IsDoubleStackSlot(); |
1715 bool double_width = destination.IsDoubleStackSlot() || | 1654 XmmRegister reg = |
1716 source.IsDoubleStackSlot(); | 1655 source.IsFpuRegister() ? source.fpu_reg() : destination.fpu_reg(); |
1717 XmmRegister reg = source.IsFpuRegister() ? source.fpu_reg() | |
1718 : destination.fpu_reg(); | |
1719 const Address& slot_address = source.IsFpuRegister() | 1656 const Address& slot_address = source.IsFpuRegister() |
1720 ? destination.ToStackSlotAddress() | 1657 ? destination.ToStackSlotAddress() |
1721 : source.ToStackSlotAddress(); | 1658 : source.ToStackSlotAddress(); |
1722 | 1659 |
1723 if (double_width) { | 1660 if (double_width) { |
1724 __ movsd(XMM0, slot_address); | 1661 __ movsd(XMM0, slot_address); |
1725 __ movsd(slot_address, reg); | 1662 __ movsd(slot_address, reg); |
1726 } else { | 1663 } else { |
1727 __ movups(XMM0, slot_address); | 1664 __ movups(XMM0, slot_address); |
1728 __ movups(slot_address, reg); | 1665 __ movups(slot_address, reg); |
1729 } | 1666 } |
1730 __ movaps(reg, XMM0); | 1667 __ movaps(reg, XMM0); |
1731 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { | 1668 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1840 __ movups(reg, Address(ESP, 0)); | 1777 __ movups(reg, Address(ESP, 0)); |
1841 __ addl(ESP, Immediate(kFpuRegisterSize)); | 1778 __ addl(ESP, Immediate(kFpuRegisterSize)); |
1842 } | 1779 } |
1843 | 1780 |
1844 | 1781 |
1845 #undef __ | 1782 #undef __ |
1846 | 1783 |
1847 } // namespace dart | 1784 } // namespace dart |
1848 | 1785 |
1849 #endif // defined TARGET_ARCH_IA32 | 1786 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |