]>
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 | #include "config.h" | |
27 | #include "Executable.h" | |
28 | ||
29 | #include "BatchedTransitionOptimizer.h" | |
30 | #include "BytecodeGenerator.h" | |
31 | #include "CodeBlock.h" | |
32 | #include "DFGDriver.h" | |
33 | #include "JIT.h" | |
34 | #include "LLIntEntrypoint.h" | |
35 | #include "JSCInlines.h" | |
36 | #include "Parser.h" | |
37 | #include "ProfilerDatabase.h" | |
38 | #include <wtf/CommaPrinter.h> | |
39 | #include <wtf/Vector.h> | |
40 | #include <wtf/text/StringBuilder.h> | |
41 | ||
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 | { | |
49 | static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); | |
50 | } | |
51 | #endif | |
52 | ||
53 | void ExecutableBase::clearCode() | |
54 | { | |
55 | #if ENABLE(JIT) | |
56 | m_jitCodeForCall.clear(); | |
57 | m_jitCodeForConstruct.clear(); | |
58 | m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); | |
59 | m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); | |
60 | m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); | |
61 | m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); | |
62 | #endif | |
63 | m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; | |
64 | m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; | |
65 | } | |
66 | ||
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 | } | |
74 | #else | |
75 | Intrinsic ExecutableBase::intrinsic() const | |
76 | { | |
77 | return NoIntrinsic; | |
78 | } | |
79 | #endif | |
80 | ||
81 | const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; | |
82 | ||
83 | #if ENABLE(JIT) | |
84 | void NativeExecutable::destroy(JSCell* cell) | |
85 | { | |
86 | static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); | |
87 | } | |
88 | #endif | |
89 | ||
90 | #if ENABLE(DFG_JIT) | |
91 | Intrinsic NativeExecutable::intrinsic() const | |
92 | { | |
93 | return m_intrinsic; | |
94 | } | |
95 | #endif | |
96 | ||
97 | const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; | |
98 | ||
99 | #if ENABLE(JIT) | |
100 | void ScriptExecutable::destroy(JSCell* cell) | |
101 | { | |
102 | static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); | |
103 | } | |
104 | #endif | |
105 | ||
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 | } | |
234 | ||
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) | |
287 | { | |
288 | LLInt::setEntrypoint(vm, codeBlock); | |
289 | } | |
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(); | |
300 | #endif | |
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 | } | |
327 | ||
328 | const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; | |
329 | ||
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) | |
351 | : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) | |
352 | { | |
353 | } | |
354 | ||
355 | void EvalExecutable::destroy(JSCell* cell) | |
356 | { | |
357 | static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); | |
358 | } | |
359 | ||
360 | const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; | |
361 | ||
362 | ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) | |
363 | : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) | |
364 | { | |
365 | } | |
366 | ||
367 | void ProgramExecutable::destroy(JSCell* cell) | |
368 | { | |
369 | static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); | |
370 | } | |
371 | ||
372 | const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; | |
373 | ||
374 | FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces) | |
375 | : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) | |
376 | , m_unlinkedExecutable(vm, this, unlinkedExecutable) | |
377 | , m_bodyIncludesBraces(bodyIncludesBraces) | |
378 | , m_didParseForTheFirstTime(false) | |
379 | { | |
380 | RELEASE_ASSERT(!source.isNull()); | |
381 | ASSERT(source.length()); | |
382 | m_firstLine = firstLine; | |
383 | m_lastLine = lastLine; | |
384 | ASSERT(startColumn != UINT_MAX); | |
385 | ASSERT(endColumn != UINT_MAX); | |
386 | m_startColumn = startColumn; | |
387 | m_endColumn = endColumn; | |
388 | } | |
389 | ||
390 | void FunctionExecutable::destroy(JSCell* cell) | |
391 | { | |
392 | static_cast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable(); | |
393 | } | |
394 | ||
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)"; | |
404 | case JITCode::FTLJIT: | |
405 | return "FTL Compilation (TOTAL)"; | |
406 | default: | |
407 | RELEASE_ASSERT_NOT_REACHED(); | |
408 | return 0; | |
409 | } | |
410 | } | |
411 | ||
412 | void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
413 | { | |
414 | EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell); | |
415 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); | |
416 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); | |
417 | ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); | |
418 | ScriptExecutable::visitChildren(thisObject, visitor); | |
419 | if (thisObject->m_evalCodeBlock) | |
420 | thisObject->m_evalCodeBlock->visitAggregate(visitor); | |
421 | visitor.append(&thisObject->m_unlinkedEvalCodeBlock); | |
422 | } | |
423 | ||
424 | void EvalExecutable::unlinkCalls() | |
425 | { | |
426 | #if ENABLE(JIT) | |
427 | if (!m_jitCodeForCall) | |
428 | return; | |
429 | RELEASE_ASSERT(m_evalCodeBlock); | |
430 | m_evalCodeBlock->unlinkCalls(); | |
431 | #endif | |
432 | } | |
433 | ||
434 | void EvalExecutable::clearCode() | |
435 | { | |
436 | m_evalCodeBlock.clear(); | |
437 | m_unlinkedEvalCodeBlock.clear(); | |
438 | Base::clearCode(); | |
439 | } | |
440 | ||
441 | JSObject* ProgramExecutable::checkSyntax(ExecState* exec) | |
442 | { | |
443 | ParserError error; | |
444 | VM* vm = &exec->vm(); | |
445 | JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); | |
446 | RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); | |
447 | if (programNode) | |
448 | return 0; | |
449 | ASSERT(error.m_type != ParserError::ErrorNone); | |
450 | return error.toErrorObject(lexicalGlobalObject, m_source); | |
451 | } | |
452 | ||
453 | void ProgramExecutable::unlinkCalls() | |
454 | { | |
455 | #if ENABLE(JIT) | |
456 | if (!m_jitCodeForCall) | |
457 | return; | |
458 | RELEASE_ASSERT(m_programCodeBlock); | |
459 | m_programCodeBlock->unlinkCalls(); | |
460 | #endif | |
461 | } | |
462 | ||
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; | |
471 | UnlinkedProgramCodeBlock* unlinkedCodeBlock = globalObject->createProgramCodeBlock(callFrame, this, &exception); | |
472 | if (exception) | |
473 | return exception; | |
474 | ||
475 | m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); | |
476 | ||
477 | BatchedTransitionOptimizer optimizer(vm, globalObject); | |
478 | ||
479 | const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); | |
480 | const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations(); | |
481 | ||
482 | for (size_t i = 0; i < functionDeclarations.size(); ++i) { | |
483 | UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); | |
484 | JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo()), scope); | |
485 | globalObject->addFunction(callFrame, functionDeclarations[i].first, value); | |
486 | } | |
487 | ||
488 | for (size_t i = 0; i < variableDeclarations.size(); ++i) { | |
489 | if (variableDeclarations[i].second & DeclarationStacks::IsConstant) | |
490 | globalObject->addConst(callFrame, variableDeclarations[i].first); | |
491 | else | |
492 | globalObject->addVar(callFrame, variableDeclarations[i].first); | |
493 | } | |
494 | return 0; | |
495 | } | |
496 | ||
497 | void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
498 | { | |
499 | ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell); | |
500 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); | |
501 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); | |
502 | ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); | |
503 | ScriptExecutable::visitChildren(thisObject, visitor); | |
504 | visitor.append(&thisObject->m_unlinkedProgramCodeBlock); | |
505 | if (thisObject->m_programCodeBlock) | |
506 | thisObject->m_programCodeBlock->visitAggregate(visitor); | |
507 | } | |
508 | ||
509 | void ProgramExecutable::clearCode() | |
510 | { | |
511 | m_programCodeBlock.clear(); | |
512 | m_unlinkedProgramCodeBlock.clear(); | |
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 { | |
522 | RELEASE_ASSERT(kind == CodeForConstruct); | |
523 | result = m_codeBlockForConstruct.get(); | |
524 | } | |
525 | if (!result) | |
526 | return 0; | |
527 | return static_cast<FunctionCodeBlock*>(result->baselineAlternative()); | |
528 | } | |
529 | ||
530 | void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
531 | { | |
532 | FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell); | |
533 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); | |
534 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); | |
535 | ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); | |
536 | ScriptExecutable::visitChildren(thisObject, visitor); | |
537 | if (thisObject->m_codeBlockForCall) | |
538 | thisObject->m_codeBlockForCall->visitAggregate(visitor); | |
539 | if (thisObject->m_codeBlockForConstruct) | |
540 | thisObject->m_codeBlockForConstruct->visitAggregate(visitor); | |
541 | visitor.append(&thisObject->m_unlinkedExecutable); | |
542 | } | |
543 | ||
544 | SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) | |
545 | { | |
546 | return codeBlockFor(kind)->symbolTable(); | |
547 | } | |
548 | ||
549 | void FunctionExecutable::clearCodeIfNotCompiling() | |
550 | { | |
551 | if (isCompiling()) | |
552 | return; | |
553 | clearCode(); | |
554 | } | |
555 | ||
556 | void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() | |
557 | { | |
558 | if (isCompiling()) | |
559 | return; | |
560 | m_unlinkedExecutable->clearCodeForRecompilation(); | |
561 | } | |
562 | ||
563 | void FunctionExecutable::clearCode() | |
564 | { | |
565 | m_codeBlockForCall.clear(); | |
566 | m_codeBlockForConstruct.clear(); | |
567 | Base::clearCode(); | |
568 | } | |
569 | ||
570 | void FunctionExecutable::unlinkCalls() | |
571 | { | |
572 | #if ENABLE(JIT) | |
573 | if (!!m_jitCodeForCall) { | |
574 | RELEASE_ASSERT(m_codeBlockForCall); | |
575 | m_codeBlockForCall->unlinkCalls(); | |
576 | } | |
577 | if (!!m_jitCodeForConstruct) { | |
578 | RELEASE_ASSERT(m_codeBlockForConstruct); | |
579 | m_codeBlockForConstruct->unlinkCalls(); | |
580 | } | |
581 | #endif | |
582 | } | |
583 | ||
584 | FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) | |
585 | { | |
586 | UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); | |
587 | if (!unlinkedExecutable) | |
588 | return 0; | |
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); | |
607 | } | |
608 | ||
609 | String FunctionExecutable::paramString() const | |
610 | { | |
611 | return m_unlinkedExecutable->paramString(); | |
612 | } | |
613 | ||
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 | ||
654 | CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const | |
655 | { | |
656 | if (this->classInfo() == NativeExecutable::info()) | |
657 | return jsCast<const NativeExecutable*>(this)->hashFor(kind); | |
658 | ||
659 | return jsCast<const ScriptExecutable*>(this)->hashFor(kind); | |
660 | } | |
661 | ||
662 | CodeBlockHash NativeExecutable::hashFor(CodeSpecializationKind kind) const | |
663 | { | |
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); | |
674 | } | |
675 | ||
676 | } |