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

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

Issue 10227006: (Redoing the change 6946) Progress toward inlined type checks for classes with type arguments: fact… (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 | « no previous file | runtime/vm/code_generator_ia32.h » ('j') | runtime/vm/object.h » ('J')
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 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 const Context& ctx = Context::CheckedHandle(arguments.At(0)); 313 const Context& ctx = Context::CheckedHandle(arguments.At(0));
314 Context& cloned_ctx = Context::Handle(Context::New(ctx.num_variables())); 314 Context& cloned_ctx = Context::Handle(Context::New(ctx.num_variables()));
315 cloned_ctx.set_parent(Context::Handle(ctx.parent())); 315 cloned_ctx.set_parent(Context::Handle(ctx.parent()));
316 for (int i = 0; i < ctx.num_variables(); i++) { 316 for (int i = 0; i < ctx.num_variables(); i++) {
317 cloned_ctx.SetAt(i, Instance::Handle(ctx.At(i))); 317 cloned_ctx.SetAt(i, Instance::Handle(ctx.At(i)));
318 } 318 }
319 arguments.SetReturn(cloned_ctx); 319 arguments.SetReturn(cloned_ctx);
320 } 320 }
321 321
322 322
323 // Helper routine for tracing a type check.
324 static void PrintTypeCheck(const char* message,
325 const Instance& instance,
326 const AbstractType&type,
327 const AbstractTypeArguments& type_instantiator,
328 const Bool& result) {
329 const Type& instance_type = Type::Handle(instance.GetType());
330 ASSERT(instance_type.IsInstantiated());
331 if (type.IsInstantiated()) {
332 OS::Print("%s: '%s' %s '%s'.\n",
333 message,
334 String::Handle(instance_type.Name()).ToCString(),
335 (result.raw() == Bool::True()) ? "is" : "is !",
336 String::Handle(type.Name()).ToCString());
337 } else {
338 // Instantiate type before printing.
339 const AbstractType& instantiated_type =
340 AbstractType::Handle(type.InstantiateFrom(type_instantiator));
341 OS::Print("%s: '%s' %s '%s' instantiated from '%s'.\n",
342 message,
343 String::Handle(instance_type.Name()).ToCString(),
344 (result.raw() == Bool::True()) ? "is" : "is !",
345 String::Handle(instantiated_type.Name()).ToCString(),
346 String::Handle(type.Name()).ToCString());
347 }
348 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
349 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
350 ASSERT(caller_frame != NULL);
351 const Function& function = Function::Handle(
352 caller_frame->LookupDartFunction());
353 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
354 }
355
356
357 // Converts InstantiatedTypeArguments to TypeArguments and stores it
358 // into the instance. The assembly code can handle only type arguments of
359 // class TypeArguments. Because of the overhead, do it only when needed.
360 static void OptimizeTypeArguments(const Instance& instance) {
361 const Class& type_class = Class::ZoneHandle(instance.clazz());
362 if (type_class.HasTypeArguments()) {
363 const AbstractTypeArguments& type_arguments =
364 AbstractTypeArguments::Handle(instance.GetTypeArguments());
365 bool canonicalize = true;
366 if (!type_arguments.IsNull() &&
367 type_arguments.IsInstantiatedTypeArguments()) {
368 TypeArguments& new_type_arguments =
369 TypeArguments::Handle(TypeArguments::New(type_arguments.Length()));
370 for (int i = 0; i < type_arguments.Length(); i++) {
371 const AbstractType& type_at =
372 AbstractType::Handle(type_arguments.TypeAt(i));
373 if (type_at.IsInstantiatedType()) {
374 // Cannot canonicalize such type.
375 canonicalize = false;
376 } else if (!type_at.IsType()) {
377 // type_at cannot be TypeParameter at runtime.
378 UNREACHABLE();
379 }
380 new_type_arguments.SetTypeAt(i, type_at);
381 }
382 if (canonicalize) {
383 new_type_arguments ^= new_type_arguments.Canonicalize();
384 }
385 instance.SetTypeArguments(new_type_arguments);
386 }
387 }
388 }
389
390
391 // This updates the type test cache, an array containing tuples (instance class,
392 // test result_. It can be applied to classes with type arguments in which
393 // case it contains just the result of the class subtype test, not including
394 // the evaluation of type arguments.
395 // Note that the 'result' contains the whole type test (including type
396 // arguments), but the type test cache contains only the result of the
397 // class test. Therefore we may need to recompute the 'result'.
398 // This operation is currently very slow (lookup of code is not efficient yet).
399 static void UpdateTypeTestCache(intptr_t node_id,
400 const Instance& instance,
401 const AbstractType& type,
402 const AbstractTypeArguments& type_instantiator,
403 const Bool& result) {
404 // Since the test is expensive, don't do it unless necessary.
405 // The list of disallowed cases will decrease as they are implemented in
406 // inlined assembly.
407 if (!type.IsInstantiated()) return;
408 // TODO(srdjan): Implement assembly code for checking type arguments then
409 // remove this check.
410 if (Class::Handle(type.type_class()).HasTypeArguments()) {
411 const AbstractTypeArguments& type_arguments =
412 AbstractTypeArguments::Handle(type.arguments());
413 const bool is_raw_type = type_arguments.IsNull() ||
414 type_arguments.IsRaw(type_arguments.Length());
415 if (!is_raw_type) {
416 return;
417 }
418 }
419 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
420 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
421 ASSERT(caller_frame != NULL);
422 const Code& code = Code::Handle(caller_frame->LookupDartCode());
423 ASSERT(!code.IsNull());
424 uword loc = code.GetTypeTestAtNodeId(node_id);
425 if (loc != 0) {
426 // Found type test cache.
427 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
428 // TODO(srdjan): Prevent type test cache from growing too much, it has been
429 // observed to grow to 100 elements.
430 const Class& instance_class = Class::Handle(instance.clazz());
431 // Don't enter duplicate entries.
432 Class& last_checked = Class::Handle();
433 for (intptr_t i = 0; i < value.Length(); i += 2) {
434 last_checked ^= value.At(i);
435 if (last_checked.raw() == instance_class.raw()) {
436 if (FLAG_trace_type_checks) {
437 PrintTypeCheck("WARING duplicate cache entry", instance, type,
438 type_instantiator, result);
439 }
440 return;
441 }
442 }
443
444 // Array must be null terminated.
445 ASSERT(last_checked.IsNull());
446
447 // Check if the result for cache needs to be recomputed.
448 const Class& cls = Class::Handle(type.type_class());
449 Bool& class_test_result = Bool::Handle(result.raw());
450 if (!result.value() && cls.HasTypeArguments()) {
451 Error& malformed_error = Error::Handle();
452 if (instance_class.IsSubtypeOf(TypeArguments::Handle(),
453 cls,
454 TypeArguments::Handle(),
455 &malformed_error)) {
456 class_test_result = Bool::True();
457 }
458 }
459 ASSERT(!value.IsNull());
460 intptr_t old_len = value.Length();
461 value = value.Grow(value, old_len + 2);
462 value.SetAt(old_len - 2, instance_class);
463 value.SetAt(old_len - 1, class_test_result);
464 CodePatcher::SetTypeTestArray(loc, value);
465 OptimizeTypeArguments(instance);
466 }
467 }
468
469
323 // Check that the given instance is an instance of the given type. 470 // Check that the given instance is an instance of the given type.
324 // Tested instance may not be null, because the null test is inlined. 471 // Tested instance may not be null, because the null test is inlined.
325 // Arg0: index of the token of the instanceof test (source location). 472 // Arg0: index of the token of the instanceof test (source location).
326 // Arg1: node id of the instanceof node. 473 // Arg1: node id of the instanceof node.
327 // Arg2: instance being checked. 474 // Arg2: instance being checked.
328 // Arg3: type. 475 // Arg3: type.
329 // Arg4: type arguments of the instantiator of the type. 476 // Arg4: type arguments of the instantiator of the type.
330 // Return value: true or false, or may throw a type error in checked mode. 477 // Return value: true or false, or may throw a type error in checked mode.
331 DEFINE_RUNTIME_ENTRY(Instanceof, 5) { 478 DEFINE_RUNTIME_ENTRY(Instanceof, 5) {
332 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); 479 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count());
333 // TODO(regis): Get the token index from the PcDesc (via DartFrame). 480 // TODO(regis): Get the token index from the PcDesc (via DartFrame).
334 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); 481 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
335 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); 482 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value();
336 const Instance& instance = Instance::CheckedHandle(arguments.At(2)); 483 const Instance& instance = Instance::CheckedHandle(arguments.At(2));
337 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3)); 484 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3));
338 const AbstractTypeArguments& type_instantiator = 485 const AbstractTypeArguments& type_instantiator =
339 AbstractTypeArguments::CheckedHandle(arguments.At(4)); 486 AbstractTypeArguments::CheckedHandle(arguments.At(4));
340 ASSERT(type.IsFinalized()); 487 ASSERT(type.IsFinalized());
341 Error& malformed_error = Error::Handle(); 488 Error& malformed_error = Error::Handle();
342 const Bool& result = Bool::Handle( 489 const Bool& result = Bool::Handle(
343 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ? 490 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ?
344 Bool::True() : Bool::False()); 491 Bool::True() : Bool::False());
345 if (FLAG_trace_type_checks) { 492 if (FLAG_trace_type_checks) {
346 const Type& instance_type = Type::Handle(instance.GetType()); 493 PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result);
347 ASSERT(instance_type.IsInstantiated());
348 if (type.IsInstantiated()) {
349 OS::Print("InstanceOf: '%s' %s '%s'.\n",
350 String::Handle(instance_type.Name()).ToCString(),
351 (result.raw() == Bool::True()) ? "is" : "is !",
352 String::Handle(type.Name()).ToCString());
353 } else {
354 // Instantiate type before printing.
355 const AbstractType& instantiated_type =
356 AbstractType::Handle(type.InstantiateFrom(type_instantiator));
357 OS::Print("InstanceOf: '%s' %s '%s' instantiated from '%s'.\n",
358 String::Handle(instance_type.Name()).ToCString(),
359 (result.raw() == Bool::True()) ? "is" : "is !",
360 String::Handle(instantiated_type.Name()).ToCString(),
361 String::Handle(type.Name()).ToCString());
362 }
363 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
364 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
365 const Function& function = Function::Handle(
366 caller_frame->LookupDartFunction());
367 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
368 } 494 }
369 if (!result.value() && !malformed_error.IsNull()) { 495 if (!result.value() && !malformed_error.IsNull()) {
370 // Throw a dynamic type error only if the instanceof test fails. 496 // Throw a dynamic type error only if the instanceof test fails.
371 String& malformed_error_message = String::Handle( 497 String& malformed_error_message = String::Handle(
372 String::New(malformed_error.ToErrorCString())); 498 String::New(malformed_error.ToErrorCString()));
373 const String& no_name = String::Handle(String::NewSymbol("")); 499 const String& no_name = String::Handle(String::NewSymbol(""));
374 Exceptions::CreateAndThrowTypeError( 500 Exceptions::CreateAndThrowTypeError(
375 location, no_name, no_name, no_name, malformed_error_message); 501 location, no_name, no_name, no_name, malformed_error_message);
376 UNREACHABLE(); 502 UNREACHABLE();
377 } 503 }
378 // Update cache: add class of instance and result. 504 UpdateTypeTestCache(node_id, instance, type, type_instantiator, result);
379 if (type.IsInstantiated() &&
380 !Class::Handle(type.type_class()).HasTypeArguments()) {
381 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
382 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
383 const Code& code = Code::Handle(caller_frame->LookupDartCode());
384 ASSERT(!code.IsNull());
385 uword loc = code.GetTypeTestAtNodeId(node_id);
386 // TODO(srdjan): Check when 'loc' can be 0, once implemented everywhere.
387 if (loc != 0) {
388 // Found type test cache.
389 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
390 const Class& instance_class = Class::Handle(instance.clazz());
391
392 #if defined(DEBUG)
393 // Check for duplicate entries.
394 Class& last_checked = Class::Handle();
395 for (intptr_t i = 0; i < value.Length(); i += 2) {
396 last_checked ^= value.At(i);
397 ASSERT(last_checked.raw() != instance_class.raw());
398 }
399 // Array must be null terminated.
400 ASSERT(last_checked.IsNull());
401 #endif
402
403 ASSERT(!value.IsNull());
404 intptr_t old_len = value.Length();
405 value = value.Grow(value, old_len + 2);
406 value.SetAt(old_len - 2, instance_class);
407 value.SetAt(old_len - 1, result);
408 CodePatcher::SetTypeTestArray(loc, value);
409 }
410 }
411 arguments.SetReturn(result); 505 arguments.SetReturn(result);
412 } 506 }
413 507
414 508
415 // For error reporting simplify type name, e.g, all integer types (Smi, Mint, 509 // For error reporting simplify type name, e.g, all integer types (Smi, Mint,
416 // Bigint) a re reported as 'int'. 510 // Bigint) a re reported as 'int'.
417 static RawString* GetSimpleTypeName(const Instance& value) { 511 static RawString* GetSimpleTypeName(const Instance& value) {
418 if (value.IsInteger()) { 512 if (value.IsInteger()) {
419 return String::NewSymbol("int"); 513 return String::NewSymbol("int");
420 } else { 514 } else {
(...skipping 23 matching lines...) Expand all
444 const String& dst_name = String::CheckedHandle(arguments.At(5)); 538 const String& dst_name = String::CheckedHandle(arguments.At(5));
445 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. 539 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment.
446 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. 540 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator.
447 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. 541 ASSERT(!src_instance.IsNull()); // Already checked in inlined code.
448 542
449 Error& malformed_error = Error::Handle(); 543 Error& malformed_error = Error::Handle();
450 const bool is_instance_of = src_instance.IsInstanceOf( 544 const bool is_instance_of = src_instance.IsInstanceOf(
451 dst_type, dst_type_instantiator, &malformed_error); 545 dst_type, dst_type_instantiator, &malformed_error);
452 546
453 if (FLAG_trace_type_checks) { 547 if (FLAG_trace_type_checks) {
454 const Type& src_type = Type::Handle(src_instance.GetType()); 548 PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator,
455 ASSERT(src_type.IsInstantiated()); 549 Bool::Handle(is_instance_of ? Bool::True() : Bool::False()));
456 if (dst_type.IsInstantiated()) {
457 OS::Print("TypeCheck: type '%s' %s a subtype of type '%s' of '%s'.\n",
458 String::Handle(src_type.Name()).ToCString(),
459 is_instance_of ? "is" : "is not",
460 String::Handle(dst_type.Name()).ToCString(),
461 dst_name.ToCString());
462 } else {
463 // Instantiate dst_type before printing.
464 const AbstractType& instantiated_dst_type = AbstractType::Handle(
465 dst_type.InstantiateFrom(dst_type_instantiator));
466 OS::Print("TypeCheck: type '%s' %s a subtype of type '%s' of '%s' "
467 "instantiated from '%s'.\n",
468 String::Handle(src_type.Name()).ToCString(),
469 is_instance_of ? "is" : "is not",
470 String::Handle(instantiated_dst_type.Name()).ToCString(),
471 dst_name.ToCString(),
472 String::Handle(dst_type.Name()).ToCString());
473 }
474 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
475 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
476 const Function& function = Function::Handle(
477 caller_frame->LookupDartFunction());
478 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
479 } 550 }
480 if (!is_instance_of) { 551 if (!is_instance_of) {
481 String& src_type_name = String::Handle(GetSimpleTypeName(src_instance)); 552 String& src_type_name = String::Handle(GetSimpleTypeName(src_instance));
482 String& dst_type_name = String::Handle(); 553 String& dst_type_name = String::Handle();
483 if (!dst_type.IsInstantiated()) { 554 if (!dst_type.IsInstantiated()) {
484 // Instantiate dst_type before reporting the error. 555 // Instantiate dst_type before reporting the error.
485 const AbstractType& instantiated_dst_type = AbstractType::Handle( 556 const AbstractType& instantiated_dst_type = AbstractType::Handle(
486 dst_type.InstantiateFrom(dst_type_instantiator)); 557 dst_type.InstantiateFrom(dst_type_instantiator));
487 dst_type_name = instantiated_dst_type.Name(); 558 dst_type_name = instantiated_dst_type.Name();
488 } else { 559 } else {
489 dst_type_name = dst_type.Name(); 560 dst_type_name = dst_type.Name();
490 } 561 }
491 String& malformed_error_message = String::Handle(); 562 String& malformed_error_message = String::Handle();
492 if (!malformed_error.IsNull()) { 563 if (!malformed_error.IsNull()) {
493 ASSERT(FLAG_enable_type_checks); 564 ASSERT(FLAG_enable_type_checks);
494 malformed_error_message = String::New(malformed_error.ToErrorCString()); 565 malformed_error_message = String::New(malformed_error.ToErrorCString());
495 } 566 }
496 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, 567 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
497 dst_name, malformed_error_message); 568 dst_name, malformed_error_message);
498 UNREACHABLE(); 569 UNREACHABLE();
499 } 570 }
500 // Update cache: add class of instance and result. 571 UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator,
501 if (dst_type.IsInstantiated() && 572 Bool::ZoneHandle(Bool::True()));
502 !Class::Handle(dst_type.type_class()).HasTypeArguments()) {
503 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
504 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
505 const Code& code = Code::Handle(caller_frame->LookupDartCode());
506 ASSERT(!code.IsNull());
507 uword loc = code.GetTypeTestAtNodeId(node_id);
508 if (loc != 0) {
509 // Found type test cache.
510 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
511 const Class& src_instance_class = Class::Handle(src_instance.clazz());
512
513 #if defined(DEBUG)
514 // Check for duplicate entries.
515 Class& last_checked = Class::Handle();
516 for (intptr_t i = 0; i < value.Length(); i += 2) {
517 last_checked ^= value.At(i);
518 ASSERT(last_checked.raw() != src_instance_class.raw());
519 }
520 // Array must be null terminated.
521 ASSERT(last_checked.IsNull());
522 #endif
523
524 ASSERT(!value.IsNull());
525 intptr_t old_len = value.Length();
526 value = value.Grow(value, old_len + 2);
527 value.SetAt(old_len - 2, src_instance_class);
528 value.SetAt(old_len - 1, Bool::ZoneHandle(Bool::True()));
529 CodePatcher::SetTypeTestArray(loc, value);
530 }
531 }
532 arguments.SetReturn(src_instance); 573 arguments.SetReturn(src_instance);
533 } 574 }
534 575
535 576
536 // Report that the type of the given object is not bool in conditional context. 577 // Report that the type of the given object is not bool in conditional context.
537 // Arg0: index of the token of the assignment (source location). 578 // Arg0: index of the token of the assignment (source location).
538 // Arg1: bad object. 579 // Arg1: bad object.
539 // Return value: none, throws a TypeError. 580 // Return value: none, throws a TypeError.
540 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) { 581 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) {
541 ASSERT(arguments.Count() == 582 ASSERT(arguments.Count() ==
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after
1439 } 1480 }
1440 } 1481 }
1441 } 1482 }
1442 // The cache is null terminated, therefore the loop above should never 1483 // The cache is null terminated, therefore the loop above should never
1443 // terminate by itself. 1484 // terminate by itself.
1444 UNREACHABLE(); 1485 UNREACHABLE();
1445 return Code::null(); 1486 return Code::null();
1446 } 1487 }
1447 1488
1448 } // namespace dart 1489 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/code_generator_ia32.h » ('j') | runtime/vm/object.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698