Use shared function info for eval cache key.

R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/678843004

Cr-Commit-Position: refs/heads/master@{#24927}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24927 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-10-28 10:00:37 +00:00
parent ef1ca7a2ed
commit 0dfbf83468
15 changed files with 113 additions and 85 deletions

View File

@ -2944,13 +2944,16 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
// r4: copy of the first argument or undefined if it doesn't exist.
// r5: copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ ldr(r4, MemOperand(sp, arg_count * kPointerSize));
__ ldr(r5, MemOperand(sp, arg_count * kPointerSize));
} else {
__ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
}
// r4: the receiver of the enclosing function.
__ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
// r3: the receiver of the enclosing function.
int receiver_offset = 2 + info_->scope()->num_parameters();
__ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize));
@ -2962,8 +2965,9 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ mov(r1, Operand(Smi::FromInt(scope()->start_position())));
// Do the runtime call.
__ Push(r5);
__ Push(r4, r3, r2, r1);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}

View File

@ -2609,11 +2609,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
// Prepare to push a copy of the first argument or undefined if it doesn't
// exist.
if (arg_count > 0) {
__ Peek(x10, arg_count * kXRegSize);
__ Peek(x9, arg_count * kXRegSize);
} else {
__ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
__ LoadRoot(x9, Heap::kUndefinedValueRootIndex);
}
__ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
// Prepare to push the receiver of the enclosing function.
int receiver_offset = 2 + info_->scope()->num_parameters();
__ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize));
@ -2624,10 +2625,10 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ Mov(x13, Smi::FromInt(scope()->start_position()));
// Push.
__ Push(x10, x11, x12, x13);
__ Push(x9, x10, x11, x12, x13);
// Do the runtime call.
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}

View File

