| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "codegen-inl.h" | 33 #include "codegen-inl.h" |
| 34 #include "compilation-cache.h" | 34 #include "compilation-cache.h" |
| 35 #include "data-flow.h" | 35 #include "data-flow.h" |
| 36 #include "debug.h" | 36 #include "debug.h" |
| 37 #include "full-codegen.h" | 37 #include "full-codegen.h" |
| 38 #include "gdb-jit.h" | 38 #include "gdb-jit.h" |
| 39 #include "hydrogen.h" | 39 #include "hydrogen.h" |
| 40 #include "lithium.h" | 40 #include "lithium.h" |
| 41 #include "liveedit.h" | 41 #include "liveedit.h" |
| 42 #include "oprofile-agent.h" | |
| 43 #include "parser.h" | 42 #include "parser.h" |
| 44 #include "rewriter.h" | 43 #include "rewriter.h" |
| 45 #include "runtime-profiler.h" | 44 #include "runtime-profiler.h" |
| 46 #include "scopeinfo.h" | 45 #include "scopeinfo.h" |
| 47 #include "scopes.h" | 46 #include "scopes.h" |
| 48 #include "vm-state-inl.h" | 47 #include "vm-state-inl.h" |
| 49 | 48 |
| 50 namespace v8 { | 49 namespace v8 { |
| 51 namespace internal { | 50 namespace internal { |
| 52 | 51 |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 // True indicates the compilation pipeline is still going, not | 218 // True indicates the compilation pipeline is still going, not |
| 220 // necessarily that we optimized the code. | 219 // necessarily that we optimized the code. |
| 221 return true; | 220 return true; |
| 222 } | 221 } |
| 223 | 222 |
| 224 // Due to an encoding limit on LUnallocated operands in the Lithium | 223 // Due to an encoding limit on LUnallocated operands in the Lithium |
| 225 // language, we cannot optimize functions with too many formal parameters | 224 // language, we cannot optimize functions with too many formal parameters |
| 226 // or perform on-stack replacement for function with too many | 225 // or perform on-stack replacement for function with too many |
| 227 // stack-allocated local variables. | 226 // stack-allocated local variables. |
| 228 // | 227 // |
| 229 // The encoding is as a signed value, with parameters using the negative | 228 // The encoding is as a signed value, with parameters and receiver using |
| 230 // indices and locals the non-negative ones. | 229 // the negative indices and locals the non-negative ones. |
| 231 const int limit = LUnallocated::kMaxFixedIndices / 2; | 230 const int limit = LUnallocated::kMaxFixedIndices / 2; |
| 232 Scope* scope = info->scope(); | 231 Scope* scope = info->scope(); |
| 233 if (scope->num_parameters() > limit || scope->num_stack_slots() > limit) { | 232 if ((scope->num_parameters() + 1) > limit || |
| 233 scope->num_stack_slots() > limit) { |
| 234 AbortAndDisable(info); | 234 AbortAndDisable(info); |
| 235 // True indicates the compilation pipeline is still going, not | 235 // True indicates the compilation pipeline is still going, not |
| 236 // necessarily that we optimized the code. | 236 // necessarily that we optimized the code. |
| 237 return true; | 237 return true; |
| 238 } | 238 } |
| 239 | 239 |
| 240 // Take --hydrogen-filter into account. | 240 // Take --hydrogen-filter into account. |
| 241 Vector<const char> filter = CStrVector(FLAG_hydrogen_filter); | 241 Vector<const char> filter = CStrVector(FLAG_hydrogen_filter); |
| 242 Handle<String> name = info->function()->debug_name(); | 242 Handle<String> name = info->function()->debug_name(); |
| 243 bool match = filter.is_empty() || name->IsEqualTo(filter); | 243 bool match = filter.is_empty() || name->IsEqualTo(filter); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 259 // optimized code. | 259 // optimized code. |
| 260 unoptimized.SetFunction(info->function()); | 260 unoptimized.SetFunction(info->function()); |
| 261 unoptimized.SetScope(info->scope()); | 261 unoptimized.SetScope(info->scope()); |
| 262 if (should_recompile) unoptimized.EnableDeoptimizationSupport(); | 262 if (should_recompile) unoptimized.EnableDeoptimizationSupport(); |
| 263 bool succeeded = FullCodeGenerator::MakeCode(&unoptimized); | 263 bool succeeded = FullCodeGenerator::MakeCode(&unoptimized); |
| 264 if (should_recompile) { | 264 if (should_recompile) { |
| 265 if (!succeeded) return false; | 265 if (!succeeded) return false; |
| 266 Handle<SharedFunctionInfo> shared = info->shared_info(); | 266 Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 267 shared->EnableDeoptimizationSupport(*unoptimized.code()); | 267 shared->EnableDeoptimizationSupport(*unoptimized.code()); |
| 268 // The existing unoptimized code was replaced with the new one. | 268 // The existing unoptimized code was replaced with the new one. |
| 269 Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, | 269 Compiler::RecordFunctionCompilation( |
| 270 Handle<String>(shared->DebugName()), | 270 Logger::LAZY_COMPILE_TAG, &unoptimized, shared); |
| 271 shared->start_position(), | |
| 272 &unoptimized); | |
| 273 } | 271 } |
| 274 } | 272 } |
| 275 | 273 |
| 276 // Check that the unoptimized, shared code is ready for | 274 // Check that the unoptimized, shared code is ready for |
| 277 // optimizations. When using the always_opt flag we disregard the | 275 // optimizations. When using the always_opt flag we disregard the |
| 278 // optimizable marker in the code object and optimize anyway. This | 276 // optimizable marker in the code object and optimize anyway. This |
| 279 // is safe as long as the unoptimized code has deoptimization | 277 // is safe as long as the unoptimized code has deoptimization |
| 280 // support. | 278 // support. |
| 281 ASSERT(FLAG_always_opt || info->shared_info()->code()->optimizable()); | 279 ASSERT(FLAG_always_opt || code->optimizable()); |
| 282 ASSERT(info->shared_info()->has_deoptimization_support()); | 280 ASSERT(info->shared_info()->has_deoptimization_support()); |
| 283 | 281 |
| 284 if (FLAG_trace_hydrogen) { | 282 if (FLAG_trace_hydrogen) { |
| 285 PrintF("-----------------------------------------------------------\n"); | 283 PrintF("-----------------------------------------------------------\n"); |
| 286 PrintF("Compiling method %s using hydrogen\n", *name->ToCString()); | 284 PrintF("Compiling method %s using hydrogen\n", *name->ToCString()); |
| 287 HTracer::Instance()->TraceCompilation(info->function()); | 285 HTracer::Instance()->TraceCompilation(info->function()); |
| 288 } | 286 } |
| 289 | 287 |
| 290 TypeFeedbackOracle oracle( | 288 TypeFeedbackOracle oracle( |
| 291 Handle<Code>(info->shared_info()->code()), | 289 code, Handle<Context>(info->closure()->context()->global_context())); |
| 292 Handle<Context>(info->closure()->context()->global_context())); | |
| 293 HGraphBuilder builder(&oracle); | 290 HGraphBuilder builder(&oracle); |
| 294 HPhase phase(HPhase::kTotal); | 291 HPhase phase(HPhase::kTotal); |
| 295 HGraph* graph = builder.CreateGraph(info); | 292 HGraph* graph = builder.CreateGraph(info); |
| 293 if (info->isolate()->has_pending_exception()) { |
| 294 info->SetCode(Handle<Code>::null()); |
| 295 return false; |
| 296 } |
| 297 |
| 296 if (graph != NULL && FLAG_build_lithium) { | 298 if (graph != NULL && FLAG_build_lithium) { |
| 297 Handle<Code> code = graph->Compile(); | 299 Handle<Code> optimized_code = graph->Compile(); |
| 298 if (!code.is_null()) { | 300 if (!optimized_code.is_null()) { |
| 299 info->SetCode(code); | 301 info->SetCode(optimized_code); |
| 300 FinishOptimization(info->closure(), start); | 302 FinishOptimization(info->closure(), start); |
| 301 return true; | 303 return true; |
| 302 } | 304 } |
| 303 } | 305 } |
| 304 | 306 |
| 305 // Compilation with the Hydrogen compiler failed. Keep using the | 307 // Compilation with the Hydrogen compiler failed. Keep using the |
| 306 // shared code but mark it as unoptimizable. | 308 // shared code but mark it as unoptimizable. |
| 307 AbortAndDisable(info); | 309 AbortAndDisable(info); |
| 308 // True indicates the compilation pipeline is still going, not necessarily | 310 // True indicates the compilation pipeline is still going, not necessarily |
| 309 // that we optimized the code. | 311 // that we optimized the code. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 HistogramTimerScope timer(rate); | 412 HistogramTimerScope timer(rate); |
| 411 | 413 |
| 412 // Compile the code. | 414 // Compile the code. |
| 413 FunctionLiteral* lit = info->function(); | 415 FunctionLiteral* lit = info->function(); |
| 414 LiveEditFunctionTracker live_edit_tracker(isolate, lit); | 416 LiveEditFunctionTracker live_edit_tracker(isolate, lit); |
| 415 if (!MakeCode(info)) { | 417 if (!MakeCode(info)) { |
| 416 isolate->StackOverflow(); | 418 isolate->StackOverflow(); |
| 417 return Handle<SharedFunctionInfo>::null(); | 419 return Handle<SharedFunctionInfo>::null(); |
| 418 } | 420 } |
| 419 | 421 |
| 422 // Allocate function. |
| 420 ASSERT(!info->code().is_null()); | 423 ASSERT(!info->code().is_null()); |
| 424 Handle<SharedFunctionInfo> result = |
| 425 isolate->factory()->NewSharedFunctionInfo( |
| 426 lit->name(), |
| 427 lit->materialized_literal_count(), |
| 428 info->code(), |
| 429 SerializedScopeInfo::Create(info->scope())); |
| 430 |
| 431 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); |
| 432 Compiler::SetFunctionInfo(result, lit, true, script); |
| 433 |
| 421 if (script->name()->IsString()) { | 434 if (script->name()->IsString()) { |
| 422 PROFILE(CodeCreateEvent( | 435 PROFILE(CodeCreateEvent( |
| 423 info->is_eval() | 436 info->is_eval() |
| 424 ? Logger::EVAL_TAG | 437 ? Logger::EVAL_TAG |
| 425 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), | 438 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), |
| 426 *info->code(), | 439 *info->code(), |
| 440 *result, |
| 427 String::cast(script->name()))); | 441 String::cast(script->name()))); |
| 428 OPROFILE(CreateNativeCodeRegion(String::cast(script->name()), | |
| 429 info->code()->instruction_start(), | |
| 430 info->code()->instruction_size())); | |
| 431 GDBJIT(AddCode(Handle<String>(String::cast(script->name())), | 442 GDBJIT(AddCode(Handle<String>(String::cast(script->name())), |
| 432 script, | 443 script, |
| 433 info->code())); | 444 info->code())); |
| 434 } else { | 445 } else { |
| 435 PROFILE(CodeCreateEvent( | 446 PROFILE(CodeCreateEvent( |
| 436 info->is_eval() | 447 info->is_eval() |
| 437 ? Logger::EVAL_TAG | 448 ? Logger::EVAL_TAG |
| 438 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), | 449 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), |
| 439 *info->code(), | 450 *info->code(), |
| 440 "")); | 451 *result, |
| 441 OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script", | 452 isolate->heap()->empty_string())); |
| 442 info->code()->instruction_start(), | |
| 443 info->code()->instruction_size())); | |
| 444 GDBJIT(AddCode(Handle<String>(), script, info->code())); | 453 GDBJIT(AddCode(Handle<String>(), script, info->code())); |
| 445 } | 454 } |
| 446 | 455 |
| 447 // Allocate function. | |
| 448 Handle<SharedFunctionInfo> result = | |
| 449 FACTORY->NewSharedFunctionInfo( | |
| 450 lit->name(), | |
| 451 lit->materialized_literal_count(), | |
| 452 info->code(), | |
| 453 SerializedScopeInfo::Create(info->scope())); | |
| 454 | |
| 455 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); | |
| 456 Compiler::SetFunctionInfo(result, lit, true, script); | |
| 457 | |
| 458 // Hint to the runtime system used when allocating space for initial | 456 // Hint to the runtime system used when allocating space for initial |
| 459 // property space by setting the expected number of properties for | 457 // property space by setting the expected number of properties for |
| 460 // the instances of the function. | 458 // the instances of the function. |
| 461 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count()); | 459 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count()); |
| 462 | 460 |
| 463 #ifdef ENABLE_DEBUGGER_SUPPORT | 461 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 464 // Notify debugger | 462 // Notify debugger |
| 465 isolate->debugger()->OnAfterCompile( | 463 isolate->debugger()->OnAfterCompile( |
| 466 script, Debugger::NO_AFTER_COMPILE_FLAGS); | 464 script, Debugger::NO_AFTER_COMPILE_FLAGS); |
| 467 #endif | 465 #endif |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 | 613 |
| 616 // Generate the AST for the lazily compiled function. | 614 // Generate the AST for the lazily compiled function. |
| 617 if (ParserApi::Parse(info)) { | 615 if (ParserApi::Parse(info)) { |
| 618 // Measure how long it takes to do the lazy compilation; only take the | 616 // Measure how long it takes to do the lazy compilation; only take the |
| 619 // rest of the function into account to avoid overlap with the lazy | 617 // rest of the function into account to avoid overlap with the lazy |
| 620 // parsing statistics. | 618 // parsing statistics. |
| 621 HistogramTimerScope timer(isolate->counters()->compile_lazy()); | 619 HistogramTimerScope timer(isolate->counters()->compile_lazy()); |
| 622 | 620 |
| 623 // Compile the code. | 621 // Compile the code. |
| 624 if (!MakeCode(info)) { | 622 if (!MakeCode(info)) { |
| 625 isolate->StackOverflow(); | 623 if (!isolate->has_pending_exception()) { |
| 624 isolate->StackOverflow(); |
| 625 } |
| 626 } else { | 626 } else { |
| 627 ASSERT(!info->code().is_null()); | 627 ASSERT(!info->code().is_null()); |
| 628 Handle<Code> code = info->code(); | 628 Handle<Code> code = info->code(); |
| 629 Handle<JSFunction> function = info->closure(); | 629 Handle<JSFunction> function = info->closure(); |
| 630 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, | 630 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); |
| 631 Handle<String>(shared->DebugName()), | |
| 632 shared->start_position(), | |
| 633 info); | |
| 634 | 631 |
| 635 if (info->IsOptimizing()) { | 632 if (info->IsOptimizing()) { |
| 636 function->ReplaceCode(*code); | 633 function->ReplaceCode(*code); |
| 637 } else { | 634 } else { |
| 638 // Update the shared function info with the compiled code and the | 635 // Update the shared function info with the compiled code and the |
| 639 // scope info. Please note, that the order of the shared function | 636 // scope info. Please note, that the order of the shared function |
| 640 // info initialization is important since set_scope_info might | 637 // info initialization is important since set_scope_info might |
| 641 // trigger a GC, causing the ASSERT below to be invalid if the code | 638 // trigger a GC, causing the ASSERT below to be invalid if the code |
| 642 // was flushed. By settting the code object last we avoid this. | 639 // was flushed. By settting the code object last we avoid this. |
| 643 Handle<SerializedScopeInfo> scope_info = | 640 Handle<SerializedScopeInfo> scope_info = |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 // We fall back to the classic V8 code generator. | 731 // We fall back to the classic V8 code generator. |
| 735 if (!AssignedVariablesAnalyzer::Analyze(&info) || | 732 if (!AssignedVariablesAnalyzer::Analyze(&info) || |
| 736 !CodeGenerator::MakeCode(&info)) { | 733 !CodeGenerator::MakeCode(&info)) { |
| 737 return Handle<SharedFunctionInfo>::null(); | 734 return Handle<SharedFunctionInfo>::null(); |
| 738 } | 735 } |
| 739 } | 736 } |
| 740 } | 737 } |
| 741 ASSERT(!info.code().is_null()); | 738 ASSERT(!info.code().is_null()); |
| 742 | 739 |
| 743 // Function compilation complete. | 740 // Function compilation complete. |
| 744 RecordFunctionCompilation(Logger::FUNCTION_TAG, | |
| 745 literal->debug_name(), | |
| 746 literal->start_position(), | |
| 747 &info); | |
| 748 scope_info = SerializedScopeInfo::Create(info.scope()); | 741 scope_info = SerializedScopeInfo::Create(info.scope()); |
| 749 } | 742 } |
| 750 | 743 |
| 751 // Create a shared function info object. | 744 // Create a shared function info object. |
| 752 Handle<SharedFunctionInfo> result = | 745 Handle<SharedFunctionInfo> result = |
| 753 FACTORY->NewSharedFunctionInfo(literal->name(), | 746 FACTORY->NewSharedFunctionInfo(literal->name(), |
| 754 literal->materialized_literal_count(), | 747 literal->materialized_literal_count(), |
| 755 info.code(), | 748 info.code(), |
| 756 scope_info); | 749 scope_info); |
| 757 SetFunctionInfo(result, literal, false, script); | 750 SetFunctionInfo(result, literal, false, script); |
| 751 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); |
| 758 result->set_allows_lazy_compilation(allow_lazy); | 752 result->set_allows_lazy_compilation(allow_lazy); |
| 759 | 753 |
| 760 // Set the expected number of properties for instances and return | 754 // Set the expected number of properties for instances and return |
| 761 // the resulting function. | 755 // the resulting function. |
| 762 SetExpectedNofPropertiesFromEstimate(result, | 756 SetExpectedNofPropertiesFromEstimate(result, |
| 763 literal->expected_property_count()); | 757 literal->expected_property_count()); |
| 764 live_edit_tracker.RecordFunctionInfo(result, literal); | 758 live_edit_tracker.RecordFunctionInfo(result, literal); |
| 765 return result; | 759 return result; |
| 766 } | 760 } |
| 767 | 761 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 786 function_info->SetThisPropertyAssignmentsInfo( | 780 function_info->SetThisPropertyAssignmentsInfo( |
| 787 lit->has_only_simple_this_property_assignments(), | 781 lit->has_only_simple_this_property_assignments(), |
| 788 *lit->this_property_assignments()); | 782 *lit->this_property_assignments()); |
| 789 function_info->set_try_full_codegen(lit->try_full_codegen()); | 783 function_info->set_try_full_codegen(lit->try_full_codegen()); |
| 790 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); | 784 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); |
| 791 function_info->set_strict_mode(lit->strict_mode()); | 785 function_info->set_strict_mode(lit->strict_mode()); |
| 792 } | 786 } |
| 793 | 787 |
| 794 | 788 |
| 795 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, | 789 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, |
| 796 Handle<String> name, | 790 CompilationInfo* info, |
| 797 int start_position, | 791 Handle<SharedFunctionInfo> shared) { |
| 798 CompilationInfo* info) { | 792 // SharedFunctionInfo is passed separately, because if CompilationInfo |
| 793 // was created using Script object, it will not have it. |
| 794 |
| 799 // Log the code generation. If source information is available include | 795 // Log the code generation. If source information is available include |
| 800 // script name and line number. Check explicitly whether logging is | 796 // script name and line number. Check explicitly whether logging is |
| 801 // enabled as finding the line number is not free. | 797 // enabled as finding the line number is not free. |
| 802 if (info->isolate()->logger()->is_logging() || | 798 if (info->isolate()->logger()->is_logging() || CpuProfiler::is_profiling()) { |
| 803 OProfileAgent::is_enabled() || | |
| 804 CpuProfiler::is_profiling()) { | |
| 805 Handle<Script> script = info->script(); | 799 Handle<Script> script = info->script(); |
| 806 Handle<Code> code = info->code(); | 800 Handle<Code> code = info->code(); |
| 801 if (*code == info->isolate()->builtins()->builtin(Builtins::LazyCompile)) |
| 802 return; |
| 807 if (script->name()->IsString()) { | 803 if (script->name()->IsString()) { |
| 808 int line_num = GetScriptLineNumber(script, start_position) + 1; | 804 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1; |
| 809 USE(line_num); | 805 USE(line_num); |
| 810 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), | 806 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), |
| 811 *code, | 807 *code, |
| 812 *name, | 808 *shared, |
| 813 String::cast(script->name()), | 809 String::cast(script->name()), |
| 814 line_num)); | 810 line_num)); |
| 815 OPROFILE(CreateNativeCodeRegion(*name, | |
| 816 String::cast(script->name()), | |
| 817 line_num, | |
| 818 code->instruction_start(), | |
| 819 code->instruction_size())); | |
| 820 } else { | 811 } else { |
| 821 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), | 812 PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), |
| 822 *code, | 813 *code, |
| 823 *name)); | 814 *shared, |
| 824 OPROFILE(CreateNativeCodeRegion(*name, | 815 shared->DebugName())); |
| 825 code->instruction_start(), | |
| 826 code->instruction_size())); | |
| 827 } | 816 } |
| 828 } | 817 } |
| 829 | 818 |
| 830 GDBJIT(AddCode(name, | 819 GDBJIT(AddCode(name, |
| 831 Handle<Script>(info->script()), | 820 Handle<Script>(info->script()), |
| 832 Handle<Code>(info->code()))); | 821 Handle<Code>(info->code()))); |
| 833 } | 822 } |
| 834 | 823 |
| 835 } } // namespace v8::internal | 824 } } // namespace v8::internal |
| OLD | NEW |