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

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, 8 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
« no previous file with comments | « runtime/vm/code_generator.h ('k') | runtime/vm/code_generator_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 4-value elements
373 // test result_. It can be applied to classes with type arguments in which 373 // (instance class, instance type arguments, instantiator type arguments and
374 // 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 375 // case it contains just the result of the class subtype test, not including
375 // the evaluation of type arguments. 376 // 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). 377 // This operation is currently very slow (lookup of code is not efficient yet).
380 static void UpdateTypeTestCache(intptr_t node_id, 378 static void UpdateTypeTestCache(intptr_t node_id,
381 const Instance& instance, 379 const Instance& instance,
382 const AbstractType& type, 380 const AbstractType& type,
383 const AbstractTypeArguments& type_instantiator, 381 const AbstractTypeArguments& type_instantiator,
384 const Bool& result) { 382 const Bool& result) {
385 // Since the test is expensive, don't do it unless necessary. 383 // Since the test is expensive, don't do it unless necessary.
386 // The list of disallowed cases will decrease as they are implemented in 384 // The list of disallowed cases will decrease as they are implemented in
387 // inlined assembly. 385 // inlined assembly.
388 if (!type.IsInstantiated()) return; 386 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()) { 387 if (Class::Handle(type.type_class()).HasTypeArguments()) {
392 const AbstractTypeArguments& type_arguments = 388 const AbstractTypeArguments& type_arguments =
393 AbstractTypeArguments::Handle(type.arguments()); 389 AbstractTypeArguments::Handle(type.arguments());
394 const bool is_raw_type = type_arguments.IsNull() || 390 const bool is_raw_type = type_arguments.IsNull() ||
395 type_arguments.IsRaw(type_arguments.Length()); 391 type_arguments.IsRaw(type_arguments.Length());
396 if (!is_raw_type) { 392 if (!is_raw_type) {
397 // We cannot inline tests for instances with more than one type argument 393 // We cannot inline tests for instances with more than one type argument
398 // or if its class has not been resolved (malformed type). 394 // or if its class has not been resolved (malformed type).
399 if (type_arguments.Length() != 1) { 395 if (type_arguments.Length() != 1) {
400 // We can handle only one argument so far. 396 // We can handle only one argument so far.
401 return; 397 return;
402 } 398 }
403 const AbstractType& tp_argument = 399 const AbstractType& tp_argument =
404 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); 400 AbstractType::ZoneHandle(type_arguments.TypeAt(0));
405 if (!tp_argument.IsType()) { 401 if (!tp_argument.IsType()) {
406 // E.g, it is TypeParameter. 402 // E.g, it is TypeParameter.
407 return; 403 return;
408 } 404 }
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()); 405 ASSERT(tp_argument.HasResolvedTypeClass());
418 } 406 }
419 } 407 }
408 AbstractTypeArguments& instance_type_arguments =
409 AbstractTypeArguments::Handle();
410 const Class& instance_class = Class::Handle(instance.clazz());
411 if (instance_class.HasTypeArguments()) {
412 OptimizeTypeArguments(instance);
413 instance_type_arguments = instance.GetTypeArguments();
414 }
415
420 DartFrameIterator iterator; 416 DartFrameIterator iterator;
421 StackFrame* caller_frame = iterator.NextFrame(); 417 StackFrame* caller_frame = iterator.NextFrame();
422 ASSERT(caller_frame != NULL); 418 ASSERT(caller_frame != NULL);
423 const Code& code = Code::Handle(caller_frame->LookupDartCode()); 419 const Code& code = Code::Handle(caller_frame->LookupDartCode());
424 ASSERT(!code.IsNull()); 420 ASSERT(!code.IsNull());
425 uword loc = code.GetTypeTestAtNodeId(node_id); 421 uword loc = code.GetTypeTestAtNodeId(node_id);
426 if (loc != 0) { 422 if (loc != 0) {
427 // Found type test cache. 423 // Found type test cache.
428 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc)); 424 Array& cache = Array::Handle(CodePatcher::GetTypeTestArray(loc));
429 // TODO(srdjan): Prevent type test cache from growing too much, it has been 425 // TODO(srdjan): Prevent type test cache from growing too much, it has been
430 // observed to grow to 100 elements. 426 // observed to grow to 100 elements.
431 const Class& instance_class = Class::Handle(instance.clazz());
432 // Don't enter duplicate entries. 427 // Don't enter duplicate entries.
433 Class& last_checked = Class::Handle(); 428 // TODO(srdjan): Check instantiator type arguments as well.
434 for (intptr_t i = 0; i < value.Length(); i += 2) { 429 Object& last_instance_class = Object::Handle();
435 last_checked ^= value.At(i); 430 Object& last_instance_type_arguments = Object::Handle();
436 if (last_checked.raw() == instance_class.raw()) { 431 for (intptr_t i = 0; i < cache.Length();
432 i += SubTypeTestCache::kNumEntries) {
433 last_instance_class = cache.At(i + SubTypeTestCache::kInstanceClass);
434 last_instance_type_arguments =
435 cache.At(i + SubTypeTestCache::kInstanceTypeArguments);
436 if ((last_instance_class.raw() == instance_class.raw()) &&
437 (last_instance_type_arguments.raw() ==
438 instance_type_arguments.raw())) {
437 if (FLAG_trace_type_checks) { 439 if (FLAG_trace_type_checks) {
438 PrintTypeCheck("WARING duplicate cache entry", instance, type, 440 PrintTypeCheck("WARNING duplicate cache entry", instance, type,
439 type_instantiator, result); 441 type_instantiator, result);
440 } 442 }
441 return; 443 return;
442 } 444 }
443 } 445 }
444 446
445 // Array must be null terminated. 447 // Array must be null terminated.
446 ASSERT(last_checked.IsNull()); 448 ASSERT(last_instance_class.IsNull());
447 449 ASSERT(!cache.IsNull());
448 // Check if the result for cache needs to be recomputed. 450 // Cache is null terminate, i.e., the last entry contains all null elements.
449 const Class& cls = Class::Handle(type.type_class()); 451 intptr_t old_len = cache.Length();
450 Bool& class_test_result = Bool::Handle(result.raw()); 452 cache = cache.Grow(cache, old_len + SubTypeTestCache::kNumEntries);
451 if (!result.value() && cls.HasTypeArguments()) { 453 intptr_t last_start = old_len - SubTypeTestCache::kNumEntries;
452 Error& malformed_error = Error::Handle(); 454 cache.SetAt(last_start + SubTypeTestCache::kInstanceClass, instance_class);
453 if (instance_class.IsSubtypeOf(TypeArguments::Handle(), 455 cache.SetAt(last_start + SubTypeTestCache::kInstanceTypeArguments,
454 cls, 456 instance_type_arguments);
455 TypeArguments::Handle(), 457 // TODO(srdjan): Store instantiator arguments instead of null.
456 &malformed_error)) { 458 cache.SetAt(last_start + SubTypeTestCache::kInstantiatorTypeArguments,
457 class_test_result = Bool::True(); 459 AbstractTypeArguments::Handle());
458 } 460 cache.SetAt(last_start + SubTypeTestCache::kTestResult , result);
461 if (FLAG_trace_type_checks) {
462 OS::Print(" Updated test cache: [0x%x %s, 0x%x %s]\n"
463 " [0x%x %s] %s\n",
464 instance_class.raw(),
465 instance_class.ToCString(),
466 instance_type_arguments.raw(),
467 instance_type_arguments.ToCString(),
468 type.type_class(),
469 Class::Handle(type.type_class()).ToCString(),
470 result.ToCString());
459 } 471 }
460 ASSERT(!value.IsNull()); 472 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 } 473 }
468 } 474 }
469 475
470 476
471 // Check that the given instance is an instance of the given type. 477 // 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. 478 // Tested instance may not be null, because the null test is inlined.
473 // Arg0: index of the token of the instanceof test (source location). 479 // Arg0: index of the token of the instanceof test (source location).
474 // Arg1: node id of the instanceof node. 480 // Arg1: node id of the instanceof node.
475 // Arg2: instance being checked. 481 // Arg2: instance being checked.
476 // Arg3: type. 482 // Arg3: type.
(...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after
1486 } 1492 }
1487 } 1493 }
1488 } 1494 }
1489 // The cache is null terminated, therefore the loop above should never 1495 // The cache is null terminated, therefore the loop above should never
1490 // terminate by itself. 1496 // terminate by itself.
1491 UNREACHABLE(); 1497 UNREACHABLE();
1492 return Code::null(); 1498 return Code::null();
1493 } 1499 }
1494 1500
1495 } // namespace dart 1501 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/code_generator.h ('k') | runtime/vm/code_generator_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698