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