TemplateObject passed to template literal tags are not always identical for the same...
[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 struct FunctionOverrideInfo;
37
38 class FunctionExecutable final : public ScriptExecutable {
39     friend class JIT;
40     friend class LLIntOffsetsExtractor;
41 public:
42     typedef ScriptExecutable Base;
43     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
44
45     template<typename CellType, SubspaceAccess>
46     static IsoSubspace* subspaceFor(VM& vm)
47     {
48         return &vm.functionExecutableSpace.space;
49     }
50
51     static FunctionExecutable* create(VM& vm, ScriptExecutable* topLevelExecutable, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, Intrinsic intrinsic)
52     {
53         FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, intrinsic);
54         executable->finishCreation(vm, topLevelExecutable);
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     int lineCount() const
194     {
195         if (UNLIKELY(m_rareData))
196             return m_rareData->m_lineCount;
197         return m_unlinkedExecutable->lineCount();
198     }
199
200     int endColumn() const
201     {
202         if (UNLIKELY(m_rareData))
203             return m_rareData->m_endColumn;
204         return m_unlinkedExecutable->linkedEndColumn(m_source.startColumn().oneBasedInt());
205     }
206
207     int firstLine() const
208     {
209         return source().firstLine().oneBasedInt();
210     }
211
212     int lastLine() const
213     {
214         return firstLine() + lineCount();
215     }
216
217     unsigned typeProfilingStartOffset(VM&) const
218     {
219         return typeProfilingStartOffset();
220     }
221
222     unsigned typeProfilingStartOffset() const
223     {
224         if (UNLIKELY(m_rareData))
225             return m_rareData->m_typeProfilingStartOffset;
226         return m_unlinkedExecutable->typeProfilingStartOffset();
227     }
228
229     unsigned typeProfilingEndOffset(VM&) const
230     {
231         return typeProfilingEndOffset();
232     }
233
234     unsigned typeProfilingEndOffset() const
235     {
236         if (UNLIKELY(m_rareData))
237             return m_rareData->m_typeProfilingEndOffset;
238         return m_unlinkedExecutable->typeProfilingEndOffset();
239     }
240
241     unsigned parametersStartOffset() const
242     {
243         if (UNLIKELY(m_rareData))
244             return m_rareData->m_parametersStartOffset;
245         return m_unlinkedExecutable->parametersStartOffset();
246     }
247
248     void overrideInfo(const FunctionOverrideInfo&);
249
250     DECLARE_INFO;
251
252     InferredValue* singletonFunction()
253     {
254         if (VM::canUseJIT())
255             return m_singletonFunction.get();
256         return nullptr;
257     }
258
259     void notifyCreation(VM& vm, JSValue value, const char* reason)
260     {
261         if (VM::canUseJIT()) {
262             singletonFunction()->notifyWrite(vm, value, reason);
263             return;
264         }
265         switch (m_singletonFunctionState) {
266         case ClearWatchpoint:
267             m_singletonFunctionState = IsWatched;
268             return;
269         case IsWatched:
270             m_singletonFunctionState = IsInvalidated;
271             return;
272         case IsInvalidated:
273             return;
274         }
275     }
276
277     bool singletonFunctionHasBeenInvalidated()
278     {
279         if (VM::canUseJIT())
280             return singletonFunction()->hasBeenInvalidated();
281         return m_singletonFunctionState == IsInvalidated;
282     }
283
284     // Cached poly proto structure for the result of constructing this executable.
285     Structure* cachedPolyProtoStructure()
286     {
287         if (UNLIKELY(m_rareData))
288             return m_rareData->m_cachedPolyProtoStructure.get();
289         return nullptr;
290     }
291     void setCachedPolyProtoStructure(VM& vm, Structure* structure)
292     {
293         ensureRareData().m_cachedPolyProtoStructure.set(vm, this, structure);
294     }
295
296     InlineWatchpointSet& ensurePolyProtoWatchpoint()
297     {
298         if (!m_polyProtoWatchpoint)
299             m_polyProtoWatchpoint = Box<InlineWatchpointSet>::create(IsWatched);
300         return *m_polyProtoWatchpoint;
301     }
302
303     Box<InlineWatchpointSet> sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
304
305     ScriptExecutable* topLevelExecutable() const { return m_topLevelExecutable.get(); }
306
307     TemplateObjectMap& ensureTemplateObjectMap(VM&);
308
309 private:
310     friend class ExecutableBase;
311     FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, Intrinsic);
312     
313     void finishCreation(VM&, ScriptExecutable* topLevelExecutable);
314
315     friend class ScriptExecutable;
316
317     struct RareData {
318         WTF_MAKE_STRUCT_FAST_ALLOCATED;
319         RefPtr<TypeSet> m_returnStatementTypeSet;
320         unsigned m_lineCount;
321         unsigned m_endColumn;
322         Markable<int, IntegralMarkableTraits<int, -1>> m_overrideLineNumber;
323         unsigned m_parametersStartOffset { 0 };
324         unsigned m_typeProfilingStartOffset { UINT_MAX };
325         unsigned m_typeProfilingEndOffset { UINT_MAX };
326         std::unique_ptr<TemplateObjectMap> m_templateObjectMap;
327         WriteBarrier<Structure> m_cachedPolyProtoStructure;
328     };
329
330     RareData& ensureRareData()
331     {
332         if (LIKELY(m_rareData))
333             return *m_rareData;
334         return ensureRareDataSlow();
335     }
336     RareData& ensureRareDataSlow();
337
338     // FIXME: We can merge rareData pointer and top-level executable pointer. First time, setting parent.
339     // If RareData is required, materialize RareData, swap it, and store top-level executable pointer inside RareData.
340     // https://bugs.webkit.org/show_bug.cgi?id=197625
341     std::unique_ptr<RareData> m_rareData;
342     WriteBarrier<ScriptExecutable> m_topLevelExecutable;
343     WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
344     WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
345     WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
346     union {
347         WriteBarrier<InferredValue> m_singletonFunction;
348         WatchpointState m_singletonFunctionState;
349     };
350     Box<InlineWatchpointSet> m_polyProtoWatchpoint;
351 };
352
353 } // namespace JSC