| 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 |