From 1d669345658420b1c6771e2315109306a3a5aa4b Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Tue, 4 Nov 2014 11:06:17 +0000 Subject: [PATCH] Optimize function across closures. R=mvstanton@chromium.org Review URL: https://codereview.chromium.org/699633002 Cr-Commit-Position: refs/heads/master@{#25102} git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25102 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/code-stubs-hydrogen.cc | 100 ++++++++++++++++++++++++++------------------ src/compiler.cc | 1 + src/factory.cc | 23 ++++++---- src/hydrogen-instructions.h | 5 +++ src/objects-inl.h | 6 +-- src/objects.h | 3 ++ src/runtime-profiler.cc | 2 +- 7 files changed, 89 insertions(+), 51 deletions(-) diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index e3cbe7d..89a8b94 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -1533,47 +1533,67 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { AddIncrementCounter(counters->fast_new_closure_total()); - // Create a new closure from the given function info in new space - HValue* size = Add(JSFunction::kSize); - HInstruction* js_function = Add(size, HType::JSObject(), - NOT_TENURED, JS_FUNCTION_TYPE); - - int map_index = Context::FunctionMapIndex(casted_stub()->strict_mode(), - casted_stub()->kind()); - - // Compute the function map in the current native context and set that - // as the map of the allocated object. - HInstruction* native_context = BuildGetNativeContext(); - HInstruction* map_slot_value = Add( - native_context, static_cast(NULL), - HObjectAccess::ForContextSlot(map_index)); - Add(js_function, HObjectAccess::ForMap(), map_slot_value); - - // Initialize the rest of the function. - Add(js_function, HObjectAccess::ForPropertiesPointer(), - empty_fixed_array); - Add(js_function, HObjectAccess::ForElementsPointer(), - empty_fixed_array); - Add(js_function, HObjectAccess::ForLiteralsPointer(), - empty_fixed_array); - Add(js_function, HObjectAccess::ForPrototypeOrInitialMap(), - graph()->GetConstantHole()); - Add(js_function, - HObjectAccess::ForSharedFunctionInfoPointer(), - shared_info); - Add(js_function, HObjectAccess::ForFunctionContextPointer(), - context()); - - // Initialize the code pointer in the function to be the one - // found in the shared function info object. - // But first check if there is an optimized version for our context. - if (FLAG_cache_optimized_code) { - BuildInstallFromOptimizedCodeMap(js_function, shared_info, native_context); - } else { - BuildInstallCode(js_function, shared_info); + IfBuilder optimize_now(this); + HInstruction* compile_hint = Add( + shared_info, static_cast(NULL), HObjectAccess::ForCompileHint()); + HValue* hint_mask = Add( + static_cast(1 << SharedFunctionInfo::kOptimizeNextClosure)); + HInstruction* optimize = + AddUncasted(Token::BIT_AND, compile_hint, hint_mask); + optimize_now.If(optimize, hint_mask, Token::EQ); + optimize_now.Then(); + { + Add(context(), shared_info, graph()->GetConstantFalse()); + Push(Add(isolate()->factory()->empty_string(), + Runtime::FunctionForId(Runtime::kNewClosure), 3)); } - - return js_function; + optimize_now.Else(); + { + // Create a new closure from the given function info in new space + HValue* size = Add(JSFunction::kSize); + HInstruction* js_function = + Add(size, HType::JSObject(), NOT_TENURED, JS_FUNCTION_TYPE); + + int map_index = Context::FunctionMapIndex(casted_stub()->strict_mode(), + casted_stub()->kind()); + + // Compute the function map in the current native context and set that + // as the map of the allocated object. + HInstruction* native_context = BuildGetNativeContext(); + HInstruction* map_slot_value = + Add(native_context, static_cast(NULL), + HObjectAccess::ForContextSlot(map_index)); + Add(js_function, HObjectAccess::ForMap(), map_slot_value); + + // Initialize the rest of the function. + Add(js_function, HObjectAccess::ForPropertiesPointer(), + empty_fixed_array); + Add(js_function, HObjectAccess::ForElementsPointer(), + empty_fixed_array); + Add(js_function, HObjectAccess::ForLiteralsPointer(), + empty_fixed_array); + Add(js_function, + HObjectAccess::ForPrototypeOrInitialMap(), + graph()->GetConstantHole()); + Add(js_function, + HObjectAccess::ForSharedFunctionInfoPointer(), + shared_info); + Add( + js_function, HObjectAccess::ForFunctionContextPointer(), context()); + + // Initialize the code pointer in the function to be the one + // found in the shared function info object. + // But first check if there is an optimized version for our context. + if (FLAG_cache_optimized_code) { + BuildInstallFromOptimizedCodeMap(js_function, shared_info, + native_context); + } else { + BuildInstallCode(js_function, shared_info); + } + Push(js_function); + } + optimize_now.End(); + return Pop(); } diff --git a/src/compiler.cc b/src/compiler.cc index ba5f3fd..2349640 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -1361,6 +1361,7 @@ MaybeHandle Compiler::GetOptimizedCode(Handle function, PostponeInterruptsScope postpone(isolate); Handle shared = info->shared_info(); + shared->set_optimize_next_closure(false); if (shared->code()->kind() != Code::FUNCTION || ScopeInfo::Empty(isolate) == shared->scope_info()) { // The function was never compiled. Compile it unoptimized first. diff --git a/src/factory.cc b/src/factory.cc index 72974a3..658702a 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1358,6 +1358,14 @@ Handle Factory::NewFunctionPrototype(Handle function) { } +static bool ShouldOptimizeNewClosure(Isolate* isolate, + Handle info) { + return isolate->use_crankshaft() && !info->is_toplevel() && + info->allows_lazy_compilation() && !info->optimization_disabled() && + !isolate->DebuggerHasBreakPoints(); +} + + Handle Factory::NewFunctionFromSharedFunctionInfo( Handle info, Handle context, @@ -1395,14 +1403,15 @@ Handle Factory::NewFunctionFromSharedFunctionInfo( return result; } - if (isolate()->use_crankshaft() && - FLAG_always_opt && - result->is_compiled() && - !info->is_toplevel() && - info->allows_lazy_compilation() && - !info->optimization_disabled() && - !isolate()->DebuggerHasBreakPoints()) { + if (FLAG_always_opt && ShouldOptimizeNewClosure(isolate(), info)) { result->MarkForOptimization(); + } else if (info->optimize_next_closure() && + ShouldOptimizeNewClosure(isolate(), info)) { + if (isolate()->concurrent_recompilation_enabled()) { + result->MarkForConcurrentOptimization(); + } else { + result->MarkForOptimization(); + } } return result; } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 810a2fd..f590381 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -6121,6 +6121,11 @@ class HObjectAccess FINAL { SharedFunctionInfo::kOptimizedCodeMapOffset); } + static HObjectAccess ForCompileHint() { + return HObjectAccess(kInobject, SharedFunctionInfo::kCompilerHintsOffset, + Representation::Smi()); + } + static HObjectAccess ForFunctionContextPointer() { return HObjectAccess(kInobject, JSFunction::kContextOffset); } diff --git a/src/objects-inl.h b/src/objects-inl.h index 6d0f8d4..cf9f800 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5493,9 +5493,9 @@ BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_expression, BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel, kIsTopLevelBit) -BOOL_ACCESSORS(SharedFunctionInfo, - compiler_hints, - allows_lazy_compilation, +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, optimize_next_closure, + kOptimizeNextClosure) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, allows_lazy_compilation, kAllowLazyCompilation) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, diff --git a/src/objects.h b/src/objects.h index d12896f..321a885 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6783,6 +6783,8 @@ class SharedFunctionInfo: public HeapObject { inline int ic_age(); inline void set_ic_age(int age); + DECL_BOOLEAN_ACCESSORS(optimize_next_closure) + // Indicates if this function can be lazy compiled. // This is used to determine if we can safely flush code from a function // when doing GC if we expect that the function will no longer be used. @@ -7073,6 +7075,7 @@ class SharedFunctionInfo: public HeapObject { enum CompilerHints { kAllowLazyCompilation, kAllowLazyCompilationWithoutContext, + kOptimizeNextClosure, kOptimizationDisabled, kStrictModeFunction, kUsesArguments, diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc index f786846..c87ba7e 100644 --- a/src/runtime-profiler.cc +++ b/src/runtime-profiler.cc @@ -106,7 +106,7 @@ void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) { PrintF("]\n"); } - + function->shared()->set_optimize_next_closure(true); if (isolate_->concurrent_recompilation_enabled() && !isolate_->bootstrapper()->IsActive()) { if (isolate_->concurrent_osr_enabled() && -- 2.7.4