Unreviewed, rolling out r143348.
[WebKit-https.git] / Source / JavaScriptCore / runtime / CodeCache.cpp
1 /*
2  * Copyright (C) 2012 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #include "CodeCache.h"
29
30 #include "BytecodeGenerator.h"
31 #include "CodeSpecializationKind.h"
32 #include "Operations.h"
33 #include "Parser.h"
34 #include "StrongInlines.h"
35 #include "UnlinkedCodeBlock.h"
36
37 namespace JSC {
38
39 CodeCache::CodeCache()
40     : m_sourceCode(CacheSize)
41 {
42 }
43
44 CodeCache::~CodeCache()
45 {
46 }
47
48 template <typename T> struct CacheTypes { };
49
50 template <> struct CacheTypes<UnlinkedProgramCodeBlock> {
51     typedef JSC::ProgramNode RootNode;
52     static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType;
53 };
54
55 template <> struct CacheTypes<UnlinkedEvalCodeBlock> {
56     typedef JSC::EvalNode RootNode;
57     static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType;
58 };
59
60 template <class UnlinkedCodeBlockType, class ExecutableType>
61 UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
62 {
63     SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
64     bool storeInCache = false;
65     if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) {
66         const Strong<JSCell>* result = m_sourceCode.find(key);
67         if (result) {
68             UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get());
69             unsigned firstLine = source.firstLine() + unlinkedCode->firstLine();
70             executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount());
71             return unlinkedCode;
72         }
73         storeInCache = true;
74     }
75
76     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
77     RefPtr<RootNode> rootNode = parse<RootNode>(&globalData, source, 0, Identifier(), strictness, JSParseProgramCode, error);
78     if (!rootNode)
79         return 0;
80     executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine());
81
82     UnlinkedCodeBlockType* unlinkedCode = UnlinkedCodeBlockType::create(&globalData, executable->executableInfo());
83     unlinkedCode->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), rootNode->lastLine() - rootNode->lineNo());
84     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, rootNode.get(), unlinkedCode, debuggerMode, profilerMode)));
85     error = generator->generate();
86     rootNode->destroyData();
87     if (error.m_type != ParserError::ErrorNone)
88         return 0;
89
90     if (storeInCache)
91         m_sourceCode.set(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode));
92
93     return unlinkedCode;
94 }
95
96 UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(JSGlobalData& globalData, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
97 {
98     return getCodeBlock<UnlinkedProgramCodeBlock>(globalData, executable, source, strictness, debuggerMode, profilerMode, error);
99 }
100
101 UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(JSGlobalData& globalData, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
102 {
103     return getCodeBlock<UnlinkedEvalCodeBlock>(globalData, executable, source, strictness, debuggerMode, profilerMode, error);
104 }
105
106 UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error)
107 {
108     SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionCallType, JSParseNormal);
109     const Strong<JSCell>* result = m_sourceCode.find(key);
110     if (result)
111         return jsCast<UnlinkedFunctionExecutable*>(result->get());
112
113     RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error);
114     if (!program) {
115         ASSERT(error.m_type != ParserError::ErrorNone);
116         return 0;
117     }
118
119     // This function assumes an input string that would result in a single anonymous function expression.
120     StatementNode* exprStatement = program->singleStatement();
121     ASSERT(exprStatement);
122     ASSERT(exprStatement->isExprStatement());
123     ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
124     ASSERT(funcExpr);
125     RELEASE_ASSERT(funcExpr->isFuncExprNode());
126     FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
127     ASSERT(body);
128     ASSERT(body->ident().isNull());
129
130     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body);
131     functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string()));
132
133     m_sourceCode.set(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable));
134     return functionExecutable;
135 }
136
137 }