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

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

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