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