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
41 namespace JSC {
42
43 const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 };
44
45 const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 };
46
~NativeExecutable()47 NativeExecutable::~NativeExecutable()
48 {
49 }
50
51 const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 };
52
EvalExecutable(ExecState * exec,const SourceCode & source,bool inStrictContext)53 EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
54 : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext)
55 {
56 }
57
~EvalExecutable()58 EvalExecutable::~EvalExecutable()
59 {
60 }
61
62 const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 };
63
ProgramExecutable(ExecState * exec,const SourceCode & source)64 ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
65 : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false)
66 {
67 }
68
~ProgramExecutable()69 ProgramExecutable::~ProgramExecutable()
70 {
71 }
72
73 const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 };
74
FunctionExecutable(JSGlobalData * globalData,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool inStrictContext,int firstLine,int lastLine)75 FunctionExecutable::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
FunctionExecutable(ExecState * exec,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool inStrictContext,int firstLine,int lastLine)87 FunctionExecutable::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
compileInternal(ExecState * exec,ScopeChainNode * scopeChainNode)100 JSObject* 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
markChildren(MarkStack & markStack)138 void EvalExecutable::markChildren(MarkStack& markStack)
139 {
140 ScriptExecutable::markChildren(markStack);
141 if (m_evalCodeBlock)
142 m_evalCodeBlock->markAggregate(markStack);
143 }
144
checkSyntax(ExecState * exec)145 JSObject* 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
compileInternal(ExecState * exec,ScopeChainNode * scopeChainNode)157 JSObject* 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)
tryDFGCompile(JSGlobalData * globalData,CodeBlock * codeBlock,JITCode & jitCode,MacroAssemblerCodePtr & jitCodeWithArityCheck)197 static 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
markChildren(MarkStack & markStack)224 void ProgramExecutable::markChildren(MarkStack& markStack)
225 {
226 ScriptExecutable::markChildren(markStack);
227 if (m_programCodeBlock)
228 m_programCodeBlock->markAggregate(markStack);
229 }
230
compileForCallInternal(ExecState * exec,ScopeChainNode * scopeChainNode)231 JSObject* 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
compileForConstructInternal(ExecState * exec,ScopeChainNode * scopeChainNode)279 JSObject* 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
markChildren(MarkStack & markStack)324 void 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
discardCode()333 void 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
fromGlobalCode(const Identifier & functionName,ExecState * exec,Debugger * debugger,const SourceCode & source,JSObject ** exception)345 FunctionExecutable* 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
paramString() const367 UString 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