[compiler] Allow optimization of top-level eval code.

This allows for top-level eval code to be parsed properly before doing
optimization. It uses the same kind of re-parsing we already perform
when compiling code for debugging.

R=bmeurer@chromium.org

Review-Url: https://codereview.chromium.org/1884143003
Cr-Commit-Position: refs/heads/master@{#36014}
This commit is contained in:
mstarzinger 2016-05-04 03:56:53 -07:00 committed by Commit bot
parent 0322c20d17
commit 22b4db544c
4 changed files with 35 additions and 16 deletions

View File

@ -418,6 +418,12 @@ void CompilationJob::RecordOptimizationStats() {
namespace {
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) {
// Log the code generation. If source information is available include
@ -765,12 +771,6 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
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>();
}
VMState<COMPILER> state(isolate);
DCHECK(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate);
@ -779,6 +779,7 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
use_turbofan ? compiler::Pipeline::NewCompilationJob(function)
: new HCompilationJob(function));
CompilationInfo* info = job->info();
ParseInfo* parse_info = info->parse_info();
info->SetOptimizingForOsr(osr_ast_id);
@ -813,6 +814,14 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
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(job.get())) {
job.Detach(); // The background recompile job owns this now.
@ -1001,12 +1010,6 @@ MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) {
}
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();

View File

@ -492,6 +492,12 @@ Node* AstGraphBuilder::GetFunctionClosureForContext() {
// Contexts nested in the native context have a canonical empty function as
// their closure, not the anonymous closure containing the global code.
return BuildLoadNativeContextField(Context::CLOSURE_INDEX);
} else if (closure_scope->is_eval_scope()) {
// Contexts nested inside eval code have the same closure as the context
// calling eval, not the anonymous closure containing the eval code.
const Operator* op =
javascript()->LoadContext(0, Context::CLOSURE_INDEX, false);
return NewNode(op, current_context());
} else {
DCHECK(closure_scope->is_function_scope());
return GetFunctionClosure();
@ -1109,7 +1115,9 @@ void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
}
break;
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
// TODO(mstarzinger): Implement this case.
SetStackOverflow();
break;
}
}
@ -1142,7 +1150,9 @@ void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
break;
}
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
// TODO(mstarzinger): Implement this case.
SetStackOverflow();
break;
}
}
@ -3185,7 +3195,7 @@ Node* AstGraphBuilder::BuildLocalActivationContext(Node* context) {
Node* AstGraphBuilder::BuildLocalFunctionContext(Scope* scope) {
DCHECK(scope->is_function_scope());
DCHECK(scope->is_function_scope() || scope->is_eval_scope());
// Allocate a new local context.
int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;

View File

@ -12355,7 +12355,11 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
SharedFunctionInfo* shared;
while ((shared = iterator.Next<SharedFunctionInfo>())) {
if (fun->function_token_position() == shared->function_token_position() &&
fun->start_position() == shared->start_position()) {
fun->start_position() == shared->start_position() &&
fun->end_position() == shared->end_position()) {
// This method is not used to find top-level SharedFunctionInfo objects,
// verify that above checks are sufficient to distinguish top-level code.
DCHECK(!shared->is_toplevel());
return Handle<SharedFunctionInfo>(shared);
}
}

View File

@ -64,6 +64,8 @@
'js1_5/Regress/regress-111557': [PASS, NO_VARIANTS],
'js1_5/Regress/regress-155081': [PASS, NO_VARIANTS],
'js1_5/Regress/regress-155081-2': [PASS, NO_VARIANTS],
'js1_5/Regress/regress-159334': [PASS, NO_VARIANTS],
'js1_5/Regress/regress-321971': [PASS, NO_VARIANTS],
'js1_5/Regress/regress-451322': [PASS, NO_VARIANTS],
# TODO(turbofan): Large switch statements crash.