2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "JSFunction.h"
31 #include "Interpreter.h"
33 #include "SamplingTool.h"
34 #include <wtf/PassOwnPtr.h>
41 class FunctionCodeBlock;
42 class ProgramCodeBlock;
47 enum CodeSpecializationKind { CodeForCall, CodeForConstruct };
49 class ExecutableBase : public JSCell {
53 static const int NUM_PARAMETERS_IS_HOST = 0;
54 static const int NUM_PARAMETERS_NOT_COMPILED = -1;
56 ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters)
57 : JSCell(globalData, structure)
58 , m_numParametersForCall(numParameters)
59 , m_numParametersForConstruct(numParameters)
63 void finishCreation(JSGlobalData& globalData)
65 Base::finishCreation(globalData);
66 Weak<ExecutableBase> finalizer(globalData, this, executableFinalizer());
67 finalizer.leakHandle();
73 static ExecutableBase* create(JSGlobalData& globalData, Structure* structure, int numParameters)
75 ExecutableBase* executable = new (allocateCell<ExecutableBase>(globalData.heap)) ExecutableBase(globalData, structure, numParameters);
76 executable->finishCreation(globalData);
80 bool isHostFunction() const
82 ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
83 return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
86 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); }
88 static const ClassInfo s_info;
90 virtual void clearCode();
93 static const unsigned StructureFlags = 0;
94 int m_numParametersForCall;
95 int m_numParametersForConstruct;
99 JITCode& generatedJITCodeForCall()
101 ASSERT(m_jitCodeForCall);
102 return m_jitCodeForCall;
105 JITCode& generatedJITCodeForConstruct()
107 ASSERT(m_jitCodeForConstruct);
108 return m_jitCodeForConstruct;
111 JITCode& generatedJITCodeFor(CodeSpecializationKind kind)
113 if (kind == CodeForCall)
114 return generatedJITCodeForCall();
115 ASSERT(kind == CodeForConstruct);
116 return generatedJITCodeForConstruct();
119 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
121 ASSERT(m_jitCodeForCall);
122 ASSERT(m_jitCodeForCallWithArityCheck);
123 return m_jitCodeForCallWithArityCheck;
126 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
128 ASSERT(m_jitCodeForConstruct);
129 ASSERT(m_jitCodeForConstructWithArityCheck);
130 return m_jitCodeForConstructWithArityCheck;
133 MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
135 if (kind == CodeForCall)
136 return generatedJITCodeForCallWithArityCheck();
137 ASSERT(kind == CodeForConstruct);
138 return generatedJITCodeForConstructWithArityCheck();
141 bool hasJITCodeForCall() const
143 return m_numParametersForCall >= 0;
146 bool hasJITCodeForConstruct() const
148 return m_numParametersForConstruct >= 0;
151 bool hasJITCodeFor(CodeSpecializationKind kind) const
153 if (kind == CodeForCall)
154 return hasJITCodeForCall();
155 ASSERT(kind == CodeForConstruct);
156 return hasJITCodeForConstruct();
160 JITCode m_jitCodeForCall;
161 JITCode m_jitCodeForConstruct;
162 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
163 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
167 static WeakHandleOwner* executableFinalizer();
170 class NativeExecutable : public ExecutableBase {
173 typedef ExecutableBase Base;
176 static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor)
178 NativeExecutable* executable;
180 executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
181 executable->finishCreation(globalData, JITCode(), JITCode());
183 executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
184 executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk));
189 static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
191 NativeExecutable* executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
192 executable->finishCreation(globalData);
199 NativeFunction function() { return m_function; }
201 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); }
203 static const ClassInfo s_info;
207 void finishCreation(JSGlobalData& globalData, JITCode callThunk, JITCode constructThunk)
209 Base::finishCreation(globalData);
210 m_jitCodeForCall = callThunk;
211 m_jitCodeForConstruct = constructThunk;
212 m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
213 m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
219 NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
220 : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
221 , m_function(function)
222 , m_constructor(constructor)
226 NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
227 : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
228 , m_function(function)
229 , m_constructor(constructor)
234 NativeFunction m_function;
235 // Probably should be a NativeConstructor, but this will currently require rewriting the JIT
236 // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList.
237 NativeFunction m_constructor;
240 class ScriptExecutable : public ExecutableBase {
242 typedef ExecutableBase Base;
244 ScriptExecutable(Structure* structure, JSGlobalData& globalData, const SourceCode& source, bool isInStrictContext)
245 : ExecutableBase(globalData, structure, NUM_PARAMETERS_NOT_COMPILED)
247 , m_features(isInStrictContext ? StrictModeFeature : 0)
251 ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
252 : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED)
254 , m_features(isInStrictContext ? StrictModeFeature : 0)
258 const SourceCode& source() { return m_source; }
259 intptr_t sourceID() const { return m_source.provider()->asID(); }
260 const UString& sourceURL() const { return m_source.provider()->url(); }
261 int lineNo() const { return m_firstLine; }
262 int lastLine() const { return m_lastLine; }
264 bool usesEval() const { return m_features & EvalFeature; }
265 bool usesArguments() const { return m_features & ArgumentsFeature; }
266 bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
267 bool isStrictMode() const { return m_features & StrictModeFeature; }
269 virtual void unlinkCalls() = 0;
271 static const ClassInfo s_info;
274 void finishCreation(JSGlobalData& globalData)
276 Base::finishCreation(globalData);
277 #if ENABLE(CODEBLOCK_SAMPLING)
278 if (SamplingTool* sampler = globalData.interpreter->sampler())
279 sampler->notifyOfScope(globalData, this);
283 void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
285 m_features = features;
286 m_hasCapturedVariables = hasCapturedVariables;
287 m_firstLine = firstLine;
288 m_lastLine = lastLine;
292 CodeFeatures m_features;
293 bool m_hasCapturedVariables;
298 class EvalExecutable : public ScriptExecutable {
300 typedef ScriptExecutable Base;
304 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
306 ASSERT(exec->globalData().dynamicGlobalObject);
308 if (!m_evalCodeBlock)
309 error = compileInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
310 ASSERT(!error == !!m_evalCodeBlock);
314 JSObject* compileOptimized(ExecState*, ScopeChainNode*);
316 EvalCodeBlock& generatedBytecode()
318 ASSERT(m_evalCodeBlock);
319 return *m_evalCodeBlock;
322 static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext)
324 EvalExecutable* executable = new (allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
325 executable->finishCreation(exec->globalData());
330 JITCode& generatedJITCode()
332 return generatedJITCodeForCall();
335 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
337 return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info);
340 static const ClassInfo s_info;
343 virtual void clearCode();
346 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
347 EvalExecutable(ExecState*, const SourceCode&, bool);
349 JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
350 virtual void visitChildren(SlotVisitor&);
353 OwnPtr<EvalCodeBlock> m_evalCodeBlock;
356 class ProgramExecutable : public ScriptExecutable {
358 typedef ScriptExecutable Base;
360 static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
362 ProgramExecutable* executable = new (allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
363 executable->finishCreation(exec->globalData());
367 ~ProgramExecutable();
369 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
371 ASSERT(exec->globalData().dynamicGlobalObject);
373 if (!m_programCodeBlock)
374 error = compileInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
375 ASSERT(!error == !!m_programCodeBlock);
379 JSObject* compileOptimized(ExecState*, ScopeChainNode*);
381 ProgramCodeBlock& generatedBytecode()
383 ASSERT(m_programCodeBlock);
384 return *m_programCodeBlock;
387 JSObject* checkSyntax(ExecState*);
390 JITCode& generatedJITCode()
392 return generatedJITCodeForCall();
396 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
398 return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info);
401 static const ClassInfo s_info;
404 virtual void clearCode();
407 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
408 ProgramExecutable(ExecState*, const SourceCode&);
410 JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
411 virtual void visitChildren(SlotVisitor&);
414 OwnPtr<ProgramCodeBlock> m_programCodeBlock;
417 class FunctionExecutable : public ScriptExecutable {
420 typedef ScriptExecutable Base;
422 static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
424 FunctionExecutable* executable = new (allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext);
425 executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
429 static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
431 FunctionExecutable* executable = new (allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext);
432 executable->finishCreation(globalData, name, firstLine, lastLine);
436 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
438 return JSFunction::create(exec, this, scopeChain);
441 // Returns either call or construct bytecode. This can be appropriate
442 // for answering questions that that don't vary between call and construct --
443 // for example, argumentsRegister().
444 FunctionCodeBlock& generatedBytecode()
446 if (m_codeBlockForCall)
447 return *m_codeBlockForCall;
448 ASSERT(m_codeBlockForConstruct);
449 return *m_codeBlockForConstruct;
452 JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode, ExecState* calleeArgsExec = 0)
454 ASSERT(exec->globalData().dynamicGlobalObject);
456 if (!m_codeBlockForCall)
457 error = compileForCallInternal(exec, scopeChainNode, calleeArgsExec, JITCode::bottomTierJIT());
458 ASSERT(!error == !!m_codeBlockForCall);
462 JSObject* compileOptimizedForCall(ExecState*, ScopeChainNode*, ExecState* calleeArgsExec = 0);
464 bool isGeneratedForCall() const
466 return m_codeBlockForCall;
469 FunctionCodeBlock& generatedBytecodeForCall()
471 ASSERT(m_codeBlockForCall);
472 return *m_codeBlockForCall;
475 JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
477 ASSERT(exec->globalData().dynamicGlobalObject);
479 if (!m_codeBlockForConstruct)
480 error = compileForConstructInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
481 ASSERT(!error == !!m_codeBlockForConstruct);
485 JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*);
487 bool isGeneratedForConstruct() const
489 return m_codeBlockForConstruct;
492 FunctionCodeBlock& generatedBytecodeForConstruct()
494 ASSERT(m_codeBlockForConstruct);
495 return *m_codeBlockForConstruct;
498 JSObject* compileFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind)
500 // compileFor should only be called with a callframe set up to call this function,
501 // since we will make speculative optimizations based on the arguments.
502 ASSERT(exec->callee());
503 ASSERT(exec->callee()->inherits(&JSFunction::s_info));
504 ASSERT(asFunction(exec->callee())->jsExecutable() == this);
506 if (kind == CodeForCall)
507 return compileForCall(exec, scopeChainNode, exec);
508 ASSERT(kind == CodeForConstruct);
509 return compileForConstruct(exec, scopeChainNode);
512 JSObject* compileOptimizedFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind)
514 // compileOptimizedFor should only be called with a callframe set up to call this function,
515 // since we will make speculative optimizations based on the arguments.
516 ASSERT(exec->callee());
517 ASSERT(exec->callee()->inherits(&JSFunction::s_info));
518 ASSERT(asFunction(exec->callee())->jsExecutable() == this);
520 if (kind == CodeForCall)
521 return compileOptimizedForCall(exec, scopeChainNode, exec);
522 ASSERT(kind == CodeForConstruct);
523 return compileOptimizedForConstruct(exec, scopeChainNode);
526 bool isGeneratedFor(CodeSpecializationKind kind)
528 if (kind == CodeForCall)
529 return isGeneratedForCall();
530 ASSERT(kind == CodeForConstruct);
531 return isGeneratedForConstruct();
534 FunctionCodeBlock& generatedBytecodeFor(CodeSpecializationKind kind)
536 if (kind == CodeForCall)
537 return generatedBytecodeForCall();
538 ASSERT(kind == CodeForConstruct);
539 return generatedBytecodeForConstruct();
542 const Identifier& name() { return m_name; }
543 JSString* nameValue() const { return m_nameValue.get(); }
544 size_t parameterCount() const { return m_parameters->size(); }
545 unsigned capturedVariableCount() const { return m_numCapturedVariables; }
546 UString paramString() const;
547 SharedSymbolTable* symbolTable() const { return m_symbolTable; }
550 void visitChildren(SlotVisitor&);
551 static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
552 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
554 return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info);
557 static const ClassInfo s_info;
560 virtual void clearCode();
562 void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
564 Base::finishCreation(globalData);
565 m_firstLine = firstLine;
566 m_lastLine = lastLine;
567 m_nameValue.set(globalData, this, jsString(&globalData, name.ustring()));
571 FunctionExecutable(JSGlobalData&, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
572 FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
574 JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, ExecState* calleeArgsExec, JITCode::JITType);
575 JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
577 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
578 unsigned m_numCapturedVariables : 31;
579 bool m_forceUsesArguments : 1;
582 RefPtr<FunctionParameters> m_parameters;
583 OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
584 OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
586 WriteBarrier<JSString> m_nameValue;
587 SharedSymbolTable* m_symbolTable;
590 inline FunctionExecutable* JSFunction::jsExecutable() const
592 ASSERT(!isHostFunctionNonInline());
593 return static_cast<FunctionExecutable*>(m_executable.get());
596 inline bool JSFunction::isHostFunction() const
598 ASSERT(m_executable);
599 return m_executable->isHostFunction();
602 inline NativeFunction JSFunction::nativeFunction()
604 ASSERT(isHostFunction());
605 return static_cast<NativeExecutable*>(m_executable.get())->function();
608 inline bool isHostFunction(JSGlobalData& globalData, JSValue value, NativeFunction nativeFunction)
610 JSFunction* function = static_cast<JSFunction*>(getJSFunction(globalData, value));
611 if (!function || !function->isHostFunction())
613 return function->nativeFunction() == nativeFunction;