We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / ScriptExecutable.cpp
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 #include "config.h"
27
28 #include "BatchedTransitionOptimizer.h"
29 #include "CodeBlock.h"
30 #include "Debugger.h"
31 #include "EvalCodeBlock.h"
32 #include "FunctionCodeBlock.h"
33 #include "IsoCellSetInlines.h"
34 #include "JIT.h"
35 #include "JSCInlines.h"
36 #include "LLIntEntrypoint.h"
37 #include "ModuleProgramCodeBlock.h"
38 #include "Parser.h"
39 #include "ProgramCodeBlock.h"
40 #include "TypeProfiler.h"
41 #include "VMInlines.h"
42 #include <wtf/CommaPrinter.h>
43
44 namespace JSC {
45
46 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ScriptExecutable) };
47
48 ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, EvalContextType evalContextType, Intrinsic intrinsic)
49     : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED, intrinsic)
50     , m_features(isInStrictContext ? StrictModeFeature : 0)
51     , m_didTryToEnterInLoop(false)
52     , m_hasCapturedVariables(false)
53     , m_neverInline(false)
54     , m_neverOptimize(false)
55     , m_neverFTLOptimize(false)
56     , m_isArrowFunctionContext(isInArrowFunctionContext)
57     , m_canUseOSRExitFuzzing(true)
58     , m_derivedContextType(static_cast<unsigned>(derivedContextType))
59     , m_evalContextType(static_cast<unsigned>(evalContextType))
60     , m_overrideLineNumber(-1)
61     , m_lastLine(-1)
62     , m_endColumn(UINT_MAX)
63     , m_typeProfilingStartOffset(UINT_MAX)
64     , m_typeProfilingEndOffset(UINT_MAX)
65     , m_source(source)
66 {
67 }
68
69 void ScriptExecutable::destroy(JSCell* cell)
70 {
71     static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
72 }
73
74 void ScriptExecutable::clearCode(IsoCellSet& clearableCodeSet)
75 {
76     Base::clearCode();
77     ASSERT(&VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor(*subspace()) == &clearableCodeSet);
78     clearableCodeSet.remove(this);
79 }
80
81 void ScriptExecutable::installCode(CodeBlock* codeBlock)
82 {
83     installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
84 }
85
86 void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind)
87 {
88     if (genericCodeBlock)
89         CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ());
90     
91     CodeBlock* oldCodeBlock = nullptr;
92     
93     switch (codeType) {
94     case GlobalCode: {
95         ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
96         ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock);
97         
98         ASSERT(kind == CodeForCall);
99         
100         oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_programCodeBlock.get());
101         executable->m_programCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
102         break;
103     }
104
105     case ModuleCode: {
106         ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
107         ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock);
108
109         ASSERT(kind == CodeForCall);
110
111         oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_moduleProgramCodeBlock.get());
112         executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
113         break;
114     }
115
116     case EvalCode: {
117         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
118         EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock);
119         
120         ASSERT(kind == CodeForCall);
121         
122         oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_evalCodeBlock.get());
123         executable->m_evalCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
124         break;
125     }
126         
127     case FunctionCode: {
128         FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
129         FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock);
130         
131         switch (kind) {
132         case CodeForCall:
133             oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForCall.get());
134             executable->m_codeBlockForCall.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
135             break;
136         case CodeForConstruct:
137             oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForConstruct.get());
138             executable->m_codeBlockForConstruct.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
139             break;
140         }
141         break;
142     }
143     }
144
145     switch (kind) {
146     case CodeForCall:
147         m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
148         m_jitCodeForCallWithArityCheck = nullptr;
149         m_numParametersForCall = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
150         break;
151     case CodeForConstruct:
152         m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
153         m_jitCodeForConstructWithArityCheck = nullptr;
154         m_numParametersForConstruct = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
155         break;
156     }
157
158     auto& clearableCodeSet = VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor(*subspace());
159     if (hasClearableCode())
160         clearableCodeSet.add(this);
161     else
162         clearableCodeSet.remove(this);
163
164     if (genericCodeBlock) {
165         RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
166         RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
167         
168         if (UNLIKELY(Options::verboseOSR()))
169             dataLog("Installing ", *genericCodeBlock, "\n");
170         
171         if (UNLIKELY(vm.m_perBytecodeProfiler))
172             vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock);
173         
174         Debugger* debugger = genericCodeBlock->globalObject()->debugger();
175         if (UNLIKELY(debugger))
176             debugger->registerCodeBlock(genericCodeBlock);
177     }
178
179     if (oldCodeBlock)
180         oldCodeBlock->unlinkIncomingCalls();
181
182     vm.heap.writeBarrier(this);
183 }
184
185 CodeBlock* ScriptExecutable::newCodeBlockFor(
186     CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception)
187 {
188     VM* vm = scope->vm();
189     auto throwScope = DECLARE_THROW_SCOPE(*vm);
190
191     ASSERT(vm->heap.isDeferred());
192     ASSERT(endColumn() != UINT_MAX);
193
194     JSGlobalObject* globalObject = scope->globalObject(*vm);
195     ExecState* exec = globalObject->globalExec();
196
197     if (classInfo(*vm) == EvalExecutable::info()) {
198         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
199         RELEASE_ASSERT(kind == CodeForCall);
200         RELEASE_ASSERT(!executable->m_evalCodeBlock);
201         RELEASE_ASSERT(!function);
202         auto codeBlock = EvalCodeBlock::create(vm,
203             executable, executable->m_unlinkedEvalCodeBlock.get(), scope,
204             executable->source().provider());
205         EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
206         if (!codeBlock) {
207             exception = throwException(
208                 exec, throwScope,
209                 createOutOfMemoryError(exec));
210             return nullptr;
211         }
212         return codeBlock;
213     }
214     
215     if (classInfo(*vm) == ProgramExecutable::info()) {
216         ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
217         RELEASE_ASSERT(kind == CodeForCall);
218         RELEASE_ASSERT(!executable->m_programCodeBlock);
219         RELEASE_ASSERT(!function);
220         auto codeBlock = ProgramCodeBlock::create(vm,
221             executable, executable->m_unlinkedProgramCodeBlock.get(), scope,
222             executable->source().provider(), startColumn());
223         EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
224         if (!codeBlock) {
225             exception = throwException(
226                 exec, throwScope,
227                 createOutOfMemoryError(exec));
228             return nullptr;
229         }
230         return codeBlock;
231     }
232
233     if (classInfo(*vm) == ModuleProgramExecutable::info()) {
234         ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
235         RELEASE_ASSERT(kind == CodeForCall);
236         RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
237         RELEASE_ASSERT(!function);
238         auto codeBlock = ModuleProgramCodeBlock::create(vm,
239             executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope,
240             executable->source().provider(), startColumn());
241         EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
242         if (!codeBlock) {
243             exception = throwException(
244                 exec, throwScope,
245                 createOutOfMemoryError(exec));
246             return nullptr;
247         }
248         return codeBlock;
249     }
250
251     RELEASE_ASSERT(classInfo(*vm) == FunctionExecutable::info());
252     RELEASE_ASSERT(function);
253     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
254     RELEASE_ASSERT(!executable->codeBlockFor(kind));
255     ParserError error;
256     DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
257     UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 
258         executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
259             *vm, executable->m_source, kind, debuggerMode, error, 
260             executable->parseMode());
261     recordParse(
262         executable->m_unlinkedExecutable->features(), 
263         executable->m_unlinkedExecutable->hasCapturedVariables(),
264         lastLine(), endColumn()); 
265     if (!unlinkedCodeBlock) {
266         exception = throwException(
267             globalObject->globalExec(), throwScope,
268             error.toErrorObject(globalObject, executable->m_source));
269         return nullptr;
270     }
271
272     throwScope.release();
273     return FunctionCodeBlock::create(vm, executable, unlinkedCodeBlock, scope, 
274         source().provider(), source().startOffset(), startColumn());
275 }
276
277 CodeBlock* ScriptExecutable::newReplacementCodeBlockFor(
278     CodeSpecializationKind kind)
279 {
280     VM& vm = *this->vm();
281     if (classInfo(vm) == EvalExecutable::info()) {
282         RELEASE_ASSERT(kind == CodeForCall);
283         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
284         EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>(
285             executable->codeBlock()->baselineVersion());
286         EvalCodeBlock* result = EvalCodeBlock::create(&vm,
287             CodeBlock::CopyParsedBlock, *baseline);
288         result->setAlternative(vm, baseline);
289         return result;
290     }
291     
292     if (classInfo(vm) == ProgramExecutable::info()) {
293         RELEASE_ASSERT(kind == CodeForCall);
294         ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
295         ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>(
296             executable->codeBlock()->baselineVersion());
297         ProgramCodeBlock* result = ProgramCodeBlock::create(&vm,
298             CodeBlock::CopyParsedBlock, *baseline);
299         result->setAlternative(vm, baseline);
300         return result;
301     }
302
303     if (classInfo(vm) == ModuleProgramExecutable::info()) {
304         RELEASE_ASSERT(kind == CodeForCall);
305         ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
306         ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>(
307             executable->codeBlock()->baselineVersion());
308         ModuleProgramCodeBlock* result = ModuleProgramCodeBlock::create(&vm,
309             CodeBlock::CopyParsedBlock, *baseline);
310         result->setAlternative(vm, baseline);
311         return result;
312     }
313
314     RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info());
315     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
316     FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>(
317         executable->codeBlockFor(kind)->baselineVersion());
318     FunctionCodeBlock* result = FunctionCodeBlock::create(&vm,
319         CodeBlock::CopyParsedBlock, *baseline);
320     result->setAlternative(vm, baseline);
321     return result;
322 }
323
324 static void setupLLInt(VM& vm, CodeBlock* codeBlock)
325 {
326     LLInt::setEntrypoint(vm, codeBlock);
327 }
328
329 static void setupJIT(VM& vm, CodeBlock* codeBlock)
330 {
331 #if ENABLE(JIT)
332     CompilationResult result = JIT::compile(&vm, codeBlock, JITCompilationMustSucceed);
333     RELEASE_ASSERT(result == CompilationSuccessful);
334 #else
335     UNUSED_PARAM(vm);
336     UNUSED_PARAM(codeBlock);
337     UNREACHABLE_FOR_PLATFORM();
338 #endif
339 }
340
341 JSObject* ScriptExecutable::prepareForExecutionImpl(
342     VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
343 {
344     auto throwScope = DECLARE_THROW_SCOPE(vm);
345     DeferGCForAWhile deferGC(vm.heap);
346
347     if (vm.getAndClearFailNextNewCodeBlock()) {
348         auto& state = *scope->globalObject(vm)->globalExec();
349         return throwException(&state, throwScope, createError(&state, "Forced Failure"_s));
350     }
351
352     JSObject* exception = nullptr;
353     CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception);
354     resultCodeBlock = codeBlock;
355     EXCEPTION_ASSERT(!!throwScope.exception() == !codeBlock);
356     if (UNLIKELY(!codeBlock))
357         return exception;
358     
359     if (Options::validateBytecode())
360         codeBlock->validate();
361     
362     if (Options::useLLInt())
363         setupLLInt(vm, codeBlock);
364     else
365         setupJIT(vm, codeBlock);
366     
367     installCode(vm, codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
368     return nullptr;
369 }
370
371 CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const
372 {
373     return CodeBlockHash(source(), kind);
374 }
375
376 } // namespace JSC