1/*
2 * Copyright (C) 2009, 2010 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 "BytecodeGenerator.h"
30#include "CodeBlock.h"
31#include "JIT.h"
32#include "Parser.h"
33#include "UStringBuilder.h"
34#include "Vector.h"
35
36#if ENABLE(DFG_JIT)
37#include "DFGByteCodeParser.h"
38#include "DFGJITCompiler.h"
39#endif
40
41namespace JSC {
42
43const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 };
44
45const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 };
46
47NativeExecutable::~NativeExecutable()
48{
49}
50
51const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 };
52
53EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
54    : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext)
55{
56}
57
58EvalExecutable::~EvalExecutable()
59{
60}
61
62const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 };
63
64ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
65    : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false)
66{
67}
68
69ProgramExecutable::~ProgramExecutable()
70{
71}
72
73const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 };
74
75FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
76    : ScriptExecutable(globalData->functionExecutableStructure.get(), globalData, source, inStrictContext)
77    , m_numCapturedVariables(0)
78    , m_forceUsesArguments(forceUsesArguments)
79    , m_parameters(parameters)
80    , m_name(name)
81    , m_symbolTable(0)
82{
83    m_firstLine = firstLine;
84    m_lastLine = lastLine;
85}
86
87FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
88    : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext)
89    , m_numCapturedVariables(0)
90    , m_forceUsesArguments(forceUsesArguments)
91    , m_parameters(parameters)
92    , m_name(name)
93    , m_symbolTable(0)
94{
95    m_firstLine = firstLine;
96    m_lastLine = lastLine;
97}
98
99
100JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
101{
102    JSObject* exception = 0;
103    JSGlobalData* globalData = &exec->globalData();
104    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
105    RefPtr<EvalNode> evalNode = globalData->parser->parse<EvalNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
106    if (!evalNode) {
107        ASSERT(exception);
108        return exception;
109    }
110    recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
111
112    JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
113
114    ASSERT(!m_evalCodeBlock);
115    m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth()));
116    OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get())));
117    if ((exception = generator->generate())) {
118        m_evalCodeBlock.clear();
119        evalNode->destroyData();
120        return exception;
121    }
122
123    evalNode->destroyData();
124
125#if ENABLE(JIT)
126    if (exec->globalData().canUseJIT()) {
127        m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get());
128#if !ENABLE(OPCODE_SAMPLING)
129        if (!BytecodeGenerator::dumpsGeneratedCode())
130            m_evalCodeBlock->discardBytecode();
131#endif
132    }
133#endif
134
135    return 0;
136}
137
138void EvalExecutable::markChildren(MarkStack& markStack)
139{
140    ScriptExecutable::markChildren(markStack);
141    if (m_evalCodeBlock)
142        m_evalCodeBlock->markAggregate(markStack);
143}
144
145JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
146{
147    JSObject* exception = 0;
148    JSGlobalData* globalData = &exec->globalData();
149    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
150    RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, JSParseNormal, &exception);
151    if (programNode)
152        return 0;
153    ASSERT(exception);
154    return exception;
155}
156
157JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
158{
159    ASSERT(!m_programCodeBlock);
160
161    JSObject* exception = 0;
162    JSGlobalData* globalData = &exec->globalData();
163    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
164    RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
165    if (!programNode) {
166        ASSERT(exception);
167        return exception;
168    }
169    recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
170
171    JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
172
173    m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()));
174    OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get())));
175    if ((exception = generator->generate())) {
176        m_programCodeBlock.clear();
177        programNode->destroyData();
178        return exception;
179    }
180
181    programNode->destroyData();
182
183#if ENABLE(JIT)
184    if (exec->globalData().canUseJIT()) {
185        m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
186#if !ENABLE(OPCODE_SAMPLING)
187        if (!BytecodeGenerator::dumpsGeneratedCode())
188            m_programCodeBlock->discardBytecode();
189#endif
190    }
191#endif
192
193   return 0;
194}
195
196#if ENABLE(JIT)
197static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
198{
199#if ENABLE(DFG_JIT)
200#if ENABLE(DFG_JIT_RESTRICTIONS)
201    // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
202    // FIXME: temporarily disable property accesses until we fix regressions.
203    if (codeBlock->numberOfJumpTargets() || codeBlock->numberOfStructureStubInfos())
204        return false;
205#endif
206
207    DFG::Graph dfg;
208    if (!parse(dfg, globalData, codeBlock))
209        return false;
210
211    DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
212    dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
213    return true;
214#else
215    UNUSED_PARAM(globalData);
216    UNUSED_PARAM(codeBlock);
217    UNUSED_PARAM(jitCode);
218    UNUSED_PARAM(jitCodeWithArityCheck);
219    return false;
220#endif
221}
222#endif
223
224void ProgramExecutable::markChildren(MarkStack& markStack)
225{
226    ScriptExecutable::markChildren(markStack);
227    if (m_programCodeBlock)
228        m_programCodeBlock->markAggregate(markStack);
229}
230
231JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
232{
233    JSObject* exception = 0;
234    JSGlobalData* globalData = scopeChainNode->globalData;
235    RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
236    if (!body) {
237        ASSERT(exception);
238        return exception;
239    }
240    if (m_forceUsesArguments)
241        body->setUsesArguments();
242    body->finishParsing(m_parameters, m_name);
243    recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
244
245    JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
246
247    ASSERT(!m_codeBlockForCall);
248    m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false));
249    OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get())));
250    if ((exception = generator->generate())) {
251        m_codeBlockForCall.clear();
252        body->destroyData();
253        return exception;
254    }
255
256    m_numParametersForCall = m_codeBlockForCall->m_numParameters;
257    ASSERT(m_numParametersForCall);
258    m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars;
259    m_symbolTable = m_codeBlockForCall->sharedSymbolTable();
260
261    body->destroyData();
262
263#if ENABLE(JIT)
264    if (exec->globalData().canUseJIT()) {
265        bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
266        if (!dfgCompiled)
267            m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck);
268
269#if !ENABLE(OPCODE_SAMPLING)
270        if (!BytecodeGenerator::dumpsGeneratedCode())
271            m_codeBlockForCall->discardBytecode();
272#endif
273    }
274#endif
275
276    return 0;
277}
278
279JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
280{
281    JSObject* exception = 0;
282    JSGlobalData* globalData = scopeChainNode->globalData;
283    RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
284    if (!body) {
285        ASSERT(exception);
286        return exception;
287    }
288    if (m_forceUsesArguments)
289        body->setUsesArguments();
290    body->finishParsing(m_parameters, m_name);
291    recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
292
293    JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
294
295    ASSERT(!m_codeBlockForConstruct);
296    m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true));
297    OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get())));
298    if ((exception = generator->generate())) {
299        m_codeBlockForConstruct.clear();
300        body->destroyData();
301        return exception;
302    }
303
304    m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters;
305    ASSERT(m_numParametersForConstruct);
306    m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars;
307    m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable();
308
309    body->destroyData();
310
311#if ENABLE(JIT)
312    if (exec->globalData().canUseJIT()) {
313        m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck);
314#if !ENABLE(OPCODE_SAMPLING)
315        if (!BytecodeGenerator::dumpsGeneratedCode())
316            m_codeBlockForConstruct->discardBytecode();
317#endif
318    }
319#endif
320
321    return 0;
322}
323
324void FunctionExecutable::markChildren(MarkStack& markStack)
325{
326    ScriptExecutable::markChildren(markStack);
327    if (m_codeBlockForCall)
328        m_codeBlockForCall->markAggregate(markStack);
329    if (m_codeBlockForConstruct)
330        m_codeBlockForConstruct->markAggregate(markStack);
331}
332
333void FunctionExecutable::discardCode()
334{
335    m_codeBlockForCall.clear();
336    m_codeBlockForConstruct.clear();
337    m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
338    m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
339#if ENABLE(JIT)
340    m_jitCodeForCall = JITCode();
341    m_jitCodeForConstruct = JITCode();
342#endif
343}
344
345FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
346{
347    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
348    RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception);
349    if (!program) {
350        ASSERT(*exception);
351        return 0;
352    }
353
354    // Uses of this function that would not result in a single function expression are invalid.
355    StatementNode* exprStatement = program->singleStatement();
356    ASSERT(exprStatement);
357    ASSERT(exprStatement->isExprStatement());
358    ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
359    ASSERT(funcExpr);
360    ASSERT(funcExpr->isFuncExprNode());
361    FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
362    ASSERT(body);
363
364    return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
365}
366
367UString FunctionExecutable::paramString() const
368{
369    FunctionParameters& parameters = *m_parameters;
370    UStringBuilder builder;
371    for (size_t pos = 0; pos < parameters.size(); ++pos) {
372        if (!builder.isEmpty())
373            builder.append(", ");
374        builder.append(parameters[pos].ustring());
375    }
376    return builder.toUString();
377}
378
379}
380