]>
Commit | Line | Data |
---|---|---|
f9bf01c6 | 1 | /* |
93a37866 | 2 | * Copyright (C) 2009, 2010, 2013 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 | ||
14957cd0 | 29 | #include "CallData.h" |
93a37866 | 30 | #include "CodeBlockHash.h" |
6fe7ccc8 | 31 | #include "CodeSpecializationKind.h" |
93a37866 | 32 | #include "HandlerInfo.h" |
f9bf01c6 A |
33 | #include "JSFunction.h" |
34 | #include "Interpreter.h" | |
93a37866 A |
35 | #include "JITCode.h" |
36 | #include "JSGlobalObject.h" | |
37 | #include "LLIntCLoop.h" | |
f9bf01c6 | 38 | #include "SamplingTool.h" |
93a37866 A |
39 | #include "SourceCode.h" |
40 | #include "UnlinkedCodeBlock.h" | |
14957cd0 | 41 | #include <wtf/PassOwnPtr.h> |
f9bf01c6 A |
42 | |
43 | namespace JSC { | |
44 | ||
45 | class CodeBlock; | |
46 | class Debugger; | |
47 | class EvalCodeBlock; | |
14957cd0 | 48 | class FunctionCodeBlock; |
6fe7ccc8 | 49 | class LLIntOffsetsExtractor; |
f9bf01c6 | 50 | class ProgramCodeBlock; |
93a37866 | 51 | class JSScope; |
6fe7ccc8 A |
52 | |
53 | enum CompilationKind { FirstCompilation, OptimizingCompilation }; | |
f9bf01c6 | 54 | |
6fe7ccc8 A |
55 | inline bool isCall(CodeSpecializationKind kind) |
56 | { | |
57 | if (kind == CodeForCall) | |
58 | return true; | |
59 | ASSERT(kind == CodeForConstruct); | |
60 | return false; | |
61 | } | |
f9bf01c6 | 62 | |
93a37866 A |
63 | class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> { |
64 | friend class WTF::DoublyLinkedListNode<ExecutableBase>; | |
f9bf01c6 A |
65 | friend class JIT; |
66 | ||
67 | protected: | |
68 | static const int NUM_PARAMETERS_IS_HOST = 0; | |
69 | static const int NUM_PARAMETERS_NOT_COMPILED = -1; | |
6fe7ccc8 | 70 | |
93a37866 A |
71 | ExecutableBase(VM& vm, Structure* structure, int numParameters) |
72 | : JSCell(vm, structure) | |
14957cd0 A |
73 | , m_numParametersForCall(numParameters) |
74 | , m_numParametersForConstruct(numParameters) | |
f9bf01c6 | 75 | { |
6fe7ccc8 A |
76 | } |
77 | ||
93a37866 | 78 | void finishCreation(VM& vm) |
6fe7ccc8 | 79 | { |
93a37866 | 80 | Base::finishCreation(vm); |
6fe7ccc8 A |
81 | } |
82 | ||
83 | public: | |
84 | typedef JSCell Base; | |
85 | ||
14957cd0 | 86 | #if ENABLE(JIT) |
93a37866 A |
87 | static const bool needsDestruction = true; |
88 | static const bool hasImmortalStructure = true; | |
6fe7ccc8 | 89 | static void destroy(JSCell*); |
14957cd0 | 90 | #endif |
93a37866 A |
91 | |
92 | CodeBlockHash hashFor(CodeSpecializationKind) const; | |
93 | ||
94 | bool isFunctionExecutable() | |
95 | { | |
96 | return structure()->typeInfo().type() == FunctionExecutableType; | |
97 | } | |
f9bf01c6 | 98 | |
14957cd0 A |
99 | bool isHostFunction() const |
100 | { | |
101 | ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); | |
102 | return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; | |
103 | } | |
f9bf01c6 | 104 | |
93a37866 | 105 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } |
14957cd0 | 106 | |
93a37866 A |
107 | void clearCode(); |
108 | ||
6fe7ccc8 | 109 | static JS_EXPORTDATA const ClassInfo s_info; |
f9bf01c6 A |
110 | |
111 | protected: | |
14957cd0 A |
112 | static const unsigned StructureFlags = 0; |
113 | int m_numParametersForCall; | |
114 | int m_numParametersForConstruct; | |
f9bf01c6 | 115 | |
f9bf01c6 | 116 | public: |
93a37866 A |
117 | static void clearCodeVirtual(ExecutableBase*); |
118 | ||
119 | #if ENABLE(JIT) | |
14957cd0 | 120 | JITCode& generatedJITCodeForCall() |
f9bf01c6 | 121 | { |
14957cd0 A |
122 | ASSERT(m_jitCodeForCall); |
123 | return m_jitCodeForCall; | |
f9bf01c6 A |
124 | } |
125 | ||
14957cd0 | 126 | JITCode& generatedJITCodeForConstruct() |
f9bf01c6 | 127 | { |
14957cd0 A |
128 | ASSERT(m_jitCodeForConstruct); |
129 | return m_jitCodeForConstruct; | |
130 | } | |
6fe7ccc8 A |
131 | |
132 | JITCode& generatedJITCodeFor(CodeSpecializationKind kind) | |
133 | { | |
134 | if (kind == CodeForCall) | |
135 | return generatedJITCodeForCall(); | |
136 | ASSERT(kind == CodeForConstruct); | |
137 | return generatedJITCodeForConstruct(); | |
138 | } | |
14957cd0 | 139 | |
6fe7ccc8 | 140 | MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck() |
14957cd0 | 141 | { |
6fe7ccc8 A |
142 | ASSERT(m_jitCodeForCall); |
143 | ASSERT(m_jitCodeForCallWithArityCheck); | |
144 | return m_jitCodeForCallWithArityCheck; | |
145 | } | |
146 | ||
147 | MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck() | |
148 | { | |
149 | ASSERT(m_jitCodeForConstruct); | |
150 | ASSERT(m_jitCodeForConstructWithArityCheck); | |
151 | return m_jitCodeForConstructWithArityCheck; | |
152 | } | |
153 | ||
154 | MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind) | |
155 | { | |
156 | if (kind == CodeForCall) | |
157 | return generatedJITCodeForCallWithArityCheck(); | |
158 | ASSERT(kind == CodeForConstruct); | |
159 | return generatedJITCodeForConstructWithArityCheck(); | |
160 | } | |
161 | ||
162 | bool hasJITCodeForCall() const | |
163 | { | |
164 | return m_numParametersForCall >= 0; | |
165 | } | |
166 | ||
167 | bool hasJITCodeForConstruct() const | |
168 | { | |
169 | return m_numParametersForConstruct >= 0; | |
170 | } | |
171 | ||
172 | bool hasJITCodeFor(CodeSpecializationKind kind) const | |
173 | { | |
174 | if (kind == CodeForCall) | |
175 | return hasJITCodeForCall(); | |
176 | ASSERT(kind == CodeForConstruct); | |
177 | return hasJITCodeForConstruct(); | |
178 | } | |
179 | ||
93a37866 A |
180 | static ptrdiff_t offsetOfJITCodeFor(CodeSpecializationKind kind) |
181 | { | |
182 | if (kind == CodeForCall) | |
183 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCall); | |
184 | ASSERT(kind == CodeForConstruct); | |
185 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstruct); | |
186 | } | |
187 | ||
188 | static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind) | |
189 | { | |
190 | if (kind == CodeForCall) | |
191 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); | |
192 | ASSERT(kind == CodeForConstruct); | |
193 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); | |
194 | } | |
195 | ||
196 | static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind) | |
197 | { | |
198 | if (kind == CodeForCall) | |
199 | return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall); | |
200 | ASSERT(kind == CodeForConstruct); | |
201 | return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct); | |
202 | } | |
203 | #endif // ENABLE(JIT) | |
204 | ||
6fe7ccc8 A |
205 | // Intrinsics are only for calls, currently. |
206 | Intrinsic intrinsic() const; | |
207 | ||
208 | Intrinsic intrinsicFor(CodeSpecializationKind kind) const | |
209 | { | |
210 | if (isCall(kind)) | |
211 | return intrinsic(); | |
212 | return NoIntrinsic; | |
f9bf01c6 | 213 | } |
93a37866 A |
214 | |
215 | #if ENABLE(JIT) || ENABLE(LLINT_C_LOOP) | |
216 | MacroAssemblerCodePtr hostCodeEntryFor(CodeSpecializationKind kind) | |
217 | { | |
218 | #if ENABLE(JIT) | |
219 | return generatedJITCodeFor(kind).addressForCall(); | |
220 | #else | |
221 | return LLInt::CLoop::hostCodeEntryFor(kind); | |
222 | #endif | |
223 | } | |
224 | ||
225 | MacroAssemblerCodePtr jsCodeEntryFor(CodeSpecializationKind kind) | |
226 | { | |
227 | #if ENABLE(JIT) | |
228 | return generatedJITCodeFor(kind).addressForCall(); | |
229 | #else | |
230 | return LLInt::CLoop::jsCodeEntryFor(kind); | |
231 | #endif | |
232 | } | |
233 | ||
234 | MacroAssemblerCodePtr jsCodeWithArityCheckEntryFor(CodeSpecializationKind kind) | |
235 | { | |
236 | #if ENABLE(JIT) | |
237 | return generatedJITCodeWithArityCheckFor(kind); | |
238 | #else | |
239 | return LLInt::CLoop::jsCodeEntryWithArityCheckFor(kind); | |
240 | #endif | |
241 | } | |
242 | ||
243 | static void* catchRoutineFor(HandlerInfo* handler, Instruction* catchPCForInterpreter) | |
244 | { | |
245 | #if ENABLE(JIT) | |
246 | UNUSED_PARAM(catchPCForInterpreter); | |
247 | return handler->nativeCode.executableAddress(); | |
248 | #else | |
249 | UNUSED_PARAM(handler); | |
250 | return LLInt::CLoop::catchRoutineFor(catchPCForInterpreter); | |
251 | #endif | |
252 | } | |
253 | #endif // ENABLE(JIT || ENABLE(LLINT_C_LOOP) | |
f9bf01c6 A |
254 | |
255 | protected: | |
93a37866 A |
256 | ExecutableBase* m_prev; |
257 | ExecutableBase* m_next; | |
258 | ||
259 | #if ENABLE(JIT) | |
14957cd0 A |
260 | JITCode m_jitCodeForCall; |
261 | JITCode m_jitCodeForConstruct; | |
262 | MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; | |
263 | MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; | |
f9bf01c6 A |
264 | #endif |
265 | }; | |
266 | ||
f9bf01c6 | 267 | class NativeExecutable : public ExecutableBase { |
14957cd0 | 268 | friend class JIT; |
6fe7ccc8 | 269 | friend class LLIntOffsetsExtractor; |
f9bf01c6 | 270 | public: |
6fe7ccc8 A |
271 | typedef ExecutableBase Base; |
272 | ||
14957cd0 | 273 | #if ENABLE(JIT) |
93a37866 | 274 | static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic) |
6fe7ccc8 | 275 | { |
6fe7ccc8 A |
276 | NativeExecutable* executable; |
277 | if (!callThunk) { | |
93a37866 A |
278 | executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); |
279 | executable->finishCreation(vm, JITCode(), JITCode(), intrinsic); | |
6fe7ccc8 | 280 | } else { |
93a37866 A |
281 | executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); |
282 | executable->finishCreation(vm, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic); | |
6fe7ccc8 | 283 | } |
6fe7ccc8 | 284 | return executable; |
f9bf01c6 | 285 | } |
6fe7ccc8 A |
286 | #endif |
287 | ||
93a37866 A |
288 | #if ENABLE(LLINT_C_LOOP) |
289 | static NativeExecutable* create(VM& vm, NativeFunction function, NativeFunction constructor) | |
14957cd0 | 290 | { |
93a37866 A |
291 | ASSERT(!vm.canUseJIT()); |
292 | NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); | |
293 | executable->finishCreation(vm); | |
6fe7ccc8 | 294 | return executable; |
14957cd0 A |
295 | } |
296 | #endif | |
f9bf01c6 | 297 | |
6fe7ccc8 A |
298 | #if ENABLE(JIT) |
299 | static void destroy(JSCell*); | |
300 | #endif | |
f9bf01c6 | 301 | |
93a37866 A |
302 | CodeBlockHash hashFor(CodeSpecializationKind) const; |
303 | ||
14957cd0 | 304 | NativeFunction function() { return m_function; } |
6fe7ccc8 | 305 | NativeFunction constructor() { return m_constructor; } |
93a37866 A |
306 | |
307 | NativeFunction nativeFunctionFor(CodeSpecializationKind kind) | |
308 | { | |
309 | if (kind == CodeForCall) | |
310 | return function(); | |
311 | ASSERT(kind == CodeForConstruct); | |
312 | return constructor(); | |
313 | } | |
314 | ||
315 | static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind) | |
316 | { | |
317 | if (kind == CodeForCall) | |
318 | return OBJECT_OFFSETOF(NativeExecutable, m_function); | |
319 | ASSERT(kind == CodeForConstruct); | |
320 | return OBJECT_OFFSETOF(NativeExecutable, m_constructor); | |
321 | } | |
14957cd0 | 322 | |
93a37866 | 323 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); } |
14957cd0 A |
324 | |
325 | static const ClassInfo s_info; | |
6fe7ccc8 A |
326 | |
327 | Intrinsic intrinsic() const; | |
328 | ||
329 | protected: | |
14957cd0 | 330 | #if ENABLE(JIT) |
93a37866 | 331 | void finishCreation(VM& vm, JITCode callThunk, JITCode constructThunk, Intrinsic intrinsic) |
14957cd0 | 332 | { |
93a37866 | 333 | Base::finishCreation(vm); |
14957cd0 A |
334 | m_jitCodeForCall = callThunk; |
335 | m_jitCodeForConstruct = constructThunk; | |
336 | m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); | |
337 | m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall(); | |
6fe7ccc8 A |
338 | m_intrinsic = intrinsic; |
339 | } | |
340 | #endif | |
341 | ||
6fe7ccc8 | 342 | private: |
93a37866 A |
343 | NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor) |
344 | : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) | |
14957cd0 A |
345 | , m_function(function) |
346 | , m_constructor(constructor) | |
f9bf01c6 A |
347 | { |
348 | } | |
349 | ||
14957cd0 | 350 | NativeFunction m_function; |
14957cd0 | 351 | NativeFunction m_constructor; |
6fe7ccc8 A |
352 | |
353 | Intrinsic m_intrinsic; | |
f9bf01c6 A |
354 | }; |
355 | ||
356 | class ScriptExecutable : public ExecutableBase { | |
357 | public: | |
6fe7ccc8 A |
358 | typedef ExecutableBase Base; |
359 | ||
93a37866 A |
360 | ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext) |
361 | : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED) | |
f9bf01c6 | 362 | , m_source(source) |
14957cd0 | 363 | , m_features(isInStrictContext ? StrictModeFeature : 0) |
f9bf01c6 | 364 | { |
f9bf01c6 A |
365 | } |
366 | ||
14957cd0 | 367 | ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext) |
93a37866 | 368 | : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED) |
f9bf01c6 | 369 | , m_source(source) |
14957cd0 | 370 | , m_features(isInStrictContext ? StrictModeFeature : 0) |
f9bf01c6 | 371 | { |
f9bf01c6 A |
372 | } |
373 | ||
6fe7ccc8 A |
374 | #if ENABLE(JIT) |
375 | static void destroy(JSCell*); | |
376 | #endif | |
93a37866 A |
377 | |
378 | CodeBlockHash hashFor(CodeSpecializationKind) const; | |
6fe7ccc8 | 379 | |
93a37866 | 380 | const SourceCode& source() const { return m_source; } |
6fe7ccc8 | 381 | intptr_t sourceID() const { return m_source.providerID(); } |
93a37866 | 382 | const String& sourceURL() const { return m_source.provider()->url(); } |
f9bf01c6 A |
383 | int lineNo() const { return m_firstLine; } |
384 | int lastLine() const { return m_lastLine; } | |
93a37866 | 385 | unsigned startColumn() const { return m_startColumn; } |
f9bf01c6 A |
386 | |
387 | bool usesEval() const { return m_features & EvalFeature; } | |
388 | bool usesArguments() const { return m_features & ArgumentsFeature; } | |
14957cd0 A |
389 | bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); } |
390 | bool isStrictMode() const { return m_features & StrictModeFeature; } | |
f9bf01c6 | 391 | |
6fe7ccc8 | 392 | void unlinkCalls(); |
93a37866 A |
393 | |
394 | CodeFeatures features() const { return m_features; } | |
14957cd0 A |
395 | |
396 | static const ClassInfo s_info; | |
6fe7ccc8 | 397 | |
93a37866 | 398 | void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn) |
f9bf01c6 A |
399 | { |
400 | m_features = features; | |
14957cd0 | 401 | m_hasCapturedVariables = hasCapturedVariables; |
f9bf01c6 A |
402 | m_firstLine = firstLine; |
403 | m_lastLine = lastLine; | |
93a37866 A |
404 | m_startColumn = startColumn; |
405 | } | |
406 | ||
407 | protected: | |
408 | void finishCreation(VM& vm) | |
409 | { | |
410 | Base::finishCreation(vm); | |
411 | vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). | |
412 | ||
413 | #if ENABLE(CODEBLOCK_SAMPLING) | |
414 | if (SamplingTool* sampler = vm.interpreter->sampler()) | |
415 | sampler->notifyOfScope(vm, this); | |
416 | #endif | |
f9bf01c6 A |
417 | } |
418 | ||
419 | SourceCode m_source; | |
420 | CodeFeatures m_features; | |
14957cd0 | 421 | bool m_hasCapturedVariables; |
f9bf01c6 A |
422 | int m_firstLine; |
423 | int m_lastLine; | |
93a37866 | 424 | unsigned m_startColumn; |
f9bf01c6 A |
425 | }; |
426 | ||
427 | class EvalExecutable : public ScriptExecutable { | |
6fe7ccc8 | 428 | friend class LLIntOffsetsExtractor; |
f9bf01c6 | 429 | public: |
6fe7ccc8 | 430 | typedef ScriptExecutable Base; |
f9bf01c6 | 431 | |
6fe7ccc8 | 432 | static void destroy(JSCell*); |
f9bf01c6 | 433 | |
93a37866 | 434 | JSObject* compile(ExecState* exec, JSScope* scope) |
f9bf01c6 | 435 | { |
93a37866 | 436 | RELEASE_ASSERT(exec->vm().dynamicGlobalObject); |
14957cd0 A |
437 | JSObject* error = 0; |
438 | if (!m_evalCodeBlock) | |
93a37866 | 439 | error = compileInternal(exec, scope, JITCode::bottomTierJIT()); |
14957cd0 A |
440 | ASSERT(!error == !!m_evalCodeBlock); |
441 | return error; | |
f9bf01c6 | 442 | } |
6fe7ccc8 | 443 | |
93a37866 | 444 | JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex); |
6fe7ccc8 A |
445 | |
446 | #if ENABLE(JIT) | |
93a37866 A |
447 | void jettisonOptimizedCode(VM&); |
448 | bool jitCompile(ExecState*); | |
6fe7ccc8 | 449 | #endif |
f9bf01c6 | 450 | |
14957cd0 | 451 | EvalCodeBlock& generatedBytecode() |
f9bf01c6 | 452 | { |
14957cd0 A |
453 | ASSERT(m_evalCodeBlock); |
454 | return *m_evalCodeBlock; | |
f9bf01c6 | 455 | } |
14957cd0 | 456 | |
93a37866 | 457 | static EvalExecutable* create(ExecState* exec, PassRefPtr<CodeCache> cache, const SourceCode& source, bool isInStrictContext) |
6fe7ccc8 | 458 | { |
93a37866 A |
459 | EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, cache, source, isInStrictContext); |
460 | executable->finishCreation(exec->vm()); | |
6fe7ccc8 A |
461 | return executable; |
462 | } | |
f9bf01c6 A |
463 | |
464 | #if ENABLE(JIT) | |
14957cd0 | 465 | JITCode& generatedJITCode() |
f9bf01c6 | 466 | { |
14957cd0 | 467 | return generatedJITCodeForCall(); |
f9bf01c6 | 468 | } |
f9bf01c6 | 469 | #endif |
93a37866 | 470 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) |
14957cd0 | 471 | { |
93a37866 | 472 | return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), &s_info); |
14957cd0 A |
473 | } |
474 | ||
475 | static const ClassInfo s_info; | |
6fe7ccc8 A |
476 | |
477 | void unlinkCalls(); | |
478 | ||
6fe7ccc8 | 479 | void clearCode(); |
93a37866 A |
480 | |
481 | ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); } | |
6fe7ccc8 | 482 | |
14957cd0 A |
483 | private: |
484 | static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; | |
93a37866 | 485 | EvalExecutable(ExecState*, PassRefPtr<CodeCache>, const SourceCode&, bool); |
14957cd0 | 486 | |
93a37866 | 487 | JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); |
6fe7ccc8 | 488 | static void visitChildren(JSCell*, SlotVisitor&); |
14957cd0 A |
489 | |
490 | OwnPtr<EvalCodeBlock> m_evalCodeBlock; | |
93a37866 A |
491 | WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; |
492 | RefPtr<CodeCache> m_codeCache; | |
f9bf01c6 A |
493 | }; |
494 | ||
495 | class ProgramExecutable : public ScriptExecutable { | |
6fe7ccc8 | 496 | friend class LLIntOffsetsExtractor; |
f9bf01c6 | 497 | public: |
6fe7ccc8 A |
498 | typedef ScriptExecutable Base; |
499 | ||
14957cd0 | 500 | static ProgramExecutable* create(ExecState* exec, const SourceCode& source) |
f9bf01c6 | 501 | { |
6fe7ccc8 | 502 | ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source); |
93a37866 | 503 | executable->finishCreation(exec->vm()); |
6fe7ccc8 | 504 | return executable; |
f9bf01c6 A |
505 | } |
506 | ||
93a37866 A |
507 | |
508 | JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*); | |
509 | ||
6fe7ccc8 | 510 | static void destroy(JSCell*); |
f9bf01c6 | 511 | |
93a37866 | 512 | JSObject* compile(ExecState* exec, JSScope* scope) |
14957cd0 | 513 | { |
93a37866 | 514 | RELEASE_ASSERT(exec->vm().dynamicGlobalObject); |
14957cd0 A |
515 | JSObject* error = 0; |
516 | if (!m_programCodeBlock) | |
93a37866 | 517 | error = compileInternal(exec, scope, JITCode::bottomTierJIT()); |
14957cd0 A |
518 | ASSERT(!error == !!m_programCodeBlock); |
519 | return error; | |
520 | } | |
521 | ||
93a37866 | 522 | JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex); |
6fe7ccc8 A |
523 | |
524 | #if ENABLE(JIT) | |
93a37866 A |
525 | void jettisonOptimizedCode(VM&); |
526 | bool jitCompile(ExecState*); | |
6fe7ccc8 A |
527 | #endif |
528 | ||
14957cd0 | 529 | ProgramCodeBlock& generatedBytecode() |
f9bf01c6 | 530 | { |
14957cd0 | 531 | ASSERT(m_programCodeBlock); |
f9bf01c6 A |
532 | return *m_programCodeBlock; |
533 | } | |
534 | ||
535 | JSObject* checkSyntax(ExecState*); | |
f9bf01c6 | 536 | |
14957cd0 A |
537 | #if ENABLE(JIT) |
538 | JITCode& generatedJITCode() | |
f9bf01c6 | 539 | { |
14957cd0 | 540 | return generatedJITCodeForCall(); |
f9bf01c6 | 541 | } |
14957cd0 A |
542 | #endif |
543 | ||
93a37866 | 544 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) |
f9bf01c6 | 545 | { |
93a37866 | 546 | return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), &s_info); |
f9bf01c6 | 547 | } |
14957cd0 A |
548 | |
549 | static const ClassInfo s_info; | |
6fe7ccc8 A |
550 | |
551 | void unlinkCalls(); | |
552 | ||
6fe7ccc8 | 553 | void clearCode(); |
93a37866 A |
554 | |
555 | ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); } | |
f9bf01c6 A |
556 | |
557 | private: | |
14957cd0 | 558 | static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; |
93a37866 | 559 | |
14957cd0 A |
560 | ProgramExecutable(ExecState*, const SourceCode&); |
561 | ||
93a37866 A |
562 | enum ConstantMode { IsConstant, IsVariable }; |
563 | enum FunctionMode { IsFunctionToSpecialize, NotFunctionOrNotSpecializable }; | |
564 | int addGlobalVar(JSGlobalObject*, const Identifier&, ConstantMode, FunctionMode); | |
565 | ||
566 | JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); | |
6fe7ccc8 | 567 | static void visitChildren(JSCell*, SlotVisitor&); |
14957cd0 | 568 | |
93a37866 | 569 | WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock; |
14957cd0 | 570 | OwnPtr<ProgramCodeBlock> m_programCodeBlock; |
f9bf01c6 A |
571 | }; |
572 | ||
93a37866 | 573 | class FunctionExecutable : public ScriptExecutable { |
f9bf01c6 | 574 | friend class JIT; |
6fe7ccc8 | 575 | friend class LLIntOffsetsExtractor; |
f9bf01c6 | 576 | public: |
6fe7ccc8 A |
577 | typedef ScriptExecutable Base; |
578 | ||
93a37866 | 579 | static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn) |
f9bf01c6 | 580 | { |
93a37866 A |
581 | FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn); |
582 | executable->finishCreation(vm); | |
6fe7ccc8 | 583 | return executable; |
f9bf01c6 | 584 | } |
93a37866 | 585 | static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception); |
f9bf01c6 | 586 | |
6fe7ccc8 | 587 | static void destroy(JSCell*); |
93a37866 A |
588 | |
589 | UnlinkedFunctionExecutable* unlinkedExecutable() | |
f9bf01c6 | 590 | { |
93a37866 | 591 | return m_unlinkedExecutable.get(); |
f9bf01c6 | 592 | } |
93a37866 | 593 | |
14957cd0 A |
594 | // Returns either call or construct bytecode. This can be appropriate |
595 | // for answering questions that that don't vary between call and construct -- | |
596 | // for example, argumentsRegister(). | |
597 | FunctionCodeBlock& generatedBytecode() | |
f9bf01c6 | 598 | { |
14957cd0 A |
599 | if (m_codeBlockForCall) |
600 | return *m_codeBlockForCall; | |
601 | ASSERT(m_codeBlockForConstruct); | |
602 | return *m_codeBlockForConstruct; | |
f9bf01c6 | 603 | } |
6fe7ccc8 | 604 | |
93a37866 | 605 | PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(JSScope*, CodeSpecializationKind, JSObject*& exception); |
f9bf01c6 | 606 | |
93a37866 | 607 | JSObject* compileForCall(ExecState* exec, JSScope* scope) |
f9bf01c6 | 608 | { |
93a37866 | 609 | RELEASE_ASSERT(exec->vm().dynamicGlobalObject); |
14957cd0 A |
610 | JSObject* error = 0; |
611 | if (!m_codeBlockForCall) | |
93a37866 | 612 | error = compileForCallInternal(exec, scope, JITCode::bottomTierJIT()); |
14957cd0 A |
613 | ASSERT(!error == !!m_codeBlockForCall); |
614 | return error; | |
f9bf01c6 A |
615 | } |
616 | ||
93a37866 | 617 | JSObject* compileOptimizedForCall(ExecState*, JSScope*, unsigned bytecodeIndex); |
6fe7ccc8 A |
618 | |
619 | #if ENABLE(JIT) | |
93a37866 A |
620 | void jettisonOptimizedCodeForCall(VM&); |
621 | bool jitCompileForCall(ExecState*); | |
6fe7ccc8 A |
622 | #endif |
623 | ||
14957cd0 | 624 | bool isGeneratedForCall() const |
f9bf01c6 | 625 | { |
14957cd0 | 626 | return m_codeBlockForCall; |
f9bf01c6 A |
627 | } |
628 | ||
14957cd0 A |
629 | FunctionCodeBlock& generatedBytecodeForCall() |
630 | { | |
631 | ASSERT(m_codeBlockForCall); | |
632 | return *m_codeBlockForCall; | |
633 | } | |
f9bf01c6 | 634 | |
93a37866 | 635 | JSObject* compileForConstruct(ExecState* exec, JSScope* scope) |
14957cd0 | 636 | { |
93a37866 | 637 | RELEASE_ASSERT(exec->vm().dynamicGlobalObject); |
14957cd0 A |
638 | JSObject* error = 0; |
639 | if (!m_codeBlockForConstruct) | |
93a37866 | 640 | error = compileForConstructInternal(exec, scope, JITCode::bottomTierJIT()); |
14957cd0 A |
641 | ASSERT(!error == !!m_codeBlockForConstruct); |
642 | return error; | |
643 | } | |
f9bf01c6 | 644 | |
93a37866 | 645 | JSObject* compileOptimizedForConstruct(ExecState*, JSScope*, unsigned bytecodeIndex); |
6fe7ccc8 A |
646 | |
647 | #if ENABLE(JIT) | |
93a37866 A |
648 | void jettisonOptimizedCodeForConstruct(VM&); |
649 | bool jitCompileForConstruct(ExecState*); | |
6fe7ccc8 A |
650 | #endif |
651 | ||
14957cd0 | 652 | bool isGeneratedForConstruct() const |
f9bf01c6 | 653 | { |
14957cd0 | 654 | return m_codeBlockForConstruct; |
f9bf01c6 A |
655 | } |
656 | ||
14957cd0 | 657 | FunctionCodeBlock& generatedBytecodeForConstruct() |
f9bf01c6 | 658 | { |
14957cd0 A |
659 | ASSERT(m_codeBlockForConstruct); |
660 | return *m_codeBlockForConstruct; | |
f9bf01c6 | 661 | } |
6fe7ccc8 | 662 | |
93a37866 | 663 | JSObject* compileFor(ExecState* exec, JSScope* scope, CodeSpecializationKind kind) |
6fe7ccc8 A |
664 | { |
665 | ASSERT(exec->callee()); | |
666 | ASSERT(exec->callee()->inherits(&JSFunction::s_info)); | |
667 | ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this); | |
668 | ||
669 | if (kind == CodeForCall) | |
93a37866 | 670 | return compileForCall(exec, scope); |
6fe7ccc8 | 671 | ASSERT(kind == CodeForConstruct); |
93a37866 | 672 | return compileForConstruct(exec, scope); |
6fe7ccc8 A |
673 | } |
674 | ||
93a37866 | 675 | JSObject* compileOptimizedFor(ExecState* exec, JSScope* scope, unsigned bytecodeIndex, CodeSpecializationKind kind) |
6fe7ccc8 A |
676 | { |
677 | ASSERT(exec->callee()); | |
678 | ASSERT(exec->callee()->inherits(&JSFunction::s_info)); | |
679 | ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this); | |
680 | ||
681 | if (kind == CodeForCall) | |
93a37866 | 682 | return compileOptimizedForCall(exec, scope, bytecodeIndex); |
6fe7ccc8 | 683 | ASSERT(kind == CodeForConstruct); |
93a37866 | 684 | return compileOptimizedForConstruct(exec, scope, bytecodeIndex); |
6fe7ccc8 A |
685 | } |
686 | ||
687 | ||
688 | #if ENABLE(JIT) | |
93a37866 | 689 | void jettisonOptimizedCodeFor(VM& vm, CodeSpecializationKind kind) |
6fe7ccc8 A |
690 | { |
691 | if (kind == CodeForCall) | |
93a37866 | 692 | jettisonOptimizedCodeForCall(vm); |
6fe7ccc8 A |
693 | else { |
694 | ASSERT(kind == CodeForConstruct); | |
93a37866 | 695 | jettisonOptimizedCodeForConstruct(vm); |
6fe7ccc8 A |
696 | } |
697 | } | |
698 | ||
93a37866 | 699 | bool jitCompileFor(ExecState* exec, CodeSpecializationKind kind) |
6fe7ccc8 A |
700 | { |
701 | if (kind == CodeForCall) | |
93a37866 | 702 | return jitCompileForCall(exec); |
6fe7ccc8 | 703 | ASSERT(kind == CodeForConstruct); |
93a37866 | 704 | return jitCompileForConstruct(exec); |
6fe7ccc8 A |
705 | } |
706 | #endif | |
707 | ||
708 | bool isGeneratedFor(CodeSpecializationKind kind) | |
709 | { | |
710 | if (kind == CodeForCall) | |
711 | return isGeneratedForCall(); | |
712 | ASSERT(kind == CodeForConstruct); | |
713 | return isGeneratedForConstruct(); | |
714 | } | |
715 | ||
716 | FunctionCodeBlock& generatedBytecodeFor(CodeSpecializationKind kind) | |
717 | { | |
718 | if (kind == CodeForCall) | |
719 | return generatedBytecodeForCall(); | |
720 | ASSERT(kind == CodeForConstruct); | |
721 | return generatedBytecodeForConstruct(); | |
722 | } | |
f9bf01c6 | 723 | |
6fe7ccc8 A |
724 | FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind); |
725 | ||
726 | FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind) | |
727 | { | |
728 | return baselineCodeBlockFor(kind); | |
729 | } | |
730 | ||
93a37866 A |
731 | const Identifier& name() { return m_unlinkedExecutable->name(); } |
732 | const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); } | |
733 | JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); } | |
734 | size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'! | |
735 | String paramString() const; | |
736 | SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); } | |
14957cd0 | 737 | |
93a37866 A |
738 | void clearCodeIfNotCompiling(); |
739 | void clearUnlinkedCodeForRecompilationIfNotCompiling(); | |
6fe7ccc8 | 740 | static void visitChildren(JSCell*, SlotVisitor&); |
93a37866 | 741 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) |
14957cd0 | 742 | { |
93a37866 | 743 | return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info); |
14957cd0 A |
744 | } |
745 | ||
746 | static const ClassInfo s_info; | |
6fe7ccc8 A |
747 | |
748 | void unlinkCalls(); | |
749 | ||
6fe7ccc8 | 750 | void clearCode(); |
f9bf01c6 | 751 | |
14957cd0 | 752 | private: |
93a37866 | 753 | FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine, unsigned startColumn); |
14957cd0 | 754 | |
93a37866 A |
755 | JSObject* compileForCallInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); |
756 | JSObject* compileForConstructInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); | |
6fe7ccc8 A |
757 | |
758 | OwnPtr<FunctionCodeBlock>& codeBlockFor(CodeSpecializationKind kind) | |
759 | { | |
760 | if (kind == CodeForCall) | |
761 | return m_codeBlockForCall; | |
762 | ASSERT(kind == CodeForConstruct); | |
763 | return m_codeBlockForConstruct; | |
764 | } | |
93a37866 A |
765 | |
766 | bool isCompiling() | |
767 | { | |
768 | #if ENABLE(JIT) | |
769 | if (!m_jitCodeForCall && m_codeBlockForCall) | |
770 | return true; | |
771 | if (!m_jitCodeForConstruct && m_codeBlockForConstruct) | |
772 | return true; | |
773 | #endif | |
774 | return false; | |
775 | } | |
4e4e5a6f | 776 | |
93a37866 A |
777 | static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; |
778 | WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; | |
14957cd0 A |
779 | OwnPtr<FunctionCodeBlock> m_codeBlockForCall; |
780 | OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; | |
f9bf01c6 A |
781 | }; |
782 | ||
93a37866 A |
783 | inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope) |
784 | : Base(vm, scope->globalObject()->functionStructure()) | |
785 | , m_executable(vm, this, executable) | |
786 | , m_scope(vm, this, scope) | |
787 | , m_allocationProfileWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching. | |
788 | { | |
789 | } | |
790 | ||
f9bf01c6 A |
791 | inline FunctionExecutable* JSFunction::jsExecutable() const |
792 | { | |
793 | ASSERT(!isHostFunctionNonInline()); | |
794 | return static_cast<FunctionExecutable*>(m_executable.get()); | |
795 | } | |
796 | ||
797 | inline bool JSFunction::isHostFunction() const | |
798 | { | |
799 | ASSERT(m_executable); | |
800 | return m_executable->isHostFunction(); | |
801 | } | |
802 | ||
14957cd0 A |
803 | inline NativeFunction JSFunction::nativeFunction() |
804 | { | |
805 | ASSERT(isHostFunction()); | |
806 | return static_cast<NativeExecutable*>(m_executable.get())->function(); | |
807 | } | |
6fe7ccc8 A |
808 | |
809 | inline NativeFunction JSFunction::nativeConstructor() | |
810 | { | |
811 | ASSERT(isHostFunction()); | |
812 | return static_cast<NativeExecutable*>(m_executable.get())->constructor(); | |
813 | } | |
814 | ||
815 | inline bool isHostFunction(JSValue value, NativeFunction nativeFunction) | |
816 | { | |
817 | JSFunction* function = jsCast<JSFunction*>(getJSFunction(value)); | |
818 | if (!function || !function->isHostFunction()) | |
819 | return false; | |
820 | return function->nativeFunction() == nativeFunction; | |
821 | } | |
822 | ||
93a37866 A |
823 | inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) |
824 | { | |
825 | switch (executable->structure()->typeInfo().type()) { | |
826 | case EvalExecutableType: | |
827 | return jsCast<EvalExecutable*>(executable)->clearCode(); | |
828 | case ProgramExecutableType: | |
829 | return jsCast<ProgramExecutable*>(executable)->clearCode(); | |
830 | case FunctionExecutableType: | |
831 | return jsCast<FunctionExecutable*>(executable)->clearCode(); | |
832 | default: | |
833 | return jsCast<NativeExecutable*>(executable)->clearCode(); | |
834 | } | |
835 | } | |
836 | ||
6fe7ccc8 A |
837 | inline void ScriptExecutable::unlinkCalls() |
838 | { | |
839 | switch (structure()->typeInfo().type()) { | |
840 | case EvalExecutableType: | |
841 | return jsCast<EvalExecutable*>(this)->unlinkCalls(); | |
842 | case ProgramExecutableType: | |
843 | return jsCast<ProgramExecutable*>(this)->unlinkCalls(); | |
844 | case FunctionExecutableType: | |
845 | return jsCast<FunctionExecutable*>(this)->unlinkCalls(); | |
846 | default: | |
93a37866 | 847 | RELEASE_ASSERT_NOT_REACHED(); |
6fe7ccc8 A |
848 | } |
849 | } | |
850 | ||
f9bf01c6 A |
851 | } |
852 | ||
853 | #endif |