Commit 0c14001a authored by oliver@apple.com's avatar oliver@apple.com

Code cache stores bogus var references for functions in eval code

https://bugs.webkit.org/show_bug.cgi?id=115747

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore:

Non-global eval now uses a per-CodeBlock cache, and only use it
when we're at the top of a function's scope.  This means that we
will no longer cache the parsing of a single string across
multiple functions, and we won't cache when we're nested inside
constructs like |with| and |catch| where previously we would, which
is good because caching in those cases is unsound.

* bytecode/EvalCodeCache.h:
(JSC):
(JSC::EvalCodeCache::getSlow):
(JSC::EvalCodeCache::get):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::codeCacheForEval):
(UnlinkedCodeBlock):
(RareData):
* debugger/Debugger.cpp:
(JSC::evaluateInGlobalCallFrame):
* debugger/DebuggerCallFrame.cpp:
(JSC::DebuggerCallFrame::evaluate):
* interpreter/Interpreter.cpp:
(JSC::eval):
* runtime/CodeCache.cpp:
(JSC::CodeCache::CodeCache):
(JSC::CodeCache::generateBytecode):
(JSC):
(JSC::CodeCache::getCodeBlock):
* runtime/CodeCache.h:
(JSC::CodeCacheMap::CodeCacheMap):
(CodeCacheMap):
(JSC::CodeCacheMap::canPruneQuickly):
(JSC::CodeCacheMap::prune):
(JSC::CodeCache::create):
(CodeCache):
* runtime/Executable.cpp:
(JSC::EvalExecutable::EvalExecutable):
(JSC::EvalExecutable::compileInternal):
* runtime/Executable.h:
(JSC::EvalExecutable::create):
(EvalExecutable):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncEval):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
(VM):

LayoutTests:

Many tests

