[JSC] Remove gcc warnings on mips and armv7
[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 "Exception.h"
33 #include "FunctionCodeBlock.h"
34 #include "IsoCellSetInlines.h"
35 #include "JIT.h"
36 #include "JSCInlines.h"
37 #include "LLIntEntrypoint.h"
38 #include "ModuleProgramCodeBlock.h"
39 #include "Parser.h"
40 #include "ProgramCodeBlock.h"
41 #include "TypeProfiler.h"
42 #include "VMInlines.h"
43 #include <wtf/CommaPrinter.h>
44
45 namespace JSC {
46
47 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ScriptExecutable) };
48
49 ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, EvalContextType evalContextType, Intrinsic intrinsic)
50     : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED, intrinsic)
51     , m_features(isInStrictContext ? StrictModeFeature : 0)
52     , m_didTryToEnterInLoop(false)
53     , m_hasCapturedVariables(false)
54     , m_neverInline(false)
55     , m_neverOptimize(false)
56     , m_neverFTLOptimize(false)
57     , m_isArrowFunctionContext(isInArrowFunctionContext)
58     , m_canUseOSRExitFuzzing(true)
59     , m_derivedContextType(static_cast<unsigned>(derivedContextType))
60     , m_evalContextType(static_cast<unsigned>(evalContextType))
61     , m_overrideLineNumber(-1)
62     , m_lastLine(-1)
63     , m_endColumn(UINT_MAX)
64     , m_typeProfilingStartOffset(UINT_MAX)
65     , m_typeProfilingEndOffset(UINT_MAX)
66     , m_source(source)
67 {
68 }
69
70 void ScriptExecutable::destroy(JSCell* cell)
71 {
72     static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
73 }
74
75 void ScriptExecutable::clearCode(IsoCellSet& clearableCodeSet)
76 {
77     Base::clearCode();
78     ASSERT(&VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor(*subspace()) == &clearableCodeSet);
79     clearableCodeSet.remove(this);
80 }
81
82 void ScriptExecutable::installCode(CodeBlock* codeBlock)
83 {
84     installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
85 }
86
87 void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind)
88 {
89     if (genericCodeBlock)
90         CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ());
91     
92     CodeBlock* oldCodeBlock = nullptr;
93     
94     switch (codeType) {
95     case GlobalCode: {
96         ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
97         ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock);
98         
99         ASSERT(kind == CodeForCall);
100         
101         oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_programCodeBlock.get());
102         executable->m_programCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
103         break;
104     }
105
106     case ModuleCode: {
107         ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
108         ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock);
109
110         ASSERT(kind == CodeForCall);
111
112         oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_moduleProgramCodeBlock.get());
113         executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
114         break;
115     }
116
117     case EvalCode: {
118         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
119         EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock);
120         
121         ASSERT(kind == CodeForCall);
122         
123         oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_evalCodeBlock.get());
124         executable->m_evalCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
125         break;
126     }
127         
128     case FunctionCode: {
129         FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
130         FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock);
131         
132         switch (kind) {
133         case CodeForCall:
134             oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForCall.get());
135             executable->m_codeBlockForCall.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
136             break;
137         case CodeForConstruct:
138             oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForConstruct.get());
139             executable->m_codeBlockForConstruct.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
140             break;
141         }
142         break;
143     }
144     }
145
146     switch (kind) {
147     case CodeForCall:
148         m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
149         m_jitCodeForCallWithArityCheck = nullptr;
150         m_numParametersForCall = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
151         break;
152     case CodeForConstruct:
153         m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
154         m_jitCodeForConstructWithArityCheck = nullptr;
155         m_numParametersForConstruct = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
156         break;
157     }
158
159     auto& clearableCodeSet = VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor(*subspace());
160     if (hasClearableCode())
161         clearableCodeSet.add(this);
162     else
163         clearableCodeSet.remove(this);
164
165     if (genericCodeBlock) {
166         RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
167         RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
168         
169         if (UNLIKELY(Options::verboseOSR()))
170             dataLog("Installing ", *genericCodeBlock, "\n");
171         
172         if (UNLIKELY(vm.m_perBytecodeProfiler))
173             vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock);
174         
175         Debugger* debugger = genericCodeBlock->globalObject()->debugger();
176         if (UNLIKELY(debugger))
177             debugger->registerCodeBlock(genericCodeBlock);
178     }
179
180     if (oldCodeBlock)
181         oldCodeBlock->unlinkIncomingCalls();
182
183     vm.heap.writeBarrier(this);
184 }
185
186 CodeBlock* ScriptExecutable::newCodeBlockFor(
187     CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception)
188 {
189     VM* vm = scope->vm();
190     auto throwScope = DECLARE_THROW_SCOPE(*vm);
191
192     ASSERT(vm->heap.isDeferred());
193     ASSERT(endColumn() != UINT_MAX);
194
195     JSGlobalObject* globalObject = scope->globalObject(*vm);
196     ExecState* exec = globalObject->globalExec();
197
198     if (classInfo(*vm) == EvalExecutable::info()) {
199         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
200         RELEASE_ASSERT(kind == CodeForCall);
201         RELEASE_ASSERT(!executable->m_evalCodeBlock);
202         RELEASE_ASSERT(!function);
203         auto codeBlock = EvalCodeBlock::create(vm,
204             executable, executable->m_unlinkedEvalCodeBlock.get(), scope,
205             executable->source().provider());
206         EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
207         if (!codeBlock) {
208             exception = throwException(
209                 exec, throwScope,
210                 createOutOfMemoryError(exec));
211             return nullptr;
212         }
213         return codeBlock;
214     }
215     
216     if (classInfo(*vm) == ProgramExecutable::info()) {
217         ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
218         RELEASE_ASSERT(kind == CodeForCall);
219         RELEASE_ASSERT(!executable->m_programCodeBlock);
220         RELEASE_ASSERT(!function);
221         auto codeBlock = ProgramCodeBlock::create(vm,
222             executable, executable->m_unlinkedProgramCodeBlock.get(), scope,
223             executable->source().provider(), startColumn());
224         EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
225         if (!codeBlock) {
226             exception = throwException(
227                 exec, throwScope,
228                 createOutOfMemoryError(exec));
229             return nullptr;
230         }
231         return codeBlock;
232     }
233
234     if (classInfo(*vm) == ModuleProgramExecutable::info()) {
235         ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
236         RELEASE_ASSERT(kind == CodeForCall);
237         RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
238         RELEASE_ASSERT(!function);
239         auto codeBlock = ModuleProgramCodeBlock::create(vm,
240             executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope,
241             executable->source().provider(), startColumn());
242         EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
243         if (!codeBlock) {
244             exception = throwException(
245                 exec, throwScope,
246                 createOutOfMemoryError(exec));
247             return nullptr;
248         }
249         return codeBlock;
250     }
251
252     RELEASE_ASSERT(classInfo(*vm) == FunctionExecutable::info());
253     RELEASE_ASSERT(function);
254     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
255     RELEASE_ASSERT(!executable->codeBlockFor(kind));
256     ParserError error;
257     DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
258     UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 
259         executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
260             *vm, executable->m_source, kind, debuggerMode, error, 
261             executable->parseMode());
262     recordParse(
263         executable->m_unlinkedExecutable->features(), 
264         executable->m_unlinkedExecutable->hasCapturedVariables(),
265         lastLine(), endColumn()); 
266     if (!unlinkedCodeBlock) {
267         exception = throwException(
268             globalObject->globalExec(), throwScope,
269             error.toErrorObject(globalObject, executable->m_source));
270         return nullptr;
271     }
272
273     RELEASE_AND_RETURN(throwScope, 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 std::optional<Exception*> 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 static_cast<Exception*>(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 static_cast<Exception*>(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 std::nullopt;
369 }
370
371 CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const
372 {
373     return CodeBlockHash(source(), kind);
374 }
375
376 } // namespace JSC