Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: runtime/vm/code_generator.cc

Issue 10243013: Simpler and better inlined type checks as discussed. Changed inline type test cache arrays to conta… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698