OLD | NEW |
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/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
7 | 7 |
8 #include "vm/code_generator.h" | 8 #include "vm/code_generator.h" |
9 | 9 |
10 #include "lib/error.h" | 10 #include "lib/error.h" |
11 #include "vm/ast_printer.h" | 11 #include "vm/ast_printer.h" |
12 #include "vm/class_finalizer.h" | 12 #include "vm/class_finalizer.h" |
13 #include "vm/dart_entry.h" | 13 #include "vm/dart_entry.h" |
14 #include "vm/debugger.h" | 14 #include "vm/debugger.h" |
15 #include "vm/longjump.h" | 15 #include "vm/longjump.h" |
16 #include "vm/object.h" | 16 #include "vm/object.h" |
17 #include "vm/object_store.h" | 17 #include "vm/object_store.h" |
18 #include "vm/parser.h" | 18 #include "vm/parser.h" |
19 #include "vm/resolver.h" | 19 #include "vm/resolver.h" |
20 #include "vm/stub_code.h" | 20 #include "vm/stub_code.h" |
21 | 21 |
22 namespace dart { | 22 namespace dart { |
23 | 23 |
24 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 24 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
25 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); | 25 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); |
26 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function."); | 26 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function."); |
27 DEFINE_FLAG(bool, print_ic_in_optimized, false, | 27 DEFINE_FLAG(bool, print_ic_in_optimized, false, |
28 "Debugging helper to identify potential performance pitfalls."); | 28 "Debugging helper to identify potential performance pitfalls."); |
29 DEFINE_FLAG(int, optimization_invocation_threshold, 1000, | 29 DECLARE_FLAG(int, optimization_counter_threshold); |
30 "Number of invocations before a function is optimized, -1 means never."); | |
31 DECLARE_FLAG(bool, enable_type_checks); | 30 DECLARE_FLAG(bool, enable_type_checks); |
32 DECLARE_FLAG(bool, report_invocation_count); | |
33 DECLARE_FLAG(bool, trace_compiler); | 31 DECLARE_FLAG(bool, trace_compiler); |
34 | 32 |
35 #define __ assembler_-> | 33 #define __ assembler_-> |
36 | 34 |
37 | 35 |
38 CodeGeneratorState::CodeGeneratorState(CodeGenerator* codegen) | 36 CodeGeneratorState::CodeGeneratorState(CodeGenerator* codegen) |
39 : StackResource(Isolate::Current()), | 37 : StackResource(Isolate::Current()), |
40 codegen_(codegen), | 38 codegen_(codegen), |
41 parent_(codegen->state()) { | 39 parent_(codegen->state()) { |
42 if (parent_ != NULL) { | 40 if (parent_ != NULL) { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 | 196 |
199 // Pre entry code is called before the frame has been constructed: | 197 // Pre entry code is called before the frame has been constructed: |
200 // - check for stack overflow. | 198 // - check for stack overflow. |
201 // - optionally count function invocations. | 199 // - optionally count function invocations. |
202 // - optionally trigger optimizing compiler if invocation threshold has been | 200 // - optionally trigger optimizing compiler if invocation threshold has been |
203 // reached. | 201 // reached. |
204 // Note that first 5 bytes may be patched with a jump. | 202 // Note that first 5 bytes may be patched with a jump. |
205 // TODO(srdjan): Add check that no object is inlined in the first | 203 // TODO(srdjan): Add check that no object is inlined in the first |
206 // 5 bytes (length of a jump instruction). | 204 // 5 bytes (length of a jump instruction). |
207 void CodeGenerator::GeneratePreEntryCode() { | 205 void CodeGenerator::GeneratePreEntryCode() { |
208 // Do not optimize if: | 206 // TODO(srdjan): Still needed? |
209 // - we count invocations. | 207 __ nop(5); |
210 // - optimization disabled via negative 'optimization_invocation_threshold; | |
211 // - function is marked as non-optimizable. | |
212 // - type checks are enabled. | |
213 const bool may_optimize = | |
214 !FLAG_report_invocation_count && | |
215 (FLAG_optimization_invocation_threshold >= 0) && | |
216 !Isolate::Current()->debugger()->IsActive() && | |
217 parsed_function_.function().is_optimizable(); | |
218 // Count invocation and check. | |
219 if (FLAG_report_invocation_count || may_optimize) { | |
220 // TODO(turnidge): It would be nice to remove this nop. Right now | |
221 // we need it to make sure the function is still patchable. | |
222 __ nop(5); | |
223 const Function& function = | |
224 Function::ZoneHandle(parsed_function_.function().raw()); | |
225 __ LoadObject(EAX, function); | |
226 __ movl(EBX, FieldAddress(EAX, Function::invocation_counter_offset())); | |
227 __ incl(EBX); | |
228 if (may_optimize) { | |
229 __ cmpl(EBX, Immediate(FLAG_optimization_invocation_threshold)); | |
230 __ j(GREATER, &StubCode::OptimizeInvokedFunctionLabel()); | |
231 } | |
232 // EBX is an integer value (not an object). | |
233 __ movl(FieldAddress(EAX, Function::invocation_counter_offset()), EBX); | |
234 } | |
235 } | 208 } |
236 | 209 |
237 | 210 |
238 // Verify assumptions (in debug mode only). | 211 // Verify assumptions (in debug mode only). |
239 // - No two deopt descriptors have the same node id (deoptimization). | 212 // - No two deopt descriptors have the same node id (deoptimization). |
240 // - No two ic-call descriptors have the same node id (type feedback). | 213 // - No two ic-call descriptors have the same node id (type feedback). |
241 // - No two descriptors of same kind have the same PC. | 214 // - No two descriptors of same kind have the same PC. |
242 // A function without unique ids is marked as non-optimizable (e.g., because of | 215 // A function without unique ids is marked as non-optimizable (e.g., because of |
243 // finally blocks). | 216 // finally blocks). |
244 static void VerifyPcDescriptors(const PcDescriptors& descriptors, | 217 static void VerifyPcDescriptors(const PcDescriptors& descriptors, |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
705 #ifdef DEBUG | 678 #ifdef DEBUG |
706 // Check that the entry stack size matches the exit stack size. | 679 // Check that the entry stack size matches the exit stack size. |
707 __ movl(EDX, EBP); | 680 __ movl(EDX, EBP); |
708 __ subl(EDX, ESP); | 681 __ subl(EDX, ESP); |
709 ASSERT(locals_space_size() >= 0); | 682 ASSERT(locals_space_size() >= 0); |
710 __ cmpl(EDX, Immediate(locals_space_size())); | 683 __ cmpl(EDX, Immediate(locals_space_size())); |
711 Label wrong_stack; | 684 Label wrong_stack; |
712 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); | 685 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); |
713 #endif // DEBUG. | 686 #endif // DEBUG. |
714 | 687 |
| 688 if (!IsOptimizing()) { |
| 689 // Count only in unoptimized code. |
| 690 // TODO(srdjan): Replace the counting code with a type feedback |
| 691 // collection and counting stub. |
| 692 const Function& function = |
| 693 Function::ZoneHandle(parsed_function_.function().raw()); |
| 694 __ LoadObject(EBX, function); |
| 695 __ incl(FieldAddress(EBX, Function::usage_counter_offset())); |
| 696 if (CodeGenerator::CanOptimize()) { |
| 697 // Do not optimize if usage count must be reported. |
| 698 __ cmpl(FieldAddress(EBX, Function::usage_counter_offset()), |
| 699 Immediate(FLAG_optimization_counter_threshold)); |
| 700 Label not_yet_hot; |
| 701 __ j(LESS_EQUAL, ¬_yet_hot); |
| 702 __ pushl(EAX); // Preserve result. |
| 703 __ pushl(EBX); // Argument for runtime: function to optimize. |
| 704 __ CallRuntimeFromDart(kOptimizeInvokedFunctionRuntimeEntry); |
| 705 __ popl(EBX); // Remove argument. |
| 706 __ popl(EAX); // Restore result. |
| 707 __ Bind(¬_yet_hot); |
| 708 } |
| 709 } |
715 if (FLAG_trace_functions) { | 710 if (FLAG_trace_functions) { |
| 711 const Function& function = |
| 712 Function::ZoneHandle(parsed_function_.function().raw()); |
| 713 __ LoadObject(EBX, function); |
716 __ pushl(EAX); // Preserve result. | 714 __ pushl(EAX); // Preserve result. |
717 const Function& function = | |
718 Function::ZoneHandle(parsed_function_.function().raw()); | |
719 __ LoadObject(EBX, function); | |
720 __ pushl(EBX); | 715 __ pushl(EBX); |
721 GenerateCallRuntime(AstNode::kNoId, | 716 GenerateCallRuntime(AstNode::kNoId, |
722 0, | 717 0, |
723 kTraceFunctionExitRuntimeEntry); | 718 kTraceFunctionExitRuntimeEntry); |
724 __ popl(EAX); // Remove argument. | 719 __ popl(EAX); // Remove argument. |
725 __ popl(EAX); // Restore result. | 720 __ popl(EAX); // Restore result. |
726 } | 721 } |
727 __ LeaveFrame(); | 722 __ LeaveFrame(); |
728 __ ret(); | 723 __ ret(); |
729 // Add a NOP to make return code pattern 5 bytes long for patching | 724 // Add a NOP to make return code pattern 5 bytes long for patching |
(...skipping 1107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1837 | 1832 |
1838 // Call operator. | 1833 // Call operator. |
1839 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); | 1834 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); |
1840 // Result is in EAX. | 1835 // Result is in EAX. |
1841 if (IsResultNeeded(node)) { | 1836 if (IsResultNeeded(node)) { |
1842 __ pushl(EAX); | 1837 __ pushl(EAX); |
1843 } | 1838 } |
1844 } | 1839 } |
1845 | 1840 |
1846 | 1841 |
1847 void CodeGenerator::CountBackwardLoop() { | |
1848 Label done; | |
1849 const Function& function = | |
1850 Function::ZoneHandle(parsed_function_.function().raw()); | |
1851 __ LoadObject(EAX, function); | |
1852 __ movl(EBX, FieldAddress(EAX, Function::invocation_counter_offset())); | |
1853 __ incl(EBX); | |
1854 if (!FLAG_report_invocation_count) { | |
1855 // Prevent overflow. | |
1856 __ cmpl(EBX, Immediate(FLAG_optimization_invocation_threshold)); | |
1857 __ j(GREATER, &done); | |
1858 } | |
1859 // EBX is an integer value (not an object). | |
1860 __ movl(FieldAddress(EAX, Function::invocation_counter_offset()), EBX); | |
1861 __ Bind(&done); | |
1862 } | |
1863 | |
1864 | |
1865 void CodeGenerator::VisitWhileNode(WhileNode* node) { | 1842 void CodeGenerator::VisitWhileNode(WhileNode* node) { |
1866 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1843 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
1867 SourceLabel* label = node->label(); | 1844 SourceLabel* label = node->label(); |
1868 __ Bind(label->continue_label()); | 1845 __ Bind(label->continue_label()); |
1869 node->condition()->Visit(this); | 1846 node->condition()->Visit(this); |
1870 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); | 1847 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
1871 __ popl(EAX); | 1848 __ popl(EAX); |
1872 __ LoadObject(EDX, bool_true); | 1849 __ LoadObject(EDX, bool_true); |
1873 __ cmpl(EAX, EDX); | 1850 __ cmpl(EAX, EDX); |
1874 __ j(NOT_EQUAL, label->break_label()); | 1851 __ j(NOT_EQUAL, label->break_label()); |
1875 node->body()->Visit(this); | 1852 node->body()->Visit(this); |
1876 CountBackwardLoop(); | |
1877 __ jmp(label->continue_label()); | 1853 __ jmp(label->continue_label()); |
1878 __ Bind(label->break_label()); | 1854 __ Bind(label->break_label()); |
1879 } | 1855 } |
1880 | 1856 |
1881 | 1857 |
1882 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { | 1858 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { |
1883 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1859 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
1884 SourceLabel* label = node->label(); | 1860 SourceLabel* label = node->label(); |
1885 Label loop; | 1861 Label loop; |
1886 __ Bind(&loop); | 1862 __ Bind(&loop); |
1887 node->body()->Visit(this); | 1863 node->body()->Visit(this); |
1888 CountBackwardLoop(); | |
1889 __ Bind(label->continue_label()); | 1864 __ Bind(label->continue_label()); |
1890 node->condition()->Visit(this); | 1865 node->condition()->Visit(this); |
1891 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); | 1866 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
1892 __ popl(EAX); | 1867 __ popl(EAX); |
1893 __ LoadObject(EDX, bool_true); | 1868 __ LoadObject(EDX, bool_true); |
1894 __ cmpl(EAX, EDX); | 1869 __ cmpl(EAX, EDX); |
1895 __ j(EQUAL, &loop); | 1870 __ j(EQUAL, &loop); |
1896 __ Bind(label->break_label()); | 1871 __ Bind(label->break_label()); |
1897 } | 1872 } |
1898 | 1873 |
1899 | 1874 |
1900 void CodeGenerator::VisitForNode(ForNode* node) { | 1875 void CodeGenerator::VisitForNode(ForNode* node) { |
1901 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1876 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
1902 node->initializer()->Visit(this); | 1877 node->initializer()->Visit(this); |
1903 SourceLabel* label = node->label(); | 1878 SourceLabel* label = node->label(); |
1904 Label loop; | 1879 Label loop; |
1905 __ Bind(&loop); | 1880 __ Bind(&loop); |
1906 if (node->condition() != NULL) { | 1881 if (node->condition() != NULL) { |
1907 node->condition()->Visit(this); | 1882 node->condition()->Visit(this); |
1908 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); | 1883 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
1909 __ popl(EAX); | 1884 __ popl(EAX); |
1910 __ LoadObject(EDX, bool_true); | 1885 __ LoadObject(EDX, bool_true); |
1911 __ cmpl(EAX, EDX); | 1886 __ cmpl(EAX, EDX); |
1912 __ j(NOT_EQUAL, label->break_label()); | 1887 __ j(NOT_EQUAL, label->break_label()); |
1913 } | 1888 } |
1914 node->body()->Visit(this); | 1889 node->body()->Visit(this); |
1915 CountBackwardLoop(); | |
1916 __ Bind(label->continue_label()); | 1890 __ Bind(label->continue_label()); |
1917 node->increment()->Visit(this); | 1891 node->increment()->Visit(this); |
1918 __ jmp(&loop); | 1892 __ jmp(&loop); |
1919 __ Bind(label->break_label()); | 1893 __ Bind(label->break_label()); |
1920 } | 1894 } |
1921 | 1895 |
1922 | 1896 |
1923 void CodeGenerator::VisitJumpNode(JumpNode* node) { | 1897 void CodeGenerator::VisitJumpNode(JumpNode* node) { |
1924 SourceLabel* label = node->label(); | 1898 SourceLabel* label = node->label(); |
1925 | 1899 |
(...skipping 819 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2745 const Error& error = Error::Handle( | 2719 const Error& error = Error::Handle( |
2746 Parser::FormatError(script, token_index, "Error", format, args)); | 2720 Parser::FormatError(script, token_index, "Error", format, args)); |
2747 va_end(args); | 2721 va_end(args); |
2748 Isolate::Current()->long_jump_base()->Jump(1, error); | 2722 Isolate::Current()->long_jump_base()->Jump(1, error); |
2749 UNREACHABLE(); | 2723 UNREACHABLE(); |
2750 } | 2724 } |
2751 | 2725 |
2752 } // namespace dart | 2726 } // namespace dart |
2753 | 2727 |
2754 #endif // defined TARGET_ARCH_IA32 | 2728 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |