Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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_index_table.h" | 7 #include "vm/code_index_table.h" |
| 8 #include "vm/code_patcher.h" | 8 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_api_impl.h" | 10 #include "vm/dart_api_impl.h" |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 | 424 |
| 425 Function& function = Function::Handle(); | 425 Function& function = Function::Handle(); |
| 426 function = Resolver::ResolveDynamic(receiver, | 426 function = Resolver::ResolveDynamic(receiver, |
| 427 function_name, | 427 function_name, |
| 428 num_arguments, | 428 num_arguments, |
| 429 num_named_arguments); | 429 num_named_arguments); |
| 430 if (function.IsNull()) { | 430 if (function.IsNull()) { |
| 431 return Code::null(); | 431 return Code::null(); |
| 432 } else { | 432 } else { |
| 433 if (!function.HasCode()) { | 433 if (!function.HasCode()) { |
| 434 Compiler::CompileFunction(function); | 434 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
|
siva
2012/01/31 00:52:34
Would it make sense to have a version of CompileFu
turnidge
2012/01/31 21:56:31
I sort of find the current version less magical.
siva
2012/02/01 19:09:38
Sure.
| |
| 435 if (!error.IsNull()) { | |
| 436 Exceptions::PropagateError(error); | |
| 437 } | |
| 435 } | 438 } |
| 436 functions_cache.AddCompiledFunction(function, | 439 functions_cache.AddCompiledFunction(function, |
| 437 num_arguments, | 440 num_arguments, |
| 438 num_named_arguments); | 441 num_named_arguments); |
| 439 return function.code(); | 442 return function.code(); |
| 440 } | 443 } |
| 441 } | 444 } |
| 442 | 445 |
| 443 | 446 |
| 444 // Result of an invoke may be an unhandled exception, in which case we | 447 // Result of an invoke may be an unhandled exception, in which case we |
| 445 // rethrow it. | 448 // rethrow it. |
| 446 static void CheckResultException(const Instance& result) { | 449 static void CheckResultError(const Object& result) { |
| 447 if (result.IsUnhandledException()) { | 450 if (result.IsError()) { |
| 448 const UnhandledException& unhandled = UnhandledException::Handle( | 451 Error& error = Error::Handle(); |
| 449 reinterpret_cast<RawUnhandledException*>(result.raw())); | 452 error ^= result.raw(); |
| 450 const Instance& excp = Instance::Handle(unhandled.exception()); | 453 Exceptions::PropagateError(error); |
| 451 const Instance& stack = Instance::Handle(unhandled.stacktrace()); | |
| 452 Exceptions::ReThrow(excp, stack); | |
| 453 } | 454 } |
|
siva
2012/01/31 00:52:34
ASSERT(result.IsNull());
turnidge
2012/01/31 21:56:31
Why should the result be null?
siva
2012/02/01 19:09:38
You are right the result does not have to be NULL,
| |
| 454 } | 455 } |
| 455 | 456 |
| 456 | 457 |
| 457 // Resolves an instance function and compiles it if necessary. | 458 // Resolves an instance function and compiles it if necessary. |
| 458 // Arg0: receiver object. | 459 // Arg0: receiver object. |
| 459 // Returns: RawCode object or NULL (method not found or not compileable). | 460 // Returns: RawCode object or NULL (method not found or not compileable). |
| 460 // This is called by the megamorphic stub when instance call does not need to be | 461 // This is called by the megamorphic stub when instance call does not need to be |
| 461 // patched. | 462 // patched. |
| 462 // Used by megamorphic lookup/no-such-method-handling. | 463 // Used by megamorphic lookup/no-such-method-handling. |
| 463 DEFINE_RUNTIME_ENTRY(ResolveCompileInstanceFunction, 1) { | 464 DEFINE_RUNTIME_ENTRY(ResolveCompileInstanceFunction, 1) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 475 DEFINE_RUNTIME_ENTRY(BreakpointStaticHandler, 1) { | 476 DEFINE_RUNTIME_ENTRY(BreakpointStaticHandler, 1) { |
| 476 ASSERT(arguments.Count() == | 477 ASSERT(arguments.Count() == |
| 477 kBreakpointStaticHandlerRuntimeEntry.argument_count()); | 478 kBreakpointStaticHandlerRuntimeEntry.argument_count()); |
| 478 ASSERT(isolate->debugger() != NULL); | 479 ASSERT(isolate->debugger() != NULL); |
| 479 isolate->debugger()->BreakpointCallback(); | 480 isolate->debugger()->BreakpointCallback(); |
| 480 // Make sure the static function that is about to be called is | 481 // Make sure the static function that is about to be called is |
| 481 // compiled. The stub will jump to the entry point without any | 482 // compiled. The stub will jump to the entry point without any |
| 482 // further tests. | 483 // further tests. |
| 483 const Function& function = Function::CheckedHandle(arguments.At(0)); | 484 const Function& function = Function::CheckedHandle(arguments.At(0)); |
| 484 if (!function.HasCode()) { | 485 if (!function.HasCode()) { |
| 485 Compiler::CompileFunction(function); | 486 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
| 487 if (!error.IsNull()) { | |
| 488 Exceptions::PropagateError(error); | |
| 489 } | |
| 486 } | 490 } |
| 487 } | 491 } |
| 488 | 492 |
| 489 | 493 |
| 490 // Gets called from debug stub when code reaches a breakpoint. | 494 // Gets called from debug stub when code reaches a breakpoint. |
| 491 DEFINE_RUNTIME_ENTRY(BreakpointDynamicHandler, 0) { | 495 DEFINE_RUNTIME_ENTRY(BreakpointDynamicHandler, 0) { |
| 492 ASSERT(arguments.Count() == | 496 ASSERT(arguments.Count() == |
| 493 kBreakpointDynamicHandlerRuntimeEntry.argument_count()); | 497 kBreakpointDynamicHandlerRuntimeEntry.argument_count()); |
| 494 ASSERT(isolate->debugger() != NULL); | 498 ASSERT(isolate->debugger() != NULL); |
| 495 isolate->debugger()->BreakpointCallback(); | 499 isolate->debugger()->BreakpointCallback(); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 getter_function_name, | 704 getter_function_name, |
| 701 kNumArguments, | 705 kNumArguments, |
| 702 kNumNamedArguments)); | 706 kNumNamedArguments)); |
| 703 Code& code = Code::Handle(); | 707 Code& code = Code::Handle(); |
| 704 if (function.IsNull()) { | 708 if (function.IsNull()) { |
| 705 arguments.SetReturn(code); | 709 arguments.SetReturn(code); |
| 706 return; // No getter function found so can't be an implicit closure. | 710 return; // No getter function found so can't be an implicit closure. |
| 707 } | 711 } |
| 708 GrowableArray<const Object*> invoke_arguments(0); | 712 GrowableArray<const Object*> invoke_arguments(0); |
| 709 const Array& kNoArgumentNames = Array::Handle(); | 713 const Array& kNoArgumentNames = Array::Handle(); |
| 710 const Instance& result = | 714 const Object& result = |
| 711 Instance::Handle( | 715 Object::Handle(DartEntry::InvokeDynamic(receiver, |
| 712 DartEntry::InvokeDynamic(receiver, | 716 function, |
| 713 function, | 717 invoke_arguments, |
| 714 invoke_arguments, | 718 kNoArgumentNames)); |
| 715 kNoArgumentNames)); | 719 if (result.IsError()) { |
| 716 if (result.IsUnhandledException()) { | 720 if (result.IsUnhandledException()) { |
| 717 arguments.SetReturn(code); | 721 // If the getter throws an exception, treat as no such method. |
| 718 return; // Error accessing getter, treat as no such method. | 722 // |
| 723 // TODO(turnidge): Is this the desired behavior? | |
|
siva
2012/01/31 00:52:34
Yes this is the desired behaviour.
turnidge
2012/01/31 21:56:31
Thanks. Updated comment.
| |
| 724 arguments.SetReturn(code); | |
| 725 return; | |
| 726 } else { | |
| 727 Error& error = Error::Handle(); | |
| 728 error ^= result.raw(); | |
| 729 Exceptions::PropagateError(error); | |
| 730 } | |
| 719 } | 731 } |
| 720 if (!result.IsSmi()) { | 732 if (!result.IsSmi()) { |
| 721 const Class& cls = Class::Handle(result.clazz()); | 733 const Class& cls = Class::Handle(result.clazz()); |
| 722 ASSERT(!cls.IsNull()); | 734 ASSERT(!cls.IsNull()); |
| 723 function = cls.signature_function(); | 735 function = cls.signature_function(); |
| 724 if (!function.IsNull()) { | 736 if (!function.IsNull()) { |
| 725 arguments.SetReturn(result); | 737 arguments.SetReturn(result); |
| 726 return; // Return closure object. | 738 return; // Return closure object. |
| 727 } | 739 } |
| 728 } | 740 } |
| 729 Exceptions::ThrowByType(Exceptions::kObjectNotClosure, invoke_arguments); | 741 Exceptions::ThrowByType(Exceptions::kObjectNotClosure, invoke_arguments); |
| 730 } | 742 } |
| 731 | 743 |
| 732 | 744 |
| 733 // Invoke Implicit Closure function. | 745 // Invoke Implicit Closure function. |
| 734 // Arg0: closure object. | 746 // Arg0: closure object. |
| 735 // Arg1: arguments descriptor (originally passed as dart instance invocation). | 747 // Arg1: arguments descriptor (originally passed as dart instance invocation). |
| 736 // Arg2: arguments array (originally passed to dart instance invocation). | 748 // Arg2: arguments array (originally passed to dart instance invocation). |
| 737 DEFINE_RUNTIME_ENTRY(InvokeImplicitClosureFunction, 3) { | 749 DEFINE_RUNTIME_ENTRY(InvokeImplicitClosureFunction, 3) { |
| 738 ASSERT(arguments.Count() == | 750 ASSERT(arguments.Count() == |
| 739 kInvokeImplicitClosureFunctionRuntimeEntry.argument_count()); | 751 kInvokeImplicitClosureFunctionRuntimeEntry.argument_count()); |
| 740 const Closure& closure = Closure::CheckedHandle(arguments.At(0)); | 752 const Closure& closure = Closure::CheckedHandle(arguments.At(0)); |
| 741 const Array& arg_descriptor = Array::CheckedHandle(arguments.At(1)); | 753 const Array& arg_descriptor = Array::CheckedHandle(arguments.At(1)); |
| 742 const Array& func_arguments = Array::CheckedHandle(arguments.At(2)); | 754 const Array& func_arguments = Array::CheckedHandle(arguments.At(2)); |
| 743 const Function& function = Function::Handle(closure.function()); | 755 const Function& function = Function::Handle(closure.function()); |
| 744 ASSERT(!function.IsNull()); | 756 ASSERT(!function.IsNull()); |
| 745 if (!function.HasCode()) { | 757 if (!function.HasCode()) { |
| 746 Compiler::CompileFunction(function); | 758 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
| 759 if (!error.IsNull()) { | |
| 760 Exceptions::PropagateError(error); | |
| 761 } | |
| 747 } | 762 } |
| 748 const Context& context = Context::Handle(closure.context()); | 763 const Context& context = Context::Handle(closure.context()); |
| 749 const Code& code = Code::Handle(function.code()); | 764 const Code& code = Code::Handle(function.code()); |
| 750 ASSERT(!code.IsNull()); | 765 ASSERT(!code.IsNull()); |
| 751 const Instructions& instrs = Instructions::Handle(code.instructions()); | 766 const Instructions& instrs = Instructions::Handle(code.instructions()); |
| 752 ASSERT(!instrs.IsNull()); | 767 ASSERT(!instrs.IsNull()); |
| 753 | 768 |
| 754 // Adjust arguments descriptor array to account for removal of the receiver | 769 // Adjust arguments descriptor array to account for removal of the receiver |
| 755 // parameter. Since the arguments descriptor array is canonicalized, create a | 770 // parameter. Since the arguments descriptor array is canonicalized, create a |
| 756 // new one instead of patching the original one. | 771 // new one instead of patching the original one. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 785 GrowableArray<const Object*> invoke_arguments(0); | 800 GrowableArray<const Object*> invoke_arguments(0); |
| 786 for (intptr_t i = 0; i < func_arguments.Length(); i++) { | 801 for (intptr_t i = 0; i < func_arguments.Length(); i++) { |
| 787 const Object& value = Object::Handle(func_arguments.At(i)); | 802 const Object& value = Object::Handle(func_arguments.At(i)); |
| 788 invoke_arguments.Add(&value); | 803 invoke_arguments.Add(&value); |
| 789 } | 804 } |
| 790 | 805 |
| 791 // Now Call the invoke stub which will invoke the closure. | 806 // Now Call the invoke stub which will invoke the closure. |
| 792 DartEntry::invokestub entrypoint = reinterpret_cast<DartEntry::invokestub>( | 807 DartEntry::invokestub entrypoint = reinterpret_cast<DartEntry::invokestub>( |
| 793 StubCode::InvokeDartCodeEntryPoint()); | 808 StubCode::InvokeDartCodeEntryPoint()); |
| 794 ASSERT(context.isolate() == Isolate::Current()); | 809 ASSERT(context.isolate() == Isolate::Current()); |
| 795 const Instance& result = Instance::Handle( | 810 const Object& result = Object::Handle( |
| 796 entrypoint(instrs.EntryPoint(), | 811 entrypoint(instrs.EntryPoint(), |
| 797 adjusted_arg_descriptor, | 812 adjusted_arg_descriptor, |
| 798 invoke_arguments.data(), | 813 invoke_arguments.data(), |
| 799 context)); | 814 context)); |
| 800 CheckResultException(result); | 815 CheckResultError(result); |
| 801 arguments.SetReturn(result); | 816 arguments.SetReturn(result); |
| 802 } | 817 } |
| 803 | 818 |
| 804 | 819 |
| 805 // Invoke appropriate noSuchMethod function. | 820 // Invoke appropriate noSuchMethod function. |
| 806 // Arg0: receiver. | 821 // Arg0: receiver. |
| 807 // Arg1: ic-data array. | 822 // Arg1: ic-data array. |
| 808 // Arg2: original arguments descriptor array. | 823 // Arg2: original arguments descriptor array. |
| 809 // Arg3: original arguments array. | 824 // Arg3: original arguments array. |
| 810 DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodFunction, 4) { | 825 DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodFunction, 4) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 826 String::Handle(String::NewSymbol("noSuchMethod")); | 841 String::Handle(String::NewSymbol("noSuchMethod")); |
| 827 const Function& function = Function::ZoneHandle( | 842 const Function& function = Function::ZoneHandle( |
| 828 Resolver::ResolveDynamic(receiver, | 843 Resolver::ResolveDynamic(receiver, |
| 829 function_name, | 844 function_name, |
| 830 kNumArguments, | 845 kNumArguments, |
| 831 kNumNamedArguments)); | 846 kNumNamedArguments)); |
| 832 ASSERT(!function.IsNull()); | 847 ASSERT(!function.IsNull()); |
| 833 GrowableArray<const Object*> invoke_arguments(2); | 848 GrowableArray<const Object*> invoke_arguments(2); |
| 834 invoke_arguments.Add(&original_function_name); | 849 invoke_arguments.Add(&original_function_name); |
| 835 invoke_arguments.Add(&orig_arguments); | 850 invoke_arguments.Add(&orig_arguments); |
| 836 const Instance& result = Instance::Handle( | 851 const Object& result = Object::Handle( |
| 837 DartEntry::InvokeDynamic(receiver, | 852 DartEntry::InvokeDynamic(receiver, |
| 838 function, | 853 function, |
| 839 invoke_arguments, | 854 invoke_arguments, |
| 840 kNoArgumentNames)); | 855 kNoArgumentNames)); |
| 841 CheckResultException(result); | 856 CheckResultError(result); |
| 842 arguments.SetReturn(result); | 857 arguments.SetReturn(result); |
| 843 } | 858 } |
| 844 | 859 |
| 845 | 860 |
| 846 // Report that an object is not a closure. | 861 // Report that an object is not a closure. |
| 847 // Arg0: non-closure object. | 862 // Arg0: non-closure object. |
| 848 // Arg1: arguments array. | 863 // Arg1: arguments array. |
| 849 DEFINE_RUNTIME_ENTRY(ReportObjectNotClosure, 2) { | 864 DEFINE_RUNTIME_ENTRY(ReportObjectNotClosure, 2) { |
| 850 ASSERT(arguments.Count() == | 865 ASSERT(arguments.Count() == |
| 851 kReportObjectNotClosureRuntimeEntry.argument_count()); | 866 kReportObjectNotClosureRuntimeEntry.argument_count()); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 908 if (function.deoptimization_counter() >= | 923 if (function.deoptimization_counter() >= |
| 909 FLAG_deoptimization_counter_threshold) { | 924 FLAG_deoptimization_counter_threshold) { |
| 910 // TODO(srdjan): Investigate excessive deoptimization. | 925 // TODO(srdjan): Investigate excessive deoptimization. |
| 911 function.set_invocation_counter(0); | 926 function.set_invocation_counter(0); |
| 912 return; | 927 return; |
| 913 } | 928 } |
| 914 if (function.is_optimizable()) { | 929 if (function.is_optimizable()) { |
| 915 ASSERT(!Code::Handle(function.code()).is_optimized()); | 930 ASSERT(!Code::Handle(function.code()).is_optimized()); |
| 916 const Code& unoptimized_code = Code::Handle(function.code()); | 931 const Code& unoptimized_code = Code::Handle(function.code()); |
| 917 // Compilation patches the entry of unoptimized code. | 932 // Compilation patches the entry of unoptimized code. |
| 918 Compiler::CompileOptimizedFunction(function); | 933 const Error& error = |
| 934 Error::Handle(Compiler::CompileOptimizedFunction(function)); | |
| 935 if (!error.IsNull()) { | |
| 936 Exceptions::PropagateError(error); | |
| 937 } | |
| 919 const Code& optimized_code = Code::Handle(function.code()); | 938 const Code& optimized_code = Code::Handle(function.code()); |
| 920 ASSERT(!optimized_code.IsNull()); | 939 ASSERT(!optimized_code.IsNull()); |
| 921 ASSERT(!unoptimized_code.IsNull()); | 940 ASSERT(!unoptimized_code.IsNull()); |
| 922 } else { | 941 } else { |
| 923 // TODO(5442338): Abort as this should not happen. | 942 // TODO(5442338): Abort as this should not happen. |
| 924 function.set_invocation_counter(0); | 943 function.set_invocation_counter(0); |
| 925 } | 944 } |
| 926 } | 945 } |
| 927 | 946 |
| 928 | 947 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1015 // types/classes have been collected. | 1034 // types/classes have been collected. |
| 1016 function.set_invocation_counter(0); | 1035 function.set_invocation_counter(0); |
| 1017 function.set_deoptimization_counter(function.deoptimization_counter() + 1); | 1036 function.set_deoptimization_counter(function.deoptimization_counter() + 1); |
| 1018 | 1037 |
| 1019 // We have to skip the following otherwise the compiler will complain | 1038 // We have to skip the following otherwise the compiler will complain |
| 1020 // when it attempts to install unoptimized code into a function that | 1039 // when it attempts to install unoptimized code into a function that |
| 1021 // was already deoptimized. | 1040 // was already deoptimized. |
| 1022 if (Code::Handle(function.code()).is_optimized()) { | 1041 if (Code::Handle(function.code()).is_optimized()) { |
| 1023 // Get unoptimized code. Compilation restores (reenables) the entry of | 1042 // Get unoptimized code. Compilation restores (reenables) the entry of |
| 1024 // unoptimized code. | 1043 // unoptimized code. |
| 1025 Compiler::CompileFunction(function); | 1044 const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
| 1045 if (!error.IsNull()) { | |
| 1046 Exceptions::PropagateError(error); | |
| 1047 } | |
| 1026 } | 1048 } |
| 1027 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized | 1049 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized |
| 1028 // code is alive on frame and gets deoptimized after the function was | 1050 // code is alive on frame and gets deoptimized after the function was |
| 1029 // optimized a second time. | 1051 // optimized a second time. |
| 1030 if (FLAG_trace_deopt) { | 1052 if (FLAG_trace_deopt) { |
| 1031 OS::Print("After patching ->0x%x:\n", continue_at_pc); | 1053 OS::Print("After patching ->0x%x:\n", continue_at_pc); |
| 1032 } | 1054 } |
| 1033 } | 1055 } |
| 1034 | 1056 |
| 1035 | 1057 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1106 } | 1128 } |
| 1107 } | 1129 } |
| 1108 } | 1130 } |
| 1109 // The cache is null terminated, therefore the loop above should never | 1131 // The cache is null terminated, therefore the loop above should never |
| 1110 // terminate by itself. | 1132 // terminate by itself. |
| 1111 UNREACHABLE(); | 1133 UNREACHABLE(); |
| 1112 return Code::null(); | 1134 return Code::null(); |
| 1113 } | 1135 } |
| 1114 | 1136 |
| 1115 } // namespace dart | 1137 } // namespace dart |
| OLD | NEW |