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