@ -221,10 +221,8 @@ void CompilationCacheScript::Put(Handle<String> source,
MaybeHandle<SharedFunctionInfo> CompilationCacheEval::Lookup(
Handle<String> source,
Handle<Context> context,
StrictMode strict_mode,
int scope_position) {
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
StrictMode strict_mode, int scope_position) {
HandleScope scope(isolate());
// Make sure not to leak the table into the surrounding handle
// scope. Otherwise, we risk keeping old tables around even after
@ -233,14 +231,14 @@ MaybeHandle<SharedFunctionInfo> CompilationCacheEval::Lookup(
int generation;
for (generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
result = table->LookupEval(source, context, strict_mode, scope_position);
result = table->LookupEval(source, outer_info, strict_mode, scope_position);
if (result->IsSharedFunctionInfo()) break;
}
if (result->IsSharedFunctionInfo()) {
Handle<SharedFunctionInfo> function_info =
Handle<SharedFunctionInfo>::cast(result);
if (generation != 0) {
Put(source, context, function_info, scope_position);
Put(source, outer_info, function_info, scope_position);
}
isolate()->counters()->compilation_cache_hits()->Increment();
return scope.CloseAndEscape(function_info);
@ -252,12 +250,12 @@ MaybeHandle<SharedFunctionInfo> CompilationCacheEval::Lookup(
void CompilationCacheEval::Put(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> outer_info,
Handle<SharedFunctionInfo> function_info,
int scope_position) {
HandleScope scope(isolate());
Handle<CompilationCacheTable> table = GetFirstTable();
table = CompilationCacheTable::PutEval(table, source, context,
table = CompilationCacheTable::PutEval(table, source, outer_info,
function_info, scope_position);
SetFirstTable(table);
}
@ -324,20 +322,18 @@ MaybeHandle<SharedFunctionInfo> CompilationCache::LookupScript(
MaybeHandle<SharedFunctionInfo> CompilationCache::LookupEval(
Handle<String> source,
Handle<Context> context,
StrictMode strict_mode,
int scope_position) {
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<Context> context, StrictMode strict_mode, int scope_position) {
if (!IsEnabled()) return MaybeHandle<SharedFunctionInfo>();
MaybeHandle<SharedFunctionInfo> result;
if (context->IsNativeContext()) {
result = eval_global_.Lookup(
source, context, strict_mode, scope_position);
result =
eval_global_.Lookup(source, outer_info, strict_mode, scope_position);
} else {
DCHECK(scope_position != RelocInfo::kNoPosition);
result = eval_contextual_.Lookup(
source, context, strict_mode, scope_position);
result = eval_contextual_.Lookup(source, outer_info, strict_mode,
scope_position);
}
return result;
}
@ -361,6 +357,7 @@ void CompilationCache::PutScript(Handle<String> source,
void CompilationCache::PutEval(Handle<String> source,
Handle<SharedFunctionInfo> outer_info,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info,
int scope_position) {
@ -368,10 +365,10 @@ void CompilationCache::PutEval(Handle<String> source,
HandleScope scope(isolate());
if (context->IsNativeContext()) {
eval_global_.Put(source, context, function_info, scope_position);
eval_global_.Put(source, outer_info, function_info, scope_position);
} else {
DCHECK(scope_position != RelocInfo::kNoPosition);
eval_contextual_.Put(source, context, function_info, scope_position);
eval_contextual_.Put(source, outer_info, function_info, scope_position);
}
}

View File

@ -114,14 +114,12 @@ class CompilationCacheEval: public CompilationSubCache {
: CompilationSubCache(isolate, generations) { }
MaybeHandle<SharedFunctionInfo> Lookup(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> outer_info,
StrictMode strict_mode,
int scope_position);
void Put(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info,
int scope_position);
void Put(Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<SharedFunctionInfo> function_info, int scope_position);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheEval);
@ -161,8 +159,8 @@ class CompilationCache {
// given context. Returns an empty handle if the cache doesn't
// contain a script for the given source string.
MaybeHandle<SharedFunctionInfo> LookupEval(
Handle<String> source, Handle<Context> context, StrictMode strict_mode,
int scope_position);
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<Context> context, StrictMode strict_mode, int scope_position);
// Returns the regexp data associated with the given regexp if it
// is in cache, otherwise an empty handle.
@ -177,10 +175,9 @@ class CompilationCache {
// Associate the (source, context->closure()->shared(), kind) triple
// with the shared function info. This may overwrite an existing mapping.
void PutEval(Handle<String> source,
void PutEval(Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<Context> context,
Handle<SharedFunctionInfo> function_info,
int scope_position);
Handle<SharedFunctionInfo> function_info, int scope_position);
// Associate the (source, flags) pair to the given regexp data.
// This may overwrite an existing mapping.

View File

@ -1096,11 +1096,9 @@ static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
Handle<String> source,
Handle<Context> context,
StrictMode strict_mode,
ParseRestriction restriction,
int scope_position) {
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<Context> context, StrictMode strict_mode,
ParseRestriction restriction, int scope_position) {
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_eval_size()->Increment(source_length);
@ -1108,7 +1106,7 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
CompilationCache* compilation_cache = isolate->compilation_cache();
MaybeHandle<SharedFunctionInfo> maybe_shared_info =
compilation_cache->LookupEval(source, context, strict_mode,
compilation_cache->LookupEval(source, outer_info, context, strict_mode,
scope_position);
Handle<SharedFunctionInfo> shared_info;
@ -1135,8 +1133,8 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
// If caller is strict mode, the result must be in strict mode as well.
DCHECK(strict_mode == SLOPPY || shared_info->strict_mode() == STRICT);
if (!shared_info->dont_cache()) {
compilation_cache->PutEval(
source, context, shared_info, scope_position);
compilation_cache->PutEval(source, outer_info, context, shared_info,
scope_position);
}
}
} else if (shared_info->ic_age() != isolate->heap()->global_ic_age()) {

View File

@ -684,11 +684,9 @@ class Compiler : public AllStatic {
// Compile a String source within a context for eval.
MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
Handle<String> source,
Handle<Context> context,
StrictMode strict_mode,
ParseRestriction restriction,
int scope_position);
Handle<String> source, Handle<SharedFunctionInfo> outer_info,
Handle<Context> context, StrictMode strict_mode,
ParseRestriction restriction, int scope_position);
// Compile a String source within a context.
static Handle<SharedFunctionInfo> CompileScript(

View File

@ -1308,12 +1308,14 @@ void AstGraphBuilder::VisitCall(Call* expr) {
// Create node to ask for help resolving potential eval call. This will
// provide a fully resolved callee and the corresponding receiver.
Node* function = GetFunctionClosure();
Node* receiver = environment()->Lookup(info()->scope()->receiver());
Node* strict = jsgraph()->Constant(strict_mode());
Node* position = jsgraph()->Constant(info()->scope()->start_position());
const Operator* op =
javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
Node* pair = NewNode(op, callee, source, receiver, strict, position);
javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
Node* pair =
NewNode(op, callee, source, function, receiver, strict, position);
PrepareFrameState(pair, expr->EvalOrLookupId(),
OutputFrameStateCombine::PokeAt(arg_count + 1));
Node* new_callee = NewNode(common()->Projection(0), pair);

View File

@ -2857,6 +2857,8 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ push(Immediate(isolate()->factory()->undefined_value()));
}
// Push the enclosing function.
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
// Push the receiver of the enclosing function.
__ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
// Push the language mode.
@ -2866,7 +2868,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ push(Immediate(Smi::FromInt(scope()->start_position())));
// Do the runtime call.
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}

View File

@ -14845,13 +14845,13 @@ Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
}
Handle<Object> CompilationCacheTable::LookupEval(Handle<String> src,
Handle<Context> context,
StrictMode strict_mode,
int scope_position) {
Handle<Object> CompilationCacheTable::LookupEval(
Handle<String> src, Handle<SharedFunctionInfo> outer_info,
StrictMode strict_mode, int scope_position) {
Isolate* isolate = GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
StringSharedKey key(src, shared, strict_mode, scope_position);
// Cache key is the tuple (source, outer shared function info, scope position)
// to unambiguously identify the context chain the cached eval code assumes.
StringSharedKey key(src, outer_info, strict_mode, scope_position);
int entry = FindEntry(&key);
if (entry == kNotFound) return isolate->factory()->undefined_value();
return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
@ -14888,11 +14888,10 @@ Handle<CompilationCacheTable> CompilationCacheTable::Put(
Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<Context> context, Handle<SharedFunctionInfo> value,
Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
int scope_position) {
Isolate* isolate = cache->GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
StringSharedKey key(src, shared, value->strict_mode(), scope_position);
StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
cache = EnsureCapacity(cache, 1, &key);
Handle<Object> k = key.AsHandle(isolate);
int entry = cache->FindInsertionEntry(key.Hash());

View File

@ -7943,15 +7943,16 @@ class CompilationCacheTable: public HashTable<CompilationCacheTable,
public:
// Find cached value for a string key, otherwise return null.
Handle<Object> Lookup(Handle<String> src, Handle<Context> context);
Handle<Object> LookupEval(Handle<String> src, Handle<Context> context,
StrictMode strict_mode, int scope_position);
Handle<Object> LookupEval(Handle<String> src,
Handle<SharedFunctionInfo> shared,
StrictMode strict_mode, int scope_position);
Handle<Object> LookupRegExp(Handle<String> source, JSRegExp::Flags flags);
static Handle<CompilationCacheTable> Put(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<Context> context, Handle<Object> value);
static Handle<CompilationCacheTable> PutEval(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<Context> context, Handle<SharedFunctionInfo> value,
Handle<SharedFunctionInfo> context, Handle<SharedFunctionInfo> value,
int scope_position);
static Handle<CompilationCacheTable> PutRegExp(
Handle<CompilationCacheTable> cache, Handle<String> src,

View File

@ -369,16 +369,18 @@ RUNTIME_FUNCTION(Runtime_CompileString) {
ParseRestriction restriction = function_literal_only
? ONLY_SINGLE_FUNCTION_LITERAL
: NO_PARSE_RESTRICTION;
Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
Handle<JSFunction> fun;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, fun,
Compiler::GetFunctionFromEval(source, context, SLOPPY, restriction,
RelocInfo::kNoPosition));
Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
restriction, RelocInfo::kNoPosition));
return *fun;
}
static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
Handle<SharedFunctionInfo> outer_info,
Handle<Object> receiver,
StrictMode strict_mode,
int scope_position) {
@ -404,8 +406,8 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
Handle<JSFunction> compiled;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, compiled,
Compiler::GetFunctionFromEval(source, context, strict_mode, restriction,
scope_position),
Compiler::GetFunctionFromEval(source, outer_info, context, strict_mode,
restriction, scope_position),
MakePair(isolate->heap()->exception(), NULL));
return MakePair(*compiled, *receiver);
}
@ -413,7 +415,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
HandleScope scope(isolate);
DCHECK(args.length() == 5);
DCHECK(args.length() == 6);
Handle<Object> callee = args.at<Object>(0);
@ -427,12 +429,14 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
return MakePair(*callee, isolate->heap()->undefined_value());
}
DCHECK(args[3]->IsSmi());
DCHECK(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT);
StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3));
DCHECK(args[4]->IsSmi());
return CompileGlobalEval(isolate, args.at<String>(1), args.at<Object>(2),
strict_mode, args.smi_at(4));
DCHECK(args.smi_at(4) == SLOPPY || args.smi_at(4) == STRICT);
StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(4));
DCHECK(args[5]->IsSmi());
Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
isolate);
return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
args.at<Object>(3), strict_mode, args.smi_at(5));
}
}
} // namespace v8::internal

