]>
Commit | Line | Data |
---|---|---|
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 | #if ENABLE(JIT) | |
46 | class ExecutableFinalizer : public WeakHandleOwner { | |
47 | virtual void finalize(Handle<Unknown> handle, void*) | |
48 | { | |
49 | Weak<ExecutableBase> executable(Weak<ExecutableBase>::Adopt, handle); | |
50 | executable->clearExecutableCode(); | |
51 | } | |
52 | }; | |
53 | ||
54 | WeakHandleOwner* ExecutableBase::executableFinalizer() | |
55 | { | |
56 | DEFINE_STATIC_LOCAL(ExecutableFinalizer, finalizer, ()); | |
57 | return &finalizer; | |
58 | } | |
59 | #endif | |
60 | ||
61 | const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 }; | |
62 | ||
63 | NativeExecutable::~NativeExecutable() | |
64 | { | |
65 | } | |
66 | ||
67 | const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0 }; | |
68 | ||
69 | const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 }; | |
70 | ||
71 | EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) | |
72 | : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext) | |
73 | { | |
74 | } | |
75 | ||
76 | EvalExecutable::~EvalExecutable() | |
77 | { | |
78 | } | |
79 | ||
80 | const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 }; | |
81 | ||
82 | ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) | |
83 | : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false) | |
84 | { | |
85 | } | |
86 | ||
87 | ProgramExecutable::~ProgramExecutable() | |
88 | { | |
89 | } | |
90 | ||
91 | const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 }; | |
92 | ||
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) | |
98 | , m_name(name) | |
99 | , m_symbolTable(0) | |
100 | { | |
101 | m_firstLine = firstLine; | |
102 | m_lastLine = lastLine; | |
103 | } | |
104 | ||
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) | |
110 | , m_name(name) | |
111 | , m_symbolTable(0) | |
112 | { | |
113 | m_firstLine = firstLine; | |
114 | m_lastLine = lastLine; | |
115 | } | |
116 | ||
117 | ||
118 | JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) | |
119 | { | |
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); | |
126 | if (!evalNode) { | |
127 | ASSERT(exception); | |
128 | return exception; | |
129 | } | |
130 | recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); | |
131 | ||
132 | JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); | |
133 | ||
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(); | |
140 | return exception; | |
141 | } | |
142 | ||
143 | evalNode->destroyData(); | |
144 | ||
145 | #if ENABLE(JIT) | |
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(); | |
151 | #endif | |
152 | } | |
153 | #endif | |
154 | ||
155 | #if ENABLE(JIT) | |
156 | #if ENABLE(INTERPRETER) | |
157 | if (!m_jitCodeForCall) | |
158 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); | |
159 | else | |
160 | #endif | |
161 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock) + m_jitCodeForCall.size()); | |
162 | #else | |
163 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); | |
164 | #endif | |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
169 | void EvalExecutable::visitChildren(SlotVisitor& visitor) | |
170 | { | |
171 | ASSERT_GC_OBJECT_INHERITS(this, &s_info); | |
172 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); | |
173 | ASSERT(structure()->typeInfo().overridesVisitChildren()); | |
174 | ScriptExecutable::visitChildren(visitor); | |
175 | if (m_evalCodeBlock) | |
176 | m_evalCodeBlock->visitAggregate(visitor); | |
177 | } | |
178 | ||
179 | void EvalExecutable::unlinkCalls() | |
180 | { | |
181 | #if ENABLE(JIT) | |
182 | if (!m_jitCodeForCall) | |
183 | return; | |
184 | ASSERT(m_evalCodeBlock); | |
185 | m_evalCodeBlock->unlinkCalls(); | |
186 | #endif | |
187 | } | |
188 | ||
189 | JSObject* ProgramExecutable::checkSyntax(ExecState* exec) | |
190 | { | |
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); | |
195 | if (programNode) | |
196 | return 0; | |
197 | ASSERT(exception); | |
198 | return exception; | |
199 | } | |
200 | ||
201 | JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) | |
202 | { | |
203 | ASSERT(!m_programCodeBlock); | |
204 | ||
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); | |
209 | if (!programNode) { | |
210 | ASSERT(exception); | |
211 | return exception; | |
212 | } | |
213 | recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); | |
214 | ||
215 | JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); | |
216 | ||
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(); | |
222 | return exception; | |
223 | } | |
224 | ||
225 | programNode->destroyData(); | |
226 | ||
227 | #if ENABLE(JIT) | |
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(); | |
233 | #endif | |
234 | } | |
235 | #endif | |
236 | ||
237 | #if ENABLE(JIT) | |
238 | #if ENABLE(INTERPRETER) | |
239 | if (!m_jitCodeForCall) | |
240 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); | |
241 | else | |
242 | #endif | |
243 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size()); | |
244 | #else | |
245 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); | |
246 | #endif | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | void ProgramExecutable::unlinkCalls() | |
252 | { | |
253 | #if ENABLE(JIT) | |
254 | if (!m_jitCodeForCall) | |
255 | return; | |
256 | ASSERT(m_programCodeBlock); | |
257 | m_programCodeBlock->unlinkCalls(); | |
258 | #endif | |
259 | } | |
260 | ||
261 | #if ENABLE(JIT) | |
262 | static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) | |
263 | { | |
264 | #if ENABLE(DFG_JIT) | |
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()) | |
269 | return false; | |
270 | #endif | |
271 | ||
272 | DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars); | |
273 | if (!parse(dfg, globalData, codeBlock)) | |
274 | return false; | |
275 | ||
276 | DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock); | |
277 | dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck); | |
278 | return true; | |
279 | #else | |
280 | UNUSED_PARAM(globalData); | |
281 | UNUSED_PARAM(codeBlock); | |
282 | UNUSED_PARAM(jitCode); | |
283 | UNUSED_PARAM(jitCodeWithArityCheck); | |
284 | return false; | |
285 | #endif | |
286 | } | |
287 | #endif | |
288 | ||
289 | void ProgramExecutable::visitChildren(SlotVisitor& visitor) | |
290 | { | |
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); | |
297 | } | |
298 | ||
299 | JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode) | |
300 | { | |
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); | |
304 | if (!body) { | |
305 | ASSERT(exception); | |
306 | return exception; | |
307 | } | |
308 | if (m_forceUsesArguments) | |
309 | body->setUsesArguments(); | |
310 | body->finishParsing(m_parameters, m_name); | |
311 | recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); | |
312 | ||
313 | JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); | |
314 | ||
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(); | |
320 | body->destroyData(); | |
321 | return exception; | |
322 | } | |
323 | ||
324 | m_numParametersForCall = m_codeBlockForCall->m_numParameters; | |
325 | ASSERT(m_numParametersForCall); | |
326 | m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; | |
327 | m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); | |
328 | ||
329 | body->destroyData(); | |
330 | ||
331 | #if ENABLE(JIT) | |
332 | if (exec->globalData().canUseJIT()) { | |
333 | bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck); | |
334 | if (!dfgCompiled) | |
335 | m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); | |
336 | ||
337 | #if !ENABLE(OPCODE_SAMPLING) | |
338 | if (!BytecodeGenerator::dumpsGeneratedCode()) | |
339 | m_codeBlockForCall->discardBytecode(); | |
340 | #endif | |
341 | } | |
342 | #endif | |
343 | ||
344 | #if ENABLE(JIT) | |
345 | #if ENABLE(INTERPRETER) | |
346 | if (!m_jitCodeForCall) | |
347 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); | |
348 | else | |
349 | #endif | |
350 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); | |
351 | #else | |
352 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); | |
353 | #endif | |
354 | ||
355 | return 0; | |
356 | } | |
357 | ||
358 | JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode) | |
359 | { | |
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); | |
363 | if (!body) { | |
364 | ASSERT(exception); | |
365 | return exception; | |
366 | } | |
367 | if (m_forceUsesArguments) | |
368 | body->setUsesArguments(); | |
369 | body->finishParsing(m_parameters, m_name); | |
370 | recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); | |
371 | ||
372 | JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); | |
373 | ||
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(); | |
379 | body->destroyData(); | |
380 | return exception; | |
381 | } | |
382 | ||
383 | m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters; | |
384 | ASSERT(m_numParametersForConstruct); | |
385 | m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; | |
386 | m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); | |
387 | ||
388 | body->destroyData(); | |
389 | ||
390 | #if ENABLE(JIT) | |
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(); | |
396 | #endif | |
397 | } | |
398 | #endif | |
399 | ||
400 | #if ENABLE(JIT) | |
401 | #if ENABLE(INTERPRETER) | |
402 | if (!m_jitCodeForConstruct) | |
403 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); | |
404 | else | |
405 | #endif | |
406 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct) + m_jitCodeForConstruct.size()); | |
407 | #else | |
408 | Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); | |
409 | #endif | |
410 | ||
411 | return 0; | |
412 | } | |
413 | ||
414 | void FunctionExecutable::visitChildren(SlotVisitor& visitor) | |
415 | { | |
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); | |
424 | } | |
425 | ||
426 | void FunctionExecutable::discardCode() | |
427 | { | |
428 | #if ENABLE(JIT) | |
429 | // These first two checks are to handle the rare case where | |
430 | // we are trying to evict code for a function during its | |
431 | // codegen. | |
432 | if (!m_jitCodeForCall && m_codeBlockForCall) | |
433 | return; | |
434 | if (!m_jitCodeForConstruct && m_codeBlockForConstruct) | |
435 | return; | |
436 | m_jitCodeForCall = JITCode(); | |
437 | m_jitCodeForConstruct = JITCode(); | |
438 | m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); | |
439 | m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); | |
440 | #endif | |
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; | |
449 | ||
450 | } | |
451 | ||
452 | void FunctionExecutable::unlinkCalls() | |
453 | { | |
454 | #if ENABLE(JIT) | |
455 | if (!!m_jitCodeForCall) { | |
456 | ASSERT(m_codeBlockForCall); | |
457 | m_codeBlockForCall->unlinkCalls(); | |
458 | } | |
459 | if (!!m_jitCodeForConstruct) { | |
460 | ASSERT(m_codeBlockForConstruct); | |
461 | m_codeBlockForConstruct->unlinkCalls(); | |
462 | } | |
463 | #endif | |
464 | } | |
465 | ||
466 | FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) | |
467 | { | |
468 | JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); | |
469 | RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception); | |
470 | if (!program) { | |
471 | ASSERT(*exception); | |
472 | return 0; | |
473 | } | |
474 | ||
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(); | |
480 | ASSERT(funcExpr); | |
481 | ASSERT(funcExpr->isFuncExprNode()); | |
482 | FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); | |
483 | ASSERT(body); | |
484 | ||
485 | return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); | |
486 | } | |
487 | ||
488 | UString FunctionExecutable::paramString() const | |
489 | { | |
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()); | |
496 | } | |
497 | return builder.toUString(); | |
498 | } | |
499 | ||
500 | } |