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

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

Issue 10228010: Address perf regression by using the expected frame layout when traversing frames in the code gener… (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 | no next file » | 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 15 matching lines...) Expand all
26 DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code."); 26 DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code.");
27 DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls."); 27 DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls.");
28 DEFINE_FLAG(int, optimization_counter_threshold, 2000, 28 DEFINE_FLAG(int, optimization_counter_threshold, 2000,
29 "function's usage-counter value before it is optimized, -1 means never."); 29 "function's usage-counter value before it is optimized, -1 means never.");
30 DECLARE_FLAG(bool, enable_type_checks); 30 DECLARE_FLAG(bool, enable_type_checks);
31 DECLARE_FLAG(bool, trace_type_checks); 31 DECLARE_FLAG(bool, trace_type_checks);
32 DECLARE_FLAG(bool, report_usage_count); 32 DECLARE_FLAG(bool, report_usage_count);
33 DECLARE_FLAG(int, deoptimization_counter_threshold); 33 DECLARE_FLAG(int, deoptimization_counter_threshold);
34 34
35 35
36 static StackFrame* GetTopDartFrame(
37 StackFrameIterator* iterator, bool has_stub_frame) {
srdjan 2012/04/25 19:31:13 You could move the StackFrameIterator in here, ins
siva 2012/04/25 20:08:49 Not really because the caller_frame that is return
38 // When runtime calls are made from dart code we assume that we will
39 // always have an exit frame and an optional stub frame before we hit
40 // the first dart frame.
41 StackFrame* exit_frame = iterator->NextFrame();
42 ASSERT(exit_frame != NULL && exit_frame->IsExitFrame());
43 if (has_stub_frame) {
44 StackFrame* stub_frame = iterator->NextFrame();
45 ASSERT(stub_frame != NULL && stub_frame->IsStubFrame());
46 }
47 StackFrame* caller_frame = iterator->NextFrame();
48 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
49 return caller_frame;
50 }
51
52
36 bool CodeGenerator::CanOptimize() { 53 bool CodeGenerator::CanOptimize() {
37 return 54 return
38 !FLAG_report_usage_count && 55 !FLAG_report_usage_count &&
39 (FLAG_optimization_counter_threshold >= 0) && 56 (FLAG_optimization_counter_threshold >= 0) &&
40 !Isolate::Current()->debugger()->IsActive(); 57 !Isolate::Current()->debugger()->IsActive();
41 } 58 }
42 59
43 60
44 const Array& CodeGenerator::ArgumentsDescriptor( 61 const Array& CodeGenerator::ArgumentsDescriptor(
45 int num_arguments, 62 int num_arguments,
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 } else { 353 } else {
337 // Instantiate type before printing. 354 // Instantiate type before printing.
338 const AbstractType& instantiated_type = 355 const AbstractType& instantiated_type =
339 AbstractType::Handle(type.InstantiateFrom(type_instantiator)); 356 AbstractType::Handle(type.InstantiateFrom(type_instantiator));
340 OS::Print("InstanceOf: '%s' %s '%s' instantiated from '%s'.\n", 357 OS::Print("InstanceOf: '%s' %s '%s' instantiated from '%s'.\n",
341 String::Handle(instance_type.Name()).ToCString(), 358 String::Handle(instance_type.Name()).ToCString(),
342 (result.raw() == Bool::True()) ? "is" : "is !", 359 (result.raw() == Bool::True()) ? "is" : "is !",
343 String::Handle(instantiated_type.Name()).ToCString(), 360 String::Handle(instantiated_type.Name()).ToCString(),
344 String::Handle(type.Name()).ToCString()); 361 String::Handle(type.Name()).ToCString());
345 } 362 }
346 DartFrameIterator iterator; 363 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
347 StackFrame* caller_frame = iterator.NextFrame(); 364 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
348 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
349 const Function& function = Function::Handle( 365 const Function& function = Function::Handle(
350 caller_frame->LookupDartFunction()); 366 caller_frame->LookupDartFunction());
351 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString()); 367 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
352 } 368 }
353 if (!result.value() && !malformed_error.IsNull()) { 369 if (!result.value() && !malformed_error.IsNull()) {
354 // Throw a dynamic type error only if the instanceof test fails. 370 // Throw a dynamic type error only if the instanceof test fails.
355 String& malformed_error_message = String::Handle( 371 String& malformed_error_message = String::Handle(
356 String::New(malformed_error.ToErrorCString())); 372 String::New(malformed_error.ToErrorCString()));
357 const String& no_name = String::Handle(String::NewSymbol("")); 373 const String& no_name = String::Handle(String::NewSymbol(""));
358 Exceptions::CreateAndThrowTypeError( 374 Exceptions::CreateAndThrowTypeError(
359 location, no_name, no_name, no_name, malformed_error_message); 375 location, no_name, no_name, no_name, malformed_error_message);
360 UNREACHABLE(); 376 UNREACHABLE();
361 } 377 }
362 // Update cache: add class of instance and result. 378 // Update cache: add class of instance and result.
363 if (type.IsInstantiated() && 379 if (type.IsInstantiated() &&
364 !Class::Handle(type.type_class()).HasTypeArguments()) { 380 !Class::Handle(type.type_class()).HasTypeArguments()) {
365 DartFrameIterator iterator; 381 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
366 StackFrame* caller_frame = iterator.NextFrame(); 382 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
367 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
368 const Code& code = Code::Handle(caller_frame->LookupDartCode()); 383 const Code& code = Code::Handle(caller_frame->LookupDartCode());
369 ASSERT(!code.IsNull()); 384 ASSERT(!code.IsNull());
370 uword loc = code.GetTypeTestAtNodeId(node_id); 385 uword loc = code.GetTypeTestAtNodeId(node_id);
371 // TODO(srdjan): Check when 'loc' can be 0, once implemented everywhere. 386 // TODO(srdjan): Check when 'loc' can be 0, once implemented everywhere.
372 if (loc != 0) { 387 if (loc != 0) {
373 // Found type test cache. 388 // Found type test cache.
374 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc)); 389 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
375 const Class& instance_class = Class::Handle(instance.clazz()); 390 const Class& instance_class = Class::Handle(instance.clazz());
376 391
377 #if defined(DEBUG) 392 #if defined(DEBUG)
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 const AbstractType& instantiated_dst_type = AbstractType::Handle( 464 const AbstractType& instantiated_dst_type = AbstractType::Handle(
450 dst_type.InstantiateFrom(dst_type_instantiator)); 465 dst_type.InstantiateFrom(dst_type_instantiator));
451 OS::Print("TypeCheck: type '%s' %s a subtype of type '%s' of '%s' " 466 OS::Print("TypeCheck: type '%s' %s a subtype of type '%s' of '%s' "
452 "instantiated from '%s'.\n", 467 "instantiated from '%s'.\n",
453 String::Handle(src_type.Name()).ToCString(), 468 String::Handle(src_type.Name()).ToCString(),
454 is_instance_of ? "is" : "is not", 469 is_instance_of ? "is" : "is not",
455 String::Handle(instantiated_dst_type.Name()).ToCString(), 470 String::Handle(instantiated_dst_type.Name()).ToCString(),
456 dst_name.ToCString(), 471 dst_name.ToCString(),
457 String::Handle(dst_type.Name()).ToCString()); 472 String::Handle(dst_type.Name()).ToCString());
458 } 473 }
459 DartFrameIterator iterator; 474 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
460 StackFrame* caller_frame = iterator.NextFrame(); 475 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
461 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
462 const Function& function = Function::Handle( 476 const Function& function = Function::Handle(
463 caller_frame->LookupDartFunction()); 477 caller_frame->LookupDartFunction());
464 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString()); 478 OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
465 } 479 }
466 if (!is_instance_of) { 480 if (!is_instance_of) {
467 String& src_type_name = String::Handle(GetSimpleTypeName(src_instance)); 481 String& src_type_name = String::Handle(GetSimpleTypeName(src_instance));
468 String& dst_type_name = String::Handle(); 482 String& dst_type_name = String::Handle();
469 if (!dst_type.IsInstantiated()) { 483 if (!dst_type.IsInstantiated()) {
470 // Instantiate dst_type before reporting the error. 484 // Instantiate dst_type before reporting the error.
471 const AbstractType& instantiated_dst_type = AbstractType::Handle( 485 const AbstractType& instantiated_dst_type = AbstractType::Handle(
472 dst_type.InstantiateFrom(dst_type_instantiator)); 486 dst_type.InstantiateFrom(dst_type_instantiator));
473 dst_type_name = instantiated_dst_type.Name(); 487 dst_type_name = instantiated_dst_type.Name();
474 } else { 488 } else {
475 dst_type_name = dst_type.Name(); 489 dst_type_name = dst_type.Name();
476 } 490 }
477 String& malformed_error_message = String::Handle(); 491 String& malformed_error_message = String::Handle();
478 if (!malformed_error.IsNull()) { 492 if (!malformed_error.IsNull()) {
479 ASSERT(FLAG_enable_type_checks); 493 ASSERT(FLAG_enable_type_checks);
480 malformed_error_message = String::New(malformed_error.ToErrorCString()); 494 malformed_error_message = String::New(malformed_error.ToErrorCString());
481 } 495 }
482 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, 496 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
483 dst_name, malformed_error_message); 497 dst_name, malformed_error_message);
484 UNREACHABLE(); 498 UNREACHABLE();
485 } 499 }
486 // Update cache: add class of instance and result. 500 // Update cache: add class of instance and result.
487 if (dst_type.IsInstantiated() && 501 if (dst_type.IsInstantiated() &&
488 !Class::Handle(dst_type.type_class()).HasTypeArguments()) { 502 !Class::Handle(dst_type.type_class()).HasTypeArguments()) {
489 DartFrameIterator iterator; 503 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
490 StackFrame* caller_frame = iterator.NextFrame(); 504 StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
491 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
492 const Code& code = Code::Handle(caller_frame->LookupDartCode()); 505 const Code& code = Code::Handle(caller_frame->LookupDartCode());
493 ASSERT(!code.IsNull()); 506 ASSERT(!code.IsNull());
494 uword loc = code.GetTypeTestAtNodeId(node_id); 507 uword loc = code.GetTypeTestAtNodeId(node_id);
495 if (loc != 0) { 508 if (loc != 0) {
496 // Found type test cache. 509 // Found type test cache.
497 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc)); 510 Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
498 const Class& src_instance_class = Class::Handle(src_instance.clazz()); 511 const Class& src_instance_class = Class::Handle(src_instance.clazz());
499 512
500 #if defined(DEBUG) 513 #if defined(DEBUG)
501 // Check for duplicate entries. 514 // Check for duplicate entries.
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 const Instance& exception = Instance::CheckedHandle(arguments.At(0)); 653 const Instance& exception = Instance::CheckedHandle(arguments.At(0));
641 const Instance& stacktrace = Instance::CheckedHandle(arguments.At(1)); 654 const Instance& stacktrace = Instance::CheckedHandle(arguments.At(1));
642 Exceptions::ReThrow(exception, stacktrace); 655 Exceptions::ReThrow(exception, stacktrace);
643 } 656 }
644 657
645 658
646 DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) { 659 DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) {
647 // This function is called after successful resolving and compilation of 660 // This function is called after successful resolving and compilation of
648 // the target method. 661 // the target method.
649 ASSERT(arguments.Count() == kPatchStaticCallRuntimeEntry.argument_count()); 662 ASSERT(arguments.Count() == kPatchStaticCallRuntimeEntry.argument_count());
650 DartFrameIterator iterator; 663 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
651 StackFrame* caller_frame = iterator.NextFrame(); 664 StackFrame* caller_frame = GetTopDartFrame(&iterator, true);
652 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
653 uword target = 0; 665 uword target = 0;
654 Function& target_function = Function::Handle(); 666 Function& target_function = Function::Handle();
655 CodePatcher::GetStaticCallAt(caller_frame->pc(), &target_function, &target); 667 CodePatcher::GetStaticCallAt(caller_frame->pc(), &target_function, &target);
656 ASSERT(target_function.HasCode()); 668 ASSERT(target_function.HasCode());
657 uword new_target = Code::Handle(target_function.CurrentCode()).EntryPoint(); 669 uword new_target = Code::Handle(target_function.CurrentCode()).EntryPoint();
658 // Verify that we are not patching repeatedly. 670 // Verify that we are not patching repeatedly.
659 ASSERT(target != new_target); 671 ASSERT(target != new_target);
660 CodePatcher::PatchStaticCallAt(caller_frame->pc(), new_target); 672 CodePatcher::PatchStaticCallAt(caller_frame->pc(), new_target);
661 if (FLAG_trace_patching) { 673 if (FLAG_trace_patching) {
662 OS::Print("PatchStaticCall: patching from 0x%x to '%s' 0x%x\n", 674 OS::Print("PatchStaticCall: patching from 0x%x to '%s' 0x%x\n",
663 caller_frame->pc(), 675 caller_frame->pc(),
664 target_function.ToFullyQualifiedCString(), 676 target_function.ToFullyQualifiedCString(),
665 new_target); 677 new_target);
666 } 678 }
667 } 679 }
668 680
669 681
670 // Resolves and compiles the target function of an instance call, updates 682 // Resolves and compiles the target function of an instance call, updates
671 // function cache of the receiver's class and returns the compiled code or null. 683 // function cache of the receiver's class and returns the compiled code or null.
672 // Only the number of named arguments is checked, but not the actual names. 684 // Only the number of named arguments is checked, but not the actual names.
673 RawCode* ResolveCompileInstanceCallTarget(Isolate* isolate, 685 RawCode* ResolveCompileInstanceCallTarget(Isolate* isolate,
674 const Instance& receiver) { 686 const Instance& receiver) {
675 DartFrameIterator iterator;
676 StackFrame* caller_frame = iterator.NextFrame();
677 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
678 int num_arguments = -1; 687 int num_arguments = -1;
679 int num_named_arguments = -1; 688 int num_named_arguments = -1;
680 uword target = 0; 689 uword target = 0;
681 String& function_name = String::Handle(); 690 String& function_name = String::Handle();
691 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
692 StackFrame* caller_frame = GetTopDartFrame(&iterator, true);
682 CodePatcher::GetInstanceCallAt(caller_frame->pc(), 693 CodePatcher::GetInstanceCallAt(caller_frame->pc(),
683 &function_name, 694 &function_name,
684 &num_arguments, 695 &num_arguments,
685 &num_named_arguments, 696 &num_named_arguments,
686 &target); 697 &target);
687 ASSERT(function_name.IsSymbol()); 698 ASSERT(function_name.IsSymbol());
688 Class& receiver_class = Class::Handle(); 699 Class& receiver_class = Class::Handle();
689 if (receiver.IsNull()) { 700 if (receiver.IsNull()) {
690 // TODO(srdjan): Clarify behavior of null objects. 701 // TODO(srdjan): Clarify behavior of null objects.
691 receiver_class = isolate->object_store()->object_class(); 702 receiver_class = isolate->object_store()->object_class();
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 // Null dispatch is slow (e.g., (null).toCString()). The only 820 // Null dispatch is slow (e.g., (null).toCString()). The only
810 // fast execution with null receiver is the "==" operator. 821 // fast execution with null receiver is the "==" operator.
811 // Special handling so that we do not pollute the inline cache with null 822 // Special handling so that we do not pollute the inline cache with null
812 // classes. 823 // classes.
813 if (FLAG_trace_ic) { 824 if (FLAG_trace_ic) {
814 OS::Print("InlineCacheMissHandler Null receiver target %s\n", 825 OS::Print("InlineCacheMissHandler Null receiver target %s\n",
815 target_function.ToCString()); 826 target_function.ToCString());
816 } 827 }
817 return target_function.raw(); 828 return target_function.raw();
818 } 829 }
819 DartFrameIterator iterator; 830 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
820 StackFrame* caller_frame = iterator.NextFrame(); 831 StackFrame* caller_frame = GetTopDartFrame(&iterator, true);
821 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
822 ICData& ic_data = ICData::Handle( 832 ICData& ic_data = ICData::Handle(
823 CodePatcher::GetInstanceCallIcDataAt(caller_frame->pc())); 833 CodePatcher::GetInstanceCallIcDataAt(caller_frame->pc()));
824 #if defined(DEBUG) 834 #if defined(DEBUG)
825 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 835 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
826 GrowableArray<const Class*> classes; 836 GrowableArray<const Class*> classes;
827 Function& target = Function::Handle(); 837 Function& target = Function::Handle();
828 ic_data.GetCheckAt(i, &classes, &target); 838 ic_data.GetCheckAt(i, &classes, &target);
829 bool matches = true; 839 bool matches = true;
830 for (intptr_t k = 0; k < classes.length(); k++) { 840 for (intptr_t k = 0; k < classes.length(); k++) {
831 if (classes[k]->raw() != args[k]->clazz()) { 841 if (classes[k]->raw() != args[k]->clazz()) {
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
1277 1287
1278 // The top Dart frame belongs to the optimized method that needs to be 1288 // The top Dart frame belongs to the optimized method that needs to be
1279 // deoptimized. The pc of the Dart frame points to the deoptimization point. 1289 // deoptimized. The pc of the Dart frame points to the deoptimization point.
1280 // Find the node id of the deoptimization point and find the continuation 1290 // Find the node id of the deoptimization point and find the continuation
1281 // pc in the unoptimized code. 1291 // pc in the unoptimized code.
1282 // Since both unoptimized and optimized code have the same layout, we need only 1292 // Since both unoptimized and optimized code have the same layout, we need only
1283 // to patch the pc of the Dart frame and to disable/enable appropriate code. 1293 // to patch the pc of the Dart frame and to disable/enable appropriate code.
1284 DEFINE_RUNTIME_ENTRY(Deoptimize, 1) { 1294 DEFINE_RUNTIME_ENTRY(Deoptimize, 1) {
1285 ASSERT(arguments.Count() == kDeoptimizeRuntimeEntry.argument_count()); 1295 ASSERT(arguments.Count() == kDeoptimizeRuntimeEntry.argument_count());
1286 const Smi& deoptimization_reason_id = Smi::CheckedHandle(arguments.At(0)); 1296 const Smi& deoptimization_reason_id = Smi::CheckedHandle(arguments.At(0));
1287 DartFrameIterator iterator; 1297 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
1288 StackFrame* caller_frame = iterator.NextFrame(); 1298 StackFrame* caller_frame = GetTopDartFrame(&iterator, true);
1289 ASSERT(caller_frame != NULL && caller_frame->IsDartFrame());
1290 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); 1299 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode());
1291 const Function& function = Function::Handle(optimized_code.function()); 1300 const Function& function = Function::Handle(optimized_code.function());
1292 ASSERT(!function.IsNull()); 1301 ASSERT(!function.IsNull());
1293 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); 1302 const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
1294 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); 1303 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized());
1295 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); 1304 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized());
1296 const PcDescriptors& descriptors = 1305 const PcDescriptors& descriptors =
1297 PcDescriptors::Handle(optimized_code.pc_descriptors()); 1306 PcDescriptors::Handle(optimized_code.pc_descriptors());
1298 ASSERT(!descriptors.IsNull()); 1307 ASSERT(!descriptors.IsNull());
1299 // Locate node id at deoptimization point inside optimized code. 1308 // Locate node id at deoptimization point inside optimized code.
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1430 } 1439 }
1431 } 1440 }
1432 } 1441 }
1433 // The cache is null terminated, therefore the loop above should never 1442 // The cache is null terminated, therefore the loop above should never
1434 // terminate by itself. 1443 // terminate by itself.
1435 UNREACHABLE(); 1444 UNREACHABLE();
1436 return Code::null(); 1445 return Code::null();
1437 } 1446 }
1438 1447
1439 } // namespace dart 1448 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698