View File

@ -2043,6 +2043,7 @@ MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
// Compile and evaluate source for the given context.
static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
Handle<SharedFunctionInfo> outer_info,
Handle<Context> context,
Handle<Object> context_extension,
Handle<Object> receiver,
@ -2054,11 +2055,11 @@ static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
}
Handle<JSFunction> eval_fun;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, eval_fun, Compiler::GetFunctionFromEval(source, context, SLOPPY,
NO_PARSE_RESTRICTION,
RelocInfo::kNoPosition),
Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
Compiler::GetFunctionFromEval(
source, outer_info, context, SLOPPY,
NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
Object);
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
@ -2118,6 +2119,7 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
JavaScriptFrame* frame = it.frame();
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
Handle<SharedFunctionInfo> outer_info(function->shared());
// Traverse the saved contexts chain to find the active context for the
// selected frame.
@ -2177,8 +2179,8 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
}
Handle<Object> receiver(frame->receiver(), isolate);
MaybeHandle<Object> maybe_result =
DebugEvaluate(isolate, eval_context, context_extension, receiver, source);
MaybeHandle<Object> maybe_result = DebugEvaluate(
isolate, outer_info, eval_context, context_extension, receiver, source);
// Remove with-context if it was inserted in between.
if (!inner_context.is_null()) inner_context->set_previous(*function_context);
@ -2224,10 +2226,11 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
// debugger was invoked.
Handle<Context> context = isolate->native_context();
Handle<JSObject> receiver(context->global_proxy());
Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
DebugEvaluate(isolate, context, context_extension, receiver, source));
isolate, result, DebugEvaluate(isolate, outer_info, context,
context_extension, receiver, source));
return *result;
}