* fast/js/eval-cache-scoped-lookup-expected.txt: Added.
* fast/js/eval-cache-scoped-lookup.html: Added.
* fast/js/script-tests/eval-cache-scoped-lookup.js: Added.
(first):
(a.string_appeared_here.second):
(third):
(fifth):
(sixth):
(seventh):
(eighth):
(nineth):
(tenth):
(eleventh):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@149836 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 22b46160
2013-05-08 Oliver Hunt <oliver@apple.com>
Code cache stores bogus var references for functions in eval code
https://bugs.webkit.org/show_bug.cgi?id=115747
Reviewed by Mark Hahnenberg.
Many tests
* fast/js/eval-cache-scoped-lookup-expected.txt: Added.
* fast/js/eval-cache-scoped-lookup.html: Added.
* fast/js/script-tests/eval-cache-scoped-lookup.js: Added.
(first):
(a.string_appeared_here.second):
(third):
(fifth):
(sixth):
(seventh):
(eighth):
(nineth):
(tenth):
(eleventh):
2013-05-08 Mark Hahnenberg <mhahnenberg@apple.com>
DFGArrayMode::fromObserved is too liberal when it sees different Array and NonArray shapes
......
Test to make sure that scoped variable access through an eval produces the correct results
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS first() is 'first'
PASS second() is 'second'
PASS third() is 'third'
PASS fourth() is 'fourth'
PASS fifth() is 'fifth'
PASS sixth() is 'sixth'
PASS seventh() is 'seventh'
PASS eighth() is 'eighth'
PASS nineth() is 'nineth'
PASS tenth() is 'tenth'
PASS eleventh() is 'eleventh'
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<script src="script-tests/eval-cache-scoped-lookup.js"></script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
description(
"Test to make sure that scoped variable access through an eval produces the correct results"
);
var str = "(function () { return a; })";
function first() {
var a = "first"
return eval(str)();
}
var a = "second"
function second() {
var b = "error"
return eval(str)();
}
function third() {
var a = "third"
return (function () {
var b = "error";
return eval(str)();
})()
}
function fourth() {
eval('var a = "fourth"');
return eval(str)();
}
function fifth() {
"use strict";
var a = "fifth"
return (function() {
eval('var a = "error"');
return eval(str)();
})();
}
function sixth() {
var a = "sixth"
try {
return eval(str)();
} catch (e) {
}
}
function seventh() {
try {
throw "seventh"
} catch (a) {
return eval(str)();
}
}
function eighth() {
var a = "eighth"
try {
throw "error"
} catch (b) {
return eval(str)();
}
}
function nineth() {
var a = "nineth"
eval(str)();
try {
throw "error"
} catch (b) {
return eval(str)();
}
}
function tenth() {
var a = "error"
eval(str)();
try {
throw "tenth"
} catch (a) {
return eval(str)();
}
}
function eleventh() {
var a = "eleventh"
try {
throw "error"
} catch (a) {
eval(str)();
}
return eval(str)();
}
shouldBe("first()", "'first'");
shouldBe("second()", "'second'");
shouldBe("third()", "'third'");
shouldBe("fourth()", "'fourth'");
shouldBe("fifth()", "'fifth'");
shouldBe("sixth()", "'sixth'");
shouldBe("seventh()", "'seventh'");
shouldBe("eighth()", "'eighth'");
shouldBe("nineth()", "'nineth'");
shouldBe("tenth()", "'tenth'");
shouldBe("eleventh()", "'eleventh'");
2013-05-08 Oliver Hunt <oliver@apple.com>
Code cache stores bogus var references for functions in eval code
https://bugs.webkit.org/show_bug.cgi?id=115747
Reviewed by Mark Hahnenberg.
Non-global eval now uses a per-CodeBlock cache, and only use it
when we're at the top of a function's scope. This means that we
will no longer cache the parsing of a single string across
multiple functions, and we won't cache when we're nested inside
constructs like |with| and |catch| where previously we would, which
is good because caching in those cases is unsound.
* bytecode/EvalCodeCache.h:
(JSC):
(JSC::EvalCodeCache::getSlow):
(JSC::EvalCodeCache::get):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::codeCacheForEval):
(UnlinkedCodeBlock):
(RareData):
* debugger/Debugger.cpp:
(JSC::evaluateInGlobalCallFrame):
* debugger/DebuggerCallFrame.cpp:
(JSC::DebuggerCallFrame::evaluate):
* interpreter/Interpreter.cpp:
(JSC::eval):
* runtime/CodeCache.cpp:
(JSC::CodeCache::CodeCache):
(JSC::CodeCache::generateBytecode):
(JSC):
(JSC::CodeCache::getCodeBlock):
* runtime/CodeCache.h:
(JSC::CodeCacheMap::CodeCacheMap):
(CodeCacheMap):
(JSC::CodeCacheMap::canPruneQuickly):
(JSC::CodeCacheMap::prune):
(JSC::CodeCache::create):
(CodeCache):
* runtime/Executable.cpp:
(JSC::EvalExecutable::EvalExecutable):
(JSC::EvalExecutable::compileInternal):
* runtime/Executable.h:
(JSC::EvalExecutable::create):
(EvalExecutable):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncEval):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
(VM):
2013-05-08 Mark Hahnenberg <mhahnenberg@apple.com>
DFGArrayMode::fromObserved is too liberal when it sees different Array and NonArray shapes
......
......@@ -874,7 +874,7 @@
FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4A331E15BD2E07006F54F3 /* VMInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = FED287B115EC9A5700DA8161 /* LLIntOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */; };
FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); };};
FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); }; };
FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */; };
/* End PBXBuildFile section */
......
......@@ -38,6 +38,7 @@
namespace JSC {
class CodeCache;
class SlotVisitor;
class EvalCodeCache {
......@@ -49,9 +50,9 @@ namespace JSC {
return 0;
}
EvalExecutable* getSlow(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const String& evalSource, JSScope* scope, JSValue& exceptionValue)
EvalExecutable* getSlow(ExecState* exec, CodeCache* codeCache, ScriptExecutable* owner, bool inStrictContext, const String& evalSource, JSScope* scope, JSValue& exceptionValue)
{
EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext);
EvalExecutable* evalExecutable = EvalExecutable::create(exec, codeCache, makeSource(evalSource), inStrictContext);
exceptionValue = evalExecutable->compile(exec, scope);
if (exceptionValue)
return 0;
......@@ -62,12 +63,12 @@ namespace JSC {
return evalExecutable;
}
EvalExecutable* get(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const String& evalSource, JSScope* scope, JSValue& exceptionValue)
EvalExecutable* get(ExecState* exec, CodeCache* codeCache, ScriptExecutable* owner, bool inStrictContext, const String& evalSource, JSScope* scope, JSValue& exceptionValue)
{
EvalExecutable* evalExecutable = tryGet(inStrictContext, evalSource, scope);
if (!evalExecutable)
evalExecutable = getSlow(exec, owner, inStrictContext, evalSource, scope, exceptionValue);
evalExecutable = getSlow(exec, codeCache, owner, inStrictContext, evalSource, scope, exceptionValue);
return evalExecutable;
}
......
......@@ -27,6 +27,7 @@
#define UnlinkedCodeBlock_h
#include "BytecodeConventions.h"
#include "CodeCache.h"
#include "CodeSpecializationKind.h"
#include "CodeType.h"
#include "ExpressionRangeInfo.h"
......@@ -470,6 +471,16 @@ public:
unsigned firstLine() const { return m_firstLine; }
unsigned lineCount() const { return m_lineCount; }
PassRefPtr<CodeCache> codeCacheForEval()
{
if (m_codeType == GlobalCode)
return m_vm->codeCache();
createRareDataIfNecessary();
if (!m_rareData->m_evalCodeCache)
m_rareData->m_evalCodeCache = CodeCache::create(CodeCache::NonGlobalCodeCache);
return m_rareData->m_evalCodeCache.get();
}
protected:
UnlinkedCodeBlock(VM*, Structure*, CodeType, const ExecutableInfo&);
~UnlinkedCodeBlock();
......@@ -556,8 +567,7 @@ public:
Vector<UnlinkedSimpleJumpTable> m_immediateSwitchJumpTables;
Vector<UnlinkedSimpleJumpTable> m_characterSwitchJumpTables;
Vector<UnlinkedStringJumpTable> m_stringSwitchJumpTables;
// Expression info - present if debugging.
RefPtr<CodeCache> m_evalCodeCache;
};
private:
......
......@@ -128,7 +128,7 @@ JSValue evaluateInGlobalCallFrame(const String& script, JSValue& exception, JSGl
CallFrame* globalCallFrame = globalObject->globalExec();
VM& vm = globalObject->vm();
EvalExecutable* eval = EvalExecutable::create(globalCallFrame, makeSource(script), false);
EvalExecutable* eval = EvalExecutable::create(globalCallFrame, vm.codeCache(), makeSource(script), false);
if (!eval) {
exception = vm.exception;
vm.exception = JSValue();
......
......@@ -91,7 +91,7 @@ JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception) co
return JSValue();
VM& vm = m_callFrame->vm();
EvalExecutable* eval = EvalExecutable::create(m_callFrame, makeSource(script), m_callFrame->codeBlock()->isStrictMode());
EvalExecutable* eval = EvalExecutable::create(m_callFrame, m_callFrame->codeBlock()->unlinkedCodeBlock()->codeCacheForEval(), makeSource(script), m_callFrame->codeBlock()->isStrictMode());
if (vm.exception) {
exception = vm.exception;
vm.exception = JSValue();
......
......@@ -185,7 +185,7 @@ JSValue eval(CallFrame* callFrame)
ASSERT(!callFrame->vm().exception);
JSValue exceptionValue;
eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain, exceptionValue);
eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->unlinkedCodeBlock()->codeCacheForEval().get(), callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), programSource, callerScopeChain, exceptionValue);
ASSERT(!eval == exceptionValue);
if (UNLIKELY(!eval))
......
......@@ -54,7 +54,9 @@ void CodeCacheMap::pruneSlowCase()
}
}
CodeCache::CodeCache()
CodeCache::CodeCache(CodeCacheKind kind)
: m_sourceCode(kind == GlobalCodeCache ? CodeCacheMap::globalWorkingSetMaxBytes : CodeCacheMap::nonGlobalWorkingSetMaxBytes,
kind == GlobalCodeCache ? CodeCacheMap::globalWorkingSetMaxEntries : CodeCacheMap::nonGlobalWorkingSetMaxEntries)
{
}
......@@ -75,24 +77,12 @@ template <> struct CacheTypes<UnlinkedEvalCodeBlock> {
};
template <class UnlinkedCodeBlockType, class ExecutableType>
UnlinkedCodeBlockType* CodeCache::getCodeBlock(VM& vm, JSScope* scope, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
UnlinkedCodeBlockType* CodeCache::generateBytecode(VM& vm, JSScope* scope, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue());
bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff;
if (!addResult.isNewEntry && canCache) {
UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get());
unsigned firstLine = source.firstLine() + unlinkedCode->firstLine();
executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount());
return unlinkedCode;
}
typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
RefPtr<RootNode> rootNode = parse<RootNode>(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error);
if (!rootNode) {
m_sourceCode.remove(addResult.iterator);
if (!rootNode)
return 0;
}
executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine());
UnlinkedCodeBlockType* unlinkedCode = UnlinkedCodeBlockType::create(&vm, executable->executableInfo());
......@@ -100,12 +90,33 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(VM& vm, JSScope* scope, Executabl
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, scope, rootNode.get(), unlinkedCode, debuggerMode, profilerMode)));
error = generator->generate();
rootNode->destroyData();
if (error.m_type != ParserError::ErrorNone) {
m_sourceCode.remove(addResult.iterator);
if (error.m_type != ParserError::ErrorNone)
return 0;
return unlinkedCode;
}
template <class UnlinkedCodeBlockType, class ExecutableType>
UnlinkedCodeBlockType* CodeCache::getCodeBlock(VM& vm, JSScope* scope, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
// We completely skip the cache if we're an eval that isn't at the top of the scope chain.
if (CacheTypes<UnlinkedCodeBlockType>::codeType == SourceCodeKey::EvalType) {
if (scope->next() && !scope->isActivationObject())
return generateBytecode<UnlinkedCodeBlockType, ExecutableType>(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error);
}
SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue());
bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff;
if (!addResult.isNewEntry && canCache) {
UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get());
unsigned firstLine = source.firstLine() + unlinkedCode->firstLine();
executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount());
return unlinkedCode;
}
UnlinkedCodeBlockType* unlinkedCode = generateBytecode<UnlinkedCodeBlockType, ExecutableType>(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error);
if (!canCache) {
if (!canCache || !unlinkedCode) {
m_sourceCode.remove(addResult.iterator);
return unlinkedCode;
}
......
......@@ -136,13 +136,15 @@ public:
typedef MapType::iterator iterator;
typedef MapType::AddResult AddResult;
CodeCacheMap()
CodeCacheMap(int64_t workingSetMaxBytes, size_t workingSetMaxEntries)
: m_size(0)
, m_sizeAtLastPrune(0)
, m_timeAtLastPrune(monotonicallyIncreasingTime())
, m_minCapacity(0)
, m_capacity(0)
, m_age(0)
, m_workingSetMaxBytes(workingSetMaxBytes)
, m_workingSetMaxEntries(workingSetMaxEntries)
{
}
......@@ -192,12 +194,20 @@ public:
int64_t age() { return m_age; }
static const int64_t globalWorkingSetMaxBytes = 16000000;
static const size_t globalWorkingSetMaxEntries = 2000;
// We have a smaller cap for the per-codeblock CodeCache that approximates the
// linked EvalCodeCache limits, but still allows us to keep large string based
// evals at least partially cached.
static const unsigned nonGlobalWorkingSetScale = 20;
static const int64_t nonGlobalWorkingSetMaxBytes = globalWorkingSetMaxBytes / nonGlobalWorkingSetScale;
static const size_t nonGlobalWorkingSetMaxEntries = globalWorkingSetMaxEntries / nonGlobalWorkingSetScale;
private:
// This constant factor biases cache capacity toward allowing a minimum
// working set to enter the cache before it starts evicting.
static const double workingSetTime;
static const int64_t workingSetMaxBytes = 16000000;
static const size_t workingSetMaxEntries = 2000;
// This constant factor biases cache capacity toward recent activity. We
// want to adapt to changing workloads.
......@@ -209,7 +219,7 @@ private:
static const int64_t oldObjectSamplingMultiplier = 32;
size_t numberOfEntries() const { return static_cast<size_t>(m_map.size()); }
bool canPruneQuickly() const { return numberOfEntries() < workingSetMaxEntries; }
bool canPruneQuickly() const { return numberOfEntries() < m_workingSetMaxEntries; }
void pruneSlowCase();
void prune()
......@@ -218,7 +228,7 @@ private:
return;
if (monotonicallyIncreasingTime() - m_timeAtLastPrune < workingSetTime
&& m_size - m_sizeAtLastPrune < workingSetMaxBytes
&& m_size - m_sizeAtLastPrune < m_workingSetMaxBytes
&& canPruneQuickly())
return;
......@@ -232,12 +242,15 @@ private:
int64_t m_minCapacity;
int64_t m_capacity;
int64_t m_age;
const int64_t m_workingSetMaxBytes;
const size_t m_workingSetMaxEntries;
};
// Caches top-level code such as <script>, eval(), new Function, and JSEvaluateScript().
class CodeCache {
class CodeCache : public RefCounted<CodeCache> {
public:
static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); }
enum CodeCacheKind { GlobalCodeCache, NonGlobalCodeCache };
static PassRefPtr<CodeCache> create(CodeCacheKind kind) { return adoptRef(new CodeCache(kind)); }
UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, JSScope*, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
......@@ -250,11 +263,14 @@ public:
}
private:
CodeCache();
CodeCache(CodeCacheKind);
template <class UnlinkedCodeBlockType, class ExecutableType>
UnlinkedCodeBlockType* getCodeBlock(VM&, JSScope*, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
template <class UnlinkedCodeBlockType, class ExecutableType>
UnlinkedCodeBlockType* generateBytecode(VM&, JSScope*, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
CodeCacheMap m_sourceCode;
};
......
......@@ -116,8 +116,9 @@ void ScriptExecutable::destroy(JSCell* cell)
const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) };
EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
EvalExecutable::EvalExecutable(ExecState* exec, PassRefPtr<CodeCache> codeCache, const SourceCode& source, bool inStrictContext)
: ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext)
, m_codeCache(codeCache)
{
}
......@@ -211,7 +212,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo
return throwError(exec, createEvalError(exec, lexicalGlobalObject->evalDisabledErrorMessage()));
JSObject* exception = 0;
UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(exec, scope, this, &exception);
UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(m_codeCache.get(), exec, scope, this, &exception);
if (!unlinkedEvalCode)
return exception;
......
......@@ -451,9 +451,9 @@ namespace JSC {
return *m_evalCodeBlock;
}
static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext)
static EvalExecutable* create(ExecState* exec, PassRefPtr<CodeCache> cache, const SourceCode& source, bool isInStrictContext)
{
EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, cache, source, isInStrictContext);
executable->finishCreation(exec->vm());
return executable;
}
......@@ -479,13 +479,14 @@ namespace JSC {
private:
static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
EvalExecutable(ExecState*, const SourceCode&, bool);
EvalExecutable(ExecState*, PassRefPtr<CodeCache>, const SourceCode&, bool);
JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX);
static void visitChildren(JSCell*, SlotVisitor&);
OwnPtr<EvalCodeBlock> m_evalCodeBlock;
WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
RefPtr<CodeCache> m_codeCache;
};
class ProgramExecutable : public ScriptExecutable {
......
......@@ -620,13 +620,13 @@ UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* call
return unlinkedCode;
}
UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, JSScope* scope, EvalExecutable* executable, JSObject** exception)
UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CodeCache* cache, CallFrame* callFrame, JSScope* scope, EvalExecutable* executable, JSObject** exception)
{
ParserError error;
JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal;
DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff;
ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff;
UnlinkedEvalCodeBlock* unlinkedCode = vm().codeCache()->getEvalCodeBlock(vm(), scope, executable, executable->source(), strictness, debuggerMode, profilerMode, error);
UnlinkedEvalCodeBlock* unlinkedCode = cache->getEvalCodeBlock(vm(), scope, executable, executable->source(), strictness, debuggerMode, profilerMode, error);
if (hasDebugger())
debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message);
......
......@@ -412,7 +412,7 @@ public:
unsigned weakRandomInteger() { return m_weakRandom.getUint32(); }
UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception);
UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, JSScope*, EvalExecutable*, JSObject** exception);
UnlinkedEvalCodeBlock* createEvalCodeBlock(CodeCache*, CallFrame*, JSScope*, EvalExecutable*, JSObject** exception);
protected:
......
......@@ -515,7 +515,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
}
JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject();
EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
EvalExecutable* eval = EvalExecutable::create(exec, exec->vm().codeCache(), makeSource(s), false);
JSObject* error = eval->compile(exec, calleeGlobalObject);
if (error)
return throwVMError(exec, error);
......
......@@ -194,7 +194,7 @@ VM::VM(VMType vmType, HeapType heapType)
, m_initializingObjectClass(0)
#endif
, m_inDefineOwnProperty(false)
, m_codeCache(CodeCache::create())
, m_codeCache(CodeCache::create(CodeCache::GlobalCodeCache))
{
interpreter = new Interpreter(*this);
......
......@@ -490,7 +490,7 @@ namespace JSC {
const ClassInfo* m_initializingObjectClass;
#endif
bool m_inDefineOwnProperty;
OwnPtr<CodeCache> m_codeCache;
RefPtr<CodeCache> m_codeCache;
TypedArrayDescriptor m_int8ArrayDescriptor;
TypedArrayDescriptor m_int16ArrayDescriptor;
......
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