diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/CodeCache.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/CodeCache.cpp | 184 |
1 files changed, 89 insertions, 95 deletions
diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index 510e383fa..6c1c0c05c 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All Rights Reserved. + * Copyright (C) 2012, 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,15 +24,9 @@ */ #include "config.h" - #include "CodeCache.h" -#include "BytecodeGenerator.h" -#include "CodeSpecializationKind.h" -#include "Operations.h" -#include "Parser.h" -#include "StrongInlines.h" -#include "UnlinkedCodeBlock.h" +#include "IndirectEvalExecutable.h" namespace JSC { @@ -54,117 +48,117 @@ void CodeCacheMap::pruneSlowCase() } } -CodeCache::CodeCache() -{ -} - -CodeCache::~CodeCache() -{ -} - -template <typename T> struct CacheTypes { }; - -template <> struct CacheTypes<UnlinkedProgramCodeBlock> { - typedef JSC::ProgramNode RootNode; - static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType; -}; - -template <> struct CacheTypes<UnlinkedEvalCodeBlock> { - typedef JSC::EvalNode RootNode; - static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType; -}; - template <class UnlinkedCodeBlockType, class ExecutableType> -UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType) { - 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* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get()); - unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine(); + DerivedContextType derivedContextType = executable->derivedContextType(); + bool isArrowFunctionContext = executable->isArrowFunctionContext(); + SourceCodeKey key( + source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictMode, scriptMode, + derivedContextType, evalContextType, isArrowFunctionContext, debuggerMode, + vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, + vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No); + SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); + if (cache && Options::useCodeCache()) { + UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(cache->cell.get()); unsigned lineCount = unlinkedCodeBlock->lineCount(); - unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn(); + unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn().oneBasedInt(); bool endColumnIsOnStartLine = !lineCount; unsigned endColumn = unlinkedCodeBlock->endColumn() + (endColumnIsOnStartLine ? startColumn : 1); - executable->recordParse(unlinkedCodeBlock->codeFeatures(), unlinkedCodeBlock->hasCapturedVariables(), firstLine, firstLine + lineCount, startColumn, endColumn); + executable->recordParse(unlinkedCodeBlock->codeFeatures(), unlinkedCodeBlock->hasCapturedVariables(), source.firstLine().oneBasedInt() + lineCount, endColumn); + source.provider()->setSourceURLDirective(unlinkedCodeBlock->sourceURLDirective()); + source.provider()->setSourceMappingURLDirective(unlinkedCodeBlock->sourceMappingURLDirective()); return unlinkedCodeBlock; } + + VariableEnvironment variablesUnderTDZ; + UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); - 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); - return 0; - } - 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); - - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode))); - error = generator->generate(); - rootNode->destroyData(); - if (error.m_type != ParserError::ErrorNone) { - m_sourceCode.remove(addResult.iterator); - return 0; - } - - if (!canCache) { - m_sourceCode.remove(addResult.iterator); - return unlinkedCodeBlock; - } + if (unlinkedCodeBlock && Options::useCodeCache()) + m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age())); - 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) +UnlinkedProgramCodeBlock* CodeCache::getUnlinkedProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error) { - return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictness, debuggerMode, profilerMode, error); + return getUnlinkedGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictMode, JSParserScriptMode::Classic, debuggerMode, error, EvalContextType::None); } -UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedEvalCodeBlock* CodeCache::getUnlinkedEvalCodeBlock(VM& vm, IndirectEvalExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType) { - return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictness, debuggerMode, profilerMode, error); + return getUnlinkedGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictMode, JSParserScriptMode::Classic, debuggerMode, error, evalContextType); } -UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) +UnlinkedModuleProgramCodeBlock* CodeCache::getUnlinkedModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error) { - SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal); - CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); - if (!addResult.isNewEntry) - return jsCast<UnlinkedFunctionExecutable*>(addResult.iterator->value.cell.get()); + return getUnlinkedGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, JSParserStrictMode::Strict, JSParserScriptMode::Module, debuggerMode, error, EvalContextType::None); +} + +UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& vm, const Identifier& name, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error) +{ + bool isArrowFunctionContext = false; + SourceCodeKey key( + source, name.string(), SourceCodeType::FunctionType, + JSParserStrictMode::NotStrict, + JSParserScriptMode::Classic, + DerivedContextType::None, + EvalContextType::None, + isArrowFunctionContext, + debuggerMode, + vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, + vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No); + SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); + if (cache && Options::useCodeCache()) { + UnlinkedFunctionExecutable* executable = jsCast<UnlinkedFunctionExecutable*>(cache->cell.get()); + source.provider()->setSourceURLDirective(executable->sourceURLDirective()); + source.provider()->setSourceMappingURLDirective(executable->sourceMappingURLDirective()); + return executable; + } JSTextPosition positionBeforeLastNewline; - RefPtr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline); + std::unique_ptr<ProgramNode> program = parse<ProgramNode>( + &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, + JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, + error, &positionBeforeLastNewline); if (!program) { - ASSERT(error.m_type != ParserError::ErrorNone); - m_sourceCode.remove(addResult.iterator); - return 0; + RELEASE_ASSERT(error.isValid()); + return nullptr; } - // This function assumes an input string that would result in a single anonymous function expression. - StatementNode* exprStatement = program->singleStatement(); - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); - ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); - ASSERT(funcExpr); - RELEASE_ASSERT(funcExpr->isFuncExprNode()); - FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); - body->setEndPosition(positionBeforeLastNewline); - ASSERT(body); - ASSERT(body->ident().isNull()); - - UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, true); - functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); - - addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age()); + // This function assumes an input string that would result in a single function declaration. + StatementNode* statement = program->singleStatement(); + if (UNLIKELY(!statement)) { + JSToken token; + error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1); + return nullptr; + } + ASSERT(statement->isBlock()); + + StatementNode* funcDecl = static_cast<BlockNode*>(statement)->singleStatement(); + if (UNLIKELY(!funcDecl)) { + JSToken token; + error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1); + return nullptr; + } + ASSERT(funcDecl->isFuncDeclNode()); + + FunctionMetadataNode* metadata = static_cast<FuncDeclNode*>(funcDecl)->metadata(); + ASSERT(metadata); + if (!metadata) + return nullptr; + + metadata->overrideName(name); + metadata->setEndPosition(positionBeforeLastNewline); + // The Function constructor only has access to global variables, so no variables will be under TDZ. + VariableEnvironment emptyTDZVariables; + ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode()); + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, emptyTDZVariables, DerivedContextType::None); + + functionExecutable->setSourceURLDirective(source.provider()->sourceURL()); + functionExecutable->setSourceMappingURLDirective(source.provider()->sourceMappingURL()); + + m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age())); return functionExecutable; } |