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 class ExecutableBase
: public JSCell
{
51 static const int NUM_PARAMETERS_IS_HOST
= 0;
52 static const int NUM_PARAMETERS_NOT_COMPILED
= -1;
55 ExecutableBase(JSGlobalData
& globalData
, Structure
* structure
, int numParameters
)
56 : JSCell(globalData
, structure
)
57 , m_numParametersForCall(numParameters
)
58 , m_numParametersForConstruct(numParameters
)
61 Weak
<ExecutableBase
> finalizer(globalData
, this, executableFinalizer());
62 finalizer
.leakHandle();
66 bool isHostFunction() const
68 ASSERT((m_numParametersForCall
== NUM_PARAMETERS_IS_HOST
) == (m_numParametersForConstruct
== NUM_PARAMETERS_IS_HOST
));
69 return m_numParametersForCall
== NUM_PARAMETERS_IS_HOST
;
72 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue proto
) { return Structure::create(globalData
, proto
, TypeInfo(CompoundType
, StructureFlags
), AnonymousSlotCount
, &s_info
); }
74 static const ClassInfo s_info
;
77 static const unsigned StructureFlags
= 0;
78 int m_numParametersForCall
;
79 int m_numParametersForConstruct
;
83 JITCode
& generatedJITCodeForCall()
85 ASSERT(m_jitCodeForCall
);
86 return m_jitCodeForCall
;
89 JITCode
& generatedJITCodeForConstruct()
91 ASSERT(m_jitCodeForConstruct
);
92 return m_jitCodeForConstruct
;
95 void clearExecutableCode()
97 m_jitCodeForCall
.clear();
98 m_jitCodeForConstruct
.clear();
102 JITCode m_jitCodeForCall
;
103 JITCode m_jitCodeForConstruct
;
104 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck
;
105 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck
;
108 static WeakHandleOwner
* executableFinalizer();
112 class NativeExecutable
: public ExecutableBase
{
116 static NativeExecutable
* create(JSGlobalData
& globalData
, MacroAssemblerCodePtr callThunk
, NativeFunction function
, MacroAssemblerCodePtr constructThunk
, NativeFunction constructor
)
119 return new (&globalData
) NativeExecutable(globalData
, JITCode(), function
, JITCode(), constructor
);
120 return new (&globalData
) NativeExecutable(globalData
, JITCode::HostFunction(callThunk
), function
, JITCode::HostFunction(constructThunk
), constructor
);
123 static NativeExecutable
* create(JSGlobalData
& globalData
, NativeFunction function
, NativeFunction constructor
)
125 return new (&globalData
) NativeExecutable(globalData
, function
, constructor
);
131 NativeFunction
function() { return m_function
; }
133 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue proto
) { return Structure::create(globalData
, proto
, TypeInfo(LeafType
, StructureFlags
), AnonymousSlotCount
, &s_info
); }
135 static const ClassInfo s_info
;
139 NativeExecutable(JSGlobalData
& globalData
, JITCode callThunk
, NativeFunction function
, JITCode constructThunk
, NativeFunction constructor
)
140 : ExecutableBase(globalData
, globalData
.nativeExecutableStructure
.get(), NUM_PARAMETERS_IS_HOST
)
141 , m_function(function
)
142 , m_constructor(constructor
)
144 m_jitCodeForCall
= callThunk
;
145 m_jitCodeForConstruct
= constructThunk
;
146 m_jitCodeForCallWithArityCheck
= callThunk
.addressForCall();
147 m_jitCodeForConstructWithArityCheck
= constructThunk
.addressForCall();
150 NativeExecutable(JSGlobalData
& globalData
, NativeFunction function
, NativeFunction constructor
)
151 : ExecutableBase(globalData
, globalData
.nativeExecutableStructure
.get(), NUM_PARAMETERS_IS_HOST
)
152 , m_function(function
)
153 , m_constructor(constructor
)
158 NativeFunction m_function
;
159 // Probably should be a NativeConstructor, but this will currently require rewriting the JIT
160 // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList.
161 NativeFunction m_constructor
;
164 class ScriptExecutable
: public ExecutableBase
{
166 ScriptExecutable(Structure
* structure
, JSGlobalData
* globalData
, const SourceCode
& source
, bool isInStrictContext
)
167 : ExecutableBase(*globalData
, structure
, NUM_PARAMETERS_NOT_COMPILED
)
169 , m_features(isInStrictContext
? StrictModeFeature
: 0)
171 #if ENABLE(CODEBLOCK_SAMPLING)
172 relaxAdoptionRequirement();
173 if (SamplingTool
* sampler
= globalData
->interpreter
->sampler())
174 sampler
->notifyOfScope(this);
176 UNUSED_PARAM(globalData
);
180 ScriptExecutable(Structure
* structure
, ExecState
* exec
, const SourceCode
& source
, bool isInStrictContext
)
181 : ExecutableBase(exec
->globalData(), structure
, NUM_PARAMETERS_NOT_COMPILED
)
183 , m_features(isInStrictContext
? StrictModeFeature
: 0)
185 #if ENABLE(CODEBLOCK_SAMPLING)
186 relaxAdoptionRequirement();
187 if (SamplingTool
* sampler
= exec
->globalData().interpreter
->sampler())
188 sampler
->notifyOfScope(this);
194 const SourceCode
& source() { return m_source
; }
195 intptr_t sourceID() const { return m_source
.provider()->asID(); }
196 const UString
& sourceURL() const { return m_source
.provider()->url(); }
197 int lineNo() const { return m_firstLine
; }
198 int lastLine() const { return m_lastLine
; }
200 bool usesEval() const { return m_features
& EvalFeature
; }
201 bool usesArguments() const { return m_features
& ArgumentsFeature
; }
202 bool needsActivation() const { return m_hasCapturedVariables
|| m_features
& (EvalFeature
| WithFeature
| CatchFeature
); }
203 bool isStrictMode() const { return m_features
& StrictModeFeature
; }
205 virtual void unlinkCalls() = 0;
207 static const ClassInfo s_info
;
209 void recordParse(CodeFeatures features
, bool hasCapturedVariables
, int firstLine
, int lastLine
)
211 m_features
= features
;
212 m_hasCapturedVariables
= hasCapturedVariables
;
213 m_firstLine
= firstLine
;
214 m_lastLine
= lastLine
;
218 CodeFeatures m_features
;
219 bool m_hasCapturedVariables
;
224 class EvalExecutable
: public ScriptExecutable
{
229 JSObject
* compile(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
231 ASSERT(exec
->globalData().dynamicGlobalObject
);
233 if (!m_evalCodeBlock
)
234 error
= compileInternal(exec
, scopeChainNode
);
235 ASSERT(!error
== !!m_evalCodeBlock
);
239 EvalCodeBlock
& generatedBytecode()
241 ASSERT(m_evalCodeBlock
);
242 return *m_evalCodeBlock
;
245 static EvalExecutable
* create(ExecState
* exec
, const SourceCode
& source
, bool isInStrictContext
) { return new (exec
) EvalExecutable(exec
, source
, isInStrictContext
); }
248 JITCode
& generatedJITCode()
250 return generatedJITCodeForCall();
253 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue proto
)
255 return Structure::create(globalData
, proto
, TypeInfo(CompoundType
, StructureFlags
), AnonymousSlotCount
, &s_info
);
258 static const ClassInfo s_info
;
260 static const unsigned StructureFlags
= OverridesVisitChildren
| ScriptExecutable::StructureFlags
;
261 EvalExecutable(ExecState
*, const SourceCode
&, bool);
263 JSObject
* compileInternal(ExecState
*, ScopeChainNode
*);
264 virtual void visitChildren(SlotVisitor
&);
267 OwnPtr
<EvalCodeBlock
> m_evalCodeBlock
;
270 class ProgramExecutable
: public ScriptExecutable
{
272 static ProgramExecutable
* create(ExecState
* exec
, const SourceCode
& source
)
274 return new (exec
) ProgramExecutable(exec
, source
);
277 ~ProgramExecutable();
279 JSObject
* compile(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
281 ASSERT(exec
->globalData().dynamicGlobalObject
);
283 if (!m_programCodeBlock
)
284 error
= compileInternal(exec
, scopeChainNode
);
285 ASSERT(!error
== !!m_programCodeBlock
);
289 ProgramCodeBlock
& generatedBytecode()
291 ASSERT(m_programCodeBlock
);
292 return *m_programCodeBlock
;
295 JSObject
* checkSyntax(ExecState
*);
298 JITCode
& generatedJITCode()
300 return generatedJITCodeForCall();
304 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue proto
)
306 return Structure::create(globalData
, proto
, TypeInfo(CompoundType
, StructureFlags
), AnonymousSlotCount
, &s_info
);
309 static const ClassInfo s_info
;
312 static const unsigned StructureFlags
= OverridesVisitChildren
| ScriptExecutable::StructureFlags
;
313 ProgramExecutable(ExecState
*, const SourceCode
&);
315 JSObject
* compileInternal(ExecState
*, ScopeChainNode
*);
316 virtual void visitChildren(SlotVisitor
&);
319 OwnPtr
<ProgramCodeBlock
> m_programCodeBlock
;
322 class FunctionExecutable
: public ScriptExecutable
{
325 static FunctionExecutable
* create(ExecState
* exec
, const Identifier
& name
, const SourceCode
& source
, bool forceUsesArguments
, FunctionParameters
* parameters
, bool isInStrictContext
, int firstLine
, int lastLine
)
327 return new (exec
) FunctionExecutable(exec
, name
, source
, forceUsesArguments
, parameters
, isInStrictContext
, firstLine
, lastLine
);
330 static FunctionExecutable
* create(JSGlobalData
* globalData
, const Identifier
& name
, const SourceCode
& source
, bool forceUsesArguments
, FunctionParameters
* parameters
, bool isInStrictContext
, int firstLine
, int lastLine
)
332 return new (globalData
) FunctionExecutable(globalData
, name
, source
, forceUsesArguments
, parameters
, isInStrictContext
, firstLine
, lastLine
);
335 JSFunction
* make(ExecState
* exec
, ScopeChainNode
* scopeChain
)
337 return new (exec
) JSFunction(exec
, this, scopeChain
);
340 // Returns either call or construct bytecode. This can be appropriate
341 // for answering questions that that don't vary between call and construct --
342 // for example, argumentsRegister().
343 FunctionCodeBlock
& generatedBytecode()
345 if (m_codeBlockForCall
)
346 return *m_codeBlockForCall
;
347 ASSERT(m_codeBlockForConstruct
);
348 return *m_codeBlockForConstruct
;
351 JSObject
* compileForCall(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
353 ASSERT(exec
->globalData().dynamicGlobalObject
);
355 if (!m_codeBlockForCall
)
356 error
= compileForCallInternal(exec
, scopeChainNode
);
357 ASSERT(!error
== !!m_codeBlockForCall
);
361 bool isGeneratedForCall() const
363 return m_codeBlockForCall
;
366 FunctionCodeBlock
& generatedBytecodeForCall()
368 ASSERT(m_codeBlockForCall
);
369 return *m_codeBlockForCall
;
372 JSObject
* compileForConstruct(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
374 ASSERT(exec
->globalData().dynamicGlobalObject
);
376 if (!m_codeBlockForConstruct
)
377 error
= compileForConstructInternal(exec
, scopeChainNode
);
378 ASSERT(!error
== !!m_codeBlockForConstruct
);
382 bool isGeneratedForConstruct() const
384 return m_codeBlockForConstruct
;
387 FunctionCodeBlock
& generatedBytecodeForConstruct()
389 ASSERT(m_codeBlockForConstruct
);
390 return *m_codeBlockForConstruct
;
393 const Identifier
& name() { return m_name
; }
394 size_t parameterCount() const { return m_parameters
->size(); }
395 unsigned capturedVariableCount() const { return m_numCapturedVariables
; }
396 UString
paramString() const;
397 SharedSymbolTable
* symbolTable() const { return m_symbolTable
; }
400 void visitChildren(SlotVisitor
&);
401 static FunctionExecutable
* fromGlobalCode(const Identifier
&, ExecState
*, Debugger
*, const SourceCode
&, JSObject
** exception
);
402 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue proto
)
404 return Structure::create(globalData
, proto
, TypeInfo(CompoundType
, StructureFlags
), AnonymousSlotCount
, &s_info
);
407 static const ClassInfo s_info
;
410 FunctionExecutable(JSGlobalData
*, const Identifier
& name
, const SourceCode
&, bool forceUsesArguments
, FunctionParameters
*, bool, int firstLine
, int lastLine
);
411 FunctionExecutable(ExecState
*, const Identifier
& name
, const SourceCode
&, bool forceUsesArguments
, FunctionParameters
*, bool, int firstLine
, int lastLine
);
413 JSObject
* compileForCallInternal(ExecState
*, ScopeChainNode
*);
414 JSObject
* compileForConstructInternal(ExecState
*, ScopeChainNode
*);
416 static const unsigned StructureFlags
= OverridesVisitChildren
| ScriptExecutable::StructureFlags
;
417 unsigned m_numCapturedVariables
: 31;
418 bool m_forceUsesArguments
: 1;
421 RefPtr
<FunctionParameters
> m_parameters
;
422 OwnPtr
<FunctionCodeBlock
> m_codeBlockForCall
;
423 OwnPtr
<FunctionCodeBlock
> m_codeBlockForConstruct
;
425 SharedSymbolTable
* m_symbolTable
;
429 MacroAssemblerCodePtr
generatedJITCodeForCallWithArityCheck()
431 ASSERT(m_jitCodeForCall
);
432 ASSERT(m_jitCodeForCallWithArityCheck
);
433 return m_jitCodeForCallWithArityCheck
;
436 MacroAssemblerCodePtr
generatedJITCodeForConstructWithArityCheck()
438 ASSERT(m_jitCodeForConstruct
);
439 ASSERT(m_jitCodeForConstructWithArityCheck
);
440 return m_jitCodeForConstructWithArityCheck
;
445 inline FunctionExecutable
* JSFunction::jsExecutable() const
447 ASSERT(!isHostFunctionNonInline());
448 return static_cast<FunctionExecutable
*>(m_executable
.get());
451 inline bool JSFunction::isHostFunction() const
453 ASSERT(m_executable
);
454 return m_executable
->isHostFunction();
457 inline NativeFunction
JSFunction::nativeFunction()
459 ASSERT(isHostFunction());
460 return static_cast<NativeExecutable
*>(m_executable
.get())->function();