We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / CodeCache.cpp
1 /*
2  * Copyright (C) 2012, 2016 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 #include "CodeCache.h"
28
29 #include "IndirectEvalExecutable.h"
30
31 namespace JSC {
32
33 const Seconds CodeCacheMap::workingSetTime = 10_s;
34
35 void CodeCacheMap::pruneSlowCase()
36 {
37     m_minCapacity = std::max(m_size - m_sizeAtLastPrune, static_cast<int64_t>(0));
38     m_sizeAtLastPrune = m_size;
39     m_timeAtLastPrune = MonotonicTime::now();
40
41     if (m_capacity < m_minCapacity)
42         m_capacity = m_minCapacity;
43
44     while (m_size > m_capacity || !canPruneQuickly()) {
45         MapType::iterator it = m_map.begin();
46         m_size -= it->key.length();
47         m_map.remove(it);
48     }
49 }
50
51 template <class UnlinkedCodeBlockType, class ExecutableType>
52 UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType)
53 {
54     DerivedContextType derivedContextType = executable->derivedContextType();
55     bool isArrowFunctionContext = executable->isArrowFunctionContext();
56     SourceCodeKey key(
57         source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictMode, scriptMode, 
58         derivedContextType, evalContextType, isArrowFunctionContext, debuggerMode, 
59         vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, 
60         vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No);
61     SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
62     if (cache && Options::useCodeCache()) {
63         UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(cache->cell.get());
64         unsigned lineCount = unlinkedCodeBlock->lineCount();
65         unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn().oneBasedInt();
66         bool endColumnIsOnStartLine = !lineCount;
67         unsigned endColumn = unlinkedCodeBlock->endColumn() + (endColumnIsOnStartLine ? startColumn : 1);
68         executable->recordParse(unlinkedCodeBlock->codeFeatures(), unlinkedCodeBlock->hasCapturedVariables(), source.firstLine().oneBasedInt() + lineCount, endColumn);
69         source.provider()->setSourceURLDirective(unlinkedCodeBlock->sourceURLDirective());
70         source.provider()->setSourceMappingURLDirective(unlinkedCodeBlock->sourceMappingURLDirective());
71         return unlinkedCodeBlock;
72     }
73     
74     VariableEnvironment variablesUnderTDZ;
75     UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ);
76
77     if (unlinkedCodeBlock && Options::useCodeCache())
78         m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()));
79
80     return unlinkedCodeBlock;
81 }
82
83 UnlinkedProgramCodeBlock* CodeCache::getUnlinkedProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error)
84 {
85     return getUnlinkedGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictMode, JSParserScriptMode::Classic, debuggerMode, error, EvalContextType::None);
86 }
87
88 UnlinkedEvalCodeBlock* CodeCache::getUnlinkedEvalCodeBlock(VM& vm, IndirectEvalExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType)
89 {
90     return getUnlinkedGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictMode, JSParserScriptMode::Classic, debuggerMode, error, evalContextType);
91 }
92
93 UnlinkedModuleProgramCodeBlock* CodeCache::getUnlinkedModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error)
94 {
95     return getUnlinkedGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, JSParserStrictMode::Strict, JSParserScriptMode::Module, debuggerMode, error, EvalContextType::None);
96 }
97
98 UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& vm, const Identifier& name, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error)
99 {
100     bool isArrowFunctionContext = false;
101     SourceCodeKey key(
102         source, name.string(), SourceCodeType::FunctionType,
103         JSParserStrictMode::NotStrict,
104         JSParserScriptMode::Classic,
105         DerivedContextType::None,
106         EvalContextType::None,
107         isArrowFunctionContext,
108         debuggerMode, 
109         vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, 
110         vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No);
111     SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
112     if (cache && Options::useCodeCache()) {
113         UnlinkedFunctionExecutable* executable = jsCast<UnlinkedFunctionExecutable*>(cache->cell.get());
114         source.provider()->setSourceURLDirective(executable->sourceURLDirective());
115         source.provider()->setSourceMappingURLDirective(executable->sourceMappingURLDirective());
116         return executable;
117     }
118
119     JSTextPosition positionBeforeLastNewline;
120     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
121         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
122         JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
123         error, &positionBeforeLastNewline);
124     if (!program) {
125         RELEASE_ASSERT(error.isValid());
126         return nullptr;
127     }
128
129     // This function assumes an input string that would result in a single function declaration.
130     StatementNode* statement = program->singleStatement();
131     if (UNLIKELY(!statement)) {
132         JSToken token;
133         error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1);
134         return nullptr;
135     }
136     ASSERT(statement->isBlock());
137
138     StatementNode* funcDecl = static_cast<BlockNode*>(statement)->singleStatement();
139     if (UNLIKELY(!funcDecl)) {
140         JSToken token;
141         error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1);
142         return nullptr;
143     }
144     ASSERT(funcDecl->isFuncDeclNode());
145
146     FunctionMetadataNode* metadata = static_cast<FuncDeclNode*>(funcDecl)->metadata();
147     ASSERT(metadata);
148     if (!metadata)
149         return nullptr;
150     
151     metadata->overrideName(name);
152     metadata->setEndPosition(positionBeforeLastNewline);
153     // The Function constructor only has access to global variables, so no variables will be under TDZ unless they're
154     // in the global lexical environment, which we always TDZ check accesses from.
155     VariableEnvironment emptyTDZVariables;
156     ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode());
157     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, emptyTDZVariables, DerivedContextType::None);
158
159     functionExecutable->setSourceURLDirective(source.provider()->sourceURL());
160     functionExecutable->setSourceMappingURLDirective(source.provider()->sourceMappingURL());
161
162     if (Options::useCodeCache())
163         m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age()));
164     return functionExecutable;
165 }
166
167 }