Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/compiler.cc b/src/compiler.cc
index 8bb5332..d649950 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -15,13 +15,11 @@
#include "src/compilation-cache.h"
#include "src/compiler/pipeline.h"
#include "src/crankshaft/hydrogen.h"
-#include "src/crankshaft/lithium.h"
-#include "src/crankshaft/typing.h"
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
#include "src/deoptimizer.h"
+#include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h"
-#include "src/gdb-jit.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h"
#include "src/log-inl.h"
@@ -32,6 +30,7 @@
#include "src/profiler/cpu-profiler.h"
#include "src/runtime-profiler.h"
#include "src/snapshot/code-serializer.h"
+#include "src/typing-asm.h"
#include "src/vm-state-inl.h"
namespace v8 {
@@ -52,15 +51,10 @@
PARSE_INFO_GETTER(Handle<Script>, script)
-PARSE_INFO_GETTER(bool, is_eval)
-PARSE_INFO_GETTER(bool, is_native)
-PARSE_INFO_GETTER(bool, is_module)
PARSE_INFO_GETTER(FunctionLiteral*, literal)
-PARSE_INFO_GETTER_WITH_DEFAULT(LanguageMode, language_mode, STRICT)
-PARSE_INFO_GETTER_WITH_DEFAULT(Handle<JSFunction>, closure,
- Handle<JSFunction>::null())
PARSE_INFO_GETTER_WITH_DEFAULT(Scope*, scope, nullptr)
-PARSE_INFO_GETTER(Handle<Context>, context)
+PARSE_INFO_GETTER_WITH_DEFAULT(Handle<Context>, context,
+ Handle<Context>::null())
PARSE_INFO_GETTER(Handle<SharedFunctionInfo>, shared_info)
#undef PARSE_INFO_GETTER
@@ -80,26 +74,17 @@
CompilationInfo* info_;
};
-// Exactly like a CompilationInfo, except being allocated via {new} and it also
-// creates and enters a Zone on construction and deallocates it on destruction.
-class CompilationInfoWithZone : public CompilationInfo {
- public:
- explicit CompilationInfoWithZone(Handle<JSFunction> function)
- : CompilationInfo(new ParseInfo(&zone_, function)),
- zone_(function->GetIsolate()->allocator()) {}
-
- // Virtual destructor because a CompilationInfoWithZone has to exit the
- // zone scope and get rid of dependent maps even when the destructor is
- // called when cast as a CompilationInfo.
- virtual ~CompilationInfoWithZone() {
- DisableFutureOptimization();
- dependencies()->Rollback();
- delete parse_info_;
- parse_info_ = nullptr;
+// Helper that times a scoped region and records the elapsed time.
+struct ScopedTimer {
+ explicit ScopedTimer(base::TimeDelta* location) : location_(location) {
+ DCHECK(location_ != NULL);
+ timer_.Start();
}
- private:
- Zone zone_;
+ ~ScopedTimer() { *location_ += timer_.Elapsed(); }
+
+ base::ElapsedTimer timer_;
+ base::TimeDelta* location_;
};
// ----------------------------------------------------------------------------
@@ -109,25 +94,12 @@
return parse_info_ && !parse_info_->shared_info().is_null();
}
+CompilationInfo::CompilationInfo(ParseInfo* parse_info,
+ Handle<JSFunction> closure)
+ : CompilationInfo(parse_info, {}, Code::ComputeFlags(Code::FUNCTION), BASE,
+ parse_info->isolate(), parse_info->zone()) {
+ closure_ = closure;
-bool CompilationInfo::has_context() const {
- return parse_info_ && !parse_info_->context().is_null();
-}
-
-
-bool CompilationInfo::has_literal() const {
- return parse_info_ && parse_info_->literal() != nullptr;
-}
-
-
-bool CompilationInfo::has_scope() const {
- return parse_info_ && parse_info_->scope() != nullptr;
-}
-
-
-CompilationInfo::CompilationInfo(ParseInfo* parse_info)
- : CompilationInfo(parse_info, nullptr, Code::ComputeFlags(Code::FUNCTION),
- BASE, parse_info->isolate(), parse_info->zone()) {
// Compiling for the snapshot typically results in different code than
// compiling later on. This means that code recompiled with deoptimization
// support won't be "equivalent" (as defined by SharedFunctionInfo::
@@ -140,19 +112,15 @@
if (FLAG_turbo_inlining) MarkAsInliningEnabled();
if (FLAG_turbo_source_positions) MarkAsSourcePositionsEnabled();
if (FLAG_turbo_splitting) MarkAsSplittingEnabled();
- if (FLAG_turbo_types) MarkAsTypingEnabled();
-
- if (has_shared_info()) {
- if (shared_info()->never_compiled()) MarkAsFirstCompile();
- }
}
-
-CompilationInfo::CompilationInfo(const char* debug_name, Isolate* isolate,
- Zone* zone, Code::Flags code_flags)
+CompilationInfo::CompilationInfo(Vector<const char> debug_name,
+ Isolate* isolate, Zone* zone,
+ Code::Flags code_flags)
: CompilationInfo(nullptr, debug_name, code_flags, STUB, isolate, zone) {}
-CompilationInfo::CompilationInfo(ParseInfo* parse_info, const char* debug_name,
+CompilationInfo::CompilationInfo(ParseInfo* parse_info,
+ Vector<const char> debug_name,
Code::Flags code_flags, Mode mode,
Isolate* isolate, Zone* zone)
: parse_info_(parse_info),
@@ -168,26 +136,20 @@
prologue_offset_(Code::kPrologueOffsetNotSet),
track_positions_(FLAG_hydrogen_track_positions ||
isolate->cpu_profiler()->is_profiling()),
- opt_count_(has_shared_info() ? shared_info()->opt_count() : 0),
parameter_count_(0),
optimization_id_(-1),
osr_expr_stack_height_(0),
debug_name_(debug_name) {}
-
CompilationInfo::~CompilationInfo() {
DisableFutureOptimization();
+ dependencies()->Rollback();
delete deferred_handles_;
-#ifdef DEBUG
- // Check that no dependent maps have been added or added dependent maps have
- // been rolled back or committed.
- DCHECK(dependencies()->IsEmpty());
-#endif // DEBUG
}
int CompilationInfo::num_parameters() const {
- return has_scope() ? scope()->num_parameters() : parameter_count_;
+ return !IsStub() ? scope()->num_parameters() : parameter_count_;
}
@@ -199,11 +161,6 @@
bool CompilationInfo::is_this_defined() const { return !IsStub(); }
-int CompilationInfo::num_heap_slots() const {
- return has_scope() ? scope()->num_heap_slots() : 0;
-}
-
-
// Primitive functions are unlikely to be picked up by the stack-walking
// profiler, so they trigger their own optimization when they're called
// for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time.
@@ -212,7 +169,7 @@
!(literal()->flags() & AstProperties::kDontSelfOptimize) &&
!literal()->dont_optimize() &&
literal()->scope()->AllowsLazyCompilation() &&
- (!has_shared_info() || !shared_info()->optimization_disabled());
+ !shared_info()->optimization_disabled();
}
@@ -221,59 +178,6 @@
}
-int CompilationInfo::TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
- SourcePosition position,
- int parent_id) {
- DCHECK(track_positions_);
-
- int inline_id = static_cast<int>(inlined_function_infos_.size());
- InlinedFunctionInfo info(parent_id, position, UnboundScript::kNoScriptId,
- shared->start_position());
- if (!shared->script()->IsUndefined()) {
- Handle<Script> script(Script::cast(shared->script()));
- info.script_id = script->id();
-
- if (FLAG_hydrogen_track_positions && !script->source()->IsUndefined()) {
- CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
- OFStream os(tracing_scope.file());
- os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
- << ") id{" << optimization_id() << "," << inline_id << "} ---\n";
- {
- DisallowHeapAllocation no_allocation;
- int start = shared->start_position();
- int len = shared->end_position() - start;
- String::SubStringRange source(String::cast(script->source()), start,
- len);
- for (const auto& c : source) {
- os << AsReversiblyEscapedUC16(c);
- }
- }
-
- os << "\n--- END ---\n";
- }
- }
-
- inlined_function_infos_.push_back(info);
-
- if (FLAG_hydrogen_track_positions && inline_id != 0) {
- CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
- OFStream os(tracing_scope.file());
- os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
- << optimization_id() << "," << inline_id << "} AS " << inline_id
- << " AT " << position << std::endl;
- }
-
- return inline_id;
-}
-
-
-void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) {
- if (!track_positions_ || IsStub()) return;
- DCHECK_LT(static_cast<size_t>(inlining_id), inlined_function_infos_.size());
- inlined_function_infos_.at(inlining_id).deopt_pc_offsets.push_back(pc_offset);
-}
-
-
base::SmartArrayPointer<char> CompilationInfo::GetDebugName() const {
if (parse_info() && parse_info()->literal()) {
AllowHandleDereference allow_deref;
@@ -282,10 +186,11 @@
if (parse_info() && !parse_info()->shared_info().is_null()) {
return parse_info()->shared_info()->DebugName()->ToCString();
}
- const char* str = debug_name_ ? debug_name_ : "unknown";
- size_t len = strlen(str) + 1;
- base::SmartArrayPointer<char> name(new char[len]);
- memcpy(name.get(), str, len);
+ Vector<const char> name_vec = debug_name_;
+ if (name_vec.is_empty()) name_vec = ArrayVector("unknown");
+ base::SmartArrayPointer<char> name(new char[name_vec.length() + 1]);
+ memcpy(name.get(), name_vec.start(), name_vec.length());
+ name[name_vec.length()] = '\0';
return name;
}
@@ -308,8 +213,15 @@
}
}
+int CompilationInfo::GetDeclareGlobalsFlags() const {
+ DCHECK(DeclareGlobalsLanguageMode::is_valid(parse_info()->language_mode()));
+ return DeclareGlobalsEvalFlag::encode(parse_info()->is_eval()) |
+ DeclareGlobalsNativeFlag::encode(parse_info()->is_native()) |
+ DeclareGlobalsLanguageMode::encode(parse_info()->language_mode());
+}
+
bool CompilationInfo::ExpectsJSReceiverAsReceiver() {
- return is_sloppy(language_mode()) && !is_native();
+ return is_sloppy(parse_info()->language_mode()) && !parse_info()->is_native();
}
#if DEBUG
@@ -320,250 +232,47 @@
#endif
// ----------------------------------------------------------------------------
-// Implementation of OptimizedCompileJob
+// Implementation of CompilationJob
-class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
- public:
- explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
- : HOptimizedGraphBuilder(info) {
- }
-
-#define DEF_VISIT(type) \
- void Visit##type(type* node) override { \
- SourcePosition old_position = SourcePosition::Unknown(); \
- if (node->position() != RelocInfo::kNoPosition) { \
- old_position = source_position(); \
- SetSourcePosition(node->position()); \
- } \
- HOptimizedGraphBuilder::Visit##type(node); \
- if (!old_position.IsUnknown()) { \
- set_source_position(old_position); \
- } \
- }
- EXPRESSION_NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-
-#define DEF_VISIT(type) \
- void Visit##type(type* node) override { \
- SourcePosition old_position = SourcePosition::Unknown(); \
- if (node->position() != RelocInfo::kNoPosition) { \
- old_position = source_position(); \
- SetSourcePosition(node->position()); \
- } \
- HOptimizedGraphBuilder::Visit##type(node); \
- if (!old_position.IsUnknown()) { \
- set_source_position(old_position); \
- } \
- }
- STATEMENT_NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-
-#define DEF_VISIT(type) \
- void Visit##type(type* node) override { \
- HOptimizedGraphBuilder::Visit##type(node); \
- }
- DECLARATION_NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-};
-
-
-OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
+CompilationJob::Status CompilationJob::CreateGraph() {
+ DisallowJavascriptExecution no_js(isolate());
DCHECK(info()->IsOptimizing());
- // Do not use Crankshaft/TurboFan if we need to be able to set break points.
- if (info()->shared_info()->HasDebugInfo()) {
- return AbortOptimization(kFunctionBeingDebugged);
- }
-
- // Resuming a suspended frame is not supported by Crankshaft/TurboFan.
- if (info()->shared_info()->HasBuiltinFunctionId() &&
- (info()->shared_info()->builtin_function_id() == kGeneratorObjectNext ||
- info()->shared_info()->builtin_function_id() == kGeneratorObjectReturn ||
- info()->shared_info()->builtin_function_id() == kGeneratorObjectThrow)) {
- return AbortOptimization(kGeneratorResumeMethod);
- }
-
- // Limit the number of times we try to optimize functions.
- const int kMaxOptCount =
- FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
- if (info()->opt_count() > kMaxOptCount) {
- return AbortOptimization(kOptimizedTooManyTimes);
- }
-
- // Check the whitelist for Crankshaft.
- if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) {
- return AbortOptimization(kHydrogenFilter);
- }
-
- // Optimization requires a version of fullcode with deoptimization support.
- // Recompile the unoptimized version of the code if the current version
- // doesn't have deoptimization support already.
- // Otherwise, if we are gathering compilation time and space statistics
- // for hydrogen, gather baseline statistics for a fullcode compilation.
- bool should_recompile = !info()->shared_info()->has_deoptimization_support();
- if (should_recompile || FLAG_hydrogen_stats) {
- base::ElapsedTimer timer;
- if (FLAG_hydrogen_stats) {
- timer.Start();
- }
- if (!Compiler::EnsureDeoptimizationSupport(info())) {
- return SetLastStatus(FAILED);
- }
- if (FLAG_hydrogen_stats) {
- isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
- }
- }
-
- DCHECK(info()->shared_info()->has_deoptimization_support());
- DCHECK(!info()->is_first_compile());
-
- bool optimization_disabled = info()->shared_info()->optimization_disabled();
- bool dont_crankshaft = info()->shared_info()->dont_crankshaft();
-
- // Check the enabling conditions for Turbofan.
- // 1. "use asm" code.
- bool is_turbofanable_asm = FLAG_turbo_asm &&
- info()->shared_info()->asm_function() &&
- !optimization_disabled;
-
- // 2. Fallback for features unsupported by Crankshaft.
- bool is_unsupported_by_crankshaft_but_turbofanable =
- dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 &&
- !optimization_disabled;
-
- // 3. Explicitly enabled by the command-line filter.
- bool passes_turbo_filter =
- info()->shared_info()->PassesFilter(FLAG_turbo_filter);
-
- // If this is OSR request, OSR must be enabled by Turbofan.
- bool passes_osr_test = FLAG_turbo_osr || !info()->is_osr();
-
- if ((is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable ||
- passes_turbo_filter) &&
- passes_osr_test) {
- // Use TurboFan for the compilation.
- if (FLAG_trace_opt) {
- OFStream os(stdout);
- os << "[compiling method " << Brief(*info()->closure())
- << " using TurboFan";
- if (info()->is_osr()) os << " OSR";
- os << "]" << std::endl;
- }
-
- if (info()->shared_info()->asm_function()) {
- if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
- info()->MarkAsFunctionContextSpecializing();
- } else {
- if (!FLAG_always_opt) {
- info()->MarkAsBailoutOnUninitialized();
- }
- if (FLAG_native_context_specialization) {
- info()->MarkAsNativeContextSpecializing();
- info()->MarkAsTypingEnabled();
- }
- }
- if (!info()->shared_info()->asm_function() ||
- FLAG_turbo_asm_deoptimization) {
- info()->MarkAsDeoptimizationEnabled();
- }
-
- Timer t(this, &time_taken_to_create_graph_);
- compiler::Pipeline pipeline(info());
- pipeline.GenerateCode();
- if (!info()->code().is_null()) {
- return SetLastStatus(SUCCEEDED);
- }
- }
-
- if (!isolate()->use_crankshaft() || dont_crankshaft) {
- // Crankshaft is entirely disabled.
- return SetLastStatus(FAILED);
- }
-
- Scope* scope = info()->scope();
- if (LUnallocated::TooManyParameters(scope->num_parameters())) {
- // Crankshaft would require too many Lithium operands.
- return AbortOptimization(kTooManyParameters);
- }
-
- if (info()->is_osr() &&
- LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
- scope->num_stack_slots())) {
- // Crankshaft would require too many Lithium operands.
- return AbortOptimization(kTooManyParametersLocals);
- }
-
if (FLAG_trace_opt) {
OFStream os(stdout);
- os << "[compiling method " << Brief(*info()->closure())
- << " using Crankshaft";
+ os << "[compiling method " << Brief(*info()->closure()) << " using "
+ << compiler_name_;
if (info()->is_osr()) os << " OSR";
os << "]" << std::endl;
}
- if (FLAG_trace_hydrogen) {
- isolate()->GetHTracer()->TraceCompilation(info());
- }
-
- // Type-check the function.
- AstTyper(info()->isolate(), info()->zone(), info()->closure(),
- info()->scope(), info()->osr_ast_id(), info()->literal())
- .Run();
-
- // Optimization could have been disabled by the parser. Note that this check
- // is only needed because the Hydrogen graph builder is missing some bailouts.
- if (info()->shared_info()->optimization_disabled()) {
- return AbortOptimization(
- info()->shared_info()->disable_optimization_reason());
- }
-
- HOptimizedGraphBuilder* graph_builder =
- (info()->is_tracking_positions() || FLAG_trace_ic)
- ? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info())
- : new (info()->zone()) HOptimizedGraphBuilder(info());
-
- Timer t(this, &time_taken_to_create_graph_);
- graph_ = graph_builder->CreateGraph();
-
- if (isolate()->has_pending_exception()) {
- return SetLastStatus(FAILED);
- }
-
- if (graph_ == NULL) return SetLastStatus(BAILED_OUT);
-
- if (info()->dependencies()->HasAborted()) {
- // Dependency has changed during graph creation. Let's try again later.
- return RetryOptimization(kBailedOutDueToDependencyChange);
- }
-
- return SetLastStatus(SUCCEEDED);
+ // Delegate to the underlying implementation.
+ DCHECK_EQ(SUCCEEDED, last_status());
+ ScopedTimer t(&time_taken_to_create_graph_);
+ return SetLastStatus(CreateGraphImpl());
}
-
-OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() {
+CompilationJob::Status CompilationJob::OptimizeGraph() {
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
DisallowCodeDependencyChange no_dependency_change;
- DCHECK(last_status() == SUCCEEDED);
- // TODO(turbofan): Currently everything is done in the first phase.
- if (!info()->code().is_null()) {
- return last_status();
- }
+ // Delegate to the underlying implementation.
+ DCHECK_EQ(SUCCEEDED, last_status());
+ ScopedTimer t(&time_taken_to_optimize_);
+ return SetLastStatus(OptimizeGraphImpl());
+}
- Timer t(this, &time_taken_to_optimize_);
- DCHECK(graph_ != NULL);
- BailoutReason bailout_reason = kNoReason;
+CompilationJob::Status CompilationJob::GenerateCode() {
+ DisallowCodeDependencyChange no_dependency_change;
+ DisallowJavascriptExecution no_js(isolate());
+ DCHECK(!info()->dependencies()->HasAborted());
- if (graph_->Optimize(&bailout_reason)) {
- chunk_ = LChunk::NewChunk(graph_);
- if (chunk_ != NULL) return SetLastStatus(SUCCEEDED);
- } else if (bailout_reason != kNoReason) {
- info_->AbortOptimization(bailout_reason);
- }
-
- return SetLastStatus(BAILED_OUT);
+ // Delegate to the underlying implementation.
+ DCHECK_EQ(SUCCEEDED, last_status());
+ ScopedTimer t(&time_taken_to_codegen_);
+ return SetLastStatus(GenerateCodeImpl());
}
@@ -578,8 +287,9 @@
heap->AddWeakObjectToCodeDependency(object, dep);
}
+} // namespace
-void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) {
+void CompilationJob::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) {
// TODO(turbofan): Move this to pipeline.cc once Crankshaft dies.
Isolate* const isolate = code->GetIsolate();
DCHECK(code->is_optimized_code());
@@ -619,53 +329,7 @@
code->set_can_have_weak_objects(true);
}
-} // namespace
-
-
-OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
- DCHECK(last_status() == SUCCEEDED);
- // TODO(turbofan): Currently everything is done in the first phase.
- if (!info()->code().is_null()) {
- info()->dependencies()->Commit(info()->code());
- if (info()->is_deoptimization_enabled()) {
- info()->parse_info()->context()->native_context()->AddOptimizedCode(
- *info()->code());
- RegisterWeakObjectsInOptimizedCode(info()->code());
- }
- RecordOptimizationStats();
- return last_status();
- }
-
- DCHECK(!info()->dependencies()->HasAborted());
- DisallowCodeDependencyChange no_dependency_change;
- DisallowJavascriptExecution no_js(isolate());
- { // Scope for timer.
- Timer timer(this, &time_taken_to_codegen_);
- DCHECK(chunk_ != NULL);
- DCHECK(graph_ != NULL);
- // Deferred handles reference objects that were accessible during
- // graph creation. To make sure that we don't encounter inconsistencies
- // between graph creation and code generation, we disallow accessing
- // objects through deferred handles during the latter, with exceptions.
- DisallowDeferredHandleDereference no_deferred_handle_deref;
- Handle<Code> optimized_code = chunk_->Codegen();
- if (optimized_code.is_null()) {
- if (info()->bailout_reason() == kNoReason) {
- return AbortOptimization(kCodeGenerationFailed);
- }
- return SetLastStatus(BAILED_OUT);
- }
- RegisterWeakObjectsInOptimizedCode(optimized_code);
- info()->SetCode(optimized_code);
- }
- RecordOptimizationStats();
- // Add to the weak list of optimized code objects.
- info()->context()->native_context()->AddOptimizedCode(*info()->code());
- return SetLastStatus(SUCCEEDED);
-}
-
-
-void OptimizedCompileJob::RecordOptimizationStats() {
+void CompilationJob::RecordOptimizationStats() {
Handle<JSFunction> function = info()->closure();
if (!function->IsOptimized()) {
// Concurrent recompilation and OSR may race. Increment only once.
@@ -706,47 +370,25 @@
namespace {
-// Sets the expected number of properties based on estimate from compiler.
-void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
- int estimate) {
- // If no properties are added in the constructor, they are more likely
- // to be added later.
- if (estimate == 0) estimate = 2;
-
- // TODO(yangguo): check whether those heuristics are still up-to-date.
- // We do not shrink objects that go into a snapshot (yet), so we adjust
- // the estimate conservatively.
- if (shared->GetIsolate()->serializer_enabled()) {
- estimate += 2;
- } else {
- // Inobject slack tracking will reclaim redundant inobject space later,
- // so we can afford to adjust the estimate generously.
- estimate += 8;
- }
-
- shared->set_expected_nof_properties(estimate);
-}
-
-void MaybeDisableOptimization(Handle<SharedFunctionInfo> shared_info,
- BailoutReason bailout_reason) {
- if (bailout_reason != kNoReason) {
- shared_info->DisableOptimization(bailout_reason);
- }
+bool IsEvalToplevel(Handle<SharedFunctionInfo> shared) {
+ return shared->is_toplevel() && shared->script()->IsScript() &&
+ Script::cast(shared->script())->compilation_type() ==
+ Script::COMPILATION_TYPE_EVAL;
}
void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
- CompilationInfo* info,
- Handle<SharedFunctionInfo> shared) {
- // SharedFunctionInfo is passed separately, because if CompilationInfo
- // was created using Script object, it will not have it.
-
+ CompilationInfo* info) {
// Log the code generation. If source information is available include
// script name and line number. Check explicitly whether logging is
// enabled as finding the line number is not free.
if (info->isolate()->logger()->is_logging_code_events() ||
info->isolate()->cpu_profiler()->is_profiling()) {
+ Handle<SharedFunctionInfo> shared = info->shared_info();
Handle<Script> script = info->parse_info()->script();
- Handle<AbstractCode> abstract_code = info->abstract_code();
+ Handle<AbstractCode> abstract_code =
+ info->has_bytecode_array()
+ ? Handle<AbstractCode>::cast(info->bytecode_array())
+ : Handle<AbstractCode>::cast(info->code());
if (abstract_code.is_identical_to(
info->isolate()->builtins()->CompileLazy())) {
return;
@@ -759,13 +401,13 @@
: info->isolate()->heap()->empty_string();
Logger::LogEventsAndTags log_tag = Logger::ToNativeByScript(tag, *script);
PROFILE(info->isolate(),
- CodeCreateEvent(log_tag, *abstract_code, *shared, info, script_name,
+ CodeCreateEvent(log_tag, *abstract_code, *shared, script_name,
line_num, column_num));
}
}
void EnsureFeedbackVector(CompilationInfo* info) {
- if (!info->has_shared_info()) return;
+ DCHECK(info->has_shared_info());
// If no type feedback vector exists, we create one now. At this point the
// AstNumbering pass has already run. Note the snapshot can contain outdated
@@ -786,28 +428,9 @@
info->literal()->feedback_vector_spec()));
}
-bool CompileUnoptimizedCode(CompilationInfo* info) {
- DCHECK(AllowCompilation::IsAllowed(info->isolate()));
- if (!Compiler::Analyze(info->parse_info()) ||
- !(EnsureFeedbackVector(info), FullCodeGenerator::MakeCode(info))) {
- Isolate* isolate = info->isolate();
- if (!isolate->has_pending_exception()) isolate->StackOverflow();
- return false;
- }
- return true;
-}
-
bool UseIgnition(CompilationInfo* info) {
- // TODO(4681): Generator functions are not yet supported.
- if (info->shared_info()->is_generator()) {
- return false;
- }
-
- // TODO(4681): Resuming a suspended frame is not supported.
- if (info->shared_info()->HasBuiltinFunctionId() &&
- (info->shared_info()->builtin_function_id() == kGeneratorObjectNext ||
- info->shared_info()->builtin_function_id() == kGeneratorObjectReturn ||
- info->shared_info()->builtin_function_id() == kGeneratorObjectThrow)) {
+ if (info->is_debug()) return false;
+ if (info->shared_info()->is_resumable() && !FLAG_ignition_generators) {
return false;
}
@@ -839,9 +462,20 @@
return size;
}
-bool GenerateBaselineCode(CompilationInfo* info) {
+bool GenerateUnoptimizedCode(CompilationInfo* info) {
bool success;
EnsureFeedbackVector(info);
+ if (FLAG_validate_asm && info->scope()->asm_module()) {
+ AsmTyper typer(info->isolate(), info->zone(), *(info->script()),
+ info->literal());
+ if (FLAG_enable_simd_asmjs) {
+ typer.set_allow_simd(true);
+ }
+ if (!typer.Validate()) {
+ DCHECK(!info->isolate()->has_pending_exception());
+ PrintF("Validation of asm.js module failed: %s", typer.error_message());
+ }
+ }
if (FLAG_ignition && UseIgnition(info)) {
success = interpreter::Interpreter::MakeBytecode(info);
} else {
@@ -850,15 +484,17 @@
if (success) {
Isolate* isolate = info->isolate();
Counters* counters = isolate->counters();
+ // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually.
counters->total_baseline_code_size()->Increment(CodeAndMetadataSize(info));
counters->total_baseline_compile_count()->Increment(1);
}
return success;
}
-bool CompileBaselineCode(CompilationInfo* info) {
+bool CompileUnoptimizedCode(CompilationInfo* info) {
DCHECK(AllowCompilation::IsAllowed(info->isolate()));
- if (!Compiler::Analyze(info->parse_info()) || !GenerateBaselineCode(info)) {
+ if (!Compiler::Analyze(info->parse_info()) ||
+ !GenerateUnoptimizedCode(info)) {
Isolate* isolate = info->isolate();
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
@@ -866,44 +502,45 @@
return true;
}
-void InstallBaselineCompilationResult(CompilationInfo* info,
- Handle<SharedFunctionInfo> shared,
- Handle<ScopeInfo> scope_info) {
+void InstallSharedScopeInfo(CompilationInfo* info,
+ Handle<SharedFunctionInfo> shared) {
+ Handle<ScopeInfo> scope_info =
+ ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
+ shared->set_scope_info(*scope_info);
+}
+
+void InstallSharedCompilationResult(CompilationInfo* info,
+ Handle<SharedFunctionInfo> shared) {
// Assert that we are not overwriting (possibly patched) debug code.
- DCHECK(!shared->HasDebugCode());
+ DCHECK(!shared->HasDebugInfo());
DCHECK(!info->code().is_null());
shared->ReplaceCode(*info->code());
- shared->set_scope_info(*scope_info);
if (info->has_bytecode_array()) {
DCHECK(!shared->HasBytecodeArray()); // Only compiled once.
shared->set_bytecode_array(*info->bytecode_array());
}
}
-MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCodeCommon(
- CompilationInfo* info) {
+MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) {
VMState<COMPILER> state(info->isolate());
PostponeInterruptsScope postpone(info->isolate());
// Parse and update CompilationInfo with the results.
if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>();
Handle<SharedFunctionInfo> shared = info->shared_info();
- FunctionLiteral* lit = info->literal();
- DCHECK_EQ(shared->language_mode(), lit->language_mode());
- SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
- MaybeDisableOptimization(shared, lit->dont_optimize_reason());
+ DCHECK_EQ(shared->language_mode(), info->literal()->language_mode());
// Compile either unoptimized code or bytecode for the interpreter.
- if (!CompileBaselineCode(info)) return MaybeHandle<Code>();
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
+ if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
- // Update the shared function info with the scope info. Allocating the
- // ScopeInfo object may cause a GC.
- Handle<ScopeInfo> scope_info =
- ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
+ // Update the shared function info with the scope info.
+ InstallSharedScopeInfo(info, shared);
// Install compilation result on the shared function info
- InstallBaselineCompilationResult(info, shared, scope_info);
+ InstallSharedCompilationResult(info, shared);
+
+ // Record the function compilation event.
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info);
return info->code();
}
@@ -964,7 +601,9 @@
if (!shared_info.is_null()) {
FunctionLiteral* lit = parse_info->literal();
shared_info->set_ast_node_count(lit->ast_node_count());
- MaybeDisableOptimization(shared_info, lit->dont_optimize_reason());
+ if (lit->dont_optimize_reason() != kNoReason) {
+ shared_info->DisableOptimization(lit->dont_optimize_reason());
+ }
shared_info->set_dont_crankshaft(
shared_info->dont_crankshaft() ||
(lit->flags() & AstProperties::kDontCrankshaft));
@@ -972,21 +611,42 @@
return true;
}
-bool GetOptimizedCodeNow(CompilationInfo* info) {
- Isolate* isolate = info->isolate();
- CanonicalHandleScope canonical(isolate);
- TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
- TRACE_EVENT0("v8", "V8.OptimizeCode");
+bool UseTurboFan(Handle<SharedFunctionInfo> shared) {
+ bool optimization_disabled = shared->optimization_disabled();
+ bool dont_crankshaft = shared->dont_crankshaft();
- if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
+ // Check the enabling conditions for Turbofan.
+ // 1. "use asm" code.
+ bool is_turbofanable_asm =
+ FLAG_turbo_asm && shared->asm_function() && !optimization_disabled;
+
+ // 2. Fallback for features unsupported by Crankshaft.
+ bool is_unsupported_by_crankshaft_but_turbofanable =
+ dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 &&
+ !optimization_disabled;
+
+ // 3. Explicitly enabled by the command-line filter.
+ bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter);
+
+ return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable ||
+ passes_turbo_filter;
+}
+
+bool GetOptimizedCodeNow(CompilationJob* job) {
+ CompilationInfo* info = job->info();
+ Isolate* isolate = info->isolate();
+
+ // Parsing is not required when optimizing from existing bytecode.
+ if (!info->is_optimizing_from_bytecode()) {
+ if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
+ }
TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
TRACE_EVENT0("v8", "V8.RecompileSynchronous");
- OptimizedCompileJob job(info);
- if (job.CreateGraph() != OptimizedCompileJob::SUCCEEDED ||
- job.OptimizeGraph() != OptimizedCompileJob::SUCCEEDED ||
- job.GenerateCode() != OptimizedCompileJob::SUCCEEDED) {
+ if (job->CreateGraph() != CompilationJob::SUCCEEDED ||
+ job->OptimizeGraph() != CompilationJob::SUCCEEDED ||
+ job->GenerateCode() != CompilationJob::SUCCEEDED) {
if (FLAG_trace_opt) {
PrintF("[aborted optimizing ");
info->closure()->ShortPrint();
@@ -996,18 +656,16 @@
}
// Success!
+ job->RecordOptimizationStats();
DCHECK(!isolate->has_pending_exception());
InsertCodeIntoOptimizedCodeMap(info);
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info,
- info->shared_info());
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info);
return true;
}
-bool GetOptimizedCodeLater(CompilationInfo* info) {
+bool GetOptimizedCodeLater(CompilationJob* job) {
+ CompilationInfo* info = job->info();
Isolate* isolate = info->isolate();
- CanonicalHandleScope canonical(isolate);
- TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
- TRACE_EVENT0("v8", "V8.OptimizeCode");
if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
if (FLAG_trace_concurrent_recompilation) {
@@ -1018,8 +676,14 @@
return false;
}
+ // All handles below this point will be allocated in a deferred handle scope
+ // that is detached and handed off to the background thread when we return.
CompilationHandleScope handle_scope(info);
- if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
+
+ // Parsing is not required when optimizing from existing bytecode.
+ if (!info->is_optimizing_from_bytecode()) {
+ if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
+ }
// Reopen handles in the new CompilationHandleScope.
info->ReopenHandlesInNewHandleScope();
@@ -1028,45 +692,23 @@
TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
TRACE_EVENT0("v8", "V8.RecompileSynchronous");
- OptimizedCompileJob* job = new (info->zone()) OptimizedCompileJob(info);
- OptimizedCompileJob::Status status = job->CreateGraph();
- if (status != OptimizedCompileJob::SUCCEEDED) return false;
+ if (job->CreateGraph() != CompilationJob::SUCCEEDED) return false;
isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Queued ");
info->closure()->ShortPrint();
- if (info->is_osr()) {
- PrintF(" for concurrent OSR at %d.\n", info->osr_ast_id().ToInt());
- } else {
- PrintF(" for concurrent optimization.\n");
- }
+ PrintF(" for concurrent optimization.\n");
}
return true;
}
-MaybeHandle<Code> GetUnoptimizedCode(Handle<JSFunction> function) {
- DCHECK(!function->GetIsolate()->has_pending_exception());
- DCHECK(!function->is_compiled());
- if (function->shared()->is_compiled()) {
- return Handle<Code>(function->shared()->code());
- }
-
- CompilationInfoWithZone info(function);
- Handle<Code> result;
- ASSIGN_RETURN_ON_EXCEPTION(info.isolate(), result,
- GetUnoptimizedCodeCommon(&info),
- Code);
- return result;
-}
-
MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
Compiler::ConcurrencyMode mode,
BailoutId osr_ast_id = BailoutId::None(),
JavaScriptFrame* osr_frame = nullptr) {
Isolate* isolate = function->GetIsolate();
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
- if (shared->HasDebugInfo()) return MaybeHandle<Code>();
Handle<Code> cached_code;
if (GetCodeFromOptimizedCodeMap(function, osr_ast_id)
@@ -1082,46 +724,186 @@
return cached_code;
}
- DCHECK(AllowCompilation::IsAllowed(isolate));
-
+ // Reset profiler ticks, function is no longer considered hot.
if (shared->is_compiled()) {
shared->code()->set_profiler_ticks(0);
}
- // TODO(mstarzinger): We cannot properly deserialize a scope chain containing
- // an eval scope and hence would fail at parsing the eval source again.
- if (shared->disable_optimization_reason() == kEval) {
- return MaybeHandle<Code>();
- }
-
- // TODO(mstarzinger): We cannot properly deserialize a scope chain for the
- // builtin context, hence Genesis::InstallExperimentalNatives would fail.
- if (shared->is_toplevel() && isolate->bootstrapper()->IsActive()) {
- return MaybeHandle<Code>();
- }
-
- base::SmartPointer<CompilationInfo> info(
- new CompilationInfoWithZone(function));
VMState<COMPILER> state(isolate);
DCHECK(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate);
+ bool use_turbofan = UseTurboFan(shared);
+ base::SmartPointer<CompilationJob> job(
+ use_turbofan ? compiler::Pipeline::NewCompilationJob(function)
+ : new HCompilationJob(function));
+ CompilationInfo* info = job->info();
+ ParseInfo* parse_info = info->parse_info();
- info->SetOptimizingForOsr(osr_ast_id);
+ info->SetOptimizingForOsr(osr_ast_id, osr_frame);
+
+ // Do not use Crankshaft/TurboFan if we need to be able to set break points.
+ if (info->shared_info()->HasDebugInfo()) {
+ info->AbortOptimization(kFunctionBeingDebugged);
+ return MaybeHandle<Code>();
+ }
+
+ // Limit the number of times we try to optimize functions.
+ const int kMaxOptCount =
+ FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
+ if (info->shared_info()->opt_count() > kMaxOptCount) {
+ info->AbortOptimization(kOptimizedTooManyTimes);
+ return MaybeHandle<Code>();
+ }
+
+ CanonicalHandleScope canonical(isolate);
+ TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
+ TRACE_EVENT0("v8", "V8.OptimizeCode");
+
+ // TurboFan can optimize directly from existing bytecode.
+ if (FLAG_turbo_from_bytecode && use_turbofan &&
+ info->shared_info()->HasBytecodeArray()) {
+ info->MarkAsOptimizeFromBytecode();
+ }
+
+ if (IsEvalToplevel(shared)) {
+ parse_info->set_eval();
+ if (function->context()->IsNativeContext()) parse_info->set_global();
+ parse_info->set_toplevel();
+ parse_info->set_allow_lazy_parsing(false);
+ parse_info->set_lazy(false);
+ }
if (mode == Compiler::CONCURRENT) {
- if (GetOptimizedCodeLater(info.get())) {
- info.Detach(); // The background recompile job owns this now.
+ if (GetOptimizedCodeLater(job.get())) {
+ job.Detach(); // The background recompile job owns this now.
return isolate->builtins()->InOptimizationQueue();
}
} else {
- info->set_osr_frame(osr_frame);
- if (GetOptimizedCodeNow(info.get())) return info->code();
+ if (GetOptimizedCodeNow(job.get())) return info->code();
}
if (isolate->has_pending_exception()) isolate->clear_pending_exception();
return MaybeHandle<Code>();
}
+class InterpreterActivationsFinder : public ThreadVisitor,
+ public OptimizedFunctionVisitor {
+ public:
+ SharedFunctionInfo* shared_;
+ bool has_activations_;
+
+ explicit InterpreterActivationsFinder(SharedFunctionInfo* shared)
+ : shared_(shared), has_activations_(false) {}
+
+ void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
+ JavaScriptFrameIterator it(isolate, top);
+ for (; !it.done() && !has_activations_; it.Advance()) {
+ JavaScriptFrame* frame = it.frame();
+ if (!frame->is_interpreted()) continue;
+ if (frame->function()->shared() == shared_) has_activations_ = true;
+ }
+ }
+
+ void VisitFunction(JSFunction* function) {
+ if (function->Inlines(shared_)) has_activations_ = true;
+ }
+
+ void EnterContext(Context* context) {}
+ void LeaveContext(Context* context) {}
+};
+
+bool HasInterpreterActivations(Isolate* isolate, SharedFunctionInfo* shared) {
+ InterpreterActivationsFinder activations_finder(shared);
+ activations_finder.VisitThread(isolate, isolate->thread_local_top());
+ isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
+ if (FLAG_turbo_from_bytecode) {
+ // If we are able to optimize functions directly from bytecode, then there
+ // might be optimized functions that rely on bytecode being around. We need
+ // to prevent switching the given function to baseline code in those cases.
+ Deoptimizer::VisitAllOptimizedFunctions(isolate, &activations_finder);
+ }
+ return activations_finder.has_activations_;
+}
+
+MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) {
+ Isolate* isolate = function->GetIsolate();
+ VMState<COMPILER> state(isolate);
+ PostponeInterruptsScope postpone(isolate);
+ Zone zone(isolate->allocator());
+ ParseInfo parse_info(&zone, function);
+ CompilationInfo info(&parse_info, function);
+
+ // Reset profiler ticks, function is no longer considered hot.
+ if (function->shared()->HasBytecodeArray()) {
+ function->shared()->set_profiler_ticks(0);
+ }
+
+ // Nothing left to do if the function already has baseline code.
+ if (function->shared()->code()->kind() == Code::FUNCTION) {
+ return Handle<Code>(function->shared()->code());
+ }
+
+ // We do not switch to baseline code when the debugger might have created a
+ // copy of the bytecode with break slots to be able to set break points.
+ if (function->shared()->HasDebugInfo()) {
+ return MaybeHandle<Code>();
+ }
+
+ // TODO(4280): For now we do not switch generators to baseline code because
+ // there might be suspended activations stored in generator objects on the
+ // heap. We could eventually go directly to TurboFan in this case.
+ if (function->shared()->is_generator()) {
+ return MaybeHandle<Code>();
+ }
+
+ // TODO(4280): For now we disable switching to baseline code in the presence
+ // of interpreter activations of the given function. The reasons are:
+ // 1) The debugger assumes each function is either full-code or bytecode.
+ // 2) The underlying bytecode is cleared below, breaking stack unwinding.
+ if (HasInterpreterActivations(isolate, function->shared())) {
+ if (FLAG_trace_opt) {
+ OFStream os(stdout);
+ os << "[unable to switch " << Brief(*function) << " due to activations]"
+ << std::endl;
+ }
+ return MaybeHandle<Code>();
+ }
+
+ if (FLAG_trace_opt) {
+ OFStream os(stdout);
+ os << "[switching method " << Brief(*function) << " to baseline code]"
+ << std::endl;
+ }
+
+ // Parse and update CompilationInfo with the results.
+ if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>();
+ Handle<SharedFunctionInfo> shared = info.shared_info();
+ DCHECK_EQ(shared->language_mode(), info.literal()->language_mode());
+
+ // Compile baseline code using the full code generator.
+ if (!Compiler::Analyze(info.parse_info()) ||
+ !FullCodeGenerator::MakeCode(&info)) {
+ if (!isolate->has_pending_exception()) isolate->StackOverflow();
+ return MaybeHandle<Code>();
+ }
+
+ // TODO(4280): For now we play it safe and remove the bytecode array when we
+ // switch to baseline code. We might consider keeping around the bytecode so
+ // that it can be used as the "source of truth" eventually.
+ shared->ClearBytecodeArray();
+
+ // Update the shared function info with the scope info.
+ InstallSharedScopeInfo(&info, shared);
+
+ // Install compilation result on the shared function info
+ InstallSharedCompilationResult(&info, shared);
+
+ // Record the function compilation event.
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &info);
+
+ return info.code();
+}
+
MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) {
Isolate* isolate = function->GetIsolate();
DCHECK(!isolate->has_pending_exception());
@@ -1129,35 +911,30 @@
TimerEventScope<TimerEventCompileCode> compile_timer(isolate);
TRACE_EVENT0("v8", "V8.CompileCode");
AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
- // If the debugger is active, do not compile with turbofan unless we can
- // deopt from turbofan code.
- if (FLAG_turbo_asm && function->shared()->asm_function() &&
- (FLAG_turbo_asm_deoptimization || !isolate->debug()->is_active()) &&
- !FLAG_turbo_osr) {
- CompilationInfoWithZone info(function);
- VMState<COMPILER> state(isolate);
- PostponeInterruptsScope postpone(isolate);
-
- info.SetOptimizing();
-
- if (GetOptimizedCodeNow(&info)) {
+ if (FLAG_turbo_cache_shared_code) {
+ Handle<Code> cached_code;
+ if (GetCodeFromOptimizedCodeMap(function, BailoutId::None())
+ .ToHandle(&cached_code)) {
+ if (FLAG_trace_opt) {
+ PrintF("[found optimized code for ");
+ function->ShortPrint();
+ PrintF(" during unoptimized compile]\n");
+ }
DCHECK(function->shared()->is_compiled());
- return info.code();
+ return cached_code;
}
- // We have failed compilation. If there was an exception clear it so that
- // we can compile unoptimized code.
- if (isolate->has_pending_exception()) isolate->clear_pending_exception();
}
if (function->shared()->is_compiled()) {
return Handle<Code>(function->shared()->code());
}
- CompilationInfoWithZone info(function);
+ Zone zone(isolate->allocator());
+ ParseInfo parse_info(&zone, function);
+ CompilationInfo info(&parse_info, function);
Handle<Code> result;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info),
- Code);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCode(&info), Code);
if (FLAG_always_opt) {
Handle<Code> opt_code;
@@ -1171,59 +948,6 @@
}
-bool CompileEvalForDebugging(Handle<JSFunction> function,
- Handle<SharedFunctionInfo> shared) {
- Handle<Script> script(Script::cast(shared->script()));
- Handle<Context> context(function->context());
-
- Zone zone(function->GetIsolate()->allocator());
- ParseInfo parse_info(&zone, script);
- CompilationInfo info(&parse_info);
- Isolate* isolate = info.isolate();
-
- parse_info.set_eval();
- parse_info.set_context(context);
- if (context->IsNativeContext()) parse_info.set_global();
- parse_info.set_toplevel();
- parse_info.set_allow_lazy_parsing(false);
- parse_info.set_language_mode(shared->language_mode());
- parse_info.set_parse_restriction(NO_PARSE_RESTRICTION);
- info.MarkAsDebug();
-
- VMState<COMPILER> state(info.isolate());
-
- if (!Parser::ParseStatic(&parse_info)) {
- isolate->clear_pending_exception();
- return false;
- }
-
- FunctionLiteral* lit = parse_info.literal();
- LiveEditFunctionTracker live_edit_tracker(isolate, lit);
-
- if (!CompileUnoptimizedCode(&info)) {
- isolate->clear_pending_exception();
- return false;
- }
- shared->ReplaceCode(*info.code());
- return true;
-}
-
-
-bool CompileForDebugging(CompilationInfo* info) {
- info->MarkAsDebug();
- if (GetUnoptimizedCodeCommon(info).is_null()) {
- info->isolate()->clear_pending_exception();
- return false;
- }
- return true;
-}
-
-inline bool IsEvalToplevel(Handle<SharedFunctionInfo> shared) {
- return shared->is_toplevel() && shared->script()->IsScript() &&
- Script::cast(shared->script())->compilation_type() ==
- Script::COMPILATION_TYPE_EVAL;
-}
-
Handle<SharedFunctionInfo> NewSharedFunctionInfoForLiteral(
Isolate* isolate, FunctionLiteral* literal, Handle<Script> script) {
Handle<Code> code = isolate->builtins()->CompileLazy();
@@ -1294,61 +1018,55 @@
DCHECK(!info->is_debug() || !parse_info->allow_lazy_parsing());
- info->MarkAsFirstCompile();
-
FunctionLiteral* lit = parse_info->literal();
- LiveEditFunctionTracker live_edit_tracker(isolate, lit);
// Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the
// parsing statistics.
- HistogramTimer* rate = info->is_eval()
- ? info->isolate()->counters()->compile_eval()
- : info->isolate()->counters()->compile();
+ RuntimeCallTimerScope runtimeTimer(
+ isolate, parse_info->is_eval() ? &RuntimeCallStats::CompileEval
+ : &RuntimeCallStats::Compile);
+ HistogramTimer* rate = parse_info->is_eval()
+ ? info->isolate()->counters()->compile_eval()
+ : info->isolate()->counters()->compile();
HistogramTimerScope timer(rate);
- TRACE_EVENT0("v8", info->is_eval() ? "V8.CompileEval" : "V8.Compile");
+ TRACE_EVENT0("v8", parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
// Allocate a shared function info object.
DCHECK_EQ(RelocInfo::kNoPosition, lit->function_token_position());
result = NewSharedFunctionInfoForLiteral(isolate, lit, script);
result->set_is_toplevel(true);
- if (info->is_eval()) {
+ if (parse_info->is_eval()) {
// Eval scripts cannot be (re-)compiled without context.
result->set_allows_lazy_compilation_without_context(false);
}
parse_info->set_shared_info(result);
// Compile the code.
- if (!CompileBaselineCode(info)) {
+ if (!CompileUnoptimizedCode(info)) {
return Handle<SharedFunctionInfo>::null();
}
+ // Update the shared function info with the scope info.
+ InstallSharedScopeInfo(info, result);
+
// Install compilation result on the shared function info
- Handle<ScopeInfo> scope_info =
- ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
- InstallBaselineCompilationResult(info, result, scope_info);
+ InstallSharedCompilationResult(info, result);
Handle<String> script_name =
script->name()->IsString()
? Handle<String>(String::cast(script->name()))
: isolate->factory()->empty_string();
- Logger::LogEventsAndTags log_tag = info->is_eval()
- ? Logger::EVAL_TAG
- : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script);
+ Logger::LogEventsAndTags log_tag =
+ parse_info->is_eval()
+ ? Logger::EVAL_TAG
+ : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script);
- PROFILE(isolate, CodeCreateEvent(log_tag, *info->abstract_code(), *result,
- info, *script_name));
-
- // Hint to the runtime system used when allocating space for initial
- // property space by setting the expected number of properties for
- // the instances of the function.
- SetExpectedNofPropertiesFromEstimate(result,
- lit->expected_property_count());
+ PROFILE(isolate, CodeCreateEvent(log_tag, result->abstract_code(), *result,
+ *script_name));
if (!script.is_null())
script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
-
- live_edit_tracker.RecordFunctionInfo(result, lit, info->zone());
}
return result;
@@ -1370,90 +1088,205 @@
bool Compiler::ParseAndAnalyze(ParseInfo* info) {
if (!Parser::ParseStatic(info)) return false;
- return Compiler::Analyze(info);
+ if (!Compiler::Analyze(info)) return false;
+ DCHECK_NOT_NULL(info->literal());
+ DCHECK_NOT_NULL(info->scope());
+ return true;
}
bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
if (function->is_compiled()) return true;
- MaybeHandle<Code> maybe_code = GetLazyCode(function);
+ Isolate* isolate = function->GetIsolate();
+ DCHECK(AllowCompilation::IsAllowed(isolate));
+
+ // Start a compilation.
Handle<Code> code;
- if (!maybe_code.ToHandle(&code)) {
+ if (!GetLazyCode(function).ToHandle(&code)) {
if (flag == CLEAR_EXCEPTION) {
- function->GetIsolate()->clear_pending_exception();
+ isolate->clear_pending_exception();
}
return false;
}
- DCHECK(code->IsJavaScriptCode());
+
+ // Install code on closure.
function->ReplaceCode(*code);
+
+ // Check postconditions on success.
+ DCHECK(!isolate->has_pending_exception());
+ DCHECK(function->shared()->is_compiled());
+ DCHECK(function->is_compiled());
+ return true;
+}
+
+bool Compiler::CompileBaseline(Handle<JSFunction> function) {
+ Isolate* isolate = function->GetIsolate();
+ DCHECK(AllowCompilation::IsAllowed(isolate));
+
+ // Start a compilation.
+ Handle<Code> code;
+ if (!GetBaselineCode(function).ToHandle(&code)) {
+ // Baseline generation failed, get unoptimized code.
+ DCHECK(function->shared()->is_compiled());
+ code = handle(function->shared()->code());
+ isolate->clear_pending_exception();
+ }
+
+ // Install code on closure.
+ function->ReplaceCode(*code);
+
+ // Check postconditions on success.
+ DCHECK(!isolate->has_pending_exception());
+ DCHECK(function->shared()->is_compiled());
DCHECK(function->is_compiled());
return true;
}
bool Compiler::CompileOptimized(Handle<JSFunction> function,
ConcurrencyMode mode) {
+ if (function->IsOptimized()) return true;
+ Isolate* isolate = function->GetIsolate();
+ DCHECK(AllowCompilation::IsAllowed(isolate));
+
+ // Start a compilation.
Handle<Code> code;
- if (GetOptimizedCode(function, mode).ToHandle(&code)) {
- // Optimization succeeded, return optimized code.
- function->ReplaceCode(*code);
- } else {
+ if (!GetOptimizedCode(function, mode).ToHandle(&code)) {
// Optimization failed, get unoptimized code.
- Isolate* isolate = function->GetIsolate();
- if (isolate->has_pending_exception()) { // Possible stack overflow.
- return false;
- }
- code = Handle<Code>(function->shared()->code(), isolate);
- if (code->kind() != Code::FUNCTION &&
- code->kind() != Code::OPTIMIZED_FUNCTION) {
- if (!GetUnoptimizedCode(function).ToHandle(&code)) {
+ DCHECK(!isolate->has_pending_exception());
+ if (function->shared()->is_compiled()) {
+ code = handle(function->shared()->code(), isolate);
+ } else {
+ Zone zone(isolate->allocator());
+ ParseInfo parse_info(&zone, function);
+ CompilationInfo info(&parse_info, function);
+ if (!GetUnoptimizedCode(&info).ToHandle(&code)) {
return false;
}
}
- function->ReplaceCode(*code);
}
- DCHECK(function->code()->kind() == Code::FUNCTION ||
- function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
- (function->code()->is_interpreter_entry_trampoline() &&
- function->shared()->HasBytecodeArray()) ||
- function->IsInOptimizationQueue());
+ // Install code on closure.
+ function->ReplaceCode(*code);
+
+ // Check postconditions on success.
+ DCHECK(!isolate->has_pending_exception());
+ DCHECK(function->shared()->is_compiled());
+ DCHECK(function->is_compiled());
return true;
}
bool Compiler::CompileDebugCode(Handle<JSFunction> function) {
- Handle<SharedFunctionInfo> shared(function->shared());
- if (IsEvalToplevel(shared)) {
- return CompileEvalForDebugging(function, shared);
- } else {
- CompilationInfoWithZone info(function);
- return CompileForDebugging(&info);
+ Isolate* isolate = function->GetIsolate();
+ DCHECK(AllowCompilation::IsAllowed(isolate));
+
+ // Start a compilation.
+ Zone zone(isolate->allocator());
+ ParseInfo parse_info(&zone, function);
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null());
+ if (IsEvalToplevel(handle(function->shared()))) {
+ parse_info.set_eval();
+ if (function->context()->IsNativeContext()) parse_info.set_global();
+ parse_info.set_toplevel();
+ parse_info.set_allow_lazy_parsing(false);
+ parse_info.set_lazy(false);
}
+ info.MarkAsDebug();
+ if (GetUnoptimizedCode(&info).is_null()) {
+ isolate->clear_pending_exception();
+ return false;
+ }
+
+ // Check postconditions on success.
+ DCHECK(!isolate->has_pending_exception());
+ DCHECK(function->shared()->is_compiled());
+ DCHECK(function->shared()->HasDebugCode());
+ return true;
}
bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) {
+ Isolate* isolate = shared->GetIsolate();
+ DCHECK(AllowCompilation::IsAllowed(isolate));
+
+ // Start a compilation.
+ Zone zone(isolate->allocator());
+ ParseInfo parse_info(&zone, shared);
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null());
DCHECK(shared->allows_lazy_compilation_without_context());
DCHECK(!IsEvalToplevel(shared));
- Zone zone(shared->GetIsolate()->allocator());
- ParseInfo parse_info(&zone, shared);
- CompilationInfo info(&parse_info);
- return CompileForDebugging(&info);
+ info.MarkAsDebug();
+ if (GetUnoptimizedCode(&info).is_null()) {
+ isolate->clear_pending_exception();
+ return false;
+ }
+
+ // Check postconditions on success.
+ DCHECK(!isolate->has_pending_exception());
+ DCHECK(shared->is_compiled());
+ DCHECK(shared->HasDebugCode());
+ return true;
+}
+
+MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
+ Isolate* isolate = script->GetIsolate();
+ DCHECK(AllowCompilation::IsAllowed(isolate));
+
+ // In order to ensure that live edit function info collection finds the newly
+ // generated shared function infos, clear the script's list temporarily
+ // and restore it at the end of this method.
+ Handle<Object> old_function_infos(script->shared_function_infos(), isolate);
+ script->set_shared_function_infos(Smi::FromInt(0));
+
+ // Start a compilation.
+ Zone zone(isolate->allocator());
+ ParseInfo parse_info(&zone, script);
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null());
+ parse_info.set_global();
+ info.MarkAsDebug();
+
+ // TODO(635): support extensions.
+ const bool compilation_succeeded = !CompileToplevel(&info).is_null();
+ Handle<JSArray> infos;
+ if (compilation_succeeded) {
+ // Check postconditions on success.
+ DCHECK(!isolate->has_pending_exception());
+ infos = LiveEditFunctionTracker::Collect(parse_info.literal(), script,
+ &zone, isolate);
+ }
+
+ // Restore the original function info list in order to remain side-effect
+ // free as much as possible, since some code expects the old shared function
+ // infos to stick around.
+ script->set_shared_function_infos(*old_function_infos);
+
+ return infos;
}
// TODO(turbofan): In the future, unoptimized code with deopt support could
// be generated lazily once deopt is triggered.
bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
DCHECK_NOT_NULL(info->literal());
- DCHECK(info->has_scope());
+ DCHECK_NOT_NULL(info->scope());
Handle<SharedFunctionInfo> shared = info->shared_info();
if (!shared->has_deoptimization_support()) {
- // TODO(titzer): just reuse the ParseInfo for the unoptimized compile.
- CompilationInfoWithZone unoptimized(info->closure());
- // Note that we use the same AST that we will use for generating the
- // optimized code.
- ParseInfo* parse_info = unoptimized.parse_info();
- parse_info->set_literal(info->literal());
- parse_info->set_scope(info->scope());
- parse_info->set_context(info->context());
+ Zone zone(info->isolate()->allocator());
+ CompilationInfo unoptimized(info->parse_info(), info->closure());
unoptimized.EnableDeoptimizationSupport();
+
+ // TODO(4280): For now we do not switch generators to baseline code because
+ // there might be suspended activations stored in generator objects on the
+ // heap. We could eventually go directly to TurboFan in this case.
+ if (shared->is_generator()) return false;
+
+ // TODO(4280): For now we disable switching to baseline code in the presence
+ // of interpreter activations of the given function. The reasons are:
+ // 1) The debugger assumes each function is either full-code or bytecode.
+ // 2) The underlying bytecode is cleared below, breaking stack unwinding.
+ // The expensive check for activations only needs to be done when the given
+ // function has bytecode, otherwise we can be sure there are no activations.
+ if (shared->HasBytecodeArray() &&
+ HasInterpreterActivations(info->isolate(), *shared)) {
+ return false;
+ }
+
// If the current code has reloc info for serialization, also include
// reloc info for serialization for the new code, so that deopt support
// can be added without losing IC state.
@@ -1464,48 +1297,32 @@
EnsureFeedbackVector(&unoptimized);
if (!FullCodeGenerator::MakeCode(&unoptimized)) return false;
- shared->EnableDeoptimizationSupport(*unoptimized.code());
-
- info->MarkAsCompiled();
+ // TODO(4280): For now we play it safe and remove the bytecode array when we
+ // switch to baseline code. We might consider keeping around the bytecode so
+ // that it can be used as the "source of truth" eventually.
+ shared->ClearBytecodeArray();
// The scope info might not have been set if a lazily compiled
// function is inlined before being called for the first time.
if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) {
- Handle<ScopeInfo> target_scope_info =
- ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
- shared->set_scope_info(*target_scope_info);
+ InstallSharedScopeInfo(info, shared);
}
+ // Install compilation result on the shared function info
+ shared->EnableDeoptimizationSupport(*unoptimized.code());
+
// The existing unoptimized code was replaced with the new one.
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &unoptimized);
}
return true;
}
-void Compiler::CompileForLiveEdit(Handle<Script> script) {
- // TODO(635): support extensions.
- Zone zone(script->GetIsolate()->allocator());
- ParseInfo parse_info(&zone, script);
- CompilationInfo info(&parse_info);
- PostponeInterruptsScope postpone(info.isolate());
- VMState<COMPILER> state(info.isolate());
-
- // Get rid of old list of shared function infos.
- info.MarkAsFirstCompile();
- info.MarkAsDebug();
- info.parse_info()->set_global();
- if (!Parser::ParseStatic(info.parse_info())) return;
-
- LiveEditFunctionTracker tracker(info.isolate(), parse_info.literal());
- if (!CompileUnoptimizedCode(&info)) return;
- tracker.RecordRootFunctionInfo(info.code());
-}
-
MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<Context> context, LanguageMode language_mode,
- ParseRestriction restriction, int line_offset, int column_offset,
- Handle<Object> script_name, ScriptOriginOptions options) {
+ ParseRestriction restriction, int eval_scope_position, int eval_position,
+ int line_offset, int column_offset, Handle<Object> script_name,
+ ScriptOriginOptions options) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_eval_size()->Increment(source_length);
@@ -1514,7 +1331,7 @@
CompilationCache* compilation_cache = isolate->compilation_cache();
MaybeHandle<SharedFunctionInfo> maybe_shared_info =
compilation_cache->LookupEval(source, outer_info, context, language_mode,
- line_offset);
+ eval_scope_position);
Handle<SharedFunctionInfo> shared_info;
Handle<Script> script;
@@ -1526,33 +1343,28 @@
script->set_column_offset(column_offset);
}
script->set_origin_options(options);
+ script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
+ Script::SetEvalOrigin(script, outer_info, eval_position);
+
Zone zone(isolate->allocator());
ParseInfo parse_info(&zone, script);
- CompilationInfo info(&parse_info);
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null());
parse_info.set_eval();
if (context->IsNativeContext()) parse_info.set_global();
parse_info.set_language_mode(language_mode);
parse_info.set_parse_restriction(restriction);
parse_info.set_context(context);
- Debug::RecordEvalCaller(script);
-
shared_info = CompileToplevel(&info);
if (shared_info.is_null()) {
return MaybeHandle<JSFunction>();
} else {
- // Explicitly disable optimization for eval code. We're not yet prepared
- // to handle eval-code in the optimizing compiler.
- if (restriction != ONLY_SINGLE_FUNCTION_LITERAL) {
- shared_info->DisableOptimization(kEval);
- }
-
// If caller is strict mode, the result must be in strict mode as well.
DCHECK(is_sloppy(language_mode) ||
is_strict(shared_info->language_mode()));
compilation_cache->PutEval(source, outer_info, context, shared_info,
- line_offset);
+ eval_scope_position);
}
}
@@ -1627,8 +1439,10 @@
timer.Start();
}
- if (!maybe_result.ToHandle(&result)) {
- // No cache entry found. Compile the script.
+ if (!maybe_result.ToHandle(&result) ||
+ (FLAG_serialize_toplevel &&
+ compile_options == ScriptCompiler::kProduceCodeCache)) {
+ // No cache entry found, or embedder wants a code cache. Compile the script.
// Create a script object describing the script to be compiled.
Handle<Script> script = isolate->factory()->NewScript(source);
@@ -1652,7 +1466,7 @@
// Compile the function and add it to the cache.
Zone zone(isolate->allocator());
ParseInfo parse_info(&zone, script);
- CompilationInfo info(&parse_info);
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null());
if (is_module) {
parse_info.set_module();
} else {
@@ -1670,7 +1484,7 @@
}
parse_info.set_language_mode(
- static_cast<LanguageMode>(info.language_mode() | language_mode));
+ static_cast<LanguageMode>(parse_info.language_mode() | language_mode));
result = CompileToplevel(&info);
if (extension == NULL && !result.is_null()) {
compilation_cache->PutScript(source, context, language_mode, result);
@@ -1709,7 +1523,7 @@
parse_info->set_language_mode(
static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
- CompilationInfo compile_info(parse_info);
+ CompilationInfo compile_info(parse_info, Handle<JSFunction>::null());
// The source was parsed lazily, so compiling for debugging is not possible.
DCHECK(!compile_info.is_debug());
@@ -1726,7 +1540,9 @@
// Precondition: code has been parsed and scopes have been analyzed.
Isolate* isolate = outer_info->isolate();
MaybeHandle<SharedFunctionInfo> maybe_existing;
- if (outer_info->is_first_compile()) {
+
+ // Find any previously allocated shared function info for the given literal.
+ if (outer_info->shared_info()->never_compiled()) {
// On the first compile, there are no existing shared function info for
// inner functions yet, so do not try to find them. All bets are off for
// live edit though.
@@ -1735,6 +1551,7 @@
} else {
maybe_existing = script->FindSharedFunctionInfo(literal);
}
+
// We found an existing shared function info. If it's already compiled,
// don't worry about compiling it, and simply return it. If it's not yet
// compiled, continue to decide whether to eagerly compile.
@@ -1742,6 +1559,7 @@
// unless we already have code with debut break slots.
Handle<SharedFunctionInfo> existing;
if (maybe_existing.ToHandle(&existing) && existing->is_compiled()) {
+ DCHECK(!existing->is_toplevel());
if (!outer_info->is_debug() || existing->HasDebugCode()) {
return existing;
}
@@ -1752,20 +1570,23 @@
if (!maybe_existing.ToHandle(&result)) {
result = NewSharedFunctionInfoForLiteral(isolate, literal, script);
result->set_is_toplevel(false);
+
+ // If the outer function has been compiled before, we cannot be sure that
+ // shared function info for this function literal has been created for the
+ // first time. It may have already been compiled previously.
+ result->set_never_compiled(outer_info->shared_info()->never_compiled());
}
Zone zone(isolate->allocator());
ParseInfo parse_info(&zone, script);
- CompilationInfo info(&parse_info);
+ CompilationInfo info(&parse_info, Handle<JSFunction>::null());
parse_info.set_literal(literal);
parse_info.set_shared_info(result);
parse_info.set_scope(literal->scope());
parse_info.set_language_mode(literal->scope()->language_mode());
if (outer_info->will_serialize()) info.PrepareForSerializing();
- if (outer_info->is_first_compile()) info.MarkAsFirstCompile();
if (outer_info->is_debug()) info.MarkAsDebug();
- LiveEditFunctionTracker live_edit_tracker(isolate, literal);
// Determine if the function can be lazily compiled. This is necessary to
// allow some of our builtin JS files to be lazily compiled. These
// builtins cannot be handled lazily by the parser, since we have to know
@@ -1775,13 +1596,7 @@
// aggressive about lazy compilation, because it might trigger compilation
// of functions without an outer context when setting a breakpoint through
// Debug::FindSharedFunctionInfoInScript.
- bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext();
- // Compile eagerly for live edit. When compiling debug code, eagerly compile
- // unless we can lazily compile without the context.
- bool allow_lazy = literal->AllowsLazyCompilation() &&
- !LiveEditFunctionTracker::IsActive(isolate) &&
- (!info.is_debug() || allow_lazy_without_ctx);
-
+ bool allow_lazy = literal->AllowsLazyCompilation() && !info.is_debug();
bool lazy = FLAG_lazy && allow_lazy && !literal->should_eager_compile();
// Consider compiling eagerly when targeting the code cache.
@@ -1796,37 +1611,24 @@
TRACE_EVENT0("v8", "V8.CompileCode");
if (lazy) {
info.SetCode(isolate->builtins()->CompileLazy());
- } else if (Renumber(info.parse_info()) && GenerateBaselineCode(&info)) {
+ } else if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) {
// Code generation will ensure that the feedback vector is present and
// appropriately sized.
DCHECK(!info.code().is_null());
- Handle<ScopeInfo> scope_info =
- ScopeInfo::Create(info.isolate(), info.zone(), info.scope());
if (literal->should_eager_compile() &&
literal->should_be_used_once_hint()) {
info.code()->MarkToBeExecutedOnce(isolate);
}
+ // Update the shared function info with the scope info.
+ InstallSharedScopeInfo(&info, result);
// Install compilation result on the shared function info.
- InstallBaselineCompilationResult(&info, result, scope_info);
+ InstallSharedCompilationResult(&info, result);
} else {
return Handle<SharedFunctionInfo>::null();
}
if (maybe_existing.is_null()) {
- // If the outer function has been compiled before, we cannot be sure that
- // shared function info for this function literal has been created for the
- // first time. It may have already been compiled previously.
- result->set_never_compiled(outer_info->is_first_compile() && lazy);
-
- RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
- result->set_allows_lazy_compilation(literal->AllowsLazyCompilation());
- result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
-
- // Set the expected number of properties for instances and return
- // the resulting function.
- SetExpectedNofPropertiesFromEstimate(result,
- literal->expected_property_count());
- live_edit_tracker.RecordFunctionInfo(result, literal, info.zone());
+ RecordFunctionCompilation(Logger::FUNCTION_TAG, &info);
}
return result;
@@ -1872,10 +1674,10 @@
return GetOptimizedCode(function, NOT_CONCURRENT, osr_ast_id, osr_frame);
}
-void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
- // Take ownership of compilation info. Deleting compilation info
- // also tears down the zone and the recompile job.
- base::SmartPointer<CompilationInfo> info(job->info());
+void Compiler::FinalizeCompilationJob(CompilationJob* raw_job) {
+ // Take ownership of compilation job. Deleting job also tears down the zone.
+ base::SmartPointer<CompilationJob> job(raw_job);
+ CompilationInfo* info = job->info();
Isolate* isolate = info->isolate();
VMState<COMPILER> state(isolate);
@@ -1892,16 +1694,17 @@
// Except when OSR already disabled optimization for some reason.
// 3) The code may have already been invalidated due to dependency change.
// 4) Code generation may have failed.
- if (job->last_status() == OptimizedCompileJob::SUCCEEDED) {
+ if (job->last_status() == CompilationJob::SUCCEEDED) {
if (shared->optimization_disabled()) {
job->RetryOptimization(kOptimizationDisabled);
} else if (info->dependencies()->HasAborted()) {
job->RetryOptimization(kBailedOutDueToDependencyChange);
- } else if (job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info.get(), shared);
+ } else if (job->GenerateCode() == CompilationJob::SUCCEEDED) {
+ job->RecordOptimizationStats();
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info);
if (shared->SearchOptimizedCodeMap(info->context()->native_context(),
info->osr_ast_id()).code == nullptr) {
- InsertCodeIntoOptimizedCodeMap(info.get());
+ InsertCodeIntoOptimizedCodeMap(info);
}
if (FLAG_trace_opt) {
PrintF("[completed optimizing ");
@@ -1913,7 +1716,7 @@
}
}
- DCHECK(job->last_status() != OptimizedCompileJob::SUCCEEDED);
+ DCHECK(job->last_status() != CompilationJob::SUCCEEDED);
if (FLAG_trace_opt) {
PrintF("[aborted optimizing ");
info->closure()->ShortPrint();