Update V8 to r6101 as required by WebKit r74534
Change-Id: I7f84af8dd732f11898fd644b2c2b1538914cb78d
diff --git a/src/compiler.cc b/src/compiler.cc
index 29bbbc7..e4864e4 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -35,12 +35,16 @@
#include "data-flow.h"
#include "debug.h"
#include "full-codegen.h"
+#include "hydrogen.h"
+#include "lithium-allocator.h"
#include "liveedit.h"
#include "oprofile-agent.h"
#include "parser.h"
#include "rewriter.h"
+#include "runtime-profiler.h"
#include "scopeinfo.h"
#include "scopes.h"
+#include "vm-state-inl.h"
namespace v8 {
namespace internal {
@@ -52,7 +56,10 @@
scope_(NULL),
script_(script),
extension_(NULL),
- pre_parse_data_(NULL) {
+ pre_parse_data_(NULL),
+ supports_deoptimization_(false),
+ osr_ast_id_(AstNode::kNoNumber) {
+ Initialize(NONOPT);
}
@@ -63,7 +70,10 @@
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL),
- pre_parse_data_(NULL) {
+ pre_parse_data_(NULL),
+ supports_deoptimization_(false),
+ osr_ast_id_(AstNode::kNoNumber) {
+ Initialize(BASE);
}
@@ -75,31 +85,213 @@
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
extension_(NULL),
- pre_parse_data_(NULL) {
+ pre_parse_data_(NULL),
+ supports_deoptimization_(false),
+ osr_ast_id_(AstNode::kNoNumber) {
+ Initialize(BASE);
}
-// For normal operation the syntax checker is used to determine whether to
-// use the full compiler for top level code or not. However if the flag
-// --always-full-compiler is specified or debugging is active the full
-// compiler will be used for all code.
+// Determine whether to use the full compiler for all code. If the flag
+// --always-full-compiler is specified this is the case. For the virtual frame
+// based compiler the full compiler is also used if a debugger is connected, as
+// the code from the full compiler supports mode precise break points. For the
+// crankshaft adaptive compiler debugging the optimized code is not possible at
+// all. However crankshaft support recompilation of functions, so in this case
+// the full compiler need not be be used if a debugger is attached, but only if
+// break points has actually been set.
static bool AlwaysFullCompiler() {
#ifdef ENABLE_DEBUGGER_SUPPORT
- return FLAG_always_full_compiler || Debugger::IsDebuggerActive();
+ if (V8::UseCrankshaft()) {
+ return FLAG_always_full_compiler || Debug::has_break_points();
+ } else {
+ return FLAG_always_full_compiler || Debugger::IsDebuggerActive();
+ }
#else
return FLAG_always_full_compiler;
#endif
}
+static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
+ int opt_count = function->shared()->opt_count();
+ function->shared()->set_opt_count(opt_count + 1);
+ double ms = static_cast<double>(OS::Ticks() - start) / 1000;
+ if (FLAG_trace_opt) {
+ PrintF("[optimizing: ");
+ function->PrintName();
+ PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
+ PrintF(" - took %0.3f ms]\n", ms);
+ }
+ if (FLAG_trace_opt_stats) {
+ static double compilation_time = 0.0;
+ static int compiled_functions = 0;
+ static int code_size = 0;
+
+ compilation_time += ms;
+ compiled_functions++;
+ code_size += function->shared()->SourceSize();
+ PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
+ compiled_functions,
+ code_size,
+ compilation_time);
+ }
+}
+
+
+static void AbortAndDisable(CompilationInfo* info) {
+ // Disable optimization for the shared function info and mark the
+ // code as non-optimizable. The marker on the shared function info
+ // is there because we flush non-optimized code thereby loosing the
+ // non-optimizable information for the code. When the code is
+ // regenerated and set on the shared function info it is marked as
+ // non-optimizable if optimization is disabled for the shared
+ // function info.
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ shared->set_optimization_disabled(true);
+ Handle<Code> code = Handle<Code>(shared->code());
+ ASSERT(code->kind() == Code::FUNCTION);
+ code->set_optimizable(false);
+ info->SetCode(code);
+ if (FLAG_trace_opt) {
+ PrintF("[disabled optimization for: ");
+ info->closure()->PrintName();
+ PrintF(" / %" V8PRIxPTR "]\n",
+ reinterpret_cast<intptr_t>(*info->closure()));
+ }
+}
+
+
+static bool MakeCrankshaftCode(CompilationInfo* info) {
+ // Test if we can optimize this function when asked to. We can only
+ // do this after the scopes are computed.
+ if (!info->AllowOptimize()) info->DisableOptimization();
+
+ // In case we are not optimizing simply return the code from
+ // the full code generator.
+ if (!info->IsOptimizing()) {
+ return FullCodeGenerator::MakeCode(info);
+ }
+
+ // We should never arrive here if there is not code object on the
+ // shared function object.
+ Handle<Code> code(info->shared_info()->code());
+ ASSERT(code->kind() == Code::FUNCTION);
+
+ // Fall back to using the full code generator if it's not possible
+ // to use the Hydrogen-based optimizing compiler. We already have
+ // generated code for this from the shared function object.
+ if (AlwaysFullCompiler() || !FLAG_use_hydrogen) {
+ info->SetCode(code);
+ return true;
+ }
+
+ // Limit the number of times we re-compile a functions with
+ // the optimizing compiler.
+ const int kMaxOptCount = FLAG_deopt_every_n_times == 0 ? 10 : 1000;
+ if (info->shared_info()->opt_count() > kMaxOptCount) {
+ AbortAndDisable(info);
+ // True indicates the compilation pipeline is still going, not
+ // necessarily that we optimized the code.
+ return true;
+ }
+
+ // Due to an encoding limit on LUnallocated operands in the Lithium
+ // language, we cannot optimize functions with too many formal parameters
+ // or perform on-stack replacement for function with too many
+ // stack-allocated local variables.
+ //
+ // The encoding is as a signed value, with parameters using the negative
+ // indices and locals the non-negative ones.
+ const int limit = LUnallocated::kMaxFixedIndices / 2;
+ Scope* scope = info->scope();
+ if (scope->num_parameters() > limit || scope->num_stack_slots() > limit) {
+ AbortAndDisable(info);
+ // True indicates the compilation pipeline is still going, not
+ // necessarily that we optimized the code.
+ return true;
+ }
+
+ // Take --hydrogen-filter into account.
+ Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
+ Handle<String> name = info->function()->debug_name();
+ bool match = filter.is_empty() || name->IsEqualTo(filter);
+ if (!match) {
+ info->SetCode(code);
+ return true;
+ }
+
+ // Recompile the unoptimized version of the code if the current version
+ // doesn't have deoptimization support. Alternatively, we may decide to
+ // run the full code generator to get a baseline for the compile-time
+ // performance of the hydrogen-based compiler.
+ int64_t start = OS::Ticks();
+ bool should_recompile = !info->shared_info()->has_deoptimization_support();
+ if (should_recompile || FLAG_time_hydrogen) {
+ HPhase phase(HPhase::kFullCodeGen);
+ CompilationInfo unoptimized(info->shared_info());
+ // Note that we use the same AST that we will use for generating the
+ // optimized code.
+ unoptimized.SetFunction(info->function());
+ unoptimized.SetScope(info->scope());
+ if (should_recompile) unoptimized.EnableDeoptimizationSupport();
+ bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
+ if (should_recompile) {
+ if (!succeeded) return false;
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ shared->EnableDeoptimizationSupport(*unoptimized.code());
+ // The existing unoptimized code was replaced with the new one.
+ Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
+ Handle<String>(shared->DebugName()),
+ shared->start_position(),
+ &unoptimized);
+ }
+ }
+
+ // Check that the unoptimized, shared code is ready for
+ // optimizations. When using the always_opt flag we disregard the
+ // optimizable marker in the code object and optimize anyway. This
+ // is safe as long as the unoptimized code has deoptimization
+ // support.
+ ASSERT(FLAG_always_opt || info->shared_info()->code()->optimizable());
+ ASSERT(info->shared_info()->has_deoptimization_support());
+
+ if (FLAG_trace_hydrogen) {
+ PrintF("-----------------------------------------------------------\n");
+ PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
+ HTracer::Instance()->TraceCompilation(info->function());
+ }
+
+ TypeFeedbackOracle oracle(Handle<Code>(info->shared_info()->code()));
+ HGraphBuilder builder(&oracle);
+ HPhase phase(HPhase::kTotal);
+ HGraph* graph = builder.CreateGraph(info);
+ if (graph != NULL && FLAG_build_lithium) {
+ Handle<Code> code = graph->Compile();
+ if (!code.is_null()) {
+ info->SetCode(code);
+ FinishOptimization(info->closure(), start);
+ return true;
+ }
+ }
+
+ // Compilation with the Hydrogen compiler failed. Keep using the
+ // shared code but mark it as unoptimizable.
+ AbortAndDisable(info);
+ // True indicates the compilation pipeline is still going, not necessarily
+ // that we optimized the code.
+ return true;
+}
+
+
static bool MakeCode(CompilationInfo* info) {
// Precondition: code has been parsed. Postcondition: the code field in
// the compilation info is set if compilation succeeded.
ASSERT(info->function() != NULL);
- if (Rewriter::Rewrite(info) &&
- Scope::Analyze(info) &&
- Rewriter::Analyze(info)) {
+ if (Rewriter::Rewrite(info) && Scope::Analyze(info)) {
+ if (V8::UseCrankshaft()) return MakeCrankshaftCode(info);
+
// Generate code and return it. Code generator selection is governed by
// which backends are enabled and whether the function is considered
// run-once code or not.
@@ -109,17 +301,19 @@
//
// The normal choice of backend can be overridden with the flags
// --always-full-compiler.
- Handle<SharedFunctionInfo> shared = info->shared_info();
- bool is_run_once = (shared.is_null())
- ? info->scope()->is_global_scope()
- : (shared->is_toplevel() || shared->try_full_codegen());
- bool can_use_full =
- FLAG_full_compiler && !info->function()->contains_loops();
- if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
- return FullCodeGenerator::MakeCode(info);
- } else {
- AssignedVariablesAnalyzer ava;
- return ava.Analyze(info) && CodeGenerator::MakeCode(info);
+ if (Rewriter::Analyze(info)) {
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ bool is_run_once = (shared.is_null())
+ ? info->scope()->is_global_scope()
+ : (shared->is_toplevel() || shared->try_full_codegen());
+ bool can_use_full =
+ FLAG_full_compiler && !info->function()->contains_loops();
+ if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
+ return FullCodeGenerator::MakeCode(info);
+ } else {
+ return AssignedVariablesAnalyzer::Analyze(info) &&
+ CodeGenerator::MakeCode(info);
+ }
}
}
@@ -280,7 +474,14 @@
ScriptDataImpl* pre_data = input_pre_data;
if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) {
- pre_data = ParserApi::PartialPreParse(source, NULL, extension);
+ if (source->IsExternalTwoByteString()) {
+ ExternalTwoByteStringUC16CharacterStream stream(
+ Handle<ExternalTwoByteString>::cast(source), 0, source->length());
+ pre_data = ParserApi::PartialPreParse(&stream, extension);
+ } else {
+ GenericStringUC16CharacterStream stream(source, 0, source->length());
+ pre_data = ParserApi::PartialPreParse(&stream, extension);
+ }
}
// Create a script object describing the script to be compiled.
@@ -374,40 +575,60 @@
Top::StackOverflow();
} else {
ASSERT(!info->code().is_null());
+ Handle<Code> code = info->code();
+ Handle<JSFunction> function = info->closure();
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
Handle<String>(shared->DebugName()),
shared->start_position(),
info);
- // Update the shared function info with the compiled code and the
- // scope info. Please note, that the order of the sharedfunction
- // initialization is important since SerializedScopeInfo::Create might
- // trigger a GC, causing the ASSERT below to be invalid if the code
- // was flushed. By setting the code object last we avoid this.
- Handle<SerializedScopeInfo> scope_info =
- SerializedScopeInfo::Create(info->scope());
- shared->set_scope_info(*scope_info);
- shared->set_code(*info->code());
- if (!info->closure().is_null()) {
- info->closure()->set_code(*info->code());
+ if (info->IsOptimizing()) {
+ function->ReplaceCode(*code);
+ } else {
+ // Update the shared function info with the compiled code and the
+ // scope info. Please note, that the order of the shared function
+ // info initialization is important since set_scope_info might
+ // trigger a GC, causing the ASSERT below to be invalid if the code
+ // was flushed. By settting the code object last we avoid this.
+ Handle<SerializedScopeInfo> scope_info =
+ SerializedScopeInfo::Create(info->scope());
+ shared->set_scope_info(*scope_info);
+ shared->set_code(*code);
+ if (!function.is_null()) {
+ function->ReplaceCode(*code);
+ ASSERT(!function->IsOptimized());
+ }
+
+ // Set the expected number of properties for instances.
+ FunctionLiteral* lit = info->function();
+ int expected = lit->expected_property_count();
+ SetExpectedNofPropertiesFromEstimate(shared, expected);
+
+ // Set the optimization hints after performing lazy compilation, as
+ // these are not set when the function is set up as a lazily
+ // compiled function.
+ shared->SetThisPropertyAssignmentsInfo(
+ lit->has_only_simple_this_property_assignments(),
+ *lit->this_property_assignments());
+
+ // Check the function has compiled code.
+ ASSERT(shared->is_compiled());
+ shared->set_code_age(0);
+
+ if (V8::UseCrankshaft() && info->AllowOptimize()) {
+ // If we're asked to always optimize, we compile the optimized
+ // version of the function right away - unless the debugger is
+ // active as it makes no sense to compile optimized code then.
+ if (FLAG_always_opt && !Debug::has_break_points()) {
+ CompilationInfo optimized(function);
+ optimized.SetOptimizing(AstNode::kNoNumber);
+ return CompileLazy(&optimized);
+ } else if (CompilationCache::ShouldOptimizeEagerly(function)) {
+ RuntimeProfiler::OptimizeSoon(*function);
+ }
+ }
}
- // Set the expected number of properties for instances.
- FunctionLiteral* lit = info->function();
- SetExpectedNofPropertiesFromEstimate(shared,
- lit->expected_property_count());
-
- // Set the optimization hints after performing lazy compilation, as
- // these are not set when the function is set up as a lazily compiled
- // function.
- shared->SetThisPropertyAssignmentsInfo(
- lit->has_only_simple_this_property_assignments(),
- *lit->this_property_assignments());
-
- // Check the function has compiled code.
- ASSERT(shared->is_compiled());
- shared->set_code_age(0);
- ASSERT(!info->code().is_null());
return true;
}
}
@@ -419,12 +640,6 @@
Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
Handle<Script> script) {
-#ifdef DEBUG
- // We should not try to compile the same function literal more than
- // once.
- literal->mark_as_compiled();
-#endif
-
// Precondition: code has been parsed and scopes have been analyzed.
CompilationInfo info(script);
info.SetFunction(literal);
@@ -446,28 +661,31 @@
Handle<Code> code(Builtins::builtin(Builtins::LazyCompile));
info.SetCode(code);
} else {
- // Generate code and return it. The way that the compilation mode
- // is controlled by the command-line flags is described in
- // the static helper function MakeCode.
- //
- // The bodies of function literals have not yet been visited by
- // the AST analyzer.
- if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null();
-
- bool is_run_once = literal->try_full_codegen();
- bool use_full = FLAG_full_compiler && !literal->contains_loops();
- if (AlwaysFullCompiler() || (use_full && is_run_once)) {
- if (!FullCodeGenerator::MakeCode(&info)) {
+ if (V8::UseCrankshaft()) {
+ if (!MakeCrankshaftCode(&info)) {
return Handle<SharedFunctionInfo>::null();
}
} else {
- // We fall back to the classic V8 code generator.
- AssignedVariablesAnalyzer ava;
- if (!ava.Analyze(&info)) return Handle<SharedFunctionInfo>::null();
- if (!CodeGenerator::MakeCode(&info)) {
- return Handle<SharedFunctionInfo>::null();
+ // The bodies of function literals have not yet been visited by the
+ // AST optimizer/analyzer.
+ if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null();
+
+ bool is_run_once = literal->try_full_codegen();
+ bool can_use_full = FLAG_full_compiler && !literal->contains_loops();
+
+ if (AlwaysFullCompiler() || (is_run_once && can_use_full)) {
+ if (!FullCodeGenerator::MakeCode(&info)) {
+ return Handle<SharedFunctionInfo>::null();
+ }
+ } else {
+ // We fall back to the classic V8 code generator.
+ if (!AssignedVariablesAnalyzer::Analyze(&info) ||
+ !CodeGenerator::MakeCode(&info)) {
+ return Handle<SharedFunctionInfo>::null();
+ }
}
}
+ ASSERT(!info.code().is_null());
// Function compilation complete.
RecordFunctionCompilation(Logger::FUNCTION_TAG,
@@ -484,6 +702,7 @@
info.code(),
scope_info);
SetFunctionInfo(result, literal, false, script);
+ result->set_allows_lazy_compilation(allow_lazy);
// Set the expected number of properties for instances and return
// the resulting function.