View File

@ -521,7 +521,7 @@ namespace internal {
#define RUNTIME_FUNCTION_LIST_RETURN_PAIR(F) \
F(LoadLookupSlot, 2, 2) \
F(LoadLookupSlotNoReferenceError, 2, 2) \
F(ResolvePossiblyDirectEval, 5, 2) \
F(ResolvePossiblyDirectEval, 6, 2) \
F(ForInInit, 2, 2) /* TODO(turbofan): Only temporary */ \
F(ForInNext, 4, 2) /* TODO(turbofan): Only temporary */

View File

@ -2855,6 +2855,9 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
}
// Push the enclosing function.
__ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
// Push the receiver of the enclosing function and do runtime call.
StackArgumentsAccessor args(rbp, info_->scope()->num_parameters());
__ Push(args.GetReceiverOperand());
@ -2866,7 +2869,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
__ Push(Smi::FromInt(scope()->start_position()));
// Do the runtime call.
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
}

View File

@ -0,0 +1,19 @@
// Copyright 2014 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.
(function f() {
try {
throw 1;
} catch (e) {
var a = 0;
var b = 0;
var c = 0;
var x = 1;
var result = eval('eval("x")').toString();
assertEquals("1", result);
}
var x = 2;
var result = eval('eval("x")').toString();
assertEquals("2", result);
})();