]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2009, 2010, 2013-2015 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 | #ifndef Executable_h | |
27 | #define Executable_h | |
28 | ||
29 | #include "ArityCheckMode.h" | |
30 | #include "CallData.h" | |
31 | #include "CodeBlockHash.h" | |
32 | #include "CodeSpecializationKind.h" | |
33 | #include "CompilationResult.h" | |
34 | #include "DFGPlan.h" | |
35 | #include "HandlerInfo.h" | |
36 | #include "InferredValue.h" | |
37 | #include "JITCode.h" | |
38 | #include "JSGlobalObject.h" | |
39 | #include "RegisterPreservationMode.h" | |
40 | #include "SamplingTool.h" | |
41 | #include "SourceCode.h" | |
42 | #include "TypeSet.h" | |
43 | #include "UnlinkedCodeBlock.h" | |
44 | ||
45 | namespace JSC { | |
46 | ||
47 | class CodeBlock; | |
48 | class Debugger; | |
49 | class EvalCodeBlock; | |
50 | class FunctionCodeBlock; | |
51 | class LLIntOffsetsExtractor; | |
52 | class ProgramCodeBlock; | |
53 | class JSScope; | |
54 | ||
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 | } | |
64 | ||
65 | class ExecutableBase : public JSCell { | |
66 | friend class JIT; | |
67 | ||
68 | protected: | |
69 | static const int NUM_PARAMETERS_IS_HOST = 0; | |
70 | static const int NUM_PARAMETERS_NOT_COMPILED = -1; | |
71 | ||
72 | ExecutableBase(VM& vm, Structure* structure, int numParameters) | |
73 | : JSCell(vm, structure) | |
74 | , m_numParametersForCall(numParameters) | |
75 | , m_numParametersForConstruct(numParameters) | |
76 | { | |
77 | } | |
78 | ||
79 | void finishCreation(VM& vm) | |
80 | { | |
81 | Base::finishCreation(vm); | |
82 | } | |
83 | ||
84 | public: | |
85 | typedef JSCell Base; | |
86 | static const unsigned StructureFlags = Base::StructureFlags; | |
87 | ||
88 | static const bool needsDestruction = true; | |
89 | static void destroy(JSCell*); | |
90 | ||
91 | CodeBlockHash hashFor(CodeSpecializationKind) const; | |
92 | ||
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 | } | |
105 | ||
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 | } | |
111 | ||
112 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } | |
113 | ||
114 | void clearCode(); | |
115 | ||
116 | DECLARE_EXPORT_INFO; | |
117 | ||
118 | protected: | |
119 | int m_numParametersForCall; | |
120 | int m_numParametersForConstruct; | |
121 | ||
122 | public: | |
123 | static void clearCodeVirtual(ExecutableBase*); | |
124 | ||
125 | PassRefPtr<JITCode> generatedJITCodeForCall() | |
126 | { | |
127 | ASSERT(m_jitCodeForCall); | |
128 | return m_jitCodeForCall; | |
129 | } | |
130 | ||
131 | PassRefPtr<JITCode> generatedJITCodeForConstruct() | |
132 | { | |
133 | ASSERT(m_jitCodeForConstruct); | |
134 | return m_jitCodeForConstruct; | |
135 | } | |
136 | ||
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 | } | |
178 | } | |
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 | } | |
205 | } | |
206 | return result; | |
207 | } | |
208 | ||
209 | static ptrdiff_t offsetOfJITCodeWithArityCheckFor( | |
210 | CodeSpecializationKind kind, RegisterPreservationMode registers) | |
211 | { | |
212 | switch (kind) { | |
213 | case CodeForCall: | |
214 | switch (registers) { | |
215 | case RegisterPreservationNotRequired: | |
216 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); | |
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 | } | |
227 | } | |
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 | } | |
239 | ||
240 | bool hasJITCodeForCall() const | |
241 | { | |
242 | return m_numParametersForCall >= 0; | |
243 | } | |
244 | ||
245 | bool hasJITCodeForConstruct() const | |
246 | { | |
247 | return m_numParametersForConstruct >= 0; | |
248 | } | |
249 | ||
250 | bool hasJITCodeFor(CodeSpecializationKind kind) const | |
251 | { | |
252 | if (kind == CodeForCall) | |
253 | return hasJITCodeForCall(); | |
254 | ASSERT(kind == CodeForConstruct); | |
255 | return hasJITCodeForConstruct(); | |
256 | } | |
257 | ||
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: | |
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 | ||
279 | class NativeExecutable final : public ExecutableBase { | |
280 | friend class JIT; | |
281 | friend class LLIntOffsetsExtractor; | |
282 | public: | |
283 | typedef ExecutableBase Base; | |
284 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; | |
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 | } | |
293 | ||
294 | static void destroy(JSCell*); | |
295 | ||
296 | CodeBlockHash hashFor(CodeSpecializationKind) const; | |
297 | ||
298 | NativeFunction function() { return m_function; } | |
299 | NativeFunction constructor() { return m_constructor; } | |
300 | ||
301 | NativeFunction nativeFunctionFor(CodeSpecializationKind kind) | |
302 | { | |
303 | if (kind == CodeForCall) | |
304 | return function(); | |
305 | ASSERT(kind == CodeForConstruct); | |
306 | return constructor(); | |
307 | } | |
308 | ||
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 | } | |
316 | ||
317 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } | |
318 | ||
319 | DECLARE_INFO; | |
320 | ||
321 | Intrinsic intrinsic() const; | |
322 | ||
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 | } | |
331 | ||
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 | } | |
339 | ||
340 | NativeFunction m_function; | |
341 | NativeFunction m_constructor; | |
342 | ||
343 | Intrinsic m_intrinsic; | |
344 | }; | |
345 | ||
346 | class ScriptExecutable : public ExecutableBase { | |
347 | public: | |
348 | typedef ExecutableBase Base; | |
349 | static const unsigned StructureFlags = Base::StructureFlags; | |
350 | ||
351 | static void destroy(JSCell*); | |
352 | ||
353 | CodeBlockHash hashFor(CodeSpecializationKind) const; | |
354 | ||
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(); } | |
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; } | |
362 | int lastLine() const { return m_lastLine; } | |
363 | unsigned startColumn() const { return m_startColumn; } | |
364 | unsigned endColumn() const { return m_endColumn; } | |
365 | unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } | |
366 | unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } | |
367 | ||
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; } | |
373 | ||
374 | void setNeverInline(bool value) { m_neverInline = value; } | |
375 | void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; } | |
376 | bool neverInline() const { return m_neverInline; } | |
377 | bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; } | |
378 | bool isInliningCandidate() const { return !neverInline(); } | |
379 | ||
380 | bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; } | |
381 | ||
382 | void unlinkCalls(); | |
383 | ||
384 | CodeFeatures features() const { return m_features; } | |
385 | ||
386 | DECLARE_INFO; | |
387 | ||
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 | } | |
399 | ||
400 | void installCode(CodeBlock*); | |
401 | RefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception); | |
402 | PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind); | |
403 | ||
404 | JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) | |
405 | { | |
406 | if (hasJITCodeFor(kind)) | |
407 | return 0; | |
408 | return prepareForExecutionImpl(exec, function, scope, kind); | |
409 | } | |
410 | ||
411 | template <typename Functor> void forEachCodeBlock(Functor&&); | |
412 | ||
413 | private: | |
414 | JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind); | |
415 | ||
416 | protected: | |
417 | ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext); | |
418 | ||
419 | void finishCreation(VM& vm) | |
420 | { | |
421 | Base::finishCreation(vm); | |
422 | vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). | |
423 | ||
424 | #if ENABLE(CODEBLOCK_SAMPLING) | |
425 | if (SamplingTool* sampler = vm.interpreter->sampler()) | |
426 | sampler->notifyOfScope(vm, this); | |
427 | #endif | |
428 | } | |
429 | ||
430 | SourceCode m_source; | |
431 | CodeFeatures m_features; | |
432 | bool m_hasCapturedVariables; | |
433 | bool m_neverInline; | |
434 | bool m_didTryToEnterInLoop; | |
435 | int m_overrideLineNumber; | |
436 | int m_firstLine; | |
437 | int m_lastLine; | |
438 | unsigned m_startColumn; | |
439 | unsigned m_endColumn; | |
440 | unsigned m_typeProfilingStartOffset; | |
441 | unsigned m_typeProfilingEndOffset; | |
442 | }; | |
443 | ||
444 | class EvalExecutable final : public ScriptExecutable { | |
445 | friend class LLIntOffsetsExtractor; | |
446 | public: | |
447 | typedef ScriptExecutable Base; | |
448 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; | |
449 | ||
450 | static void destroy(JSCell*); | |
451 | ||
452 | EvalCodeBlock* codeBlock() | |
453 | { | |
454 | return m_evalCodeBlock.get(); | |
455 | } | |
456 | ||
457 | static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode); | |
458 | ||
459 | PassRefPtr<JITCode> generatedJITCode() | |
460 | { | |
461 | return generatedJITCodeForCall(); | |
462 | } | |
463 | ||
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; | |
470 | ||
471 | void unlinkCalls(); | |
472 | ||
473 | void clearCode(); | |
474 | ||
475 | ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); } | |
476 | ||
477 | unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); } | |
478 | unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); } | |
479 | ||
480 | private: | |
481 | friend class ScriptExecutable; | |
482 | EvalExecutable(ExecState*, const SourceCode&, bool); | |
483 | ||
484 | static void visitChildren(JSCell*, SlotVisitor&); | |
485 | ||
486 | RefPtr<EvalCodeBlock> m_evalCodeBlock; | |
487 | WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; | |
488 | }; | |
489 | ||
490 | class ProgramExecutable final : public ScriptExecutable { | |
491 | friend class LLIntOffsetsExtractor; | |
492 | public: | |
493 | typedef ScriptExecutable Base; | |
494 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; | |
495 | ||
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 | } | |
502 | ||
503 | ||
504 | JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*); | |
505 | ||
506 | static void destroy(JSCell*); | |
507 | ||
508 | ProgramCodeBlock* codeBlock() | |
509 | { | |
510 | return m_programCodeBlock.get(); | |
511 | } | |
512 | ||
513 | JSObject* checkSyntax(ExecState*); | |
514 | ||
515 | PassRefPtr<JITCode> generatedJITCode() | |
516 | { | |
517 | return generatedJITCodeForCall(); | |
518 | } | |
519 | ||
520 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) | |
521 | { | |
522 | return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), info()); | |
523 | } | |
524 | ||
525 | DECLARE_INFO; | |
526 | ||
527 | void unlinkCalls(); | |
528 | ||
529 | void clearCode(); | |
530 | ||
531 | ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); } | |
532 | ||
533 | private: | |
534 | friend class ScriptExecutable; | |
535 | ||
536 | ProgramExecutable(ExecState*, const SourceCode&); | |
537 | ||
538 | static void visitChildren(JSCell*, SlotVisitor&); | |
539 | ||
540 | WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock; | |
541 | RefPtr<ProgramCodeBlock> m_programCodeBlock; | |
542 | }; | |
543 | ||
544 | class FunctionExecutable final : public ScriptExecutable { | |
545 | friend class JIT; | |
546 | friend class LLIntOffsetsExtractor; | |
547 | public: | |
548 | typedef ScriptExecutable Base; | |
549 | static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; | |
550 | ||
551 | static FunctionExecutable* create( | |
552 | VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, | |
553 | unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn) | |
554 | { | |
555 | FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn); | |
556 | executable->finishCreation(vm); | |
557 | return executable; | |
558 | } | |
559 | static FunctionExecutable* fromGlobalCode( | |
560 | const Identifier& name, ExecState&, const SourceCode&, | |
561 | JSObject*& exception, int overrideLineNumber); | |
562 | ||
563 | static void destroy(JSCell*); | |
564 | ||
565 | UnlinkedFunctionExecutable* unlinkedExecutable() | |
566 | { | |
567 | return m_unlinkedExecutable.get(); | |
568 | } | |
569 | ||
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() | |
574 | { | |
575 | if (m_codeBlockForCall) | |
576 | return m_codeBlockForCall.get(); | |
577 | return m_codeBlockForConstruct.get(); | |
578 | } | |
579 | ||
580 | bool isGeneratedForCall() const | |
581 | { | |
582 | return m_codeBlockForCall; | |
583 | } | |
584 | ||
585 | FunctionCodeBlock* codeBlockForCall() | |
586 | { | |
587 | return m_codeBlockForCall.get(); | |
588 | } | |
589 | ||
590 | bool isGeneratedForConstruct() const | |
591 | { | |
592 | return m_codeBlockForConstruct; | |
593 | } | |
594 | ||
595 | FunctionCodeBlock* codeBlockForConstruct() | |
596 | { | |
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(); | |
614 | } | |
615 | ||
616 | FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind); | |
617 | ||
618 | FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind) | |
619 | { | |
620 | return baselineCodeBlockFor(kind); | |
621 | } | |
622 | ||
623 | RefPtr<TypeSet> returnStatementTypeSet() | |
624 | { | |
625 | if (!m_returnStatementTypeSet) | |
626 | m_returnStatementTypeSet = TypeSet::create(); | |
627 | ||
628 | return m_returnStatementTypeSet; | |
629 | } | |
630 | ||
631 | FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); } | |
632 | bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); } | |
633 | bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); } | |
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'! | |
638 | SymbolTable* symbolTable(CodeSpecializationKind); | |
639 | ||
640 | void clearUnlinkedCodeForRecompilation(); | |
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 | } | |
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 | ||
656 | DECLARE_INFO; | |
657 | ||
658 | void unlinkCalls(); | |
659 | ||
660 | void clearCode(); | |
661 | ||
662 | InferredValue* singletonFunction() { return m_singletonFunction.get(); } | |
663 | ||
664 | private: | |
665 | FunctionExecutable( | |
666 | VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, | |
667 | unsigned lastLine, unsigned startColumn, unsigned endColumn); | |
668 | ||
669 | void finishCreation(VM&); | |
670 | ||
671 | friend class ScriptExecutable; | |
672 | ||
673 | WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; | |
674 | RefPtr<FunctionCodeBlock> m_codeBlockForCall; | |
675 | RefPtr<FunctionCodeBlock> m_codeBlockForConstruct; | |
676 | RefPtr<TypeSet> m_returnStatementTypeSet; | |
677 | unsigned m_parametersStartOffset; | |
678 | WriteBarrier<InferredValue> m_singletonFunction; | |
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(); | |
692 | } | |
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 | } | |
708 | ||
709 | } | |
710 | ||
711 | #endif |