2 * Copyright (C) 2009, 2010, 2013 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 "CodeBlockHash.h"
31 #include "CodeSpecializationKind.h"
32 #include "CompilationResult.h"
34 #include "HandlerInfo.h"
35 #include "JSFunction.h"
36 #include "Interpreter.h"
38 #include "JSGlobalObject.h"
39 #include "LLIntCLoop.h"
40 #include "SamplingTool.h"
41 #include "SourceCode.h"
42 #include "UnlinkedCodeBlock.h"
43 #include <wtf/PassOwnPtr.h>
50 class FunctionCodeBlock;
51 class LLIntOffsetsExtractor;
52 class ProgramCodeBlock;
55 enum CompilationKind { FirstCompilation, OptimizingCompilation };
57 inline bool isCall(CodeSpecializationKind kind)
59 if (kind == CodeForCall)
61 ASSERT(kind == CodeForConstruct);
65 class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> {
66 friend class WTF::DoublyLinkedListNode<ExecutableBase>;
70 static const int NUM_PARAMETERS_IS_HOST = 0;
71 static const int NUM_PARAMETERS_NOT_COMPILED = -1;
73 ExecutableBase(VM& vm, Structure* structure, int numParameters)
74 : JSCell(vm, structure)
75 , m_numParametersForCall(numParameters)
76 , m_numParametersForConstruct(numParameters)
80 void finishCreation(VM& vm)
82 Base::finishCreation(vm);
89 static const bool needsDestruction = true;
90 static const bool hasImmortalStructure = true;
91 static void destroy(JSCell*);
94 CodeBlockHash hashFor(CodeSpecializationKind) const;
96 bool isFunctionExecutable()
98 return structure()->typeInfo().type() == FunctionExecutableType;
101 bool isHostFunction() const
103 ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
104 return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
107 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), info()); }
114 static const unsigned StructureFlags = 0;
115 int m_numParametersForCall;
116 int m_numParametersForConstruct;
119 static void clearCodeVirtual(ExecutableBase*);
122 PassRefPtr<JITCode> generatedJITCodeForCall()
124 ASSERT(m_jitCodeForCall);
125 return m_jitCodeForCall;
128 PassRefPtr<JITCode> generatedJITCodeForConstruct()
130 ASSERT(m_jitCodeForConstruct);
131 return m_jitCodeForConstruct;
134 PassRefPtr<JITCode> generatedJITCodeFor(CodeSpecializationKind kind)
136 if (kind == CodeForCall)
137 return generatedJITCodeForCall();
138 ASSERT(kind == CodeForConstruct);
139 return generatedJITCodeForConstruct();
142 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
144 ASSERT(m_jitCodeForCall);
145 ASSERT(m_jitCodeForCallWithArityCheck);
146 return m_jitCodeForCallWithArityCheck;
149 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
151 ASSERT(m_jitCodeForConstruct);
152 ASSERT(m_jitCodeForConstructWithArityCheck);
153 return m_jitCodeForConstructWithArityCheck;
156 MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
158 if (kind == CodeForCall)
159 return generatedJITCodeForCallWithArityCheck();
160 ASSERT(kind == CodeForConstruct);
161 return generatedJITCodeForConstructWithArityCheck();
164 static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind)
166 if (kind == CodeForCall)
167 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
168 ASSERT(kind == CodeForConstruct);
169 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
172 static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind)
174 if (kind == CodeForCall)
175 return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall);
176 ASSERT(kind == CodeForConstruct);
177 return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct);
179 #endif // ENABLE(JIT)
181 bool hasJITCodeForCall() const
183 return m_numParametersForCall >= 0;
186 bool hasJITCodeForConstruct() const
188 return m_numParametersForConstruct >= 0;
191 bool hasJITCodeFor(CodeSpecializationKind kind) const
193 if (kind == CodeForCall)
194 return hasJITCodeForCall();
195 ASSERT(kind == CodeForConstruct);
196 return hasJITCodeForConstruct();
199 // Intrinsics are only for calls, currently.
200 Intrinsic intrinsic() const;
202 Intrinsic intrinsicFor(CodeSpecializationKind kind) const
209 #if ENABLE(JIT) || ENABLE(LLINT_C_LOOP)
210 MacroAssemblerCodePtr hostCodeEntryFor(CodeSpecializationKind kind)
213 return generatedJITCodeFor(kind)->addressForCall();
215 return LLInt::CLoop::hostCodeEntryFor(kind);
219 MacroAssemblerCodePtr jsCodeEntryFor(CodeSpecializationKind kind)
222 return generatedJITCodeFor(kind)->addressForCall();
224 return LLInt::CLoop::jsCodeEntryFor(kind);
228 MacroAssemblerCodePtr jsCodeWithArityCheckEntryFor(CodeSpecializationKind kind)
231 return generatedJITCodeWithArityCheckFor(kind);
233 return LLInt::CLoop::jsCodeEntryWithArityCheckFor(kind);
237 static void* catchRoutineFor(HandlerInfo* handler, Instruction* catchPCForInterpreter)
240 UNUSED_PARAM(catchPCForInterpreter);
241 return handler->nativeCode.executableAddress();
243 UNUSED_PARAM(handler);
244 return LLInt::CLoop::catchRoutineFor(catchPCForInterpreter);
248 #endif // ENABLE(JIT || ENABLE(LLINT_C_LOOP)
251 ExecutableBase* m_prev;
252 ExecutableBase* m_next;
254 RefPtr<JITCode> m_jitCodeForCall;
255 RefPtr<JITCode> m_jitCodeForConstruct;
256 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
257 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
260 class NativeExecutable : public ExecutableBase {
262 friend class LLIntOffsetsExtractor;
264 typedef ExecutableBase Base;
267 static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic)
269 NativeExecutable* executable;
271 executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
272 executable->finishCreation(vm, 0, 0, intrinsic);
274 executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
275 executable->finishCreation(vm, JITCode::hostFunction(callThunk), JITCode::hostFunction(constructThunk), intrinsic);
281 #if ENABLE(LLINT_C_LOOP)
282 static NativeExecutable* create(VM& vm, NativeFunction function, NativeFunction constructor)
284 ASSERT(!vm.canUseJIT());
285 NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
286 executable->finishCreation(vm);
292 static void destroy(JSCell*);
295 CodeBlockHash hashFor(CodeSpecializationKind) const;
297 NativeFunction function() { return m_function; }
298 NativeFunction constructor() { return m_constructor; }
300 NativeFunction nativeFunctionFor(CodeSpecializationKind kind)
302 if (kind == CodeForCall)
304 ASSERT(kind == CodeForConstruct);
305 return constructor();
308 static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind)
310 if (kind == CodeForCall)
311 return OBJECT_OFFSETOF(NativeExecutable, m_function);
312 ASSERT(kind == CodeForConstruct);
313 return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
316 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), info()); }
320 Intrinsic intrinsic() const;
324 void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic)
326 Base::finishCreation(vm);
327 m_jitCodeForCallWithArityCheck = callThunk ? callThunk->addressForCall() : MacroAssemblerCodePtr();
328 m_jitCodeForConstructWithArityCheck = constructThunk ? constructThunk->addressForCall() : MacroAssemblerCodePtr();
329 m_jitCodeForCall = callThunk;
330 m_jitCodeForConstruct = constructThunk;
331 m_intrinsic = intrinsic;
336 NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
337 : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
338 , m_function(function)
339 , m_constructor(constructor)
343 NativeFunction m_function;
344 NativeFunction m_constructor;
346 Intrinsic m_intrinsic;
349 class ScriptExecutable : public ExecutableBase {
351 typedef ExecutableBase Base;
353 ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext)
354 : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
356 , m_features(isInStrictContext ? StrictModeFeature : 0)
357 , m_neverInline(false)
361 ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
362 : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED)
364 , m_features(isInStrictContext ? StrictModeFeature : 0)
365 , m_neverInline(false)
370 static void destroy(JSCell*);
373 CodeBlockHash hashFor(CodeSpecializationKind) const;
375 const SourceCode& source() const { return m_source; }
376 intptr_t sourceID() const { return m_source.providerID(); }
377 const String& sourceURL() const { return m_source.provider()->url(); }
378 int lineNo() const { return m_firstLine; }
379 int lastLine() const { return m_lastLine; }
380 unsigned startColumn() const { return m_startColumn; }
382 bool usesEval() const { return m_features & EvalFeature; }
383 bool usesArguments() const { return m_features & ArgumentsFeature; }
384 bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
385 bool isStrictMode() const { return m_features & StrictModeFeature; }
387 void setNeverInline(bool value) { m_neverInline = value; }
388 bool neverInline() const { return m_neverInline; }
389 bool isInliningCandidate() const { return !neverInline(); }
393 CodeFeatures features() const { return m_features; }
397 void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn)
399 m_features = features;
400 m_hasCapturedVariables = hasCapturedVariables;
401 m_firstLine = firstLine;
402 m_lastLine = lastLine;
403 m_startColumn = startColumn;
406 void installCode(CodeBlock*);
407 PassRefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSScope*, JSObject*& exception);
408 PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind);
410 JSObject* prepareForExecution(ExecState* exec, JSScope* scope, CodeSpecializationKind kind)
412 if (hasJITCodeFor(kind))
414 return prepareForExecutionImpl(exec, scope, kind);
418 JSObject* prepareForExecutionImpl(ExecState*, JSScope*, CodeSpecializationKind);
421 void finishCreation(VM& vm)
423 Base::finishCreation(vm);
424 vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
426 #if ENABLE(CODEBLOCK_SAMPLING)
427 if (SamplingTool* sampler = vm.interpreter->sampler())
428 sampler->notifyOfScope(vm, this);
433 CodeFeatures m_features;
434 bool m_hasCapturedVariables;
438 unsigned m_startColumn;
441 class EvalExecutable : public ScriptExecutable {
442 friend class LLIntOffsetsExtractor;
444 typedef ScriptExecutable Base;
446 static void destroy(JSCell*);
449 void jettisonOptimizedCode(VM&);
452 EvalCodeBlock& generatedBytecode()
454 ASSERT(m_evalCodeBlock);
455 return *m_evalCodeBlock;
458 static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext);
461 PassRefPtr<JITCode> generatedJITCode()
463 return generatedJITCodeForCall();
466 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
468 return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), info());
477 ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
479 unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
480 unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
483 friend class ScriptExecutable;
484 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
485 EvalExecutable(ExecState*, const SourceCode&, bool);
487 static void visitChildren(JSCell*, SlotVisitor&);
489 RefPtr<EvalCodeBlock> m_evalCodeBlock;
490 WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
493 class ProgramExecutable : public ScriptExecutable {
494 friend class LLIntOffsetsExtractor;
496 typedef ScriptExecutable Base;
498 static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
500 ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
501 executable->finishCreation(exec->vm());
506 JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*);
508 static void destroy(JSCell*);
511 void jettisonOptimizedCode(VM&);
514 ProgramCodeBlock& generatedBytecode()
516 ASSERT(m_programCodeBlock);
517 return *m_programCodeBlock;
520 JSObject* checkSyntax(ExecState*);
523 PassRefPtr<JITCode> generatedJITCode()
525 return generatedJITCodeForCall();
529 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
531 return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), info());
540 ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
543 friend class ScriptExecutable;
545 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
547 ProgramExecutable(ExecState*, const SourceCode&);
549 static void visitChildren(JSCell*, SlotVisitor&);
551 WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
552 RefPtr<ProgramCodeBlock> m_programCodeBlock;
555 class FunctionExecutable : public ScriptExecutable {
557 friend class LLIntOffsetsExtractor;
559 typedef ScriptExecutable Base;
561 static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn)
563 FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn);
564 executable->finishCreation(vm);
567 static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
569 static void destroy(JSCell*);
571 UnlinkedFunctionExecutable* unlinkedExecutable()
573 return m_unlinkedExecutable.get();
576 // Returns either call or construct bytecode. This can be appropriate
577 // for answering questions that that don't vary between call and construct --
578 // for example, argumentsRegister().
579 FunctionCodeBlock& generatedBytecode()
581 if (m_codeBlockForCall)
582 return *m_codeBlockForCall;
583 ASSERT(m_codeBlockForConstruct);
584 return *m_codeBlockForConstruct;
588 void jettisonOptimizedCodeForCall(VM&);
591 bool isGeneratedForCall() const
593 return m_codeBlockForCall;
596 FunctionCodeBlock& generatedBytecodeForCall()
598 ASSERT(m_codeBlockForCall);
599 return *m_codeBlockForCall;
603 void jettisonOptimizedCodeForConstruct(VM&);
606 bool isGeneratedForConstruct() const
608 return m_codeBlockForConstruct;
611 FunctionCodeBlock& generatedBytecodeForConstruct()
613 ASSERT(m_codeBlockForConstruct);
614 return *m_codeBlockForConstruct;
618 void jettisonOptimizedCodeFor(VM& vm, CodeSpecializationKind kind)
620 if (kind == CodeForCall)
621 jettisonOptimizedCodeForCall(vm);
623 ASSERT(kind == CodeForConstruct);
624 jettisonOptimizedCodeForConstruct(vm);
629 bool isGeneratedFor(CodeSpecializationKind kind)
631 if (kind == CodeForCall)
632 return isGeneratedForCall();
633 ASSERT(kind == CodeForConstruct);
634 return isGeneratedForConstruct();
637 FunctionCodeBlock& generatedBytecodeFor(CodeSpecializationKind kind)
639 if (kind == CodeForCall)
640 return generatedBytecodeForCall();
641 ASSERT(kind == CodeForConstruct);
642 return generatedBytecodeForConstruct();
645 FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
647 FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
649 return baselineCodeBlockFor(kind);
652 const Identifier& name() { return m_unlinkedExecutable->name(); }
653 const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
654 JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); }
655 size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
656 String paramString() const;
657 SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); }
659 void clearCodeIfNotCompiling();
660 void clearUnlinkedCodeForRecompilationIfNotCompiling();
661 static void visitChildren(JSCell*, SlotVisitor&);
662 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
664 return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
674 FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine, unsigned startColumn);
676 RefPtr<FunctionCodeBlock>& codeBlockFor(CodeSpecializationKind kind)
678 if (kind == CodeForCall)
679 return m_codeBlockForCall;
680 ASSERT(kind == CodeForConstruct);
681 return m_codeBlockForConstruct;
687 if (!m_jitCodeForCall && m_codeBlockForCall)
689 if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
695 friend class ScriptExecutable;
697 static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
698 WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
699 RefPtr<FunctionCodeBlock> m_codeBlockForCall;
700 RefPtr<FunctionCodeBlock> m_codeBlockForConstruct;
703 inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
705 JSFunction* function = jsCast<JSFunction*>(getJSFunction(value));
706 if (!function || !function->isHostFunction())
708 return function->nativeFunction() == nativeFunction;
711 inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
713 switch (executable->structure()->typeInfo().type()) {
714 case EvalExecutableType:
715 return jsCast<EvalExecutable*>(executable)->clearCode();
716 case ProgramExecutableType:
717 return jsCast<ProgramExecutable*>(executable)->clearCode();
718 case FunctionExecutableType:
719 return jsCast<FunctionExecutable*>(executable)->clearCode();
721 return jsCast<NativeExecutable*>(executable)->clearCode();
725 inline void ScriptExecutable::unlinkCalls()
727 switch (structure()->typeInfo().type()) {
728 case EvalExecutableType:
729 return jsCast<EvalExecutable*>(this)->unlinkCalls();
730 case ProgramExecutableType:
731 return jsCast<ProgramExecutable*>(this)->unlinkCalls();
732 case FunctionExecutableType:
733 return jsCast<FunctionExecutable*>(this)->unlinkCalls();
735 RELEASE_ASSERT_NOT_REACHED();