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 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 | 265 |
268 // Pre entry code is called before the frame has been constructed: | 266 // Pre entry code is called before the frame has been constructed: |
269 // - check for stack overflow. | 267 // - check for stack overflow. |
270 // - optionally count function invocations. | 268 // - optionally count function invocations. |
271 // - optionally trigger optimizing compiler if invocation threshold has been | 269 // - optionally trigger optimizing compiler if invocation threshold has been |
272 // reached. | 270 // reached. |
273 // Note that first 5 bytes may be patched with a jump. | 271 // Note that first 5 bytes may be patched with a jump. |
274 // TODO(srdjan): Add check that no object is inlined in the first | 272 // TODO(srdjan): Add check that no object is inlined in the first |
275 // 5 bytes (length of a jump instruction). | 273 // 5 bytes (length of a jump instruction). |
276 void CodeGenerator::GeneratePreEntryCode() { | 274 void CodeGenerator::GeneratePreEntryCode() { |
277 // Do not optimize if: | 275 // TODO(srdjan): Still needed? |
278 // - we count invocations. | 276 __ nop(5); |
279 // - optimization disabled via negative 'optimization_invocation_threshold; | |
280 // - function is marked as non-optimizable. | |
281 // - type checks are enabled. | |
282 const bool may_optimize = | |
283 !FLAG_report_invocation_count && | |
284 (FLAG_optimization_invocation_threshold >= 0) && | |
285 !Isolate::Current()->debugger()->IsActive() && | |
286 parsed_function_.function().is_optimizable(); | |
287 // Count invocation and check. | |
288 if (FLAG_report_invocation_count || may_optimize) { | |
289 // TODO(turnidge): It would be nice to remove this nop. Right now | |
290 // we need it to make sure the function is still patchable. | |
291 __ nop(5); | |
292 const Function& function = | |
293 Function::ZoneHandle(parsed_function_.function().raw()); | |
294 __ LoadObject(EAX, function); | |
295 __ movl(EBX, FieldAddress(EAX, Function::invocation_counter_offset())); | |
296 __ incl(EBX); | |
297 if (may_optimize) { | |
298 __ cmpl(EBX, Immediate(FLAG_optimization_invocation_threshold)); | |
299 __ j(GREATER, &StubCode::OptimizeInvokedFunctionLabel()); | |
300 } | |
301 // EBX is an integer value (not an object). | |
302 __ movl(FieldAddress(EAX, Function::invocation_counter_offset()), EBX); | |
303 } | |
304 } | 277 } |
305 | 278 |
306 | 279 |
307 // Verify assumptions (in debug mode only). | 280 // Verify assumptions (in debug mode only). |
308 // - No two deopt descriptors have the same node id (deoptimization). | 281 // - No two deopt descriptors have the same node id (deoptimization). |
309 // - No two ic-call descriptors have the same node id (type feedback). | 282 // - No two ic-call descriptors have the same node id (type feedback). |
310 // - No two descriptors of same kind have the same PC. | 283 // - No two descriptors of same kind have the same PC. |
311 // A function without unique ids is marked as non-optimizable (e.g., because of | 284 // A function without unique ids is marked as non-optimizable (e.g., because of |
312 // finally blocks). | 285 // finally blocks). |
313 static void VerifyPcDescriptors(const PcDescriptors& descriptors, | 286 static void VerifyPcDescriptors(const PcDescriptors& descriptors, |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 #ifdef DEBUG | 747 #ifdef DEBUG |
775 // Check that the entry stack size matches the exit stack size. | 748 // Check that the entry stack size matches the exit stack size. |
776 __ movl(EDX, EBP); | 749 __ movl(EDX, EBP); |
777 __ subl(EDX, ESP); | 750 __ subl(EDX, ESP); |
778 ASSERT(locals_space_size() >= 0); | 751 ASSERT(locals_space_size() >= 0); |
779 __ cmpl(EDX, Immediate(locals_space_size())); | 752 __ cmpl(EDX, Immediate(locals_space_size())); |
780 Label wrong_stack; | 753 Label wrong_stack; |
781 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); | 754 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); |
782 #endif // DEBUG. | 755 #endif // DEBUG. |
783 | 756 |
| 757 if (!IsOptimizing()) { |
| 758 // Count only in unoptimized code. |
| 759 // TODO(srdjan): Replace the counting code with a type feedback |
| 760 // collection and counting stub. |
| 761 const Function& function = |
| 762 Function::ZoneHandle(parsed_function_.function().raw()); |
| 763 __ LoadObject(EBX, function); |
| 764 __ incl(FieldAddress(EBX, Function::usage_counter_offset())); |
| 765 if (CodeGenerator::CanOptimize()) { |
| 766 // Do not optimize if usage count must be reported. |
| 767 __ cmpl(FieldAddress(EBX, Function::usage_counter_offset()), |
| 768 Immediate(FLAG_optimization_counter_threshold)); |
| 769 Label not_yet_hot; |
| 770 __ j(LESS_EQUAL, ¬_yet_hot); |
| 771 __ pushl(EAX); // Preserve result. |
| 772 __ pushl(EBX); // Argument for runtime: function to optimize. |
| 773 __ CallRuntimeFromDart(kOptimizeInvokedFunctionRuntimeEntry); |
| 774 __ popl(EBX); // Remove argument. |
| 775 __ popl(EAX); // Restore result. |
| 776 __ Bind(¬_yet_hot); |
| 777 } |
| 778 } |
784 if (FLAG_trace_functions) { | 779 if (FLAG_trace_functions) { |
| 780 const Function& function = |
| 781 Function::ZoneHandle(parsed_function_.function().raw()); |
| 782 __ LoadObject(EBX, function); |
785 __ pushl(EAX); // Preserve result. | 783 __ pushl(EAX); // Preserve result. |
786 const Function& function = | |
787 Function::ZoneHandle(parsed_function_.function().raw()); | |
788 __ LoadObject(EBX, function); | |
789 __ pushl(EBX); | 784 __ pushl(EBX); |
790 GenerateCallRuntime(AstNode::kNoId, | 785 GenerateCallRuntime(AstNode::kNoId, |
791 0, | 786 0, |
792 kTraceFunctionExitRuntimeEntry); | 787 kTraceFunctionExitRuntimeEntry); |
793 __ popl(EAX); // Remove argument. | 788 __ popl(EAX); // Remove argument. |
794 __ popl(EAX); // Restore result. | 789 __ popl(EAX); // Restore result. |
795 } | 790 } |
796 __ LeaveFrame(); | 791 __ LeaveFrame(); |
797 __ ret(); | 792 __ ret(); |
798 // Add a NOP to make return code pattern 5 bytes long for patching | 793 // 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... |
1906 | 1901 |
1907 // Call operator. | 1902 // Call operator. |
1908 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); | 1903 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); |
1909 // Result is in EAX. | 1904 // Result is in EAX. |
1910 if (IsResultNeeded(node)) { | 1905 if (IsResultNeeded(node)) { |
1911 __ pushl(EAX); | 1906 __ pushl(EAX); |
1912 } | 1907 } |
1913 } | 1908 } |
1914 | 1909 |
1915 | 1910 |
1916 void CodeGenerator::CountBackwardLoop() { | |
1917 Label done; | |
1918 const Function& function = | |
1919 Function::ZoneHandle(parsed_function_.function().raw()); | |
1920 __ LoadObject(EAX, function); | |
1921 __ movl(EBX, FieldAddress(EAX, Function::invocation_counter_offset())); | |
1922 __ incl(EBX); | |
1923 if (!FLAG_report_invocation_count) { | |
1924 // Prevent overflow. | |
1925 __ cmpl(EBX, Immediate(FLAG_optimization_invocation_threshold)); | |
1926 __ j(GREATER, &done); | |
1927 } | |
1928 // EBX is an integer value (not an object). | |
1929 __ movl(FieldAddress(EAX, Function::invocation_counter_offset()), EBX); | |
1930 __ Bind(&done); | |
1931 } | |
1932 | |
1933 | |
1934 void CodeGenerator::VisitWhileNode(WhileNode* node) { | 1911 void CodeGenerator::VisitWhileNode(WhileNode* node) { |
1935 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1912 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
1936 SourceLabel* label = node->label(); | 1913 SourceLabel* label = node->label(); |
1937 __ Bind(label->continue_label()); | 1914 __ Bind(label->continue_label()); |
1938 node->condition()->Visit(this); | 1915 node->condition()->Visit(this); |
1939 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); | 1916 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
1940 __ popl(EAX); | 1917 __ popl(EAX); |
1941 __ LoadObject(EDX, bool_true); | 1918 __ LoadObject(EDX, bool_true); |
1942 __ cmpl(EAX, EDX); | 1919 __ cmpl(EAX, EDX); |
1943 __ j(NOT_EQUAL, label->break_label()); | 1920 __ j(NOT_EQUAL, label->break_label()); |
1944 node->body()->Visit(this); | 1921 node->body()->Visit(this); |
1945 CountBackwardLoop(); | |
1946 __ jmp(label->continue_label()); | 1922 __ jmp(label->continue_label()); |
1947 __ Bind(label->break_label()); | 1923 __ Bind(label->break_label()); |
1948 } | 1924 } |
1949 | 1925 |
1950 | 1926 |
1951 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { | 1927 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { |
1952 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1928 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
1953 SourceLabel* label = node->label(); | 1929 SourceLabel* label = node->label(); |
1954 Label loop; | 1930 Label loop; |
1955 __ Bind(&loop); | 1931 __ Bind(&loop); |
1956 node->body()->Visit(this); | 1932 node->body()->Visit(this); |
1957 CountBackwardLoop(); | |
1958 __ Bind(label->continue_label()); | 1933 __ Bind(label->continue_label()); |
1959 node->condition()->Visit(this); | 1934 node->condition()->Visit(this); |
1960 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); | 1935 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
1961 __ popl(EAX); | 1936 __ popl(EAX); |
1962 __ LoadObject(EDX, bool_true); | 1937 __ LoadObject(EDX, bool_true); |
1963 __ cmpl(EAX, EDX); | 1938 __ cmpl(EAX, EDX); |
1964 __ j(EQUAL, &loop); | 1939 __ j(EQUAL, &loop); |
1965 __ Bind(label->break_label()); | 1940 __ Bind(label->break_label()); |
1966 } | 1941 } |
1967 | 1942 |
1968 | 1943 |
1969 void CodeGenerator::VisitForNode(ForNode* node) { | 1944 void CodeGenerator::VisitForNode(ForNode* node) { |
1970 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1945 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
1971 node->initializer()->Visit(this); | 1946 node->initializer()->Visit(this); |
1972 SourceLabel* label = node->label(); | 1947 SourceLabel* label = node->label(); |
1973 Label loop; | 1948 Label loop; |
1974 __ Bind(&loop); | 1949 __ Bind(&loop); |
1975 if (node->condition() != NULL) { | 1950 if (node->condition() != NULL) { |
1976 node->condition()->Visit(this); | 1951 node->condition()->Visit(this); |
1977 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); | 1952 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); |
1978 __ popl(EAX); | 1953 __ popl(EAX); |
1979 __ LoadObject(EDX, bool_true); | 1954 __ LoadObject(EDX, bool_true); |
1980 __ cmpl(EAX, EDX); | 1955 __ cmpl(EAX, EDX); |
1981 __ j(NOT_EQUAL, label->break_label()); | 1956 __ j(NOT_EQUAL, label->break_label()); |
1982 } | 1957 } |
1983 node->body()->Visit(this); | 1958 node->body()->Visit(this); |
1984 CountBackwardLoop(); | |
1985 __ Bind(label->continue_label()); | 1959 __ Bind(label->continue_label()); |
1986 node->increment()->Visit(this); | 1960 node->increment()->Visit(this); |
1987 __ jmp(&loop); | 1961 __ jmp(&loop); |
1988 __ Bind(label->break_label()); | 1962 __ Bind(label->break_label()); |
1989 } | 1963 } |
1990 | 1964 |
1991 | 1965 |
1992 void CodeGenerator::VisitJumpNode(JumpNode* node) { | 1966 void CodeGenerator::VisitJumpNode(JumpNode* node) { |
1993 SourceLabel* label = node->label(); | 1967 SourceLabel* label = node->label(); |
1994 | 1968 |
(...skipping 819 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2814 const Error& error = Error::Handle( | 2788 const Error& error = Error::Handle( |
2815 Parser::FormatError(script, token_index, "Error", format, args)); | 2789 Parser::FormatError(script, token_index, "Error", format, args)); |
2816 va_end(args); | 2790 va_end(args); |
2817 Isolate::Current()->long_jump_base()->Jump(1, error); | 2791 Isolate::Current()->long_jump_base()->Jump(1, error); |
2818 UNREACHABLE(); | 2792 UNREACHABLE(); |
2819 } | 2793 } |
2820 | 2794 |
2821 } // namespace dart | 2795 } // namespace dart |
2822 | 2796 |
2823 #endif // defined TARGET_ARCH_IA32 | 2797 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |