2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "Executable.h"
29 #include "BytecodeGenerator.h"
30 #include "CodeBlock.h"
33 #include "UStringBuilder.h"
37 #include "DFGByteCodeParser.h"
38 #include "DFGJITCompiler.h"
43 const ClassInfo
ExecutableBase::s_info
= { "Executable", 0, 0, 0 };
46 class ExecutableFinalizer
: public WeakHandleOwner
{
47 virtual void finalize(Handle
<Unknown
> handle
, void*)
49 Weak
<ExecutableBase
> executable(Weak
<ExecutableBase
>::Adopt
, handle
);
50 executable
->clearExecutableCode();
54 WeakHandleOwner
* ExecutableBase::executableFinalizer()
56 DEFINE_STATIC_LOCAL(ExecutableFinalizer
, finalizer
, ());
61 const ClassInfo
NativeExecutable::s_info
= { "NativeExecutable", &ExecutableBase::s_info
, 0, 0 };
63 NativeExecutable::~NativeExecutable()
67 const ClassInfo
ScriptExecutable::s_info
= { "ScriptExecutable", &ExecutableBase::s_info
, 0, 0 };
69 const ClassInfo
EvalExecutable::s_info
= { "EvalExecutable", &ScriptExecutable::s_info
, 0, 0 };
71 EvalExecutable::EvalExecutable(ExecState
* exec
, const SourceCode
& source
, bool inStrictContext
)
72 : ScriptExecutable(exec
->globalData().evalExecutableStructure
.get(), exec
, source
, inStrictContext
)
76 EvalExecutable::~EvalExecutable()
80 const ClassInfo
ProgramExecutable::s_info
= { "ProgramExecutable", &ScriptExecutable::s_info
, 0, 0 };
82 ProgramExecutable::ProgramExecutable(ExecState
* exec
, const SourceCode
& source
)
83 : ScriptExecutable(exec
->globalData().programExecutableStructure
.get(), exec
, source
, false)
87 ProgramExecutable::~ProgramExecutable()
91 const ClassInfo
FunctionExecutable::s_info
= { "FunctionExecutable", &ScriptExecutable::s_info
, 0, 0 };
93 FunctionExecutable::FunctionExecutable(JSGlobalData
* globalData
, const Identifier
& name
, const SourceCode
& source
, bool forceUsesArguments
, FunctionParameters
* parameters
, bool inStrictContext
, int firstLine
, int lastLine
)
94 : ScriptExecutable(globalData
->functionExecutableStructure
.get(), globalData
, source
, inStrictContext
)
95 , m_numCapturedVariables(0)
96 , m_forceUsesArguments(forceUsesArguments
)
97 , m_parameters(parameters
)
101 m_firstLine
= firstLine
;
102 m_lastLine
= lastLine
;
105 FunctionExecutable::FunctionExecutable(ExecState
* exec
, const Identifier
& name
, const SourceCode
& source
, bool forceUsesArguments
, FunctionParameters
* parameters
, bool inStrictContext
, int firstLine
, int lastLine
)
106 : ScriptExecutable(exec
->globalData().functionExecutableStructure
.get(), exec
, source
, inStrictContext
)
107 , m_numCapturedVariables(0)
108 , m_forceUsesArguments(forceUsesArguments
)
109 , m_parameters(parameters
)
113 m_firstLine
= firstLine
;
114 m_lastLine
= lastLine
;
118 JSObject
* EvalExecutable::compileInternal(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
120 JSObject
* exception
= 0;
121 JSGlobalData
* globalData
= &exec
->globalData();
122 JSGlobalObject
* lexicalGlobalObject
= exec
->lexicalGlobalObject();
123 if (!lexicalGlobalObject
->isEvalEnabled())
124 return throwError(exec
, createEvalError(exec
, "Eval is disabled"));
125 RefPtr
<EvalNode
> evalNode
= globalData
->parser
->parse
<EvalNode
>(lexicalGlobalObject
, lexicalGlobalObject
->debugger(), exec
, m_source
, 0, isStrictMode() ? JSParseStrict
: JSParseNormal
, &exception
);
130 recordParse(evalNode
->features(), evalNode
->hasCapturedVariables(), evalNode
->lineNo(), evalNode
->lastLine());
132 JSGlobalObject
* globalObject
= scopeChainNode
->globalObject
.get();
134 ASSERT(!m_evalCodeBlock
);
135 m_evalCodeBlock
= adoptPtr(new EvalCodeBlock(this, globalObject
, source().provider(), scopeChainNode
->localDepth()));
136 OwnPtr
<BytecodeGenerator
> generator(adoptPtr(new BytecodeGenerator(evalNode
.get(), scopeChainNode
, m_evalCodeBlock
->symbolTable(), m_evalCodeBlock
.get())));
137 if ((exception
= generator
->generate())) {
138 m_evalCodeBlock
.clear();
139 evalNode
->destroyData();
143 evalNode
->destroyData();
146 if (exec
->globalData().canUseJIT()) {
147 m_jitCodeForCall
= JIT::compile(scopeChainNode
->globalData
, m_evalCodeBlock
.get());
148 #if !ENABLE(OPCODE_SAMPLING)
149 if (!BytecodeGenerator::dumpsGeneratedCode())
150 m_evalCodeBlock
->discardBytecode();
156 #if ENABLE(INTERPRETER)
157 if (!m_jitCodeForCall
)
158 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock
));
161 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock
) + m_jitCodeForCall
.size());
163 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock
));
169 void EvalExecutable::visitChildren(SlotVisitor
& visitor
)
171 ASSERT_GC_OBJECT_INHERITS(this, &s_info
);
172 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
173 ASSERT(structure()->typeInfo().overridesVisitChildren());
174 ScriptExecutable::visitChildren(visitor
);
176 m_evalCodeBlock
->visitAggregate(visitor
);
179 void EvalExecutable::unlinkCalls()
182 if (!m_jitCodeForCall
)
184 ASSERT(m_evalCodeBlock
);
185 m_evalCodeBlock
->unlinkCalls();
189 JSObject
* ProgramExecutable::checkSyntax(ExecState
* exec
)
191 JSObject
* exception
= 0;
192 JSGlobalData
* globalData
= &exec
->globalData();
193 JSGlobalObject
* lexicalGlobalObject
= exec
->lexicalGlobalObject();
194 RefPtr
<ProgramNode
> programNode
= globalData
->parser
->parse
<ProgramNode
>(lexicalGlobalObject
, lexicalGlobalObject
->debugger(), exec
, m_source
, 0, JSParseNormal
, &exception
);
201 JSObject
* ProgramExecutable::compileInternal(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
203 ASSERT(!m_programCodeBlock
);
205 JSObject
* exception
= 0;
206 JSGlobalData
* globalData
= &exec
->globalData();
207 JSGlobalObject
* lexicalGlobalObject
= exec
->lexicalGlobalObject();
208 RefPtr
<ProgramNode
> programNode
= globalData
->parser
->parse
<ProgramNode
>(lexicalGlobalObject
, lexicalGlobalObject
->debugger(), exec
, m_source
, 0, isStrictMode() ? JSParseStrict
: JSParseNormal
, &exception
);
213 recordParse(programNode
->features(), programNode
->hasCapturedVariables(), programNode
->lineNo(), programNode
->lastLine());
215 JSGlobalObject
* globalObject
= scopeChainNode
->globalObject
.get();
217 m_programCodeBlock
= adoptPtr(new ProgramCodeBlock(this, GlobalCode
, globalObject
, source().provider()));
218 OwnPtr
<BytecodeGenerator
> generator(adoptPtr(new BytecodeGenerator(programNode
.get(), scopeChainNode
, &globalObject
->symbolTable(), m_programCodeBlock
.get())));
219 if ((exception
= generator
->generate())) {
220 m_programCodeBlock
.clear();
221 programNode
->destroyData();
225 programNode
->destroyData();
228 if (exec
->globalData().canUseJIT()) {
229 m_jitCodeForCall
= JIT::compile(scopeChainNode
->globalData
, m_programCodeBlock
.get());
230 #if !ENABLE(OPCODE_SAMPLING)
231 if (!BytecodeGenerator::dumpsGeneratedCode())
232 m_programCodeBlock
->discardBytecode();
238 #if ENABLE(INTERPRETER)
239 if (!m_jitCodeForCall
)
240 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock
));
243 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock
) + m_jitCodeForCall
.size());
245 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock
));
251 void ProgramExecutable::unlinkCalls()
254 if (!m_jitCodeForCall
)
256 ASSERT(m_programCodeBlock
);
257 m_programCodeBlock
->unlinkCalls();
262 static bool tryDFGCompile(JSGlobalData
* globalData
, CodeBlock
* codeBlock
, JITCode
& jitCode
, MacroAssemblerCodePtr
& jitCodeWithArityCheck
)
265 #if ENABLE(DFG_JIT_RESTRICTIONS)
266 // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
267 // FIXME: temporarily disable property accesses until we fix regressions.
268 if (codeBlock
->numberOfJumpTargets() || codeBlock
->numberOfStructureStubInfos())
272 DFG::Graph
dfg(codeBlock
->m_numParameters
, codeBlock
->m_numVars
);
273 if (!parse(dfg
, globalData
, codeBlock
))
276 DFG::JITCompiler
dataFlowJIT(globalData
, dfg
, codeBlock
);
277 dataFlowJIT
.compileFunction(jitCode
, jitCodeWithArityCheck
);
280 UNUSED_PARAM(globalData
);
281 UNUSED_PARAM(codeBlock
);
282 UNUSED_PARAM(jitCode
);
283 UNUSED_PARAM(jitCodeWithArityCheck
);
289 void ProgramExecutable::visitChildren(SlotVisitor
& visitor
)
291 ASSERT_GC_OBJECT_INHERITS(this, &s_info
);
292 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
293 ASSERT(structure()->typeInfo().overridesVisitChildren());
294 ScriptExecutable::visitChildren(visitor
);
295 if (m_programCodeBlock
)
296 m_programCodeBlock
->visitAggregate(visitor
);
299 JSObject
* FunctionExecutable::compileForCallInternal(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
301 JSObject
* exception
= 0;
302 JSGlobalData
* globalData
= scopeChainNode
->globalData
;
303 RefPtr
<FunctionBodyNode
> body
= globalData
->parser
->parse
<FunctionBodyNode
>(exec
->lexicalGlobalObject(), 0, 0, m_source
, m_parameters
.get(), isStrictMode() ? JSParseStrict
: JSParseNormal
, &exception
);
308 if (m_forceUsesArguments
)
309 body
->setUsesArguments();
310 body
->finishParsing(m_parameters
, m_name
);
311 recordParse(body
->features(), body
->hasCapturedVariables(), body
->lineNo(), body
->lastLine());
313 JSGlobalObject
* globalObject
= scopeChainNode
->globalObject
.get();
315 ASSERT(!m_codeBlockForCall
);
316 m_codeBlockForCall
= adoptPtr(new FunctionCodeBlock(this, FunctionCode
, globalObject
, source().provider(), source().startOffset(), false));
317 OwnPtr
<BytecodeGenerator
> generator(adoptPtr(new BytecodeGenerator(body
.get(), scopeChainNode
, m_codeBlockForCall
->symbolTable(), m_codeBlockForCall
.get())));
318 if ((exception
= generator
->generate())) {
319 m_codeBlockForCall
.clear();
324 m_numParametersForCall
= m_codeBlockForCall
->m_numParameters
;
325 ASSERT(m_numParametersForCall
);
326 m_numCapturedVariables
= m_codeBlockForCall
->m_numCapturedVars
;
327 m_symbolTable
= m_codeBlockForCall
->sharedSymbolTable();
332 if (exec
->globalData().canUseJIT()) {
333 bool dfgCompiled
= tryDFGCompile(&exec
->globalData(), m_codeBlockForCall
.get(), m_jitCodeForCall
, m_jitCodeForCallWithArityCheck
);
335 m_jitCodeForCall
= JIT::compile(scopeChainNode
->globalData
, m_codeBlockForCall
.get(), &m_jitCodeForCallWithArityCheck
);
337 #if !ENABLE(OPCODE_SAMPLING)
338 if (!BytecodeGenerator::dumpsGeneratedCode())
339 m_codeBlockForCall
->discardBytecode();
345 #if ENABLE(INTERPRETER)
346 if (!m_jitCodeForCall
)
347 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall
));
350 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall
) + m_jitCodeForCall
.size());
352 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall
));
358 JSObject
* FunctionExecutable::compileForConstructInternal(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
360 JSObject
* exception
= 0;
361 JSGlobalData
* globalData
= scopeChainNode
->globalData
;
362 RefPtr
<FunctionBodyNode
> body
= globalData
->parser
->parse
<FunctionBodyNode
>(exec
->lexicalGlobalObject(), 0, 0, m_source
, m_parameters
.get(), isStrictMode() ? JSParseStrict
: JSParseNormal
, &exception
);
367 if (m_forceUsesArguments
)
368 body
->setUsesArguments();
369 body
->finishParsing(m_parameters
, m_name
);
370 recordParse(body
->features(), body
->hasCapturedVariables(), body
->lineNo(), body
->lastLine());
372 JSGlobalObject
* globalObject
= scopeChainNode
->globalObject
.get();
374 ASSERT(!m_codeBlockForConstruct
);
375 m_codeBlockForConstruct
= adoptPtr(new FunctionCodeBlock(this, FunctionCode
, globalObject
, source().provider(), source().startOffset(), true));
376 OwnPtr
<BytecodeGenerator
> generator(adoptPtr(new BytecodeGenerator(body
.get(), scopeChainNode
, m_codeBlockForConstruct
->symbolTable(), m_codeBlockForConstruct
.get())));
377 if ((exception
= generator
->generate())) {
378 m_codeBlockForConstruct
.clear();
383 m_numParametersForConstruct
= m_codeBlockForConstruct
->m_numParameters
;
384 ASSERT(m_numParametersForConstruct
);
385 m_numCapturedVariables
= m_codeBlockForConstruct
->m_numCapturedVars
;
386 m_symbolTable
= m_codeBlockForConstruct
->sharedSymbolTable();
391 if (exec
->globalData().canUseJIT()) {
392 m_jitCodeForConstruct
= JIT::compile(scopeChainNode
->globalData
, m_codeBlockForConstruct
.get(), &m_jitCodeForConstructWithArityCheck
);
393 #if !ENABLE(OPCODE_SAMPLING)
394 if (!BytecodeGenerator::dumpsGeneratedCode())
395 m_codeBlockForConstruct
->discardBytecode();
401 #if ENABLE(INTERPRETER)
402 if (!m_jitCodeForConstruct
)
403 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct
));
406 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct
) + m_jitCodeForConstruct
.size());
408 Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct
));
414 void FunctionExecutable::visitChildren(SlotVisitor
& visitor
)
416 ASSERT_GC_OBJECT_INHERITS(this, &s_info
);
417 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
418 ASSERT(structure()->typeInfo().overridesVisitChildren());
419 ScriptExecutable::visitChildren(visitor
);
420 if (m_codeBlockForCall
)
421 m_codeBlockForCall
->visitAggregate(visitor
);
422 if (m_codeBlockForConstruct
)
423 m_codeBlockForConstruct
->visitAggregate(visitor
);
426 void FunctionExecutable::discardCode()
429 // These first two checks are to handle the rare case where
430 // we are trying to evict code for a function during its
432 if (!m_jitCodeForCall
&& m_codeBlockForCall
)
434 if (!m_jitCodeForConstruct
&& m_codeBlockForConstruct
)
436 m_jitCodeForCall
= JITCode();
437 m_jitCodeForConstruct
= JITCode();
438 m_jitCodeForCallWithArityCheck
= MacroAssemblerCodePtr();
439 m_jitCodeForConstructWithArityCheck
= MacroAssemblerCodePtr();
441 if (m_codeBlockForCall
)
442 m_codeBlockForCall
->clearEvalCache();
443 m_codeBlockForCall
.clear();
444 if (m_codeBlockForConstruct
)
445 m_codeBlockForConstruct
->clearEvalCache();
446 m_codeBlockForConstruct
.clear();
447 m_numParametersForCall
= NUM_PARAMETERS_NOT_COMPILED
;
448 m_numParametersForConstruct
= NUM_PARAMETERS_NOT_COMPILED
;
452 void FunctionExecutable::unlinkCalls()
455 if (!!m_jitCodeForCall
) {
456 ASSERT(m_codeBlockForCall
);
457 m_codeBlockForCall
->unlinkCalls();
459 if (!!m_jitCodeForConstruct
) {
460 ASSERT(m_codeBlockForConstruct
);
461 m_codeBlockForConstruct
->unlinkCalls();
466 FunctionExecutable
* FunctionExecutable::fromGlobalCode(const Identifier
& functionName
, ExecState
* exec
, Debugger
* debugger
, const SourceCode
& source
, JSObject
** exception
)
468 JSGlobalObject
* lexicalGlobalObject
= exec
->lexicalGlobalObject();
469 RefPtr
<ProgramNode
> program
= exec
->globalData().parser
->parse
<ProgramNode
>(lexicalGlobalObject
, debugger
, exec
, source
, 0, JSParseNormal
, exception
);
475 // Uses of this function that would not result in a single function expression are invalid.
476 StatementNode
* exprStatement
= program
->singleStatement();
477 ASSERT(exprStatement
);
478 ASSERT(exprStatement
->isExprStatement());
479 ExpressionNode
* funcExpr
= static_cast<ExprStatementNode
*>(exprStatement
)->expr();
481 ASSERT(funcExpr
->isFuncExprNode());
482 FunctionBodyNode
* body
= static_cast<FuncExprNode
*>(funcExpr
)->body();
485 return FunctionExecutable::create(&exec
->globalData(), functionName
, body
->source(), body
->usesArguments(), body
->parameters(), body
->isStrictMode(), body
->lineNo(), body
->lastLine());
488 UString
FunctionExecutable::paramString() const
490 FunctionParameters
& parameters
= *m_parameters
;
491 UStringBuilder builder
;
492 for (size_t pos
= 0; pos
< parameters
.size(); ++pos
) {
493 if (!builder
.isEmpty())
494 builder
.append(", ");
495 builder
.append(parameters
[pos
].ustring());
497 return builder
.toUString();