Commit eefe11a1 authored by vogelheim's avatar vogelheim Committed by Commit bot

Treat a '!' preceding a function literal as eager-compile hint.

Some minifiers use the pattern !function ... () for JS code that should
be immediately executed. This change recognizes that pattern and treats
it equally to parenthesized functions.

A bit more background info is in the referenced bug.

R=verwaest@chromium.org
BUG=v8:5643

Review-Url: https://codereview.chromium.org/2509143003
Cr-Commit-Position: refs/heads/master@{#41114}
parent 7724a255
......@@ -458,16 +458,12 @@ class ParserBase {
return &non_patterns_to_rewrite_;
}
bool next_function_is_parenthesized() const {
return next_function_is_parenthesized_;
bool next_function_is_likely_called() const {
return next_function_is_likely_called_;
}
void set_next_function_is_parenthesized(bool parenthesized) {
next_function_is_parenthesized_ = parenthesized;
}
bool this_function_is_parenthesized() const {
return this_function_is_parenthesized_;
void set_next_function_is_likely_called() {
next_function_is_likely_called_ = true;
}
private:
......@@ -508,13 +504,12 @@ class ParserBase {
ZoneList<typename ExpressionClassifier::Error> reported_errors_;
// If true, the next (and immediately following) function literal is
// preceded by a parenthesis.
bool next_function_is_parenthesized_;
// The value of the parents' next_function_is_parenthesized_, as it applies
// to this function. Filled in by constructor.
bool this_function_is_parenthesized_;
// Record whether the next (=== immediately following) function literal is
// preceded by a parenthesis / exclamation mark.
// The FunctionState constructor will reset a parents'
// next_function_is_likely_called_ to prevent it from being 'reused' in the
// next function literal.
bool next_function_is_likely_called_;
friend Impl;
friend class Checkpoint;
......@@ -1466,13 +1461,10 @@ ParserBase<Impl>::FunctionState::FunctionState(
return_expr_context_(ReturnExprContext::kInsideValidBlock),
non_patterns_to_rewrite_(0, scope->zone()),
reported_errors_(16, scope->zone()),
next_function_is_parenthesized_(false),
this_function_is_parenthesized_(false) {
next_function_is_likely_called_(false) {
*function_state_stack = this;
if (outer_function_state_) {
this_function_is_parenthesized_ =
outer_function_state_->next_function_is_parenthesized_;
outer_function_state_->next_function_is_parenthesized_ = false;
outer_function_state_->next_function_is_likely_called_ = false;
}
}
......@@ -1789,8 +1781,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
}
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
function_state_->set_next_function_is_parenthesized(peek() ==
Token::FUNCTION);
if (peek() == Token::FUNCTION) {
function_state_->set_next_function_is_likely_called();
}
ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
return expr;
......@@ -2944,6 +2937,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
op = Next();
int pos = position();
// Assume "! function ..." indicates the function is likely to be called.
if (op == Token::NOT && peek() == Token::FUNCTION) {
function_state_->set_next_function_is_likely_called();
}
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
......
......@@ -2530,7 +2530,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
FunctionLiteral::EagerCompileHint eager_compile_hint =
function_state_->next_function_is_parenthesized()
function_state_->next_function_is_likely_called()
? FunctionLiteral::kShouldEagerCompile
: default_eager_compile_hint();
......
......@@ -91,6 +91,7 @@ v8_executable("cctest") {
"interpreter/test-source-positions.cc",
"libplatform/test-tracing.cc",
"libsampler/test-sampler.cc",
"parsing/test-parse-decision.cc",
"parsing/test-scanner-streams.cc",
"parsing/test-scanner.cc",
"print-extension.cc",
......
......@@ -112,6 +112,7 @@
'heap/test-spaces.cc',
'libplatform/test-tracing.cc',
'libsampler/test-sampler.cc',
'parsing/test-parse-decision.cc',
'parsing/test-scanner-streams.cc',
'parsing/test-scanner.cc',
'print-extension.cc',
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Test specific cases of the lazy/eager-parse decision.
//
// Note that presently most unit tests for parsing are found in
// cctest/test-parsing.cc.
#include <unordered_map>
#include "include/v8.h"
#include "src/api.h"
#include "src/handles-inl.h"
#include "src/isolate.h"
#include "src/utils.h"
#include "test/cctest/cctest.h"
using namespace v8::internal;
TEST(EagerlyCompileImmediateUseFunctions) {
if (!FLAG_lazy) return;
// Test parenthesized, exclaimed, and regular functions. Make sure these
// occur both intermixed and after each other, to make sure the 'reset'
// mechanism works.
const char src[] =
"function normal() { var a; }\n" // Normal: Should lazy parse.
"(function parenthesized() { var b; })()\n" // Parenthesized: Pre-parse.
"!function exclaimed() { var c; }() \n" // Exclaimed: Pre-parse.
"function normal2() { var d; }\n"
"(function parenthesized2() { var e; })()\n"
"function normal3() { var f; }\n"
"!function exclaimed2() { var g; }() \n"
"function normal4() { var h; }\n";
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
LocalContext env;
// Compile src & record the 'compiled' state of all top level functions in
// is_compiled.
std::unordered_map<std::string, bool> is_compiled;
{
v8::Local<v8::Script> api_script = v8_compile(src);
Handle<JSFunction> toplevel_fn = v8::Utils::OpenHandle(*api_script);
Handle<Script> script =
handle(Script::cast(toplevel_fn->shared()->script()));
WeakFixedArray::Iterator iter(script->shared_function_infos());
while (SharedFunctionInfo* shared = iter.Next<SharedFunctionInfo>()) {
std::unique_ptr<char[]> name = String::cast(shared->name())->ToCString();
is_compiled[name.get()] = shared->is_compiled();
}
}
DCHECK(is_compiled.find("normal") != is_compiled.end());
DCHECK(is_compiled["parenthesized"]);
DCHECK(is_compiled["parenthesized2"]);
DCHECK(is_compiled["exclaimed"]);
DCHECK(is_compiled["exclaimed2"]);
DCHECK(!is_compiled["normal"]);
DCHECK(!is_compiled["normal2"]);
DCHECK(!is_compiled["normal3"]);
DCHECK(!is_compiled["normal4"]);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment