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 "StringBuilder.h"
|
---|
34 | #include "Vector.h"
|
---|
35 |
|
---|
36 | namespace JSC {
|
---|
37 |
|
---|
38 | #if ENABLE(JIT)
|
---|
39 | NativeExecutable::~NativeExecutable()
|
---|
40 | {
|
---|
41 | }
|
---|
42 | #endif
|
---|
43 |
|
---|
44 | VPtrHackExecutable::~VPtrHackExecutable()
|
---|
45 | {
|
---|
46 | }
|
---|
47 |
|
---|
48 | EvalExecutable::~EvalExecutable()
|
---|
49 | {
|
---|
50 | delete m_evalCodeBlock;
|
---|
51 | }
|
---|
52 |
|
---|
53 | ProgramExecutable::~ProgramExecutable()
|
---|
54 | {
|
---|
55 | delete m_programCodeBlock;
|
---|
56 | }
|
---|
57 |
|
---|
58 | FunctionExecutable::~FunctionExecutable()
|
---|
59 | {
|
---|
60 | delete m_codeBlockForCall;
|
---|
61 | delete m_codeBlockForConstruct;
|
---|
62 | }
|
---|
63 |
|
---|
64 | JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode)
|
---|
65 | {
|
---|
66 | int errLine;
|
---|
67 | UString errMsg;
|
---|
68 | JSGlobalData* globalData = &exec->globalData();
|
---|
69 | JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
|
---|
70 | RefPtr<EvalNode> evalNode = globalData->parser->parse<EvalNode>(globalData, lexicalGlobalObject->debugger(), exec, m_source, &errLine, &errMsg);
|
---|
71 | if (!evalNode)
|
---|
72 | return addErrorInfo(globalData, createSyntaxError(lexicalGlobalObject, errMsg), errLine, m_source);
|
---|
73 | recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine());
|
---|
74 |
|
---|
75 | ScopeChain scopeChain(scopeChainNode);
|
---|
76 | JSGlobalObject* globalObject = scopeChain.globalObject();
|
---|
77 |
|
---|
78 | ASSERT(!m_evalCodeBlock);
|
---|
79 | m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth());
|
---|
80 | OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock)));
|
---|
81 | generator->generate();
|
---|
82 |
|
---|
83 | evalNode->destroyData();
|
---|
84 | return 0;
|
---|
85 | }
|
---|
86 |
|
---|
87 | JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
|
---|
88 | {
|
---|
89 | int errLine;
|
---|
90 | UString errMsg;
|
---|
91 | JSGlobalData* globalData = &exec->globalData();
|
---|
92 | JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
|
---|
93 | RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(globalData, lexicalGlobalObject->debugger(), exec, m_source, &errLine, &errMsg);
|
---|
94 | if (!programNode)
|
---|
95 | return addErrorInfo(globalData, createSyntaxError(lexicalGlobalObject, errMsg), errLine, m_source);
|
---|
96 | return 0;
|
---|
97 | }
|
---|
98 |
|
---|
99 | JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode)
|
---|
100 | {
|
---|
101 | int errLine;
|
---|
102 | UString errMsg;
|
---|
103 | JSGlobalData* globalData = &exec->globalData();
|
---|
104 | JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
|
---|
105 | RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(globalData, lexicalGlobalObject->debugger(), exec, m_source, &errLine, &errMsg);
|
---|
106 | if (!programNode)
|
---|
107 | return addErrorInfo(globalData, createSyntaxError(lexicalGlobalObject, errMsg), errLine, m_source);
|
---|
108 | recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine());
|
---|
109 |
|
---|
110 | ScopeChain scopeChain(scopeChainNode);
|
---|
111 | JSGlobalObject* globalObject = scopeChain.globalObject();
|
---|
112 |
|
---|
113 | ASSERT(!m_programCodeBlock);
|
---|
114 | m_programCodeBlock = new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider());
|
---|
115 | OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock)));
|
---|
116 | generator->generate();
|
---|
117 |
|
---|
118 | programNode->destroyData();
|
---|
119 | return 0;
|
---|
120 | }
|
---|
121 |
|
---|
122 | bool FunctionExecutable::compileForCall(ExecState*, ScopeChainNode* scopeChainNode)
|
---|
123 | {
|
---|
124 | JSGlobalData* globalData = scopeChainNode->globalData;
|
---|
125 | RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source);
|
---|
126 | if (!body)
|
---|
127 | return false;
|
---|
128 | if (m_forceUsesArguments)
|
---|
129 | body->setUsesArguments();
|
---|
130 | body->finishParsing(m_parameters, m_name);
|
---|
131 | recordParse(body->features(), body->lineNo(), body->lastLine());
|
---|
132 |
|
---|
133 | ScopeChain scopeChain(scopeChainNode);
|
---|
134 | JSGlobalObject* globalObject = scopeChain.globalObject();
|
---|
135 |
|
---|
136 | ASSERT(!m_codeBlockForCall);
|
---|
137 | m_codeBlockForCall = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), false);
|
---|
138 | OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall)));
|
---|
139 | generator->generate();
|
---|
140 | m_numParametersForCall = m_codeBlockForCall->m_numParameters;
|
---|
141 | ASSERT(m_numParametersForCall);
|
---|
142 | m_numVariables = m_codeBlockForCall->m_numVars;
|
---|
143 | m_symbolTable = m_codeBlockForCall->sharedSymbolTable();
|
---|
144 |
|
---|
145 | body->destroyData();
|
---|
146 | return true;
|
---|
147 | }
|
---|
148 |
|
---|
149 | bool FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeChainNode)
|
---|
150 | {
|
---|
151 | JSGlobalData* globalData = scopeChainNode->globalData;
|
---|
152 | RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source);
|
---|
153 | if (!body)
|
---|
154 | return false;
|
---|
155 | if (m_forceUsesArguments)
|
---|
156 | body->setUsesArguments();
|
---|
157 | body->finishParsing(m_parameters, m_name);
|
---|
158 | recordParse(body->features(), body->lineNo(), body->lastLine());
|
---|
159 |
|
---|
160 | ScopeChain scopeChain(scopeChainNode);
|
---|
161 | JSGlobalObject* globalObject = scopeChain.globalObject();
|
---|
162 |
|
---|
163 | ASSERT(!m_codeBlockForConstruct);
|
---|
164 | m_codeBlockForConstruct = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), true);
|
---|
165 | OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct)));
|
---|
166 | generator->generate();
|
---|
167 | m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters;
|
---|
168 | ASSERT(m_numParametersForConstruct);
|
---|
169 | m_numVariables = m_codeBlockForConstruct->m_numVars;
|
---|
170 | m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable();
|
---|
171 |
|
---|
172 | body->destroyData();
|
---|
173 | return true;
|
---|
174 | }
|
---|
175 |
|
---|
176 | #if ENABLE(JIT)
|
---|
177 |
|
---|
178 | void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode)
|
---|
179 | {
|
---|
180 | #if ENABLE(INTERPRETER)
|
---|
181 | ASSERT(exec->globalData().canUseJIT());
|
---|
182 | #endif
|
---|
183 | CodeBlock* codeBlock = &bytecode(exec, scopeChainNode);
|
---|
184 | m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock);
|
---|
185 |
|
---|
186 | #if !ENABLE(OPCODE_SAMPLING)
|
---|
187 | if (!BytecodeGenerator::dumpsGeneratedCode())
|
---|
188 | codeBlock->discardBytecode();
|
---|
189 | #endif
|
---|
190 | }
|
---|
191 |
|
---|
192 | void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode)
|
---|
193 | {
|
---|
194 | #if ENABLE(INTERPRETER)
|
---|
195 | ASSERT(exec->globalData().canUseJIT());
|
---|
196 | #endif
|
---|
197 | CodeBlock* codeBlock = &bytecode(exec, scopeChainNode);
|
---|
198 | m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock);
|
---|
199 |
|
---|
200 | #if !ENABLE(OPCODE_SAMPLING)
|
---|
201 | if (!BytecodeGenerator::dumpsGeneratedCode())
|
---|
202 | codeBlock->discardBytecode();
|
---|
203 | #endif
|
---|
204 | }
|
---|
205 |
|
---|
206 | void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
|
---|
207 | {
|
---|
208 | #if ENABLE(INTERPRETER)
|
---|
209 | ASSERT(exec->globalData().canUseJIT());
|
---|
210 | #endif
|
---|
211 | CodeBlock* codeBlock = bytecodeForCall(exec, scopeChainNode);
|
---|
212 | m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForCallWithArityCheck);
|
---|
213 |
|
---|
214 | #if !ENABLE(OPCODE_SAMPLING)
|
---|
215 | if (!BytecodeGenerator::dumpsGeneratedCode())
|
---|
216 | codeBlock->discardBytecode();
|
---|
217 | #endif
|
---|
218 | }
|
---|
219 |
|
---|
220 | void FunctionExecutable::generateJITCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
|
---|
221 | {
|
---|
222 | #if ENABLE(INTERPRETER)
|
---|
223 | ASSERT(exec->globalData().canUseJIT());
|
---|
224 | #endif
|
---|
225 | CodeBlock* codeBlock = bytecodeForConstruct(exec, scopeChainNode);
|
---|
226 | m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForConstructWithArityCheck);
|
---|
227 |
|
---|
228 | #if !ENABLE(OPCODE_SAMPLING)
|
---|
229 | if (!BytecodeGenerator::dumpsGeneratedCode())
|
---|
230 | codeBlock->discardBytecode();
|
---|
231 | #endif
|
---|
232 | }
|
---|
233 |
|
---|
234 | #endif
|
---|
235 |
|
---|
236 | void FunctionExecutable::markAggregate(MarkStack& markStack)
|
---|
237 | {
|
---|
238 | if (m_codeBlockForCall)
|
---|
239 | m_codeBlockForCall->markAggregate(markStack);
|
---|
240 | if (m_codeBlockForConstruct)
|
---|
241 | m_codeBlockForConstruct->markAggregate(markStack);
|
---|
242 | }
|
---|
243 |
|
---|
244 | PassOwnPtr<ExceptionInfo> FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
|
---|
245 | {
|
---|
246 | RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source);
|
---|
247 | if (!newFunctionBody)
|
---|
248 | return PassOwnPtr<ExceptionInfo>();
|
---|
249 | if (m_forceUsesArguments)
|
---|
250 | newFunctionBody->setUsesArguments();
|
---|
251 | newFunctionBody->finishParsing(m_parameters, m_name);
|
---|
252 |
|
---|
253 | ScopeChain scopeChain(scopeChainNode);
|
---|
254 | JSGlobalObject* globalObject = scopeChain.globalObject();
|
---|
255 |
|
---|
256 | OwnPtr<CodeBlock> newCodeBlock(adoptPtr(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), codeBlock->m_isConstructor)));
|
---|
257 | globalData->functionCodeBlockBeingReparsed = newCodeBlock.get();
|
---|
258 |
|
---|
259 | OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())));
|
---|
260 | generator->setRegeneratingForExceptionInfo(static_cast<FunctionCodeBlock*>(codeBlock));
|
---|
261 | generator->generate();
|
---|
262 |
|
---|
263 | ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount());
|
---|
264 |
|
---|
265 | #if ENABLE(JIT)
|
---|
266 | #if ENABLE(INTERPRETER)
|
---|
267 | if (globalData->canUseJIT())
|
---|
268 | #endif
|
---|
269 | {
|
---|
270 | JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get());
|
---|
271 | ASSERT(codeBlock->m_isConstructor ? newJITCode.size() == generatedJITCodeForConstruct().size() : newJITCode.size() == generatedJITCodeForCall().size());
|
---|
272 | }
|
---|
273 | #endif
|
---|
274 |
|
---|
275 | globalData->functionCodeBlockBeingReparsed = 0;
|
---|
276 |
|
---|
277 | return newCodeBlock->extractExceptionInfo();
|
---|
278 | }
|
---|
279 |
|
---|
280 | PassOwnPtr<ExceptionInfo> EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock)
|
---|
281 | {
|
---|
282 | RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(globalData, 0, 0, m_source);
|
---|
283 | if (!newEvalBody)
|
---|
284 | return PassOwnPtr<ExceptionInfo>();
|
---|
285 |
|
---|
286 | ScopeChain scopeChain(scopeChainNode);
|
---|
287 | JSGlobalObject* globalObject = scopeChain.globalObject();
|
---|
288 |
|
---|
289 | OwnPtr<EvalCodeBlock> newCodeBlock(adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())));
|
---|
290 |
|
---|
291 | OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())));
|
---|
292 | generator->setRegeneratingForExceptionInfo(static_cast<EvalCodeBlock*>(codeBlock));
|
---|
293 | generator->generate();
|
---|
294 |
|
---|
295 | ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount());
|
---|
296 |
|
---|
297 | #if ENABLE(JIT)
|
---|
298 | #if ENABLE(INTERPRETER)
|
---|
299 | if (globalData->canUseJIT())
|
---|
300 | #endif
|
---|
301 | {
|
---|
302 | JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get());
|
---|
303 | ASSERT(newJITCode.size() == generatedJITCodeForCall().size());
|
---|
304 | }
|
---|
305 | #endif
|
---|
306 |
|
---|
307 | return newCodeBlock->extractExceptionInfo();
|
---|
308 | }
|
---|
309 |
|
---|
310 | void FunctionExecutable::recompile(ExecState*)
|
---|
311 | {
|
---|
312 | delete m_codeBlockForCall;
|
---|
313 | m_codeBlockForCall = 0;
|
---|
314 | delete m_codeBlockForConstruct;
|
---|
315 | m_codeBlockForConstruct = 0;
|
---|
316 | m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
|
---|
317 | m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
|
---|
318 | #if ENABLE(JIT)
|
---|
319 | m_jitCodeForCall = JITCode();
|
---|
320 | m_jitCodeForConstruct = JITCode();
|
---|
321 | #endif
|
---|
322 | }
|
---|
323 |
|
---|
324 | PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg)
|
---|
325 | {
|
---|
326 | RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), debugger, exec, source, errLine, errMsg);
|
---|
327 | if (!program)
|
---|
328 | return 0;
|
---|
329 |
|
---|
330 | StatementNode* exprStatement = program->singleStatement();
|
---|
331 | ASSERT(exprStatement);
|
---|
332 | ASSERT(exprStatement->isExprStatement());
|
---|
333 | if (!exprStatement || !exprStatement->isExprStatement())
|
---|
334 | return 0;
|
---|
335 |
|
---|
336 | ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
|
---|
337 | ASSERT(funcExpr);
|
---|
338 | ASSERT(funcExpr->isFuncExprNode());
|
---|
339 | if (!funcExpr || !funcExpr->isFuncExprNode())
|
---|
340 | return 0;
|
---|
341 |
|
---|
342 | FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
|
---|
343 | ASSERT(body);
|
---|
344 | return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
|
---|
345 | }
|
---|
346 |
|
---|
347 | UString FunctionExecutable::paramString() const
|
---|
348 | {
|
---|
349 | FunctionParameters& parameters = *m_parameters;
|
---|
350 | StringBuilder builder;
|
---|
351 | for (size_t pos = 0; pos < parameters.size(); ++pos) {
|
---|
352 | if (!builder.isEmpty())
|
---|
353 | builder.append(", ");
|
---|
354 | builder.append(parameters[pos].ustring());
|
---|
355 | }
|
---|
356 | return builder.build();
|
---|
357 | }
|
---|
358 |
|
---|
359 | PassOwnPtr<ExceptionInfo> ProgramExecutable::reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*)
|
---|
360 | {
|
---|
361 | // CodeBlocks for program code are transient and therefore do not gain from from throwing out their exception information.
|
---|
362 | return PassOwnPtr<ExceptionInfo>();
|
---|
363 | }
|
---|
364 |
|
---|
365 | }
|
---|