[JSC] Shrink UnlinkedFunctionExecutable
[WebKit-https.git] / Source / JavaScriptCore / runtime / FunctionExecutable.h
1 /*
2  * Copyright (C) 2009-2018 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 #pragma once
27
28 #include "ExecutableToCodeBlockEdge.h"
29 #include "ScriptExecutable.h"
30 #include "SourceCode.h"
31 #include <wtf/Box.h>
32 #include <wtf/Markable.h>
33
34 namespace JSC {
35
36 class FunctionExecutable final : public ScriptExecutable {
37     friend class JIT;
38     friend class LLIntOffsetsExtractor;
39 public:
40     typedef ScriptExecutable Base;
41     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
42
43     template<typename CellType, SubspaceAccess>
44     static IsoSubspace* subspaceFor(VM& vm)
45     {
46         return &vm.functionExecutableSpace.space;
47     }
48
49     static FunctionExecutable* create(
50         VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, 
51         unsigned lastLine, unsigned endColumn, Intrinsic intrinsic)
52     {
53         FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, lastLine, endColumn, intrinsic);
54         executable->finishCreation(vm);
55         return executable;
56     }
57     static FunctionExecutable* fromGlobalCode(
58         const Identifier& name, ExecState&, const SourceCode&, 
59         JSObject*& exception, int overrideLineNumber, Optional<int> functionConstructorParametersEndPosition);
60
61     static void destroy(JSCell*);
62         
63     UnlinkedFunctionExecutable* unlinkedExecutable() const
64     {
65         return m_unlinkedExecutable.get();
66     }
67
68     // Returns either call or construct bytecode. This can be appropriate
69     // for answering questions that that don't vary between call and construct --
70     // for example, argumentsRegister().
71     FunctionCodeBlock* eitherCodeBlock()
72     {
73         ExecutableToCodeBlockEdge* edge;
74         if (m_codeBlockForCall)
75             edge = m_codeBlockForCall.get();
76         else
77             edge = m_codeBlockForConstruct.get();
78         return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(edge));
79     }
80         
81     bool isGeneratedForCall() const
82     {
83         return !!m_codeBlockForCall;
84     }
85
86     FunctionCodeBlock* codeBlockForCall()
87     {
88         return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_codeBlockForCall.get()));
89     }
90
91     bool isGeneratedForConstruct() const
92     {
93         return !!m_codeBlockForConstruct;
94     }
95
96     FunctionCodeBlock* codeBlockForConstruct()
97     {
98         return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_codeBlockForConstruct.get()));
99     }
100         
101     bool isGeneratedFor(CodeSpecializationKind kind)
102     {
103         if (kind == CodeForCall)
104             return isGeneratedForCall();
105         ASSERT(kind == CodeForConstruct);
106         return isGeneratedForConstruct();
107     }
108         
109     FunctionCodeBlock* codeBlockFor(CodeSpecializationKind kind)
110     {
111         if (kind == CodeForCall)
112             return codeBlockForCall();
113         ASSERT(kind == CodeForConstruct);
114         return codeBlockForConstruct();
115     }
116
117     FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
118         
119     FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
120     {
121         return baselineCodeBlockFor(kind);
122     }
123
124     RefPtr<TypeSet> returnStatementTypeSet() 
125     {
126         RareData& rareData = ensureRareData();
127         if (!rareData.m_returnStatementTypeSet)
128             rareData.m_returnStatementTypeSet = TypeSet::create();
129         return rareData.m_returnStatementTypeSet;
130     }
131         
132     FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
133     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
134     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
135     bool isClass() const { return m_unlinkedExecutable->isClass(); }
136     bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
137     bool isGetter() const { return parseMode() == SourceParseMode::GetterMode; }
138     bool isSetter() const { return parseMode() == SourceParseMode::SetterMode; }
139     bool isGenerator() const { return isGeneratorParseMode(parseMode()); }
140     bool isAsyncGenerator() const { return isAsyncGeneratorParseMode(parseMode()); }
141     bool isMethod() const { return parseMode() == SourceParseMode::MethodMode; }
142     bool hasCallerAndArgumentsProperties() const
143     {
144         // Per https://tc39.github.io/ecma262/#sec-forbidden-extensions, only sloppy-mode non-builtin functions in old-style (pre-ES6) syntactic forms can contain
145         // "caller" and "arguments".
146         return !isStrictMode() && parseMode() == SourceParseMode::NormalFunctionMode && !isClassConstructorFunction();
147     }
148     bool hasPrototypeProperty() const
149     {
150         return SourceParseModeSet(
151             SourceParseMode::NormalFunctionMode,
152             SourceParseMode::GeneratorBodyMode,
153             SourceParseMode::GeneratorWrapperFunctionMode,
154             SourceParseMode::GeneratorWrapperMethodMode,
155             SourceParseMode::AsyncGeneratorWrapperFunctionMode,
156             SourceParseMode::AsyncGeneratorWrapperMethodMode,
157             SourceParseMode::AsyncGeneratorBodyMode
158         ).contains(parseMode()) || isClass();
159     }
160     DerivedContextType derivedContextType() const { return m_unlinkedExecutable->derivedContextType(); }
161     bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
162     const Identifier& name() { return m_unlinkedExecutable->name(); }
163     const Identifier& ecmaName() { return m_unlinkedExecutable->ecmaName(); }
164     const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
165     unsigned parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
166     SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
167     JSParserScriptMode scriptMode() const { return m_unlinkedExecutable->scriptMode(); }
168     SourceCode classSource() const { return m_unlinkedExecutable->classSource(); }
169
170     static void visitChildren(JSCell*, SlotVisitor&);
171     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
172     {
173         return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
174     }
175
176     void setOverrideLineNumber(int overrideLineNumber)
177     {
178         if (overrideLineNumber == -1) {
179             if (UNLIKELY(m_rareData))
180                 m_rareData->m_overrideLineNumber = WTF::nullopt;
181             return;
182         }
183         ensureRareData().m_overrideLineNumber = overrideLineNumber;
184     }
185
186     Optional<int> overrideLineNumber() const
187     {
188         if (UNLIKELY(m_rareData))
189             return m_rareData->m_overrideLineNumber;
190         return WTF::nullopt;
191     }
192
193     unsigned typeProfilingStartOffset(VM&) const
194     {
195         if (UNLIKELY(m_rareData))
196             return m_rareData->m_typeProfilingStartOffset;
197         return m_unlinkedExecutable->typeProfilingStartOffset();
198     }
199
200     unsigned typeProfilingEndOffset(VM&) const
201     {
202         if (UNLIKELY(m_rareData))
203             return m_rareData->m_typeProfilingEndOffset;
204         return m_unlinkedExecutable->typeProfilingEndOffset();
205     }
206
207     unsigned parametersStartOffset() const
208     {
209         if (UNLIKELY(m_rareData))
210             return m_rareData->m_parametersStartOffset;
211         return m_unlinkedExecutable->parametersStartOffset();
212     }
213
214     void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset)
215     {
216         auto& rareData = ensureRareData();
217         rareData.m_parametersStartOffset = parametersStartOffset;
218         rareData.m_typeProfilingStartOffset = typeProfilingStartOffset;
219         rareData.m_typeProfilingEndOffset = typeProfilingEndOffset;
220     }
221
222     DECLARE_INFO;
223
224     InferredValue* singletonFunction()
225     {
226         if (VM::canUseJIT())
227             return m_singletonFunction.get();
228         return nullptr;
229     }
230
231     void notifyCreation(VM& vm, JSValue value, const char* reason)
232     {
233         if (VM::canUseJIT()) {
234             singletonFunction()->notifyWrite(vm, value, reason);
235             return;
236         }
237         switch (m_singletonFunctionState) {
238         case ClearWatchpoint:
239             m_singletonFunctionState = IsWatched;
240             return;
241         case IsWatched:
242             m_singletonFunctionState = IsInvalidated;
243             return;
244         case IsInvalidated:
245             return;
246         }
247     }
248
249     bool singletonFunctionHasBeenInvalidated()
250     {
251         if (VM::canUseJIT())
252             return singletonFunction()->hasBeenInvalidated();
253         return m_singletonFunctionState == IsInvalidated;
254     }
255
256     // Cached poly proto structure for the result of constructing this executable.
257     Structure* cachedPolyProtoStructure() { return m_cachedPolyProtoStructure.get(); }
258     void setCachedPolyProtoStructure(VM& vm, Structure* structure) { m_cachedPolyProtoStructure.set(vm, this, structure); }
259
260     InlineWatchpointSet& ensurePolyProtoWatchpoint()
261     {
262         if (!m_polyProtoWatchpoint)
263             m_polyProtoWatchpoint = Box<InlineWatchpointSet>::create(IsWatched);
264         return *m_polyProtoWatchpoint;
265     }
266
267     Box<InlineWatchpointSet> sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
268
269 private:
270     friend class ExecutableBase;
271     FunctionExecutable(
272         VM&, const SourceCode&, UnlinkedFunctionExecutable*,
273         unsigned lastLine, unsigned endColumn, Intrinsic);
274     
275     void finishCreation(VM&);
276
277     friend class ScriptExecutable;
278
279     struct RareData {
280         WTF_MAKE_STRUCT_FAST_ALLOCATED;
281         Markable<int, IntegralMarkableTraits<int, -1>> m_overrideLineNumber;
282         unsigned m_parametersStartOffset { 0 };
283         unsigned m_typeProfilingStartOffset { UINT_MAX };
284         unsigned m_typeProfilingEndOffset { UINT_MAX };
285         RefPtr<TypeSet> m_returnStatementTypeSet;
286     };
287
288     RareData& ensureRareData()
289     {
290         if (LIKELY(m_rareData))
291             return *m_rareData;
292         return ensureRareDataSlow();
293     }
294     RareData& ensureRareDataSlow();
295
296     std::unique_ptr<RareData> m_rareData;
297     WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
298     WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
299     WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
300     union {
301         WriteBarrier<InferredValue> m_singletonFunction;
302         WatchpointState m_singletonFunctionState;
303     };
304     WriteBarrier<Structure> m_cachedPolyProtoStructure;
305     Box<InlineWatchpointSet> m_polyProtoWatchpoint;
306 };
307
308 } // namespace JSC