X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/93a3786624b2768d89bfa27e46598dc64e2fb70a..81345200c95645a1b0d2635520f96ad55dfde63f:/runtime/CodeCache.cpp?ds=sidebyside diff --git a/runtime/CodeCache.cpp b/runtime/CodeCache.cpp index de904ae..442835b 100644 --- a/runtime/CodeCache.cpp +++ b/runtime/CodeCache.cpp @@ -29,7 +29,7 @@ #include "BytecodeGenerator.h" #include "CodeSpecializationKind.h" -#include "Operations.h" +#include "JSCInlines.h" #include "Parser.h" #include "StrongInlines.h" #include "UnlinkedCodeBlock.h" @@ -37,11 +37,6 @@ namespace JSC { const double CodeCacheMap::workingSetTime = 10.0; -const int64_t CodeCacheMap::globalWorkingSetMaxBytes = 16000000; -const size_t CodeCacheMap::globalWorkingSetMaxEntries = 2000; -const unsigned CodeCacheMap::nonGlobalWorkingSetScale = 20; -const int64_t CodeCacheMap::nonGlobalWorkingSetMaxBytes = CodeCacheMap::globalWorkingSetMaxBytes / CodeCacheMap::nonGlobalWorkingSetScale; -const size_t CodeCacheMap::nonGlobalWorkingSetMaxEntries = CodeCacheMap::globalWorkingSetMaxEntries / CodeCacheMap::nonGlobalWorkingSetScale; void CodeCacheMap::pruneSlowCase() { @@ -59,9 +54,7 @@ void CodeCacheMap::pruneSlowCase() } } -CodeCache::CodeCache(CodeCacheKind kind) -: m_sourceCode(kind == GlobalCodeCache ? CodeCacheMap::globalWorkingSetMaxBytes : CodeCacheMap::nonGlobalWorkingSetMaxBytes, - kind == GlobalCodeCache ? CodeCacheMap::globalWorkingSetMaxEntries : CodeCacheMap::nonGlobalWorkingSetMaxEntries) +CodeCache::CodeCache() { } @@ -82,63 +75,63 @@ template <> struct CacheTypes { }; template -UnlinkedCodeBlockType* CodeCache::generateBytecode(VM& vm, JSScope* scope, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { + SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes::codeType, strictness); + CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); + bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff; + if (!addResult.isNewEntry && canCache) { + UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast(addResult.iterator->value.cell.get()); + unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine(); + unsigned lineCount = unlinkedCodeBlock->lineCount(); + unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn(); + bool endColumnIsOnStartLine = !lineCount; + unsigned endColumn = unlinkedCodeBlock->endColumn() + (endColumnIsOnStartLine ? startColumn : 1); + executable->recordParse(unlinkedCodeBlock->codeFeatures(), unlinkedCodeBlock->hasCapturedVariables(), firstLine, firstLine + lineCount, startColumn, endColumn); + return unlinkedCodeBlock; + } + typedef typename CacheTypes::RootNode RootNode; RefPtr rootNode = parse(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error); - if (!rootNode) + if (!rootNode) { + m_sourceCode.remove(addResult.iterator); return 0; - executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine(), rootNode->startColumn()); + } + unsigned lineCount = rootNode->lastLine() - rootNode->lineNo(); + unsigned startColumn = rootNode->startColumn() + 1; + bool endColumnIsOnStartLine = !lineCount; + unsigned unlinkedEndColumn = rootNode->endColumn(); + unsigned endColumn = unlinkedEndColumn + (endColumnIsOnStartLine ? startColumn : 1); + executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine(), startColumn, endColumn); + + UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo()); + unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), lineCount, unlinkedEndColumn); - UnlinkedCodeBlockType* unlinkedCode = UnlinkedCodeBlockType::create(&vm, executable->executableInfo()); - unlinkedCode->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), rootNode->lastLine() - rootNode->lineNo()); - OwnPtr generator(adoptPtr(new BytecodeGenerator(vm, scope, rootNode.get(), unlinkedCode, debuggerMode, profilerMode))); + OwnPtr generator(adoptPtr(new BytecodeGenerator(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode))); error = generator->generate(); rootNode->destroyData(); - if (error.m_type != ParserError::ErrorNone) + if (error.m_type != ParserError::ErrorNone) { + m_sourceCode.remove(addResult.iterator); return 0; - return unlinkedCode; -} - -template -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::codeType == SourceCodeKey::EvalType) { - if (scope->next() && !scope->isActivationObject()) - return generateBytecode(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error); - } - - SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes::codeType, strictness); - CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); - bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff; - - if (!addResult.isNewEntry && canCache) { - UnlinkedCodeBlockType* unlinkedCode = jsCast(addResult.iterator->value.cell.get()); - unsigned firstLine = source.firstLine() + unlinkedCode->firstLine(); - unsigned startColumn = source.firstLine() ? source.startColumn() : 0; - executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount(), startColumn); - return unlinkedCode; } - UnlinkedCodeBlockType* unlinkedCode = generateBytecode(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error); - if (!canCache || !unlinkedCode) { + if (!canCache) { m_sourceCode.remove(addResult.iterator); - return unlinkedCode; + return unlinkedCodeBlock; } - addResult.iterator->value = SourceCodeValue(vm, unlinkedCode, m_sourceCode.age()); - return unlinkedCode; + addResult.iterator->value = SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()); + return unlinkedCodeBlock; } UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - return getCodeBlock(vm, 0, executable, source, strictness, debuggerMode, profilerMode, error); + return getGlobalCodeBlock(vm, executable, source, strictness, debuggerMode, profilerMode, error); } -UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, JSScope* scope, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - return getCodeBlock(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error); + return getGlobalCodeBlock(vm, executable, source, strictness, debuggerMode, profilerMode, error); } UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) @@ -148,25 +141,29 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v if (!addResult.isNewEntry) return jsCast(addResult.iterator->value.cell.get()); - RefPtr program = parse(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + JSTextPosition positionBeforeLastNewline; + RefPtr program = parse(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline); if (!program) { - ASSERT(error.m_type != ParserError::ErrorNone); + RELEASE_ASSERT(error.m_type != ParserError::ErrorNone); m_sourceCode.remove(addResult.iterator); return 0; } // This function assumes an input string that would result in a single anonymous function expression. StatementNode* exprStatement = program->singleStatement(); - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); + RELEASE_ASSERT(exprStatement); + RELEASE_ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast(exprStatement)->expr(); - ASSERT(funcExpr); + RELEASE_ASSERT(funcExpr); RELEASE_ASSERT(funcExpr->isFuncExprNode()); FunctionBodyNode* body = static_cast(funcExpr)->body(); - ASSERT(body); - ASSERT(body->ident().isNull()); + RELEASE_ASSERT(!program->hasCapturedVariables()); + + body->setEndPosition(positionBeforeLastNewline); + RELEASE_ASSERT(body); + RELEASE_ASSERT(body->ident().isNull()); - UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body); + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, UnlinkedNormalFunction); functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age());