Commit 723bed31 authored by ager@chromium.org's avatar ager@chromium.org

Optimize calls to evals. Most of the time there is no reason to

perform a context lookup in the runtime system for the 'eval'
function. Instead load the 'eval' function from the global context in
generated code if it is not shadowed.

Will port to other platforms as a separate change.

Review URL: http://codereview.chromium.org/2666001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4794 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ed90d564
......@@ -5762,26 +5762,66 @@ void CodeGenerator::VisitCall(Call* node) {
// Allocate a frame slot for the receiver.
frame_->Push(Factory::undefined_value());
// Load the arguments.
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
frame_->SpillTop();
}
// Prepare the stack for the call to ResolvePossiblyDirectEval.
// Result to hold the result of the function resolution and the
// final result of the eval call.
Result result;
// If we know that eval can only be shadowed by eval-introduced
// variables we attempt to load the global eval function directly
// in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
JumpTarget done;
if (var->slot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
ASSERT(var->slot()->type() == Slot::LOOKUP);
JumpTarget slow;
// Prepare the stack for the call to
// ResolvePossiblyDirectEvalNoLookup by pushing the loaded
// function, the first argument to the eval call and the
// receiver.
Result fun = LoadFromGlobalSlotCheckExtensions(var->slot(),
NOT_INSIDE_TYPEOF,
&slow);
frame_->Push(&fun);
if (arg_count > 0) {
frame_->PushElementAt(arg_count);
} else {
frame_->Push(Factory::undefined_value());
}
frame_->PushParameterAt(-1);
// Resolve the call.
result =
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 3);
done.Jump(&result);
slow.Bind();
}
// Prepare the stack for the call to ResolvePossiblyDirectEval by
// pushing the loaded function, the first argument to the eval
// call and the receiver.
frame_->PushElementAt(arg_count + 1);
if (arg_count > 0) {
frame_->PushElementAt(arg_count);
} else {
frame_->Push(Factory::undefined_value());
}
// Push the receiver.
frame_->PushParameterAt(-1);
// Resolve the call.
Result result =
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// If we generated fast-case code bind the jump-target where fast
// and slow case merge.
if (done.is_linked()) done.Bind(&result);
// The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values.
......
......@@ -7245,6 +7245,24 @@ static Object* Runtime_CompileString(Arguments args) {
}
static ObjectPair CompileGlobalEval(Handle<String> source,
Handle<Object> receiver) {
// Deal with a normal eval call with a string argument. Compile it
// and return the compiled function bound in the local context.
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source,
Handle<Context>(Top::context()),
Top::context()->IsGlobalContext(),
Compiler::DONT_VALIDATE_JSON);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
shared,
Handle<Context>(Top::context()),
NOT_TENURED);
return MakePair(*compiled, *receiver);
}
static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ASSERT(args.length() == 3);
if (!args[0]->IsJSFunction()) {
......@@ -7310,20 +7328,27 @@ static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
return MakePair(*callee, Top::context()->global()->global_receiver());
}
// Deal with a normal eval call with a string argument. Compile it
// and return the compiled function bound in the local context.
Handle<String> source = args.at<String>(1);
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source,
Handle<Context>(Top::context()),
Top::context()->IsGlobalContext(),
Compiler::DONT_VALIDATE_JSON);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
callee = Factory::NewFunctionFromSharedFunctionInfo(
shared,
Handle<Context>(Top::context()),
NOT_TENURED);
return MakePair(*callee, args[2]);
return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
}
static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ASSERT(args.length() == 3);
if (!args[0]->IsJSFunction()) {
return MakePair(Top::ThrowIllegalOperation(), NULL);
}
HandleScope scope;
Handle<JSFunction> callee = args.at<JSFunction>(0);
// 'eval' is bound in the global context, but it may have been overwritten.
// Compare it to the builtin 'GlobalEval' function to make sure.
if (*callee != Top::global_context()->global_eval_fun() ||
!args[1]->IsString()) {
return MakePair(*callee, Top::context()->global()->global_receiver());
}
return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
}
......
......@@ -222,6 +222,7 @@ namespace internal {
/* Eval */ \
F(GlobalReceiver, 1, 1) \
F(ResolvePossiblyDirectEval, 3, 2) \
F(ResolvePossiblyDirectEvalNoLookup, 3, 2) \
\
F(SetProperty, -1 /* 3 or 4 */, 1) \
F(DefineOrRedefineDataProperty, 4, 1) \
......
......@@ -50,7 +50,7 @@ global_eval = eval;
assertEquals(void 0, eval(eval("var eval = function f(x) { return 'hest';}")))
eval = global_eval;
//Test eval with different number of parameters.
// Test eval with different number of parameters.
global_eval = eval;
eval = function(x, y) { return x + y; };
assertEquals(4, eval(2, 2));
......
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