Diff
Modified: trunk/LayoutTests/ChangeLog (149835 => 149836)
--- trunk/LayoutTests/ChangeLog 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/LayoutTests/ChangeLog 2013-05-09 20:03:23 UTC (rev 149836)
@@ -1,3 +1,26 @@
+2013-05-08 Oliver Hunt <[email protected]>
+
+ 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 <[email protected]>
DFGArrayMode::fromObserved is too liberal when it sees different Array and NonArray shapes
Added: trunk/LayoutTests/fast/js/eval-cache-scoped-lookup-expected.txt (0 => 149836)
--- trunk/LayoutTests/fast/js/eval-cache-scoped-lookup-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/js/eval-cache-scoped-lookup-expected.txt 2013-05-09 20:03:23 UTC (rev 149836)
@@ -0,0 +1,20 @@
+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
+
Added: trunk/LayoutTests/fast/js/eval-cache-scoped-lookup.html (0 => 149836)
--- trunk/LayoutTests/fast/js/eval-cache-scoped-lookup.html (rev 0)
+++ trunk/LayoutTests/fast/js/eval-cache-scoped-lookup.html 2013-05-09 20:03:23 UTC (rev 149836)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/js/script-tests/eval-cache-scoped-lookup.js (0 => 149836)
--- trunk/LayoutTests/fast/js/script-tests/eval-cache-scoped-lookup.js (rev 0)
+++ trunk/LayoutTests/fast/js/script-tests/eval-cache-scoped-lookup.js 2013-05-09 20:03:23 UTC (rev 149836)
@@ -0,0 +1,109 @@
+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'");
+
Modified: trunk/Source/_javascript_Core/ChangeLog (149835 => 149836)
--- trunk/Source/_javascript_Core/ChangeLog 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-05-09 20:03:23 UTC (rev 149836)
@@ -1,3 +1,60 @@
+2013-05-08 Oliver Hunt <[email protected]>
+
+ 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 <[email protected]>
DFGArrayMode::fromObserved is too liberal when it sees different Array and NonArray shapes
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (149835 => 149836)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2013-05-09 20:03:23 UTC (rev 149836)
@@ -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 */
Modified: trunk/Source/_javascript_Core/bytecode/EvalCodeCache.h (149835 => 149836)
--- trunk/Source/_javascript_Core/bytecode/EvalCodeCache.h 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/bytecode/EvalCodeCache.h 2013-05-09 20:03:23 UTC (rev 149836)
@@ -38,6 +38,7 @@
namespace JSC {
+ class CodeCache;
class SlotVisitor;
class EvalCodeCache {
@@ -49,9 +50,9 @@
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 @@
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;
}
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (149835 => 149836)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h 2013-05-09 20:03:23 UTC (rev 149836)
@@ -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 @@
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 @@
Vector<UnlinkedSimpleJumpTable> m_immediateSwitchJumpTables;
Vector<UnlinkedSimpleJumpTable> m_characterSwitchJumpTables;
Vector<UnlinkedStringJumpTable> m_stringSwitchJumpTables;
-
- // _expression_ info - present if debugging.
+ RefPtr<CodeCache> m_evalCodeCache;
};
private:
Modified: trunk/Source/_javascript_Core/debugger/Debugger.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/debugger/Debugger.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/debugger/Debugger.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -128,7 +128,7 @@
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();
Modified: trunk/Source/_javascript_Core/debugger/DebuggerCallFrame.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/debugger/DebuggerCallFrame.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/debugger/DebuggerCallFrame.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -91,7 +91,7 @@
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();
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -185,7 +185,7 @@
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))
Modified: trunk/Source/_javascript_Core/runtime/CodeCache.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/CodeCache.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -54,7 +54,9 @@
}
}
-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 <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 @@
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);
}
- if (!canCache) {
+ 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 || !unlinkedCode) {
m_sourceCode.remove(addResult.iterator);
return unlinkedCode;
}
Modified: trunk/Source/_javascript_Core/runtime/CodeCache.h (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/CodeCache.h 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.h 2013-05-09 20:03:23 UTC (rev 149836)
@@ -136,13 +136,15 @@
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 @@
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 @@
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 @@
return;
if (monotonicallyIncreasingTime() - m_timeAtLastPrune < workingSetTime
- && m_size - m_sizeAtLastPrune < workingSetMaxBytes
+ && m_size - m_sizeAtLastPrune < m_workingSetMaxBytes
&& canPruneQuickly())
return;
@@ -232,12 +242,15 @@
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 @@
}
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;
};
Modified: trunk/Source/_javascript_Core/runtime/Executable.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/Executable.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/Executable.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -116,8 +116,9 @@
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 @@
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;
Modified: trunk/Source/_javascript_Core/runtime/Executable.h (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/Executable.h 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/Executable.h 2013-05-09 20:03:23 UTC (rev 149836)
@@ -451,9 +451,9 @@
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 @@
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 {
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -620,13 +620,13 @@
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);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2013-05-09 20:03:23 UTC (rev 149836)
@@ -412,7 +412,7 @@
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:
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -515,7 +515,7 @@
}
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);
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2013-05-09 20:03:23 UTC (rev 149836)
@@ -194,7 +194,7 @@
, m_initializingObjectClass(0)
#endif
, m_inDefineOwnProperty(false)
- , m_codeCache(CodeCache::create())
+ , m_codeCache(CodeCache::create(CodeCache::GlobalCodeCache))
{
interpreter = new Interpreter(*this);
Modified: trunk/Source/_javascript_Core/runtime/VM.h (149835 => 149836)
--- trunk/Source/_javascript_Core/runtime/VM.h 2013-05-09 19:41:23 UTC (rev 149835)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2013-05-09 20:03:23 UTC (rev 149836)
@@ -490,7 +490,7 @@
const ClassInfo* m_initializingObjectClass;
#endif
bool m_inDefineOwnProperty;
- OwnPtr<CodeCache> m_codeCache;
+ RefPtr<CodeCache> m_codeCache;
TypedArrayDescriptor m_int8ArrayDescriptor;
TypedArrayDescriptor m_int16ArrayDescriptor;