]>
Commit | Line | Data |
---|---|---|
f9bf01c6 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2009, 2010, 2013, 2015 Apple Inc. All rights reserved. |
f9bf01c6 A |
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 | #include "Executable.h" | |
28 | ||
93a37866 | 29 | #include "BatchedTransitionOptimizer.h" |
f9bf01c6 | 30 | #include "CodeBlock.h" |
6fe7ccc8 | 31 | #include "DFGDriver.h" |
f9bf01c6 | 32 | #include "JIT.h" |
81345200 | 33 | #include "JSCInlines.h" |
ed1e77d3 A |
34 | #include "JSFunctionNameScope.h" |
35 | #include "LLIntEntrypoint.h" | |
f9bf01c6 | 36 | #include "Parser.h" |
81345200 | 37 | #include "ProfilerDatabase.h" |
ed1e77d3 | 38 | #include "TypeProfiler.h" |
81345200 | 39 | #include <wtf/CommaPrinter.h> |
6fe7ccc8 | 40 | #include <wtf/Vector.h> |
93a37866 | 41 | #include <wtf/text/StringBuilder.h> |
f9bf01c6 | 42 | |
6fe7ccc8 A |
43 | namespace JSC { |
44 | ||
ed1e77d3 | 45 | const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; |
6fe7ccc8 | 46 | |
6fe7ccc8 A |
47 | void ExecutableBase::destroy(JSCell* cell) |
48 | { | |
93a37866 | 49 | static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); |
6fe7ccc8 | 50 | } |
14957cd0 | 51 | |
93a37866 | 52 | void ExecutableBase::clearCode() |
6fe7ccc8 A |
53 | { |
54 | #if ENABLE(JIT) | |
ed1e77d3 A |
55 | m_jitCodeForCall = nullptr; |
56 | m_jitCodeForConstruct = nullptr; | |
6fe7ccc8 A |
57 | m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); |
58 | m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); | |
81345200 A |
59 | m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); |
60 | m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); | |
6fe7ccc8 A |
61 | #endif |
62 | m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; | |
63 | m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; | |
64 | } | |
f9bf01c6 | 65 | |
6fe7ccc8 A |
66 | #if ENABLE(DFG_JIT) |
67 | Intrinsic ExecutableBase::intrinsic() const | |
68 | { | |
69 | if (const NativeExecutable* nativeExecutable = jsDynamicCast<const NativeExecutable*>(this)) | |
70 | return nativeExecutable->intrinsic(); | |
71 | return NoIntrinsic; | |
72 | } | |
93a37866 A |
73 | #else |
74 | Intrinsic ExecutableBase::intrinsic() const | |
75 | { | |
76 | return NoIntrinsic; | |
77 | } | |
6fe7ccc8 A |
78 | #endif |
79 | ||
ed1e77d3 | 80 | const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) }; |
14957cd0 | 81 | |
6fe7ccc8 A |
82 | void NativeExecutable::destroy(JSCell* cell) |
83 | { | |
93a37866 | 84 | static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); |
6fe7ccc8 | 85 | } |
6fe7ccc8 A |
86 | |
87 | #if ENABLE(DFG_JIT) | |
88 | Intrinsic NativeExecutable::intrinsic() const | |
89 | { | |
90 | return m_intrinsic; | |
91 | } | |
92 | #endif | |
14957cd0 | 93 | |
ed1e77d3 A |
94 | const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; |
95 | ||
96 | ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext) | |
97 | : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED) | |
98 | , m_source(source) | |
99 | , m_features(isInStrictContext ? StrictModeFeature : 0) | |
100 | , m_hasCapturedVariables(false) | |
101 | , m_neverInline(false) | |
102 | , m_didTryToEnterInLoop(false) | |
103 | , m_overrideLineNumber(-1) | |
104 | , m_firstLine(-1) | |
105 | , m_lastLine(-1) | |
106 | , m_startColumn(UINT_MAX) | |
107 | , m_endColumn(UINT_MAX) | |
108 | , m_typeProfilingStartOffset(UINT_MAX) | |
109 | , m_typeProfilingEndOffset(UINT_MAX) | |
110 | { | |
111 | } | |
81345200 | 112 | |
81345200 | 113 | void ScriptExecutable::destroy(JSCell* cell) |
f9bf01c6 | 114 | { |
81345200 | 115 | static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); |
f9bf01c6 | 116 | } |
f9bf01c6 | 117 | |
81345200 A |
118 | void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) |
119 | { | |
120 | RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); | |
121 | RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); | |
122 | ||
ed1e77d3 A |
123 | if (Options::verboseOSR()) |
124 | dataLog("Installing ", *genericCodeBlock, "\n"); | |
125 | ||
81345200 A |
126 | VM& vm = *genericCodeBlock->vm(); |
127 | ||
128 | if (vm.m_perBytecodeProfiler) | |
129 | vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock); | |
130 | ||
131 | ASSERT(vm.heap.isDeferred()); | |
132 | ||
133 | CodeSpecializationKind kind = genericCodeBlock->specializationKind(); | |
134 | ||
135 | RefPtr<CodeBlock> oldCodeBlock; | |
136 | ||
137 | switch (kind) { | |
138 | case CodeForCall: | |
139 | m_jitCodeForCall = genericCodeBlock->jitCode(); | |
140 | m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); | |
141 | m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); | |
142 | m_numParametersForCall = genericCodeBlock->numParameters(); | |
143 | break; | |
144 | case CodeForConstruct: | |
145 | m_jitCodeForConstruct = genericCodeBlock->jitCode(); | |
146 | m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); | |
147 | m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); | |
148 | m_numParametersForConstruct = genericCodeBlock->numParameters(); | |
149 | break; | |
150 | } | |
151 | ||
152 | switch (genericCodeBlock->codeType()) { | |
153 | case GlobalCode: { | |
154 | ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); | |
155 | ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock); | |
156 | ||
157 | ASSERT(kind == CodeForCall); | |
158 | ||
159 | oldCodeBlock = executable->m_programCodeBlock; | |
160 | executable->m_programCodeBlock = codeBlock; | |
161 | break; | |
162 | } | |
163 | ||
164 | case EvalCode: { | |
165 | EvalExecutable* executable = jsCast<EvalExecutable*>(this); | |
166 | EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock); | |
167 | ||
168 | ASSERT(kind == CodeForCall); | |
169 | ||
170 | oldCodeBlock = executable->m_evalCodeBlock; | |
171 | executable->m_evalCodeBlock = codeBlock; | |
172 | break; | |
173 | } | |
174 | ||
175 | case FunctionCode: { | |
176 | FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); | |
177 | FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock); | |
178 | ||
179 | switch (kind) { | |
180 | case CodeForCall: | |
181 | oldCodeBlock = executable->m_codeBlockForCall; | |
182 | executable->m_codeBlockForCall = codeBlock; | |
183 | break; | |
184 | case CodeForConstruct: | |
185 | oldCodeBlock = executable->m_codeBlockForConstruct; | |
186 | executable->m_codeBlockForConstruct = codeBlock; | |
187 | break; | |
188 | } | |
189 | break; | |
190 | } } | |
191 | ||
192 | if (oldCodeBlock) | |
193 | oldCodeBlock->unlinkIncomingCalls(); | |
194 | ||
195 | Debugger* debugger = genericCodeBlock->globalObject()->debugger(); | |
196 | if (debugger) | |
197 | debugger->registerCodeBlock(genericCodeBlock); | |
198 | ||
199 | Heap::heap(this)->writeBarrier(this); | |
200 | } | |
201 | ||
ed1e77d3 A |
202 | RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( |
203 | CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception) | |
81345200 | 204 | { |
ed1e77d3 | 205 | VM* vm = scope->vm(); |
81345200 A |
206 | |
207 | ASSERT(vm->heap.isDeferred()); | |
208 | ASSERT(startColumn() != UINT_MAX); | |
209 | ASSERT(endColumn() != UINT_MAX); | |
210 | ||
211 | if (classInfo() == EvalExecutable::info()) { | |
212 | EvalExecutable* executable = jsCast<EvalExecutable*>(this); | |
213 | RELEASE_ASSERT(kind == CodeForCall); | |
214 | RELEASE_ASSERT(!executable->m_evalCodeBlock); | |
215 | RELEASE_ASSERT(!function); | |
216 | return adoptRef(new EvalCodeBlock( | |
ed1e77d3 | 217 | executable, executable->m_unlinkedEvalCodeBlock.get(), scope, |
81345200 A |
218 | executable->source().provider())); |
219 | } | |
220 | ||
221 | if (classInfo() == ProgramExecutable::info()) { | |
222 | ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); | |
223 | RELEASE_ASSERT(kind == CodeForCall); | |
224 | RELEASE_ASSERT(!executable->m_programCodeBlock); | |
225 | RELEASE_ASSERT(!function); | |
226 | return adoptRef(new ProgramCodeBlock( | |
ed1e77d3 | 227 | executable, executable->m_unlinkedProgramCodeBlock.get(), scope, |
81345200 A |
228 | executable->source().provider(), executable->source().startColumn())); |
229 | } | |
230 | ||
231 | RELEASE_ASSERT(classInfo() == FunctionExecutable::info()); | |
232 | RELEASE_ASSERT(function); | |
233 | FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); | |
234 | RELEASE_ASSERT(!executable->codeBlockFor(kind)); | |
ed1e77d3 | 235 | JSGlobalObject* globalObject = scope->globalObject(); |
81345200 A |
236 | ParserError error; |
237 | DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; | |
238 | ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; | |
239 | UnlinkedFunctionCodeBlock* unlinkedCodeBlock = | |
240 | executable->m_unlinkedExecutable->codeBlockFor( | |
ed1e77d3 A |
241 | *vm, executable->m_source, kind, debuggerMode, profilerMode, error); |
242 | recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(), lastLine(), startColumn(), endColumn()); | |
81345200 A |
243 | if (!unlinkedCodeBlock) { |
244 | exception = vm->throwException( | |
245 | globalObject->globalExec(), | |
246 | error.toErrorObject(globalObject, executable->m_source)); | |
ed1e77d3 | 247 | return nullptr; |
81345200 | 248 | } |
14957cd0 | 249 | |
81345200 A |
250 | // Parsing reveals whether our function uses features that require a separate function name object in the scope chain. |
251 | // Be sure to add this scope before linking the bytecode because this scope will change the resolution depth of non-local variables. | |
ed1e77d3 A |
252 | if (functionNameIsInScope(executable->name(), executable->functionMode()) |
253 | && functionNameScopeIsDynamic(executable->usesEval(), executable->isStrictMode())) { | |
254 | // We shouldn't have to do this. But we do, because bytecode linking requires a real scope | |
255 | // chain. | |
256 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141885 | |
257 | SymbolTable* symbolTable = | |
258 | SymbolTable::createNameScopeTable(*vm, executable->name(), ReadOnly | DontDelete); | |
259 | scope = JSFunctionNameScope::create( | |
260 | *vm, scope->globalObject(), scope, symbolTable, function); | |
81345200 A |
261 | } |
262 | ||
263 | SourceProvider* provider = executable->source().provider(); | |
264 | unsigned sourceOffset = executable->source().startOffset(); | |
265 | unsigned startColumn = executable->source().startColumn(); | |
266 | ||
267 | return adoptRef(new FunctionCodeBlock( | |
ed1e77d3 | 268 | executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn)); |
81345200 A |
269 | } |
270 | ||
271 | PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( | |
272 | CodeSpecializationKind kind) | |
273 | { | |
274 | if (classInfo() == EvalExecutable::info()) { | |
275 | RELEASE_ASSERT(kind == CodeForCall); | |
276 | EvalExecutable* executable = jsCast<EvalExecutable*>(this); | |
277 | EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>( | |
278 | executable->m_evalCodeBlock->baselineVersion()); | |
279 | RefPtr<EvalCodeBlock> result = adoptRef(new EvalCodeBlock( | |
280 | CodeBlock::CopyParsedBlock, *baseline)); | |
281 | result->setAlternative(baseline); | |
282 | return result; | |
283 | } | |
284 | ||
285 | if (classInfo() == ProgramExecutable::info()) { | |
286 | RELEASE_ASSERT(kind == CodeForCall); | |
287 | ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); | |
288 | ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>( | |
289 | executable->m_programCodeBlock->baselineVersion()); | |
290 | RefPtr<ProgramCodeBlock> result = adoptRef(new ProgramCodeBlock( | |
291 | CodeBlock::CopyParsedBlock, *baseline)); | |
292 | result->setAlternative(baseline); | |
293 | return result; | |
294 | } | |
295 | ||
296 | RELEASE_ASSERT(classInfo() == FunctionExecutable::info()); | |
297 | FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); | |
298 | FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>( | |
299 | executable->codeBlockFor(kind)->baselineVersion()); | |
300 | RefPtr<FunctionCodeBlock> result = adoptRef(new FunctionCodeBlock( | |
301 | CodeBlock::CopyParsedBlock, *baseline)); | |
302 | result->setAlternative(baseline); | |
303 | return result; | |
304 | } | |
305 | ||
306 | static void setupLLInt(VM& vm, CodeBlock* codeBlock) | |
6fe7ccc8 | 307 | { |
81345200 | 308 | LLInt::setEntrypoint(vm, codeBlock); |
6fe7ccc8 | 309 | } |
81345200 A |
310 | |
311 | static void setupJIT(VM& vm, CodeBlock* codeBlock) | |
312 | { | |
313 | #if ENABLE(JIT) | |
314 | CompilationResult result = JIT::compile(&vm, codeBlock, JITCompilationMustSucceed); | |
315 | RELEASE_ASSERT(result == CompilationSuccessful); | |
316 | #else | |
317 | UNUSED_PARAM(vm); | |
318 | UNUSED_PARAM(codeBlock); | |
319 | UNREACHABLE_FOR_PLATFORM(); | |
6fe7ccc8 | 320 | #endif |
81345200 A |
321 | } |
322 | ||
323 | JSObject* ScriptExecutable::prepareForExecutionImpl( | |
ed1e77d3 | 324 | ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) |
81345200 A |
325 | { |
326 | VM& vm = exec->vm(); | |
327 | DeferGC deferGC(vm.heap); | |
328 | ||
329 | JSObject* exception = 0; | |
330 | RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, function, scope, exception); | |
331 | if (!codeBlock) { | |
332 | RELEASE_ASSERT(exception); | |
333 | return exception; | |
334 | } | |
335 | ||
336 | if (Options::validateBytecode()) | |
337 | codeBlock->validate(); | |
338 | ||
339 | if (Options::useLLInt()) | |
340 | setupLLInt(vm, codeBlock.get()); | |
341 | else | |
342 | setupJIT(vm, codeBlock.get()); | |
343 | ||
344 | installCode(codeBlock.get()); | |
345 | return 0; | |
346 | } | |
6fe7ccc8 | 347 | |
ed1e77d3 | 348 | const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) }; |
14957cd0 | 349 | |
ed1e77d3 | 350 | EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode) |
81345200 A |
351 | { |
352 | JSGlobalObject* globalObject = exec->lexicalGlobalObject(); | |
353 | if (!globalObject->evalEnabled()) { | |
354 | exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage())); | |
355 | return 0; | |
356 | } | |
357 | ||
358 | EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); | |
359 | executable->finishCreation(exec->vm()); | |
360 | ||
ed1e77d3 | 361 | UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode); |
81345200 A |
362 | if (!unlinkedEvalCode) |
363 | return 0; | |
364 | ||
365 | executable->m_unlinkedEvalCodeBlock.set(exec->vm(), executable, unlinkedEvalCode); | |
366 | ||
367 | return executable; | |
368 | } | |
369 | ||
370 | EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) | |
ed1e77d3 | 371 | : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext) |
f9bf01c6 A |
372 | { |
373 | } | |
374 | ||
6fe7ccc8 | 375 | void EvalExecutable::destroy(JSCell* cell) |
f9bf01c6 | 376 | { |
93a37866 | 377 | static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); |
14957cd0 A |
378 | } |
379 | ||
ed1e77d3 | 380 | const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; |
14957cd0 A |
381 | |
382 | ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) | |
ed1e77d3 | 383 | : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false) |
14957cd0 | 384 | { |
ed1e77d3 A |
385 | m_typeProfilingStartOffset = 0; |
386 | m_typeProfilingEndOffset = source.length() - 1; | |
387 | if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler()) | |
388 | exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset); | |
f9bf01c6 A |
389 | } |
390 | ||
6fe7ccc8 | 391 | void ProgramExecutable::destroy(JSCell* cell) |
f9bf01c6 | 392 | { |
93a37866 | 393 | static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); |
f9bf01c6 A |
394 | } |
395 | ||
ed1e77d3 | 396 | const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; |
14957cd0 | 397 | |
ed1e77d3 A |
398 | FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, |
399 | UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, | |
400 | unsigned lastLine, unsigned startColumn, unsigned endColumn) | |
93a37866 A |
401 | : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) |
402 | , m_unlinkedExecutable(vm, this, unlinkedExecutable) | |
6fe7ccc8 | 403 | { |
93a37866 A |
404 | RELEASE_ASSERT(!source.isNull()); |
405 | ASSERT(source.length()); | |
406 | m_firstLine = firstLine; | |
407 | m_lastLine = lastLine; | |
81345200 A |
408 | ASSERT(startColumn != UINT_MAX); |
409 | ASSERT(endColumn != UINT_MAX); | |
93a37866 | 410 | m_startColumn = startColumn; |
81345200 | 411 | m_endColumn = endColumn; |
ed1e77d3 A |
412 | m_parametersStartOffset = unlinkedExecutable->parametersStartOffset(); |
413 | m_typeProfilingStartOffset = unlinkedExecutable->typeProfilingStartOffset(); | |
414 | m_typeProfilingEndOffset = unlinkedExecutable->typeProfilingEndOffset(); | |
415 | } | |
416 | ||
417 | void FunctionExecutable::finishCreation(VM& vm) | |
418 | { | |
419 | Base::finishCreation(vm); | |
420 | m_singletonFunction.set(vm, this, InferredValue::create(vm)); | |
6fe7ccc8 A |
421 | } |
422 | ||
423 | void FunctionExecutable::destroy(JSCell* cell) | |
424 | { | |
93a37866 | 425 | static_cast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable(); |
6fe7ccc8 A |
426 | } |
427 | ||
6fe7ccc8 A |
428 | inline const char* samplingDescription(JITCode::JITType jitType) |
429 | { | |
430 | switch (jitType) { | |
431 | case JITCode::InterpreterThunk: | |
432 | return "Interpreter Compilation (TOTAL)"; | |
433 | case JITCode::BaselineJIT: | |
434 | return "Baseline Compilation (TOTAL)"; | |
435 | case JITCode::DFGJIT: | |
436 | return "DFG Compilation (TOTAL)"; | |
81345200 A |
437 | case JITCode::FTLJIT: |
438 | return "FTL Compilation (TOTAL)"; | |
6fe7ccc8 | 439 | default: |
93a37866 | 440 | RELEASE_ASSERT_NOT_REACHED(); |
6fe7ccc8 A |
441 | return 0; |
442 | } | |
443 | } | |
14957cd0 | 444 | |
6fe7ccc8 | 445 | void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) |
f9bf01c6 | 446 | { |
6fe7ccc8 | 447 | EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell); |
81345200 | 448 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); |
6fe7ccc8 A |
449 | ScriptExecutable::visitChildren(thisObject, visitor); |
450 | if (thisObject->m_evalCodeBlock) | |
451 | thisObject->m_evalCodeBlock->visitAggregate(visitor); | |
93a37866 | 452 | visitor.append(&thisObject->m_unlinkedEvalCodeBlock); |
f9bf01c6 A |
453 | } |
454 | ||
14957cd0 | 455 | void EvalExecutable::unlinkCalls() |
f9bf01c6 | 456 | { |
14957cd0 A |
457 | #if ENABLE(JIT) |
458 | if (!m_jitCodeForCall) | |
459 | return; | |
93a37866 | 460 | RELEASE_ASSERT(m_evalCodeBlock); |
14957cd0 A |
461 | m_evalCodeBlock->unlinkCalls(); |
462 | #endif | |
463 | } | |
f9bf01c6 | 464 | |
93a37866 | 465 | void EvalExecutable::clearCode() |
6fe7ccc8 | 466 | { |
ed1e77d3 | 467 | m_evalCodeBlock = nullptr; |
93a37866 | 468 | m_unlinkedEvalCodeBlock.clear(); |
6fe7ccc8 A |
469 | Base::clearCode(); |
470 | } | |
471 | ||
14957cd0 A |
472 | JSObject* ProgramExecutable::checkSyntax(ExecState* exec) |
473 | { | |
93a37866 A |
474 | ParserError error; |
475 | VM* vm = &exec->vm(); | |
14957cd0 | 476 | JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); |
ed1e77d3 A |
477 | std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>( |
478 | vm, m_source, 0, Identifier(), JSParserBuiltinMode::NotBuiltin, | |
479 | JSParserStrictMode::NotStrict, JSParserCodeType::Program, error); | |
14957cd0 A |
480 | if (programNode) |
481 | return 0; | |
ed1e77d3 | 482 | ASSERT(error.isValid()); |
93a37866 | 483 | return error.toErrorObject(lexicalGlobalObject, m_source); |
f9bf01c6 A |
484 | } |
485 | ||
14957cd0 | 486 | void ProgramExecutable::unlinkCalls() |
f9bf01c6 | 487 | { |
14957cd0 A |
488 | #if ENABLE(JIT) |
489 | if (!m_jitCodeForCall) | |
490 | return; | |
93a37866 | 491 | RELEASE_ASSERT(m_programCodeBlock); |
14957cd0 | 492 | m_programCodeBlock->unlinkCalls(); |
f9bf01c6 A |
493 | #endif |
494 | } | |
495 | ||
93a37866 A |
496 | JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) |
497 | { | |
498 | RELEASE_ASSERT(scope); | |
499 | JSGlobalObject* globalObject = scope->globalObject(); | |
500 | RELEASE_ASSERT(globalObject); | |
501 | ASSERT(&globalObject->vm() == &vm); | |
502 | ||
503 | JSObject* exception = 0; | |
81345200 | 504 | UnlinkedProgramCodeBlock* unlinkedCodeBlock = globalObject->createProgramCodeBlock(callFrame, this, &exception); |
93a37866 A |
505 | if (exception) |
506 | return exception; | |
507 | ||
81345200 | 508 | m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); |
93a37866 A |
509 | |
510 | BatchedTransitionOptimizer optimizer(vm, globalObject); | |
511 | ||
81345200 | 512 | const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); |
93a37866 | 513 | |
ed1e77d3 A |
514 | for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { |
515 | UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); | |
516 | ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); | |
517 | globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); | |
518 | if (vm.typeProfiler() || vm.controlFlowProfiler()) { | |
519 | vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), | |
520 | unlinkedFunctionExecutable->typeProfilingStartOffset(), | |
521 | unlinkedFunctionExecutable->typeProfilingEndOffset()); | |
522 | } | |
93a37866 A |
523 | } |
524 | ||
525 | for (size_t i = 0; i < variableDeclarations.size(); ++i) { | |
81345200 A |
526 | if (variableDeclarations[i].second & DeclarationStacks::IsConstant) |
527 | globalObject->addConst(callFrame, variableDeclarations[i].first); | |
528 | else | |
529 | globalObject->addVar(callFrame, variableDeclarations[i].first); | |
93a37866 A |
530 | } |
531 | return 0; | |
532 | } | |
533 | ||
6fe7ccc8 | 534 | void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) |
f9bf01c6 | 535 | { |
6fe7ccc8 | 536 | ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell); |
81345200 | 537 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); |
6fe7ccc8 | 538 | ScriptExecutable::visitChildren(thisObject, visitor); |
93a37866 | 539 | visitor.append(&thisObject->m_unlinkedProgramCodeBlock); |
6fe7ccc8 A |
540 | if (thisObject->m_programCodeBlock) |
541 | thisObject->m_programCodeBlock->visitAggregate(visitor); | |
542 | } | |
f9bf01c6 | 543 | |
93a37866 | 544 | void ProgramExecutable::clearCode() |
6fe7ccc8 | 545 | { |
ed1e77d3 | 546 | m_programCodeBlock = nullptr; |
93a37866 | 547 | m_unlinkedProgramCodeBlock.clear(); |
6fe7ccc8 A |
548 | Base::clearCode(); |
549 | } | |
550 | ||
551 | FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) | |
552 | { | |
553 | FunctionCodeBlock* result; | |
554 | if (kind == CodeForCall) | |
555 | result = m_codeBlockForCall.get(); | |
556 | else { | |
93a37866 | 557 | RELEASE_ASSERT(kind == CodeForConstruct); |
6fe7ccc8 A |
558 | result = m_codeBlockForConstruct.get(); |
559 | } | |
560 | if (!result) | |
561 | return 0; | |
81345200 | 562 | return static_cast<FunctionCodeBlock*>(result->baselineAlternative()); |
6fe7ccc8 | 563 | } |
6fe7ccc8 A |
564 | |
565 | void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
566 | { | |
567 | FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell); | |
81345200 | 568 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); |
6fe7ccc8 | 569 | ScriptExecutable::visitChildren(thisObject, visitor); |
6fe7ccc8 A |
570 | if (thisObject->m_codeBlockForCall) |
571 | thisObject->m_codeBlockForCall->visitAggregate(visitor); | |
572 | if (thisObject->m_codeBlockForConstruct) | |
573 | thisObject->m_codeBlockForConstruct->visitAggregate(visitor); | |
93a37866 | 574 | visitor.append(&thisObject->m_unlinkedExecutable); |
ed1e77d3 | 575 | visitor.append(&thisObject->m_singletonFunction); |
f9bf01c6 A |
576 | } |
577 | ||
81345200 A |
578 | SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) |
579 | { | |
580 | return codeBlockFor(kind)->symbolTable(); | |
581 | } | |
582 | ||
ed1e77d3 | 583 | void FunctionExecutable::clearUnlinkedCodeForRecompilation() |
6fe7ccc8 | 584 | { |
93a37866 | 585 | m_unlinkedExecutable->clearCodeForRecompilation(); |
6fe7ccc8 A |
586 | } |
587 | ||
93a37866 | 588 | void FunctionExecutable::clearCode() |
6fe7ccc8 | 589 | { |
ed1e77d3 A |
590 | m_codeBlockForCall = nullptr; |
591 | m_codeBlockForConstruct = nullptr; | |
6fe7ccc8 | 592 | Base::clearCode(); |
f9bf01c6 A |
593 | } |
594 | ||
14957cd0 | 595 | void FunctionExecutable::unlinkCalls() |
f9bf01c6 | 596 | { |
14957cd0 A |
597 | #if ENABLE(JIT) |
598 | if (!!m_jitCodeForCall) { | |
93a37866 | 599 | RELEASE_ASSERT(m_codeBlockForCall); |
14957cd0 A |
600 | m_codeBlockForCall->unlinkCalls(); |
601 | } | |
602 | if (!!m_jitCodeForConstruct) { | |
93a37866 | 603 | RELEASE_ASSERT(m_codeBlockForConstruct); |
14957cd0 A |
604 | m_codeBlockForConstruct->unlinkCalls(); |
605 | } | |
606 | #endif | |
607 | } | |
608 | ||
ed1e77d3 A |
609 | FunctionExecutable* FunctionExecutable::fromGlobalCode( |
610 | const Identifier& name, ExecState& exec, const SourceCode& source, | |
611 | JSObject*& exception, int overrideLineNumber) | |
14957cd0 | 612 | { |
ed1e77d3 A |
613 | UnlinkedFunctionExecutable* unlinkedExecutable = |
614 | UnlinkedFunctionExecutable::fromGlobalCode( | |
615 | name, exec, source, exception, overrideLineNumber); | |
81345200 | 616 | if (!unlinkedExecutable) |
ed1e77d3 | 617 | return nullptr; |
81345200 | 618 | |
ed1e77d3 | 619 | return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber); |
93a37866 | 620 | } |
14957cd0 | 621 | |
81345200 A |
622 | void ExecutableBase::dump(PrintStream& out) const |
623 | { | |
624 | ExecutableBase* realThis = const_cast<ExecutableBase*>(this); | |
625 | ||
626 | if (classInfo() == NativeExecutable::info()) { | |
627 | NativeExecutable* native = jsCast<NativeExecutable*>(realThis); | |
628 | out.print("NativeExecutable:", RawPointer(bitwise_cast<void*>(native->function())), "/", RawPointer(bitwise_cast<void*>(native->constructor()))); | |
629 | return; | |
630 | } | |
631 | ||
632 | if (classInfo() == EvalExecutable::info()) { | |
633 | EvalExecutable* eval = jsCast<EvalExecutable*>(realThis); | |
634 | if (CodeBlock* codeBlock = eval->codeBlock()) | |
635 | out.print(*codeBlock); | |
636 | else | |
637 | out.print("EvalExecutable w/o CodeBlock"); | |
638 | return; | |
639 | } | |
640 | ||
641 | if (classInfo() == ProgramExecutable::info()) { | |
642 | ProgramExecutable* eval = jsCast<ProgramExecutable*>(realThis); | |
643 | if (CodeBlock* codeBlock = eval->codeBlock()) | |
644 | out.print(*codeBlock); | |
645 | else | |
646 | out.print("ProgramExecutable w/o CodeBlock"); | |
647 | return; | |
648 | } | |
649 | ||
650 | FunctionExecutable* function = jsCast<FunctionExecutable*>(realThis); | |
651 | if (!function->eitherCodeBlock()) | |
652 | out.print("FunctionExecutable w/o CodeBlock"); | |
653 | else { | |
654 | CommaPrinter comma("/"); | |
655 | if (function->codeBlockForCall()) | |
656 | out.print(comma, *function->codeBlockForCall()); | |
657 | if (function->codeBlockForConstruct()) | |
658 | out.print(comma, *function->codeBlockForConstruct()); | |
659 | } | |
660 | } | |
661 | ||
93a37866 A |
662 | CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const |
663 | { | |
81345200 | 664 | if (this->classInfo() == NativeExecutable::info()) |
93a37866 A |
665 | return jsCast<const NativeExecutable*>(this)->hashFor(kind); |
666 | ||
667 | return jsCast<const ScriptExecutable*>(this)->hashFor(kind); | |
f9bf01c6 A |
668 | } |
669 | ||
93a37866 | 670 | CodeBlockHash NativeExecutable::hashFor(CodeSpecializationKind kind) const |
f9bf01c6 | 671 | { |
93a37866 A |
672 | if (kind == CodeForCall) |
673 | return CodeBlockHash(static_cast<unsigned>(bitwise_cast<size_t>(m_function))); | |
674 | ||
675 | RELEASE_ASSERT(kind == CodeForConstruct); | |
676 | return CodeBlockHash(static_cast<unsigned>(bitwise_cast<size_t>(m_constructor))); | |
677 | } | |
678 | ||
679 | CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const | |
680 | { | |
681 | return CodeBlockHash(source(), kind); | |
f9bf01c6 A |
682 | } |
683 | ||
14957cd0 | 684 | } |