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