Allow lazy compilation (and thus optimisation) of functions inside eval.
For strict-mode eval, this requires _disabling_ lazy parsing of inner functions, because we need to collect their free variables to do allocation for the eval scope properly. R=mstarzinger@chromium.org BUG=v8:2315 Review URL: https://codereview.chromium.org/11438042 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13161 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
3388f92e63
commit
3348b5c2b4
@ -351,9 +351,13 @@ class Context: public FixedArray {
|
||||
// Compute the native context by traversing the context chain.
|
||||
Context* native_context();
|
||||
|
||||
// Predicates for context types. IsNativeContext is defined on Object
|
||||
// Predicates for context types. IsNativeContext is also defined on Object
|
||||
// because we frequently have to know if arbitrary objects are natives
|
||||
// contexts.
|
||||
bool IsNativeContext() {
|
||||
Map* map = this->map();
|
||||
return map == map->GetHeap()->native_context_map();
|
||||
}
|
||||
bool IsFunctionContext() {
|
||||
Map* map = this->map();
|
||||
return map == map->GetHeap()->function_context_map();
|
||||
|
@ -156,8 +156,8 @@ class LUnallocated: public LOperand {
|
||||
};
|
||||
|
||||
static const int kMaxVirtualRegisters = 1 << kVirtualRegisterWidth;
|
||||
static const int kMaxFixedIndex = (1 << kFixedIndexWidth) - 1;
|
||||
static const int kMinFixedIndex = -(1 << kFixedIndexWidth);
|
||||
static const int kMaxFixedIndex = (1 << (kFixedIndexWidth - 1)) - 1;
|
||||
static const int kMinFixedIndex = -(1 << (kFixedIndexWidth - 1));
|
||||
|
||||
bool HasAnyPolicy() const {
|
||||
return policy() == ANY;
|
||||
|
@ -614,11 +614,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
||||
ASSERT(target_stack_ == NULL);
|
||||
if (pre_data_ != NULL) pre_data_->Initialize();
|
||||
|
||||
// Compute the parsing mode.
|
||||
Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
|
||||
if (allow_natives_syntax_ || extension_ != NULL) mode = PARSE_EAGERLY;
|
||||
ParsingModeScope parsing_mode(this, mode);
|
||||
|
||||
Handle<String> no_name = isolate()->factory()->empty_symbol();
|
||||
|
||||
FunctionLiteral* result = NULL;
|
||||
@ -637,6 +632,13 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
||||
scope->set_start_position(0);
|
||||
scope->set_end_position(source->length());
|
||||
|
||||
// Compute the parsing mode.
|
||||
Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY;
|
||||
if (allow_natives_syntax_ || extension_ != NULL || scope->is_eval_scope()) {
|
||||
mode = PARSE_EAGERLY;
|
||||
}
|
||||
ParsingModeScope parsing_mode(this, mode);
|
||||
|
||||
FunctionState function_state(this, scope, isolate()); // Enters 'scope'.
|
||||
top_scope_->SetLanguageMode(info->language_mode());
|
||||
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
|
||||
@ -1059,12 +1061,14 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
||||
// as specified in ES5 10.4.2(3). The correct fix would be to always
|
||||
// add this scope in DoParseProgram(), but that requires adaptations
|
||||
// all over the code base, so we go with a quick-fix for now.
|
||||
// In the same manner, we have to patch the parsing mode.
|
||||
if (is_eval && !top_scope_->is_eval_scope()) {
|
||||
ASSERT(top_scope_->is_global_scope());
|
||||
Scope* scope = NewScope(top_scope_, EVAL_SCOPE);
|
||||
scope->set_start_position(top_scope_->start_position());
|
||||
scope->set_end_position(top_scope_->end_position());
|
||||
top_scope_ = scope;
|
||||
mode_ = PARSE_EAGERLY;
|
||||
}
|
||||
// TODO(ES6): Fix entering extended mode, once it is specified.
|
||||
top_scope_->SetLanguageMode(FLAG_harmony_scoping
|
||||
|
@ -150,11 +150,11 @@ class PreParser {
|
||||
|
||||
// Parses a single function literal, from the opening parentheses before
|
||||
// parameters to the closing brace after the body.
|
||||
// Returns a FunctionEntry describing the body of the funciton in enough
|
||||
// Returns a FunctionEntry describing the body of the function in enough
|
||||
// detail that it can be lazily compiled.
|
||||
// The scanner is expected to have matched the "function" keyword and
|
||||
// parameters, and have consumed the initial '{'.
|
||||
// At return, unless an error occured, the scanner is positioned before the
|
||||
// At return, unless an error occurred, the scanner is positioned before the
|
||||
// the final '}'.
|
||||
PreParseResult PreParseLazyFunction(i::LanguageMode mode,
|
||||
i::ParserRecorder* log);
|
||||
|
@ -729,17 +729,12 @@ bool Scope::HasTrivialOuterContext() const {
|
||||
bool Scope::HasLazyCompilableOuterContext() const {
|
||||
Scope* outer = outer_scope_;
|
||||
if (outer == NULL) return true;
|
||||
// There are several reasons that prevent lazy compilation:
|
||||
// - This scope is inside a with scope and all declaration scopes between
|
||||
// them have empty contexts. Such declaration scopes become invisible
|
||||
// during scope info deserialization.
|
||||
// - This scope is inside a strict eval scope with variables that are
|
||||
// potentially context allocated in an artificial function scope that
|
||||
// is not deserialized correctly.
|
||||
// We have to prevent lazy compilation if this scope is inside a with scope
|
||||
// and all declaration scopes between them have empty contexts. Such
|
||||
// declaration scopes may become invisible during scope info deserialization.
|
||||
outer = outer->DeclarationScope();
|
||||
bool found_non_trivial_declarations = false;
|
||||
for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) {
|
||||
if (scope->is_eval_scope()) return false;
|
||||
if (scope->is_with_scope() && !found_non_trivial_declarations) return false;
|
||||
if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) {
|
||||
found_non_trivial_declarations = true;
|
||||
|
40
test/mjsunit/regress/regress-2315.js
Normal file
40
test/mjsunit/regress/regress-2315.js
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
var foo = (function() {
|
||||
return eval("(function bar() { return 1; })");
|
||||
})();
|
||||
|
||||
foo();
|
||||
foo();
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo();
|
||||
|
||||
// Function should be optimized now.
|
||||
assertTrue(%GetOptimizationStatus(foo) != 2);
|
@ -29,7 +29,7 @@
|
||||
// This should not hit any asserts in debug mode on ARM.
|
||||
|
||||
function function_with_n_args(n) {
|
||||
var source = '(function f(';
|
||||
var source = '(function f' + n + '(';
|
||||
for (var arg = 0; arg < n; arg++) {
|
||||
if (arg != 0) source += ',';
|
||||
source += 'arg' + arg;
|
||||
@ -50,3 +50,41 @@ for (args = 500; args < 520; args++) {
|
||||
for (args = 1019; args < 1041; args++) {
|
||||
function_with_n_args(args);
|
||||
}
|
||||
|
||||
|
||||
function foo(
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x
|
||||
) {}
|
||||
|
||||
for (var i = 0; i < 10000; ++i) foo();
|
||||
|
@ -29,25 +29,27 @@
|
||||
var filler = "//" + new Array(1024).join('x');
|
||||
|
||||
// Test strict eval in global context.
|
||||
eval(
|
||||
assertEquals(23, eval(
|
||||
"'use strict';" +
|
||||
"var x = 23;" +
|
||||
"var f = function bozo1() {" +
|
||||
" return x;" +
|
||||
"};" +
|
||||
"assertSame(23, f());" +
|
||||
"f;" +
|
||||
filler
|
||||
);
|
||||
)());
|
||||
|
||||
// Test default eval in strict context.
|
||||
(function() {
|
||||
assertEquals(42, (function() {
|
||||
"use strict";
|
||||
eval(
|
||||
return eval(
|
||||
"var y = 42;" +
|
||||
"var g = function bozo2() {" +
|
||||
" return y;" +
|
||||
"};" +
|
||||
"assertSame(42, g());" +
|
||||
"g;" +
|
||||
filler
|
||||
);
|
||||
})();
|
||||
)();
|
||||
})());
|
||||
|
Loading…
Reference in New Issue
Block a user