]>
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 | #ifndef Executable_h | |
27 | #define Executable_h | |
28 | ||
81345200 | 29 | #include "ArityCheckMode.h" |
14957cd0 | 30 | #include "CallData.h" |
93a37866 | 31 | #include "CodeBlockHash.h" |
6fe7ccc8 | 32 | #include "CodeSpecializationKind.h" |
81345200 A |
33 | #include "CompilationResult.h" |
34 | #include "DFGPlan.h" | |
93a37866 | 35 | #include "HandlerInfo.h" |
ed1e77d3 | 36 | #include "InferredValue.h" |
93a37866 A |
37 | #include "JITCode.h" |
38 | #include "JSGlobalObject.h" | |
81345200 | 39 | #include "RegisterPreservationMode.h" |
f9bf01c6 | 40 | #include "SamplingTool.h" |
93a37866 | 41 | #include "SourceCode.h" |
ed1e77d3 | 42 | #include "TypeSet.h" |
93a37866 | 43 | #include "UnlinkedCodeBlock.h" |
f9bf01c6 A |
44 | |
45 | namespace JSC { | |
46 | ||
81345200 A |
47 | class CodeBlock; |
48 | class Debugger; | |
49 | class EvalCodeBlock; | |
50 | class FunctionCodeBlock; | |
51 | class LLIntOffsetsExtractor; | |
52 | class ProgramCodeBlock; | |
53 | class JSScope; | |
6fe7ccc8 | 54 | |
81345200 A |
55 | enum CompilationKind { FirstCompilation, OptimizingCompilation }; |
56 | ||
57 | inline bool isCall(CodeSpecializationKind kind) | |
58 | { | |
59 | if (kind == CodeForCall) | |
60 | return true; | |
61 | ASSERT(kind == CodeForConstruct); | |
62 | return false; | |
63 | } | |
f9bf01c6 | 64 | |
ed1e77d3 | 65 | class ExecutableBase : public JSCell { |
81345200 | 66 | friend class JIT; |
f9bf01c6 | 67 | |
81345200 A |
68 | protected: |
69 | static const int NUM_PARAMETERS_IS_HOST = 0; | |
70 | static const int NUM_PARAMETERS_NOT_COMPILED = -1; | |
6fe7ccc8 | 71 | |
81345200 A |
72 | ExecutableBase(VM& vm, Structure* structure, int numParameters) |
73 | : JSCell(vm, structure) | |
74 | , m_numParametersForCall(numParameters) | |
75 | , m_numParametersForConstruct(numParameters) | |
76 | { | |
77 | } | |
6fe7ccc8 | 78 | |
81345200 A |
79 | void finishCreation(VM& vm) |
80 | { | |
81 | Base::finishCreation(vm); | |
82 | } | |
6fe7ccc8 | 83 | |
81345200 A |
84 | public: |
85 | typedef JSCell Base; | |
ed1e77d3 | 86 | static const unsigned StructureFlags = Base::StructureFlags; |
6fe7ccc8 | 87 | |
81345200 | 88 | static const bool needsDestruction = true; |
81345200 | 89 | static void destroy(JSCell*); |
93a37866 | 90 | |
81345200 | 91 | CodeBlockHash hashFor(CodeSpecializationKind) const; |
93a37866 | 92 | |
81345200 A |
93 | bool isEvalExecutable() |
94 | { | |
95 | return type() == EvalExecutableType; | |
96 | } | |
97 | bool isFunctionExecutable() | |
98 | { | |
99 | return type() == FunctionExecutableType; | |
100 | } | |
101 | bool isProgramExecutable() | |
102 | { | |
103 | return type() == ProgramExecutableType; | |
104 | } | |
f9bf01c6 | 105 | |
81345200 A |
106 | bool isHostFunction() const |
107 | { | |
108 | ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); | |
109 | return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; | |
110 | } | |
f9bf01c6 | 111 | |
ed1e77d3 | 112 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } |
14957cd0 | 113 | |
81345200 | 114 | void clearCode(); |
93a37866 | 115 | |
81345200 | 116 | DECLARE_EXPORT_INFO; |
f9bf01c6 | 117 | |
81345200 | 118 | protected: |
81345200 A |
119 | int m_numParametersForCall; |
120 | int m_numParametersForConstruct; | |
f9bf01c6 | 121 | |
81345200 A |
122 | public: |
123 | static void clearCodeVirtual(ExecutableBase*); | |
93a37866 | 124 | |
81345200 A |
125 | PassRefPtr<JITCode> generatedJITCodeForCall() |
126 | { | |
127 | ASSERT(m_jitCodeForCall); | |
128 | return m_jitCodeForCall; | |
129 | } | |
6fe7ccc8 | 130 | |
81345200 A |
131 | PassRefPtr<JITCode> generatedJITCodeForConstruct() |
132 | { | |
133 | ASSERT(m_jitCodeForConstruct); | |
134 | return m_jitCodeForConstruct; | |
135 | } | |
6fe7ccc8 | 136 | |
81345200 A |
137 | PassRefPtr<JITCode> generatedJITCodeFor(CodeSpecializationKind kind) |
138 | { | |
139 | if (kind == CodeForCall) | |
140 | return generatedJITCodeForCall(); | |
141 | ASSERT(kind == CodeForConstruct); | |
142 | return generatedJITCodeForConstruct(); | |
143 | } | |
144 | ||
145 | MacroAssemblerCodePtr entrypointFor( | |
146 | VM& vm, CodeSpecializationKind kind, ArityCheckMode arity, RegisterPreservationMode registers) | |
147 | { | |
148 | // Check if we have a cached result. We only have it for arity check because we use the | |
149 | // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in | |
150 | // machine code. | |
151 | if (arity == MustCheckArity) { | |
152 | switch (kind) { | |
153 | case CodeForCall: | |
154 | switch (registers) { | |
155 | case RegisterPreservationNotRequired: | |
156 | if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck) | |
157 | return result; | |
158 | break; | |
159 | case MustPreserveRegisters: | |
160 | if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheckAndPreserveRegs) | |
161 | return result; | |
162 | break; | |
163 | } | |
164 | break; | |
165 | case CodeForConstruct: | |
166 | switch (registers) { | |
167 | case RegisterPreservationNotRequired: | |
168 | if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck) | |
169 | return result; | |
170 | break; | |
171 | case MustPreserveRegisters: | |
172 | if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheckAndPreserveRegs) | |
173 | return result; | |
174 | break; | |
175 | } | |
176 | break; | |
177 | } | |
6fe7ccc8 | 178 | } |
81345200 A |
179 | MacroAssemblerCodePtr result = |
180 | generatedJITCodeFor(kind)->addressForCall(vm, this, arity, registers); | |
181 | if (arity == MustCheckArity) { | |
182 | // Cache the result; this is necessary for the JIT's virtual call optimizations. | |
183 | switch (kind) { | |
184 | case CodeForCall: | |
185 | switch (registers) { | |
186 | case RegisterPreservationNotRequired: | |
187 | m_jitCodeForCallWithArityCheck = result; | |
188 | break; | |
189 | case MustPreserveRegisters: | |
190 | m_jitCodeForCallWithArityCheckAndPreserveRegs = result; | |
191 | break; | |
192 | } | |
193 | break; | |
194 | case CodeForConstruct: | |
195 | switch (registers) { | |
196 | case RegisterPreservationNotRequired: | |
197 | m_jitCodeForConstructWithArityCheck = result; | |
198 | break; | |
199 | case MustPreserveRegisters: | |
200 | m_jitCodeForConstructWithArityCheckAndPreserveRegs = result; | |
201 | break; | |
202 | } | |
203 | break; | |
204 | } | |
6fe7ccc8 | 205 | } |
81345200 A |
206 | return result; |
207 | } | |
6fe7ccc8 | 208 | |
81345200 A |
209 | static ptrdiff_t offsetOfJITCodeWithArityCheckFor( |
210 | CodeSpecializationKind kind, RegisterPreservationMode registers) | |
211 | { | |
212 | switch (kind) { | |
213 | case CodeForCall: | |
214 | switch (registers) { | |
215 | case RegisterPreservationNotRequired: | |
93a37866 | 216 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); |
81345200 A |
217 | case MustPreserveRegisters: |
218 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheckAndPreserveRegs); | |
219 | } | |
220 | case CodeForConstruct: | |
221 | switch (registers) { | |
222 | case RegisterPreservationNotRequired: | |
223 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); | |
224 | case MustPreserveRegisters: | |
225 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheckAndPreserveRegs); | |
226 | } | |
93a37866 | 227 | } |
81345200 A |
228 | RELEASE_ASSERT_NOT_REACHED(); |
229 | return 0; | |
230 | } | |
231 | ||
232 | static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind) | |
233 | { | |
234 | if (kind == CodeForCall) | |
235 | return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall); | |
236 | ASSERT(kind == CodeForConstruct); | |
237 | return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct); | |
238 | } | |
93a37866 | 239 | |
81345200 A |
240 | bool hasJITCodeForCall() const |
241 | { | |
242 | return m_numParametersForCall >= 0; | |
243 | } | |
6fe7ccc8 | 244 | |
81345200 A |
245 | bool hasJITCodeForConstruct() const |
246 | { | |
247 | return m_numParametersForConstruct >= 0; | |
248 | } | |
93a37866 | 249 | |
81345200 A |
250 | bool hasJITCodeFor(CodeSpecializationKind kind) const |
251 | { | |
252 | if (kind == CodeForCall) | |
253 | return hasJITCodeForCall(); | |
254 | ASSERT(kind == CodeForConstruct); | |
255 | return hasJITCodeForConstruct(); | |
256 | } | |
6fe7ccc8 | 257 | |
81345200 A |
258 | // Intrinsics are only for calls, currently. |
259 | Intrinsic intrinsic() const; | |
260 | ||
261 | Intrinsic intrinsicFor(CodeSpecializationKind kind) const | |
262 | { | |
263 | if (isCall(kind)) | |
264 | return intrinsic(); | |
265 | return NoIntrinsic; | |
266 | } | |
267 | ||
268 | void dump(PrintStream&) const; | |
269 | ||
270 | protected: | |
81345200 A |
271 | RefPtr<JITCode> m_jitCodeForCall; |
272 | RefPtr<JITCode> m_jitCodeForConstruct; | |
273 | MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; | |
274 | MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; | |
275 | MacroAssemblerCodePtr m_jitCodeForCallWithArityCheckAndPreserveRegs; | |
276 | MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheckAndPreserveRegs; | |
277 | }; | |
278 | ||
ed1e77d3 | 279 | class NativeExecutable final : public ExecutableBase { |
81345200 A |
280 | friend class JIT; |
281 | friend class LLIntOffsetsExtractor; | |
282 | public: | |
283 | typedef ExecutableBase Base; | |
ed1e77d3 | 284 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; |
81345200 A |
285 | |
286 | static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic) | |
287 | { | |
288 | NativeExecutable* executable; | |
289 | executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); | |
290 | executable->finishCreation(vm, callThunk, constructThunk, intrinsic); | |
291 | return executable; | |
292 | } | |
f9bf01c6 | 293 | |
81345200 | 294 | static void destroy(JSCell*); |
f9bf01c6 | 295 | |
81345200 | 296 | CodeBlockHash hashFor(CodeSpecializationKind) const; |
93a37866 | 297 | |
81345200 A |
298 | NativeFunction function() { return m_function; } |
299 | NativeFunction constructor() { return m_constructor; } | |
93a37866 | 300 | |
81345200 A |
301 | NativeFunction nativeFunctionFor(CodeSpecializationKind kind) |
302 | { | |
303 | if (kind == CodeForCall) | |
304 | return function(); | |
305 | ASSERT(kind == CodeForConstruct); | |
306 | return constructor(); | |
307 | } | |
93a37866 | 308 | |
81345200 A |
309 | static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind) |
310 | { | |
311 | if (kind == CodeForCall) | |
312 | return OBJECT_OFFSETOF(NativeExecutable, m_function); | |
313 | ASSERT(kind == CodeForConstruct); | |
314 | return OBJECT_OFFSETOF(NativeExecutable, m_constructor); | |
315 | } | |
14957cd0 | 316 | |
ed1e77d3 | 317 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } |
14957cd0 | 318 | |
81345200 | 319 | DECLARE_INFO; |
6fe7ccc8 | 320 | |
81345200 | 321 | Intrinsic intrinsic() const; |
6fe7ccc8 | 322 | |
81345200 A |
323 | protected: |
324 | void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic) | |
325 | { | |
326 | Base::finishCreation(vm); | |
327 | m_jitCodeForCall = callThunk; | |
328 | m_jitCodeForConstruct = constructThunk; | |
329 | m_intrinsic = intrinsic; | |
330 | } | |
6fe7ccc8 | 331 | |
81345200 A |
332 | private: |
333 | NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor) | |
334 | : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) | |
335 | , m_function(function) | |
336 | , m_constructor(constructor) | |
337 | { | |
338 | } | |
f9bf01c6 | 339 | |
81345200 A |
340 | NativeFunction m_function; |
341 | NativeFunction m_constructor; | |
6fe7ccc8 | 342 | |
81345200 A |
343 | Intrinsic m_intrinsic; |
344 | }; | |
f9bf01c6 | 345 | |
81345200 A |
346 | class ScriptExecutable : public ExecutableBase { |
347 | public: | |
348 | typedef ExecutableBase Base; | |
ed1e77d3 | 349 | static const unsigned StructureFlags = Base::StructureFlags; |
81345200 | 350 | |
81345200 | 351 | static void destroy(JSCell*); |
93a37866 | 352 | |
81345200 | 353 | CodeBlockHash hashFor(CodeSpecializationKind) const; |
6fe7ccc8 | 354 | |
81345200 A |
355 | const SourceCode& source() const { return m_source; } |
356 | intptr_t sourceID() const { return m_source.providerID(); } | |
357 | const String& sourceURL() const { return m_source.provider()->url(); } | |
ed1e77d3 A |
358 | int firstLine() const { return m_firstLine; } |
359 | void setOverrideLineNumber(int overrideLineNumber) { m_overrideLineNumber = overrideLineNumber; } | |
360 | bool hasOverrideLineNumber() const { return m_overrideLineNumber != -1; } | |
361 | int overrideLineNumber() const { return m_overrideLineNumber; } | |
81345200 A |
362 | int lastLine() const { return m_lastLine; } |
363 | unsigned startColumn() const { return m_startColumn; } | |
364 | unsigned endColumn() const { return m_endColumn; } | |
ed1e77d3 A |
365 | unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } |
366 | unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } | |
f9bf01c6 | 367 | |
81345200 A |
368 | bool usesEval() const { return m_features & EvalFeature; } |
369 | bool usesArguments() const { return m_features & ArgumentsFeature; } | |
370 | bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); } | |
371 | bool isStrictMode() const { return m_features & StrictModeFeature; } | |
372 | ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; } | |
14957cd0 | 373 | |
81345200 | 374 | void setNeverInline(bool value) { m_neverInline = value; } |
ed1e77d3 | 375 | void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; } |
81345200 | 376 | bool neverInline() const { return m_neverInline; } |
ed1e77d3 | 377 | bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; } |
81345200 | 378 | bool isInliningCandidate() const { return !neverInline(); } |
ed1e77d3 A |
379 | |
380 | bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; } | |
f9bf01c6 | 381 | |
81345200 | 382 | void unlinkCalls(); |
6fe7ccc8 | 383 | |
81345200 | 384 | CodeFeatures features() const { return m_features; } |
6fe7ccc8 | 385 | |
81345200 | 386 | DECLARE_INFO; |
14957cd0 | 387 | |
81345200 A |
388 | void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn, unsigned endColumn) |
389 | { | |
390 | m_features = features; | |
391 | m_hasCapturedVariables = hasCapturedVariables; | |
392 | m_firstLine = firstLine; | |
393 | m_lastLine = lastLine; | |
394 | ASSERT(startColumn != UINT_MAX); | |
395 | m_startColumn = startColumn; | |
396 | ASSERT(endColumn != UINT_MAX); | |
397 | m_endColumn = endColumn; | |
398 | } | |
f9bf01c6 | 399 | |
81345200 | 400 | void installCode(CodeBlock*); |
ed1e77d3 | 401 | RefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception); |
81345200 A |
402 | PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind); |
403 | ||
ed1e77d3 | 404 | JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) |
81345200 A |
405 | { |
406 | if (hasJITCodeFor(kind)) | |
407 | return 0; | |
408 | return prepareForExecutionImpl(exec, function, scope, kind); | |
409 | } | |
6fe7ccc8 | 410 | |
81345200 | 411 | template <typename Functor> void forEachCodeBlock(Functor&&); |
6fe7ccc8 | 412 | |
81345200 | 413 | private: |
ed1e77d3 | 414 | JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind); |
93a37866 | 415 | |
81345200 | 416 | protected: |
ed1e77d3 A |
417 | ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext); |
418 | ||
81345200 A |
419 | void finishCreation(VM& vm) |
420 | { | |
421 | Base::finishCreation(vm); | |
422 | vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). | |
6fe7ccc8 | 423 | |
81345200 A |
424 | #if ENABLE(CODEBLOCK_SAMPLING) |
425 | if (SamplingTool* sampler = vm.interpreter->sampler()) | |
426 | sampler->notifyOfScope(vm, this); | |
427 | #endif | |
428 | } | |
14957cd0 | 429 | |
81345200 A |
430 | SourceCode m_source; |
431 | CodeFeatures m_features; | |
432 | bool m_hasCapturedVariables; | |
433 | bool m_neverInline; | |
ed1e77d3 A |
434 | bool m_didTryToEnterInLoop; |
435 | int m_overrideLineNumber; | |
81345200 A |
436 | int m_firstLine; |
437 | int m_lastLine; | |
438 | unsigned m_startColumn; | |
439 | unsigned m_endColumn; | |
ed1e77d3 A |
440 | unsigned m_typeProfilingStartOffset; |
441 | unsigned m_typeProfilingEndOffset; | |
81345200 | 442 | }; |
14957cd0 | 443 | |
ed1e77d3 | 444 | class EvalExecutable final : public ScriptExecutable { |
81345200 A |
445 | friend class LLIntOffsetsExtractor; |
446 | public: | |
447 | typedef ScriptExecutable Base; | |
ed1e77d3 | 448 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; |
f9bf01c6 | 449 | |
81345200 | 450 | static void destroy(JSCell*); |
6fe7ccc8 | 451 | |
81345200 A |
452 | EvalCodeBlock* codeBlock() |
453 | { | |
454 | return m_evalCodeBlock.get(); | |
455 | } | |
f9bf01c6 | 456 | |
ed1e77d3 | 457 | static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode); |
93a37866 | 458 | |
81345200 A |
459 | PassRefPtr<JITCode> generatedJITCode() |
460 | { | |
461 | return generatedJITCodeForCall(); | |
462 | } | |
93a37866 | 463 | |
81345200 A |
464 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) |
465 | { | |
466 | return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), info()); | |
467 | } | |
468 | ||
469 | DECLARE_INFO; | |
f9bf01c6 | 470 | |
81345200 | 471 | void unlinkCalls(); |
14957cd0 | 472 | |
81345200 | 473 | void clearCode(); |
6fe7ccc8 | 474 | |
ed1e77d3 | 475 | ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); } |
f9bf01c6 | 476 | |
81345200 A |
477 | unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); } |
478 | unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); } | |
f9bf01c6 | 479 | |
81345200 A |
480 | private: |
481 | friend class ScriptExecutable; | |
81345200 | 482 | EvalExecutable(ExecState*, const SourceCode&, bool); |
6fe7ccc8 | 483 | |
81345200 | 484 | static void visitChildren(JSCell*, SlotVisitor&); |
93a37866 | 485 | |
81345200 A |
486 | RefPtr<EvalCodeBlock> m_evalCodeBlock; |
487 | WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; | |
488 | }; | |
f9bf01c6 | 489 | |
ed1e77d3 | 490 | class ProgramExecutable final : public ScriptExecutable { |
81345200 A |
491 | friend class LLIntOffsetsExtractor; |
492 | public: | |
493 | typedef ScriptExecutable Base; | |
ed1e77d3 | 494 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; |
93a37866 | 495 | |
81345200 A |
496 | static ProgramExecutable* create(ExecState* exec, const SourceCode& source) |
497 | { | |
498 | ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source); | |
499 | executable->finishCreation(exec->vm()); | |
500 | return executable; | |
501 | } | |
14957cd0 | 502 | |
93a37866 | 503 | |
81345200 | 504 | JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*); |
14957cd0 | 505 | |
81345200 | 506 | static void destroy(JSCell*); |
f9bf01c6 | 507 | |
81345200 A |
508 | ProgramCodeBlock* codeBlock() |
509 | { | |
510 | return m_programCodeBlock.get(); | |
511 | } | |
6fe7ccc8 | 512 | |
81345200 | 513 | JSObject* checkSyntax(ExecState*); |
f9bf01c6 | 514 | |
81345200 A |
515 | PassRefPtr<JITCode> generatedJITCode() |
516 | { | |
517 | return generatedJITCodeForCall(); | |
518 | } | |
93a37866 | 519 | |
81345200 A |
520 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) |
521 | { | |
522 | return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), info()); | |
523 | } | |
6fe7ccc8 | 524 | |
81345200 | 525 | DECLARE_INFO; |
6fe7ccc8 | 526 | |
81345200 | 527 | void unlinkCalls(); |
6fe7ccc8 | 528 | |
81345200 | 529 | void clearCode(); |
f9bf01c6 | 530 | |
ed1e77d3 | 531 | ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); } |
6fe7ccc8 | 532 | |
81345200 A |
533 | private: |
534 | friend class ScriptExecutable; | |
f9bf01c6 | 535 | |
81345200 | 536 | ProgramExecutable(ExecState*, const SourceCode&); |
6fe7ccc8 | 537 | |
81345200 | 538 | static void visitChildren(JSCell*, SlotVisitor&); |
f9bf01c6 | 539 | |
81345200 A |
540 | WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock; |
541 | RefPtr<ProgramCodeBlock> m_programCodeBlock; | |
542 | }; | |
6fe7ccc8 | 543 | |
ed1e77d3 | 544 | class FunctionExecutable final : public ScriptExecutable { |
81345200 A |
545 | friend class JIT; |
546 | friend class LLIntOffsetsExtractor; | |
547 | public: | |
548 | typedef ScriptExecutable Base; | |
ed1e77d3 | 549 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; |
f9bf01c6 | 550 | |
ed1e77d3 A |
551 | static FunctionExecutable* create( |
552 | VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, | |
553 | unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn) | |
81345200 | 554 | { |
ed1e77d3 | 555 | FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn); |
81345200 A |
556 | executable->finishCreation(vm); |
557 | return executable; | |
558 | } | |
ed1e77d3 A |
559 | static FunctionExecutable* fromGlobalCode( |
560 | const Identifier& name, ExecState&, const SourceCode&, | |
561 | JSObject*& exception, int overrideLineNumber); | |
14957cd0 | 562 | |
81345200 | 563 | static void destroy(JSCell*); |
6fe7ccc8 | 564 | |
81345200 | 565 | UnlinkedFunctionExecutable* unlinkedExecutable() |
93a37866 | 566 | { |
81345200 | 567 | return m_unlinkedExecutable.get(); |
93a37866 A |
568 | } |
569 | ||
81345200 A |
570 | // Returns either call or construct bytecode. This can be appropriate |
571 | // for answering questions that that don't vary between call and construct -- | |
572 | // for example, argumentsRegister(). | |
573 | FunctionCodeBlock* eitherCodeBlock() | |
f9bf01c6 | 574 | { |
81345200 A |
575 | if (m_codeBlockForCall) |
576 | return m_codeBlockForCall.get(); | |
577 | return m_codeBlockForConstruct.get(); | |
f9bf01c6 | 578 | } |
81345200 A |
579 | |
580 | bool isGeneratedForCall() const | |
f9bf01c6 | 581 | { |
81345200 | 582 | return m_codeBlockForCall; |
f9bf01c6 A |
583 | } |
584 | ||
81345200 | 585 | FunctionCodeBlock* codeBlockForCall() |
14957cd0 | 586 | { |
81345200 | 587 | return m_codeBlockForCall.get(); |
14957cd0 | 588 | } |
6fe7ccc8 | 589 | |
81345200 | 590 | bool isGeneratedForConstruct() const |
6fe7ccc8 | 591 | { |
81345200 | 592 | return m_codeBlockForConstruct; |
6fe7ccc8 A |
593 | } |
594 | ||
81345200 | 595 | FunctionCodeBlock* codeBlockForConstruct() |
6fe7ccc8 | 596 | { |
81345200 A |
597 | return m_codeBlockForConstruct.get(); |
598 | } | |
599 | ||
600 | bool isGeneratedFor(CodeSpecializationKind kind) | |
601 | { | |
602 | if (kind == CodeForCall) | |
603 | return isGeneratedForCall(); | |
604 | ASSERT(kind == CodeForConstruct); | |
605 | return isGeneratedForConstruct(); | |
606 | } | |
607 | ||
608 | FunctionCodeBlock* codeBlockFor(CodeSpecializationKind kind) | |
609 | { | |
610 | if (kind == CodeForCall) | |
611 | return codeBlockForCall(); | |
612 | ASSERT(kind == CodeForConstruct); | |
613 | return codeBlockForConstruct(); | |
6fe7ccc8 A |
614 | } |
615 | ||
81345200 A |
616 | FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind); |
617 | ||
618 | FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind) | |
93a37866 | 619 | { |
81345200 | 620 | return baselineCodeBlockFor(kind); |
93a37866 | 621 | } |
ed1e77d3 A |
622 | |
623 | RefPtr<TypeSet> returnStatementTypeSet() | |
624 | { | |
625 | if (!m_returnStatementTypeSet) | |
626 | m_returnStatementTypeSet = TypeSet::create(); | |
627 | ||
628 | return m_returnStatementTypeSet; | |
629 | } | |
81345200 A |
630 | |
631 | FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); } | |
632 | bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); } | |
ed1e77d3 | 633 | bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); } |
81345200 A |
634 | const Identifier& name() { return m_unlinkedExecutable->name(); } |
635 | const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); } | |
636 | JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); } | |
637 | size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'! | |
81345200 A |
638 | SymbolTable* symbolTable(CodeSpecializationKind); |
639 | ||
ed1e77d3 | 640 | void clearUnlinkedCodeForRecompilation(); |
81345200 A |
641 | static void visitChildren(JSCell*, SlotVisitor&); |
642 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) | |
643 | { | |
644 | return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info()); | |
645 | } | |
ed1e77d3 A |
646 | |
647 | unsigned parametersStartOffset() const { return m_parametersStartOffset; } | |
648 | ||
649 | void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset) | |
650 | { | |
651 | m_parametersStartOffset = parametersStartOffset; | |
652 | m_typeProfilingStartOffset = typeProfilingStartOffset; | |
653 | m_typeProfilingEndOffset = typeProfilingEndOffset; | |
654 | } | |
655 | ||
81345200 A |
656 | DECLARE_INFO; |
657 | ||
658 | void unlinkCalls(); | |
659 | ||
660 | void clearCode(); | |
ed1e77d3 A |
661 | |
662 | InferredValue* singletonFunction() { return m_singletonFunction.get(); } | |
81345200 A |
663 | |
664 | private: | |
ed1e77d3 A |
665 | FunctionExecutable( |
666 | VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, | |
667 | unsigned lastLine, unsigned startColumn, unsigned endColumn); | |
668 | ||
669 | void finishCreation(VM&); | |
81345200 A |
670 | |
671 | friend class ScriptExecutable; | |
ed1e77d3 | 672 | |
81345200 A |
673 | WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; |
674 | RefPtr<FunctionCodeBlock> m_codeBlockForCall; | |
675 | RefPtr<FunctionCodeBlock> m_codeBlockForConstruct; | |
ed1e77d3 A |
676 | RefPtr<TypeSet> m_returnStatementTypeSet; |
677 | unsigned m_parametersStartOffset; | |
678 | WriteBarrier<InferredValue> m_singletonFunction; | |
81345200 A |
679 | }; |
680 | ||
681 | inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) | |
682 | { | |
683 | switch (executable->type()) { | |
684 | case EvalExecutableType: | |
685 | return jsCast<EvalExecutable*>(executable)->clearCode(); | |
686 | case ProgramExecutableType: | |
687 | return jsCast<ProgramExecutable*>(executable)->clearCode(); | |
688 | case FunctionExecutableType: | |
689 | return jsCast<FunctionExecutable*>(executable)->clearCode(); | |
690 | default: | |
691 | return jsCast<NativeExecutable*>(executable)->clearCode(); | |
6fe7ccc8 | 692 | } |
81345200 A |
693 | } |
694 | ||
695 | inline void ScriptExecutable::unlinkCalls() | |
696 | { | |
697 | switch (type()) { | |
698 | case EvalExecutableType: | |
699 | return jsCast<EvalExecutable*>(this)->unlinkCalls(); | |
700 | case ProgramExecutableType: | |
701 | return jsCast<ProgramExecutable*>(this)->unlinkCalls(); | |
702 | case FunctionExecutableType: | |
703 | return jsCast<FunctionExecutable*>(this)->unlinkCalls(); | |
704 | default: | |
705 | RELEASE_ASSERT_NOT_REACHED(); | |
706 | } | |
707 | } | |
6fe7ccc8 | 708 | |
f9bf01c6 A |
709 | } |
710 | ||
711 | #endif |