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

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

Powered by Google App Engine
This is Rietveld 408576698