Allow closures to be optimized if outer contexts that call eval are all in strict mode.
R=kmillikin@chromium.org BUG= TEST=mjsunit/compiler/eval-introduced-closure.js Review URL: http://codereview.chromium.org/6993008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7853 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
fa2a92b45f
commit
8a0b1f5bc9
@ -99,7 +99,7 @@ void CompilationInfo::DisableOptimization() {
|
|||||||
FLAG_optimize_closures &&
|
FLAG_optimize_closures &&
|
||||||
closure_.is_null() &&
|
closure_.is_null() &&
|
||||||
!scope_->HasTrivialOuterContext() &&
|
!scope_->HasTrivialOuterContext() &&
|
||||||
!scope_->outer_scope_calls_eval() &&
|
!scope_->outer_scope_calls_non_strict_eval() &&
|
||||||
!scope_->inside_with();
|
!scope_->inside_with();
|
||||||
SetMode(is_optimizable_closure ? BASE : NONOPT);
|
SetMode(is_optimizable_closure ? BASE : NONOPT);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
@ -243,6 +243,27 @@ bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
|
||||||
|
bool* outer_scope_calls_non_strict_eval) {
|
||||||
|
Context* context = this;
|
||||||
|
while (true) {
|
||||||
|
Handle<SerializedScopeInfo> scope_info(
|
||||||
|
context->closure()->shared()->scope_info());
|
||||||
|
if (scope_info->CallsEval()) {
|
||||||
|
*outer_scope_calls_eval = true;
|
||||||
|
if (!scope_info->IsStrictMode()) {
|
||||||
|
// No need to go further since the answers will not change
|
||||||
|
// from here.
|
||||||
|
*outer_scope_calls_non_strict_eval = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context->IsGlobalContext()) break;
|
||||||
|
context = Context::cast(context->closure()->context());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Context::AddOptimizedFunction(JSFunction* function) {
|
void Context::AddOptimizedFunction(JSFunction* function) {
|
||||||
ASSERT(IsGlobalContext());
|
ASSERT(IsGlobalContext());
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -351,6 +351,11 @@ class Context: public FixedArray {
|
|||||||
// eval.
|
// eval.
|
||||||
bool GlobalIfNotShadowedByEval(Handle<String> name);
|
bool GlobalIfNotShadowedByEval(Handle<String> name);
|
||||||
|
|
||||||
|
// Determine if any function scope in the context call eval and if
|
||||||
|
// any of those calls are in non-strict mode.
|
||||||
|
void ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
|
||||||
|
bool* outer_scope_calls_non_strict_eval);
|
||||||
|
|
||||||
// Code generation support.
|
// Code generation support.
|
||||||
static int SlotOffset(int index) {
|
static int SlotOffset(int index) {
|
||||||
return kHeaderSize + index * kPointerSize - kHeapObjectTag;
|
return kHeaderSize + index * kPointerSize - kHeapObjectTag;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
@ -52,6 +52,7 @@ template<class Allocator>
|
|||||||
ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
|
ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
|
||||||
: function_name_(FACTORY->empty_symbol()),
|
: function_name_(FACTORY->empty_symbol()),
|
||||||
calls_eval_(scope->calls_eval()),
|
calls_eval_(scope->calls_eval()),
|
||||||
|
is_strict_mode_(scope->is_strict_mode()),
|
||||||
parameters_(scope->num_parameters()),
|
parameters_(scope->num_parameters()),
|
||||||
stack_slots_(scope->num_stack_slots()),
|
stack_slots_(scope->num_stack_slots()),
|
||||||
context_slots_(scope->num_heap_slots()),
|
context_slots_(scope->num_heap_slots()),
|
||||||
@ -248,6 +249,7 @@ ScopeInfo<Allocator>::ScopeInfo(SerializedScopeInfo* data)
|
|||||||
Object** p = p0;
|
Object** p = p0;
|
||||||
p = ReadSymbol(p, &function_name_);
|
p = ReadSymbol(p, &function_name_);
|
||||||
p = ReadBool(p, &calls_eval_);
|
p = ReadBool(p, &calls_eval_);
|
||||||
|
p = ReadBool(p, &is_strict_mode_);
|
||||||
p = ReadList<Allocator>(p, &context_slots_, &context_modes_);
|
p = ReadList<Allocator>(p, &context_slots_, &context_modes_);
|
||||||
p = ReadList<Allocator>(p, ¶meters_);
|
p = ReadList<Allocator>(p, ¶meters_);
|
||||||
p = ReadList<Allocator>(p, &stack_slots_);
|
p = ReadList<Allocator>(p, &stack_slots_);
|
||||||
@ -301,8 +303,8 @@ static Object** WriteList(Object** p,
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
|
Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
|
||||||
// function name, calls eval, length for 3 tables:
|
// function name, calls eval, is_strict_mode, length for 3 tables:
|
||||||
const int extra_slots = 1 + 1 + 3;
|
const int extra_slots = 1 + 1 + 1 + 3;
|
||||||
int length = extra_slots +
|
int length = extra_slots +
|
||||||
context_slots_.length() * 2 +
|
context_slots_.length() * 2 +
|
||||||
parameters_.length() +
|
parameters_.length() +
|
||||||
@ -316,6 +318,7 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
|
|||||||
Object** p = p0;
|
Object** p = p0;
|
||||||
p = WriteSymbol(p, function_name_);
|
p = WriteSymbol(p, function_name_);
|
||||||
p = WriteBool(p, calls_eval_);
|
p = WriteBool(p, calls_eval_);
|
||||||
|
p = WriteBool(p, is_strict_mode_);
|
||||||
p = WriteList(p, &context_slots_, &context_modes_);
|
p = WriteList(p, &context_slots_, &context_modes_);
|
||||||
p = WriteList(p, ¶meters_);
|
p = WriteList(p, ¶meters_);
|
||||||
p = WriteList(p, &stack_slots_);
|
p = WriteList(p, &stack_slots_);
|
||||||
@ -363,7 +366,8 @@ SerializedScopeInfo* SerializedScopeInfo::Empty() {
|
|||||||
|
|
||||||
Object** SerializedScopeInfo::ContextEntriesAddr() {
|
Object** SerializedScopeInfo::ContextEntriesAddr() {
|
||||||
ASSERT(length() > 0);
|
ASSERT(length() > 0);
|
||||||
return data_start() + 2; // +2 for function name and calls eval.
|
// +3 for function name, calls eval, strict mode.
|
||||||
|
return data_start() + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -392,7 +396,18 @@ bool SerializedScopeInfo::CallsEval() {
|
|||||||
p = ReadBool(p, &calls_eval);
|
p = ReadBool(p, &calls_eval);
|
||||||
return calls_eval;
|
return calls_eval;
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SerializedScopeInfo::IsStrictMode() {
|
||||||
|
if (length() > 0) {
|
||||||
|
Object** p = data_start() + 2; // +2 for function name, calls eval.
|
||||||
|
bool strict_mode;
|
||||||
|
p = ReadBool(p, &strict_mode);
|
||||||
|
return strict_mode;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
@ -93,6 +93,7 @@ class ScopeInfo BASE_EMBEDDED {
|
|||||||
private:
|
private:
|
||||||
Handle<String> function_name_;
|
Handle<String> function_name_;
|
||||||
bool calls_eval_;
|
bool calls_eval_;
|
||||||
|
bool is_strict_mode_;
|
||||||
List<Handle<String>, Allocator > parameters_;
|
List<Handle<String>, Allocator > parameters_;
|
||||||
List<Handle<String>, Allocator > stack_slots_;
|
List<Handle<String>, Allocator > stack_slots_;
|
||||||
List<Handle<String>, Allocator > context_slots_;
|
List<Handle<String>, Allocator > context_slots_;
|
||||||
@ -113,6 +114,9 @@ class SerializedScopeInfo : public FixedArray {
|
|||||||
// Does this scope call eval?
|
// Does this scope call eval?
|
||||||
bool CallsEval();
|
bool CallsEval();
|
||||||
|
|
||||||
|
// Is this scope a strict mode scope?
|
||||||
|
bool IsStrictMode();
|
||||||
|
|
||||||
// Does this scope have an arguments shadow?
|
// Does this scope have an arguments shadow?
|
||||||
bool HasArgumentsShadow() {
|
bool HasArgumentsShadow() {
|
||||||
return StackSlotIndex(GetHeap()->arguments_shadow_symbol()) >= 0;
|
return StackSlotIndex(GetHeap()->arguments_shadow_symbol()) >= 0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
@ -199,6 +199,7 @@ void Scope::SetDefaults(Type type,
|
|||||||
// Inherit the strict mode from the parent scope.
|
// Inherit the strict mode from the parent scope.
|
||||||
strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
|
strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
|
||||||
outer_scope_calls_eval_ = false;
|
outer_scope_calls_eval_ = false;
|
||||||
|
outer_scope_calls_non_strict_eval_ = false;
|
||||||
inner_scope_calls_eval_ = false;
|
inner_scope_calls_eval_ = false;
|
||||||
outer_scope_is_eval_scope_ = false;
|
outer_scope_is_eval_scope_ = false;
|
||||||
force_eager_compilation_ = false;
|
force_eager_compilation_ = false;
|
||||||
@ -483,8 +484,17 @@ void Scope::AllocateVariables(Handle<Context> context) {
|
|||||||
// and assume they may invoke eval themselves. Eventually we could capture
|
// and assume they may invoke eval themselves. Eventually we could capture
|
||||||
// this information in the ScopeInfo and then use it here (by traversing
|
// this information in the ScopeInfo and then use it here (by traversing
|
||||||
// the call chain stack, at compile time).
|
// the call chain stack, at compile time).
|
||||||
|
|
||||||
bool eval_scope = is_eval_scope();
|
bool eval_scope = is_eval_scope();
|
||||||
PropagateScopeInfo(eval_scope, eval_scope);
|
bool outer_scope_calls_eval = false;
|
||||||
|
bool outer_scope_calls_non_strict_eval = false;
|
||||||
|
if (!is_global_scope()) {
|
||||||
|
context->ComputeEvalScopeInfo(&outer_scope_calls_eval,
|
||||||
|
&outer_scope_calls_non_strict_eval);
|
||||||
|
}
|
||||||
|
PropagateScopeInfo(outer_scope_calls_eval,
|
||||||
|
outer_scope_calls_non_strict_eval,
|
||||||
|
eval_scope);
|
||||||
|
|
||||||
// 2) Resolve variables.
|
// 2) Resolve variables.
|
||||||
Scope* global_scope = NULL;
|
Scope* global_scope = NULL;
|
||||||
@ -616,10 +626,14 @@ void Scope::Print(int n) {
|
|||||||
if (HasTrivialOuterContext()) {
|
if (HasTrivialOuterContext()) {
|
||||||
Indent(n1, "// scope has trivial outer context\n");
|
Indent(n1, "// scope has trivial outer context\n");
|
||||||
}
|
}
|
||||||
|
if (is_strict_mode()) Indent(n1, "// strict mode scope\n");
|
||||||
if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
|
if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
|
||||||
if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
|
if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
|
||||||
if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
|
if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
|
||||||
if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
|
if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
|
||||||
|
if (outer_scope_calls_non_strict_eval_) {
|
||||||
|
Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
|
||||||
|
}
|
||||||
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
|
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
|
||||||
if (outer_scope_is_eval_scope_) {
|
if (outer_scope_is_eval_scope_) {
|
||||||
Indent(n1, "// outer scope is 'eval' scope\n");
|
Indent(n1, "// outer scope is 'eval' scope\n");
|
||||||
@ -846,20 +860,30 @@ void Scope::ResolveVariablesRecursively(Scope* global_scope,
|
|||||||
|
|
||||||
|
|
||||||
bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
|
bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
|
||||||
|
bool outer_scope_calls_non_strict_eval,
|
||||||
bool outer_scope_is_eval_scope) {
|
bool outer_scope_is_eval_scope) {
|
||||||
if (outer_scope_calls_eval) {
|
if (outer_scope_calls_eval) {
|
||||||
outer_scope_calls_eval_ = true;
|
outer_scope_calls_eval_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outer_scope_calls_non_strict_eval) {
|
||||||
|
outer_scope_calls_non_strict_eval_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (outer_scope_is_eval_scope) {
|
if (outer_scope_is_eval_scope) {
|
||||||
outer_scope_is_eval_scope_ = true;
|
outer_scope_is_eval_scope_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
|
bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
|
||||||
bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
|
bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
|
||||||
|
bool calls_non_strict_eval =
|
||||||
|
(scope_calls_eval_ && !is_strict_mode()) ||
|
||||||
|
outer_scope_calls_non_strict_eval_;
|
||||||
for (int i = 0; i < inner_scopes_.length(); i++) {
|
for (int i = 0; i < inner_scopes_.length(); i++) {
|
||||||
Scope* inner_scope = inner_scopes_[i];
|
Scope* inner_scope = inner_scopes_[i];
|
||||||
if (inner_scope->PropagateScopeInfo(calls_eval, is_eval)) {
|
if (inner_scope->PropagateScopeInfo(calls_eval,
|
||||||
|
calls_non_strict_eval,
|
||||||
|
is_eval)) {
|
||||||
inner_scope_calls_eval_ = true;
|
inner_scope_calls_eval_ = true;
|
||||||
}
|
}
|
||||||
if (inner_scope->force_eager_compilation_) {
|
if (inner_scope->force_eager_compilation_) {
|
||||||
|
@ -218,6 +218,9 @@ class Scope: public ZoneObject {
|
|||||||
// Information about which scopes calls eval.
|
// Information about which scopes calls eval.
|
||||||
bool calls_eval() const { return scope_calls_eval_; }
|
bool calls_eval() const { return scope_calls_eval_; }
|
||||||
bool outer_scope_calls_eval() const { return outer_scope_calls_eval_; }
|
bool outer_scope_calls_eval() const { return outer_scope_calls_eval_; }
|
||||||
|
bool outer_scope_calls_non_strict_eval() const {
|
||||||
|
return outer_scope_calls_non_strict_eval_;
|
||||||
|
}
|
||||||
|
|
||||||
// Is this scope inside a with statement.
|
// Is this scope inside a with statement.
|
||||||
bool inside_with() const { return scope_inside_with_; }
|
bool inside_with() const { return scope_inside_with_; }
|
||||||
@ -372,6 +375,7 @@ class Scope: public ZoneObject {
|
|||||||
|
|
||||||
// Computed via PropagateScopeInfo.
|
// Computed via PropagateScopeInfo.
|
||||||
bool outer_scope_calls_eval_;
|
bool outer_scope_calls_eval_;
|
||||||
|
bool outer_scope_calls_non_strict_eval_;
|
||||||
bool inner_scope_calls_eval_;
|
bool inner_scope_calls_eval_;
|
||||||
bool outer_scope_is_eval_scope_;
|
bool outer_scope_is_eval_scope_;
|
||||||
bool force_eager_compilation_;
|
bool force_eager_compilation_;
|
||||||
@ -400,6 +404,7 @@ class Scope: public ZoneObject {
|
|||||||
|
|
||||||
// Scope analysis.
|
// Scope analysis.
|
||||||
bool PropagateScopeInfo(bool outer_scope_calls_eval,
|
bool PropagateScopeInfo(bool outer_scope_calls_eval,
|
||||||
|
bool outer_scope_calls_non_strict_eval,
|
||||||
bool outer_scope_is_eval_scope);
|
bool outer_scope_is_eval_scope);
|
||||||
bool HasTrivialContext() const;
|
bool HasTrivialContext() const;
|
||||||
|
|
||||||
|
95
test/mjsunit/compiler/eval-introduced-closure.js
Normal file
95
test/mjsunit/compiler/eval-introduced-closure.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// Test that functions introduced by eval work both when there are
|
||||||
|
// strict mode and non-strict mode eval in scopes.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax
|
||||||
|
|
||||||
|
var x = 27;
|
||||||
|
|
||||||
|
function f() { return x; }
|
||||||
|
|
||||||
|
assertEquals(27, f());
|
||||||
|
|
||||||
|
function do_eval(str) {
|
||||||
|
"use strict";
|
||||||
|
return eval(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
var eval_f = do_eval('(' + f + ')');
|
||||||
|
for (var i = 0; i < 5; i++) assertEquals(27, eval_f());
|
||||||
|
%OptimizeFunctionOnNextCall(eval_f);
|
||||||
|
assertEquals(27, eval_f());
|
||||||
|
|
||||||
|
function do_eval_local(str) {
|
||||||
|
"use strict";
|
||||||
|
var x = 42;
|
||||||
|
return eval(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
eval_f = do_eval_local('(' + f + ')');
|
||||||
|
for (var i = 0; i < 5; i++) assertEquals(42, eval_f());
|
||||||
|
%OptimizeFunctionOnNextCall(eval_f);
|
||||||
|
assertEquals(42, eval_f());
|
||||||
|
|
||||||
|
function do_eval_with_other_eval_call(str) {
|
||||||
|
"use strict";
|
||||||
|
var f = eval(str);
|
||||||
|
eval('var x = 1');
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
eval_f = do_eval_with_other_eval_call('(' + f + ')');
|
||||||
|
for (var i = 0; i < 5; i++) assertEquals(27, eval_f());
|
||||||
|
%OptimizeFunctionOnNextCall(eval_f);
|
||||||
|
assertEquals(27, eval_f());
|
||||||
|
|
||||||
|
function test_non_strict_outer_eval() {
|
||||||
|
function strict_eval(str) { "use strict"; return eval(str); }
|
||||||
|
var eval_f = strict_eval('(' + f + ')');
|
||||||
|
for (var i = 0; i < 5; i++) assertEquals(27, eval_f());
|
||||||
|
%OptimizeFunctionOnNextCall(eval_f);
|
||||||
|
assertEquals(27, eval_f());
|
||||||
|
eval("var x = 3");
|
||||||
|
assertEquals(3, eval_f());
|
||||||
|
}
|
||||||
|
|
||||||
|
test_non_strict_outer_eval();
|
||||||
|
|
||||||
|
function test_strict_outer_eval() {
|
||||||
|
"use strict";
|
||||||
|
function strict_eval(str) { "use strict"; return eval(str); }
|
||||||
|
var eval_f = strict_eval('(' + f + ')');
|
||||||
|
for (var i = 0; i < 5; i++) assertEquals(27, eval_f());
|
||||||
|
%OptimizeFunctionOnNextCall(eval_f);
|
||||||
|
assertEquals(27, eval_f());
|
||||||
|
eval("var x = 3");
|
||||||
|
assertEquals(27, eval_f());
|
||||||
|
}
|
||||||
|
|
||||||
|
test_non_strict_outer_eval();
|
Loading…
Reference in New Issue
Block a user