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 };
48 enum CompilationKind { FirstCompilation, OptimizingCompilation };
50 inline bool isCall(CodeSpecializationKind kind)
52 if (kind == CodeForCall)
54 ASSERT(kind == CodeForConstruct);
58 class ExecutableBase : public JSCell {
62 static const int NUM_PARAMETERS_IS_HOST = 0;
63 static const int NUM_PARAMETERS_NOT_COMPILED = -1;
65 ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters)
66 : JSCell(globalData, structure)
67 , m_numParametersForCall(numParameters)
68 , m_numParametersForConstruct(numParameters)
72 void finishCreation(JSGlobalData& globalData)
74 Base::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;
91 static const unsigned StructureFlags = 0;
92 int m_numParametersForCall;
93 int m_numParametersForConstruct;
97 JITCode& generatedJITCodeForCall()
99 ASSERT(m_jitCodeForCall);
100 return m_jitCodeForCall;
103 JITCode& generatedJITCodeForConstruct()
105 ASSERT(m_jitCodeForConstruct);
106 return m_jitCodeForConstruct;
109 JITCode& generatedJITCodeFor(CodeSpecializationKind kind)
111 if (kind == CodeForCall)
112 return generatedJITCodeForCall();
113 ASSERT(kind == CodeForConstruct);
114 return generatedJITCodeForConstruct();
117 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
119 ASSERT(m_jitCodeForCall);
120 ASSERT(m_jitCodeForCallWithArityCheck);
121 return m_jitCodeForCallWithArityCheck;
124 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
126 ASSERT(m_jitCodeForConstruct);
127 ASSERT(m_jitCodeForConstructWithArityCheck);
128 return m_jitCodeForConstructWithArityCheck;
131 MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
133 if (kind == CodeForCall)
134 return generatedJITCodeForCallWithArityCheck();
135 ASSERT(kind == CodeForConstruct);
136 return generatedJITCodeForConstructWithArityCheck();
139 bool hasJITCodeForCall() const
141 return m_numParametersForCall >= 0;
144 bool hasJITCodeForConstruct() const
146 return m_numParametersForConstruct >= 0;
149 bool hasJITCodeFor(CodeSpecializationKind kind) const
151 if (kind == CodeForCall)
152 return hasJITCodeForCall();
153 ASSERT(kind == CodeForConstruct);
154 return hasJITCodeForConstruct();
158 // Intrinsics are only for calls, currently.
159 DFG::Intrinsic intrinsic() const;
161 DFG::Intrinsic intrinsicFor(CodeSpecializationKind kind) const
165 return DFG::NoIntrinsic;
170 JITCode m_jitCodeForCall;
171 JITCode m_jitCodeForConstruct;
172 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
173 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
178 class NativeExecutable : public ExecutableBase {
181 typedef ExecutableBase Base;
184 static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, DFG::Intrinsic intrinsic)
186 NativeExecutable* executable;
188 executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
189 executable->finishCreation(globalData, JITCode(), JITCode(), intrinsic);
191 executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
192 executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic);
194 globalData.heap.addFinalizer(executable, &finalize);
198 static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
200 NativeExecutable* executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
201 executable->finishCreation(globalData);
202 globalData.heap.addFinalizer(executable, &finalize);
207 virtual ~NativeExecutable();
209 NativeFunction function() { return m_function; }
210 NativeFunction constructor() { return m_constructor; }
212 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); }
214 static const ClassInfo s_info;
217 DFG::Intrinsic intrinsic() const;
222 void finishCreation(JSGlobalData& globalData, JITCode callThunk, JITCode constructThunk, DFG::Intrinsic intrinsic)
224 Base::finishCreation(globalData);
225 m_jitCodeForCall = callThunk;
226 m_jitCodeForConstruct = constructThunk;
227 m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
228 m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
230 m_intrinsic = intrinsic;
232 UNUSED_PARAM(intrinsic);
237 static void finalize(JSCell*);
240 NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
241 : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
242 , m_function(function)
243 , m_constructor(constructor)
247 NativeFunction m_function;
248 NativeFunction m_constructor;
250 DFG::Intrinsic m_intrinsic;
253 class ScriptExecutable : public ExecutableBase {
255 typedef ExecutableBase Base;
257 ScriptExecutable(Structure* structure, JSGlobalData& globalData, const SourceCode& source, bool isInStrictContext)
258 : ExecutableBase(globalData, structure, NUM_PARAMETERS_NOT_COMPILED)
260 , m_features(isInStrictContext ? StrictModeFeature : 0)
264 ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
265 : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED)
267 , m_features(isInStrictContext ? StrictModeFeature : 0)
271 const SourceCode& source() { return m_source; }
272 intptr_t sourceID() const { return m_source.provider()->asID(); }
273 const UString& sourceURL() const { return m_source.provider()->url(); }
274 int lineNo() const { return m_firstLine; }
275 int lastLine() const { return m_lastLine; }
277 bool usesEval() const { return m_features & EvalFeature; }
278 bool usesArguments() const { return m_features & ArgumentsFeature; }
279 bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
280 bool isStrictMode() const { return m_features & StrictModeFeature; }
284 static const ClassInfo s_info;
287 void finishCreation(JSGlobalData& globalData)
289 Base::finishCreation(globalData);
290 #if ENABLE(CODEBLOCK_SAMPLING)
291 if (SamplingTool* sampler = globalData.interpreter->sampler())
292 sampler->notifyOfScope(globalData, this);
296 void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
298 m_features = features;
299 m_hasCapturedVariables = hasCapturedVariables;
300 m_firstLine = firstLine;
301 m_lastLine = lastLine;
305 CodeFeatures m_features;
306 bool m_hasCapturedVariables;
311 class EvalExecutable : public ScriptExecutable {
313 typedef ScriptExecutable Base;
315 virtual ~EvalExecutable();
317 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
319 ASSERT(exec->globalData().dynamicGlobalObject);
321 if (!m_evalCodeBlock)
322 error = compileInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
323 ASSERT(!error == !!m_evalCodeBlock);
327 JSObject* compileOptimized(ExecState*, ScopeChainNode*);
330 void jettisonOptimizedCode(JSGlobalData&);
333 EvalCodeBlock& generatedBytecode()
335 ASSERT(m_evalCodeBlock);
336 return *m_evalCodeBlock;
339 static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext)
341 EvalExecutable* executable = new (allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
342 executable->finishCreation(exec->globalData());
343 exec->globalData().heap.addFinalizer(executable, &finalize);
348 JITCode& generatedJITCode()
350 return generatedJITCodeForCall();
353 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
355 return Structure::create(globalData, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), &s_info);
358 static const ClassInfo s_info;
364 static void finalize(JSCell*);
367 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
368 EvalExecutable(ExecState*, const SourceCode&, bool);
370 JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
371 static void visitChildren(JSCell*, SlotVisitor&);
373 OwnPtr<EvalCodeBlock> m_evalCodeBlock;
376 class ProgramExecutable : public ScriptExecutable {
378 typedef ScriptExecutable Base;
380 static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
382 ProgramExecutable* executable = new (allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
383 executable->finishCreation(exec->globalData());
384 exec->globalData().heap.addFinalizer(executable, &finalize);
388 virtual ~ProgramExecutable();
390 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
392 ASSERT(exec->globalData().dynamicGlobalObject);
394 if (!m_programCodeBlock)
395 error = compileInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
396 ASSERT(!error == !!m_programCodeBlock);
400 JSObject* compileOptimized(ExecState*, ScopeChainNode*);
403 void jettisonOptimizedCode(JSGlobalData&);
406 ProgramCodeBlock& generatedBytecode()
408 ASSERT(m_programCodeBlock);
409 return *m_programCodeBlock;
412 JSObject* checkSyntax(ExecState*);
415 JITCode& generatedJITCode()
417 return generatedJITCodeForCall();
421 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
423 return Structure::create(globalData, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), &s_info);
426 static const ClassInfo s_info;
432 static void finalize(JSCell*);
435 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
436 ProgramExecutable(ExecState*, const SourceCode&);
438 JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
439 static void visitChildren(JSCell*, SlotVisitor&);
441 OwnPtr<ProgramCodeBlock> m_programCodeBlock;
444 class FunctionExecutable : public ScriptExecutable {
447 typedef ScriptExecutable Base;
449 static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
451 FunctionExecutable* executable = new (allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext);
452 executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
453 exec->globalData().heap.addFinalizer(executable, &finalize);
457 static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
459 FunctionExecutable* executable = new (allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext);
460 executable->finishCreation(globalData, name, firstLine, lastLine);
461 globalData.heap.addFinalizer(executable, &finalize);
465 virtual ~FunctionExecutable();
467 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
469 return JSFunction::create(exec, this, scopeChain);
472 // Returns either call or construct bytecode. This can be appropriate
473 // for answering questions that that don't vary between call and construct --
474 // for example, argumentsRegister().
475 FunctionCodeBlock& generatedBytecode()
477 if (m_codeBlockForCall)
478 return *m_codeBlockForCall;
479 ASSERT(m_codeBlockForConstruct);
480 return *m_codeBlockForConstruct;
483 FunctionCodeBlock* codeBlockWithBytecodeFor(CodeSpecializationKind);
485 PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(ScopeChainNode*, CompilationKind, CodeSpecializationKind, JSObject*& exception);
487 JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
489 ASSERT(exec->globalData().dynamicGlobalObject);
491 if (!m_codeBlockForCall)
492 error = compileForCallInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
493 ASSERT(!error == !!m_codeBlockForCall);
497 JSObject* compileOptimizedForCall(ExecState*, ScopeChainNode*);
500 void jettisonOptimizedCodeForCall(JSGlobalData&);
503 bool isGeneratedForCall() const
505 return m_codeBlockForCall;
508 FunctionCodeBlock& generatedBytecodeForCall()
510 ASSERT(m_codeBlockForCall);
511 return *m_codeBlockForCall;
514 JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
516 ASSERT(exec->globalData().dynamicGlobalObject);
518 if (!m_codeBlockForConstruct)
519 error = compileForConstructInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
520 ASSERT(!error == !!m_codeBlockForConstruct);
524 JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*);
527 void jettisonOptimizedCodeForConstruct(JSGlobalData&);
530 bool isGeneratedForConstruct() const
532 return m_codeBlockForConstruct;
535 FunctionCodeBlock& generatedBytecodeForConstruct()
537 ASSERT(m_codeBlockForConstruct);
538 return *m_codeBlockForConstruct;
541 JSObject* compileFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind)
543 ASSERT(exec->callee());
544 ASSERT(exec->callee()->inherits(&JSFunction::s_info));
545 ASSERT(asFunction(exec->callee())->jsExecutable() == this);
547 if (kind == CodeForCall)
548 return compileForCall(exec, scopeChainNode);
549 ASSERT(kind == CodeForConstruct);
550 return compileForConstruct(exec, scopeChainNode);
553 JSObject* compileOptimizedFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind)
555 ASSERT(exec->callee());
556 ASSERT(exec->callee()->inherits(&JSFunction::s_info));
557 ASSERT(asFunction(exec->callee())->jsExecutable() == this);
559 if (kind == CodeForCall)
560 return compileOptimizedForCall(exec, scopeChainNode);
561 ASSERT(kind == CodeForConstruct);
562 return compileOptimizedForConstruct(exec, scopeChainNode);
566 void jettisonOptimizedCodeFor(JSGlobalData& globalData, CodeSpecializationKind kind)
568 if (kind == CodeForCall)
569 jettisonOptimizedCodeForCall(globalData);
571 ASSERT(kind == CodeForConstruct);
572 jettisonOptimizedCodeForConstruct(globalData);
577 bool isGeneratedFor(CodeSpecializationKind kind)
579 if (kind == CodeForCall)
580 return isGeneratedForCall();
581 ASSERT(kind == CodeForConstruct);
582 return isGeneratedForConstruct();
585 FunctionCodeBlock& generatedBytecodeFor(CodeSpecializationKind kind)
587 if (kind == CodeForCall)
588 return generatedBytecodeForCall();
589 ASSERT(kind == CodeForConstruct);
590 return generatedBytecodeForConstruct();
593 FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
595 FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
597 return baselineCodeBlockFor(kind);
600 const Identifier& name() { return m_name; }
601 JSString* nameValue() const { return m_nameValue.get(); }
602 size_t parameterCount() const { return m_parameters->size(); } // Excluding 'this'!
603 unsigned capturedVariableCount() const { return m_numCapturedVariables; }
604 UString paramString() const;
605 SharedSymbolTable* symbolTable() const { return m_symbolTable; }
608 static void visitChildren(JSCell*, SlotVisitor&);
609 static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
610 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
612 return Structure::create(globalData, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info);
615 static const ClassInfo s_info;
621 static void finalize(JSCell*);
623 void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
625 Base::finishCreation(globalData);
626 m_firstLine = firstLine;
627 m_lastLine = lastLine;
628 m_nameValue.set(globalData, this, jsString(&globalData, name.ustring()));
632 FunctionExecutable(JSGlobalData&, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
633 FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
635 JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
636 JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
638 OwnPtr<FunctionCodeBlock>& codeBlockFor(CodeSpecializationKind kind)
640 if (kind == CodeForCall)
641 return m_codeBlockForCall;
642 ASSERT(kind == CodeForConstruct);
643 return m_codeBlockForConstruct;
646 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
647 unsigned m_numCapturedVariables : 31;
648 bool m_forceUsesArguments : 1;
650 RefPtr<FunctionParameters> m_parameters;
651 OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
652 OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
654 WriteBarrier<JSString> m_nameValue;
655 SharedSymbolTable* m_symbolTable;
658 inline FunctionExecutable* JSFunction::jsExecutable() const
660 ASSERT(!isHostFunctionNonInline());
661 return static_cast<FunctionExecutable*>(m_executable.get());
664 inline bool JSFunction::isHostFunction() const
666 ASSERT(m_executable);
667 return m_executable->isHostFunction();
670 inline NativeFunction JSFunction::nativeFunction()
672 ASSERT(isHostFunction());
673 return static_cast<NativeExecutable*>(m_executable.get())->function();
676 inline NativeFunction JSFunction::nativeConstructor()
678 ASSERT(isHostFunction());
679 return static_cast<NativeExecutable*>(m_executable.get())->constructor();
682 inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
684 JSFunction* function = static_cast<JSFunction*>(getJSFunction(value));
685 if (!function || !function->isHostFunction())
687 return function->nativeFunction() == nativeFunction;
690 inline void ScriptExecutable::unlinkCalls()
692 switch (structure()->typeInfo().type()) {
693 case EvalExecutableType:
694 return jsCast<EvalExecutable*>(this)->unlinkCalls();
695 case ProgramExecutableType:
696 return jsCast<ProgramExecutable*>(this)->unlinkCalls();
697 case FunctionExecutableType:
698 return jsCast<FunctionExecutable*>(this)->unlinkCalls();
700 ASSERT_NOT_REACHED();