Commit 3348b5c2 authored by rossberg@chromium.org's avatar rossberg@chromium.org

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
parent 3388f92e
......@@ -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;
......
// 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
);
})();
)();
})());
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