Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/code_generator.h" | 5 #include "vm/code_generator.h" |
| 6 | 6 |
| 7 #include "vm/code_patcher.h" | 7 #include "vm/code_patcher.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/dart_api_impl.h" | 9 #include "vm/dart_api_impl.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 } | 362 } |
| 363 new_type_arguments.SetTypeAt(i, type_at); | 363 new_type_arguments.SetTypeAt(i, type_at); |
| 364 } | 364 } |
| 365 new_type_arguments ^= new_type_arguments.Canonicalize(); | 365 new_type_arguments ^= new_type_arguments.Canonicalize(); |
| 366 instance.SetTypeArguments(new_type_arguments); | 366 instance.SetTypeArguments(new_type_arguments); |
| 367 } | 367 } |
| 368 } | 368 } |
| 369 } | 369 } |
| 370 | 370 |
| 371 | 371 |
| 372 // This updates the type test cache, an array containing tuples (instance class, | 372 // This updates the type test cache, an array containing tuples (instance class, |
|
regis
2012/04/27 23:27:48
The tuple contains 4 entries, right?
srdjan
2012/04/27 23:43:19
Done.
| |
| 373 // test result_. It can be applied to classes with type arguments in which | 373 // test result_. It can be applied to classes with type arguments in which |
| 374 // case it contains just the result of the class subtype test, not including | 374 // case it contains just the result of the class subtype test, not including |
| 375 // the evaluation of type arguments. | 375 // the evaluation of type arguments. |
| 376 // Note that the 'result' contains the whole type test (including type | |
| 377 // arguments), but the type test cache contains only the result of the | |
| 378 // class test. Therefore we may need to recompute the 'result'. | |
| 379 // This operation is currently very slow (lookup of code is not efficient yet). | 376 // This operation is currently very slow (lookup of code is not efficient yet). |
| 380 static void UpdateTypeTestCache(intptr_t node_id, | 377 static void UpdateTypeTestCache(intptr_t node_id, |
| 381 const Instance& instance, | 378 const Instance& instance, |
| 382 const AbstractType& type, | 379 const AbstractType& type, |
| 383 const AbstractTypeArguments& type_instantiator, | 380 const AbstractTypeArguments& type_instantiator, |
| 384 const Bool& result) { | 381 const Bool& result) { |
| 385 // Since the test is expensive, don't do it unless necessary. | 382 // Since the test is expensive, don't do it unless necessary. |
| 386 // The list of disallowed cases will decrease as they are implemented in | 383 // The list of disallowed cases will decrease as they are implemented in |
| 387 // inlined assembly. | 384 // inlined assembly. |
| 388 if (!type.IsInstantiated()) return; | 385 if (!type.IsInstantiated()) return; |
| 389 // TODO(srdjan): Implement assembly code for checking type arguments then | |
| 390 // remove this check. | |
| 391 if (Class::Handle(type.type_class()).HasTypeArguments()) { | 386 if (Class::Handle(type.type_class()).HasTypeArguments()) { |
| 392 const AbstractTypeArguments& type_arguments = | 387 const AbstractTypeArguments& type_arguments = |
| 393 AbstractTypeArguments::Handle(type.arguments()); | 388 AbstractTypeArguments::Handle(type.arguments()); |
| 394 const bool is_raw_type = type_arguments.IsNull() || | 389 const bool is_raw_type = type_arguments.IsNull() || |
| 395 type_arguments.IsRaw(type_arguments.Length()); | 390 type_arguments.IsRaw(type_arguments.Length()); |
| 396 if (!is_raw_type) { | 391 if (!is_raw_type) { |
| 397 // We cannot inline tests for instances with more than one type argument | 392 // We cannot inline tests for instances with more than one type argument |
| 398 // or if its class has not been resolved (malformed type). | 393 // or if its class has not been resolved (malformed type). |
| 399 if (type_arguments.Length() != 1) { | 394 if (type_arguments.Length() != 1) { |
| 400 // We can handle only one argument so far. | 395 // We can handle only one argument so far. |
| 401 return; | 396 return; |
| 402 } | 397 } |
| 403 const AbstractType& tp_argument = | 398 const AbstractType& tp_argument = |
| 404 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); | 399 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); |
| 405 if (!tp_argument.IsType()) { | 400 if (!tp_argument.IsType()) { |
| 406 // E.g, it is TypeParameter. | 401 // E.g, it is TypeParameter. |
| 407 return; | 402 return; |
| 408 } | 403 } |
| 409 const Type& list_type = | |
| 410 Type::Handle(Isolate::Current()->object_store()->list_interface()); | |
| 411 Error& malformed_error = Error::Handle(); | |
| 412 if (!list_type.IsSubtypeOf(type, &malformed_error)) { | |
| 413 return; | |
| 414 } | |
| 415 // The type argument at index 0 must be instantiated and not malformed. | |
| 416 // A malformed type would have caused a type error earlier. | |
| 417 ASSERT(tp_argument.HasResolvedTypeClass()); | 404 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 418 } | 405 } |
| 419 } | 406 } |
| 407 AbstractTypeArguments& instance_type_arguments = | |
| 408 AbstractTypeArguments::Handle(); | |
| 409 const Class& instance_class = Class::Handle(instance.clazz()); | |
| 410 if (instance_class.HasTypeArguments()) { | |
| 411 OptimizeTypeArguments(instance); | |
| 412 instance_type_arguments = instance.GetTypeArguments(); | |
| 413 } | |
| 414 | |
| 420 DartFrameIterator iterator; | 415 DartFrameIterator iterator; |
| 421 StackFrame* caller_frame = iterator.NextFrame(); | 416 StackFrame* caller_frame = iterator.NextFrame(); |
| 422 ASSERT(caller_frame != NULL); | 417 ASSERT(caller_frame != NULL); |
| 423 const Code& code = Code::Handle(caller_frame->LookupDartCode()); | 418 const Code& code = Code::Handle(caller_frame->LookupDartCode()); |
| 424 ASSERT(!code.IsNull()); | 419 ASSERT(!code.IsNull()); |
| 425 uword loc = code.GetTypeTestAtNodeId(node_id); | 420 uword loc = code.GetTypeTestAtNodeId(node_id); |
| 426 if (loc != 0) { | 421 if (loc != 0) { |
| 427 // Found type test cache. | 422 // Found type test cache. |
| 428 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc)); | 423 Array& cache = Array::Handle(CodePatcher::GetTypeTestArray(loc)); |
| 429 // TODO(srdjan): Prevent type test cache from growing too much, it has been | 424 // TODO(srdjan): Prevent type test cache from growing too much, it has been |
| 430 // observed to grow to 100 elements. | 425 // observed to grow to 100 elements. |
| 431 const Class& instance_class = Class::Handle(instance.clazz()); | |
| 432 // Don't enter duplicate entries. | 426 // Don't enter duplicate entries. |
| 433 Class& last_checked = Class::Handle(); | 427 // TODO(srdjan): Check instantiator type arguments as well. |
| 434 for (intptr_t i = 0; i < value.Length(); i += 2) { | 428 Object& last_instance_class = Object::Handle(); |
| 435 last_checked ^= value.At(i); | 429 Object& last_instance_type_arguments = Object::Handle(); |
| 436 if (last_checked.raw() == instance_class.raw()) { | 430 for (intptr_t i = 0; i < cache.Length(); |
| 431 i += SubTypeTestCache::kNumEntries) { | |
| 432 last_instance_class = cache.At(i + SubTypeTestCache::kInstanceClass); | |
| 433 last_instance_type_arguments = | |
| 434 cache.At(i + SubTypeTestCache::kInstanceTypeArguments); | |
| 435 if ((last_instance_class.raw() == instance_class.raw()) && | |
| 436 (last_instance_type_arguments.raw() == | |
| 437 instance_type_arguments.raw())) { | |
| 437 if (FLAG_trace_type_checks) { | 438 if (FLAG_trace_type_checks) { |
| 438 PrintTypeCheck("WARING duplicate cache entry", instance, type, | 439 PrintTypeCheck("WARNING duplicate cache entry", instance, type, |
| 439 type_instantiator, result); | 440 type_instantiator, result); |
| 440 } | 441 } |
| 441 return; | 442 return; |
| 442 } | 443 } |
| 443 } | 444 } |
| 444 | 445 |
| 445 // Array must be null terminated. | 446 // Array must be null terminated. |
| 446 ASSERT(last_checked.IsNull()); | 447 ASSERT(last_instance_class.IsNull()); |
| 447 | 448 ASSERT(!cache.IsNull()); |
| 448 // Check if the result for cache needs to be recomputed. | 449 // Cache is null terminate, i.e., the last entry contains all null elements. |
| 449 const Class& cls = Class::Handle(type.type_class()); | 450 intptr_t old_len = cache.Length(); |
| 450 Bool& class_test_result = Bool::Handle(result.raw()); | 451 cache = cache.Grow(cache, old_len + SubTypeTestCache::kNumEntries); |
| 451 if (!result.value() && cls.HasTypeArguments()) { | 452 intptr_t last_start = old_len - SubTypeTestCache::kNumEntries; |
| 452 Error& malformed_error = Error::Handle(); | 453 cache.SetAt(last_start + SubTypeTestCache::kInstanceClass, instance_class); |
| 453 if (instance_class.IsSubtypeOf(TypeArguments::Handle(), | 454 cache.SetAt(last_start + SubTypeTestCache::kInstanceTypeArguments, |
| 454 cls, | 455 instance_type_arguments); |
| 455 TypeArguments::Handle(), | 456 // TODO(srdjan): Store instantiator arguments instead of null. |
| 456 &malformed_error)) { | 457 cache.SetAt(last_start + SubTypeTestCache::kInstantiatorArguments, |
| 457 class_test_result = Bool::True(); | 458 AbstractTypeArguments::Handle()); |
| 458 } | 459 cache.SetAt(last_start + SubTypeTestCache::kTestResult , result); |
| 460 if (FLAG_trace_type_checks) { | |
| 461 OS::Print(" Updated test cache: [0x%x %s, 0x%x %s]\n" | |
| 462 " [0x%x %s] %s\n", | |
| 463 instance_class.raw(), | |
| 464 instance_class.ToCString(), | |
| 465 instance_type_arguments.raw(), | |
| 466 instance_type_arguments.ToCString(), | |
| 467 type.type_class(), | |
| 468 Class::Handle(type.type_class()).ToCString(), | |
| 469 result.ToCString()); | |
| 459 } | 470 } |
| 460 ASSERT(!value.IsNull()); | 471 CodePatcher::SetTypeTestArray(loc, cache); |
| 461 intptr_t old_len = value.Length(); | |
| 462 value = value.Grow(value, old_len + 2); | |
| 463 value.SetAt(old_len - 2, instance_class); | |
| 464 value.SetAt(old_len - 1, class_test_result); | |
| 465 CodePatcher::SetTypeTestArray(loc, value); | |
| 466 OptimizeTypeArguments(instance); | |
| 467 } | 472 } |
| 468 } | 473 } |
| 469 | 474 |
| 470 | 475 |
| 471 // Check that the given instance is an instance of the given type. | 476 // Check that the given instance is an instance of the given type. |
| 472 // Tested instance may not be null, because the null test is inlined. | 477 // Tested instance may not be null, because the null test is inlined. |
| 473 // Arg0: index of the token of the instanceof test (source location). | 478 // Arg0: index of the token of the instanceof test (source location). |
| 474 // Arg1: node id of the instanceof node. | 479 // Arg1: node id of the instanceof node. |
| 475 // Arg2: instance being checked. | 480 // Arg2: instance being checked. |
| 476 // Arg3: type. | 481 // Arg3: type. |
| (...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1486 } | 1491 } |
| 1487 } | 1492 } |
| 1488 } | 1493 } |
| 1489 // The cache is null terminated, therefore the loop above should never | 1494 // The cache is null terminated, therefore the loop above should never |
| 1490 // terminate by itself. | 1495 // terminate by itself. |
| 1491 UNREACHABLE(); | 1496 UNREACHABLE(); |
| 1492 return Code::null(); | 1497 return Code::null(); |
| 1493 } | 1498 } |
| 1494 | 1499 |
| 1495 } // namespace dart | 1500 } // namespace dart |
| OLD | NEW |