2 * Copyright (C) 2009, 2010, 2013-2015 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.
29 #include "ArityCheckMode.h"
31 #include "CodeBlockHash.h"
32 #include "CodeSpecializationKind.h"
33 #include "CompilationResult.h"
35 #include "ExecutableInfo.h"
36 #include "HandlerInfo.h"
37 #include "InferredValue.h"
39 #include "JSGlobalObject.h"
40 #include "RegisterPreservationMode.h"
41 #include "SamplingTool.h"
42 #include "SourceCode.h"
44 #include "UnlinkedCodeBlock.h"
45 #include "UnlinkedFunctionExecutable.h"
52 class FunctionCodeBlock;
53 class LLIntOffsetsExtractor;
54 class ProgramCodeBlock;
57 enum CompilationKind { FirstCompilation, OptimizingCompilation };
59 inline bool isCall(CodeSpecializationKind kind)
61 if (kind == CodeForCall)
63 ASSERT(kind == CodeForConstruct);
67 class ExecutableBase : public JSCell {
71 static const int NUM_PARAMETERS_IS_HOST = 0;
72 static const int NUM_PARAMETERS_NOT_COMPILED = -1;
74 ExecutableBase(VM& vm, Structure* structure, int numParameters)
75 : JSCell(vm, structure)
76 , m_numParametersForCall(numParameters)
77 , m_numParametersForConstruct(numParameters)
81 void finishCreation(VM& vm)
83 Base::finishCreation(vm);
88 static const unsigned StructureFlags = Base::StructureFlags;
90 static const bool needsDestruction = true;
91 static void destroy(JSCell*);
93 CodeBlockHash hashFor(CodeSpecializationKind) const;
95 bool isEvalExecutable()
97 return type() == EvalExecutableType;
99 bool isFunctionExecutable()
101 return type() == FunctionExecutableType;
103 bool isProgramExecutable()
105 return type() == ProgramExecutableType;
108 bool isHostFunction() const
110 ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
111 return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
114 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
121 int m_numParametersForCall;
122 int m_numParametersForConstruct;
125 static void clearCodeVirtual(ExecutableBase*);
127 PassRefPtr<JITCode> generatedJITCodeForCall()
129 ASSERT(m_jitCodeForCall);
130 return m_jitCodeForCall;
133 PassRefPtr<JITCode> generatedJITCodeForConstruct()
135 ASSERT(m_jitCodeForConstruct);
136 return m_jitCodeForConstruct;
139 PassRefPtr<JITCode> generatedJITCodeFor(CodeSpecializationKind kind)
141 if (kind == CodeForCall)
142 return generatedJITCodeForCall();
143 ASSERT(kind == CodeForConstruct);
144 return generatedJITCodeForConstruct();
147 MacroAssemblerCodePtr entrypointFor(
148 VM& vm, CodeSpecializationKind kind, ArityCheckMode arity, RegisterPreservationMode registers)
150 // Check if we have a cached result. We only have it for arity check because we use the
151 // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in
153 if (arity == MustCheckArity) {
157 case RegisterPreservationNotRequired:
158 if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck)
161 case MustPreserveRegisters:
162 if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheckAndPreserveRegs)
167 case CodeForConstruct:
169 case RegisterPreservationNotRequired:
170 if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck)
173 case MustPreserveRegisters:
174 if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheckAndPreserveRegs)
181 MacroAssemblerCodePtr result =
182 generatedJITCodeFor(kind)->addressForCall(vm, this, arity, registers);
183 if (arity == MustCheckArity) {
184 // Cache the result; this is necessary for the JIT's virtual call optimizations.
188 case RegisterPreservationNotRequired:
189 m_jitCodeForCallWithArityCheck = result;
191 case MustPreserveRegisters:
192 m_jitCodeForCallWithArityCheckAndPreserveRegs = result;
196 case CodeForConstruct:
198 case RegisterPreservationNotRequired:
199 m_jitCodeForConstructWithArityCheck = result;
201 case MustPreserveRegisters:
202 m_jitCodeForConstructWithArityCheckAndPreserveRegs = result;
211 static ptrdiff_t offsetOfJITCodeWithArityCheckFor(
212 CodeSpecializationKind kind, RegisterPreservationMode registers)
217 case RegisterPreservationNotRequired:
218 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
219 case MustPreserveRegisters:
220 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheckAndPreserveRegs);
222 case CodeForConstruct:
224 case RegisterPreservationNotRequired:
225 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
226 case MustPreserveRegisters:
227 return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheckAndPreserveRegs);
230 RELEASE_ASSERT_NOT_REACHED();
234 static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind)
236 if (kind == CodeForCall)
237 return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall);
238 ASSERT(kind == CodeForConstruct);
239 return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct);
242 bool hasJITCodeForCall() const
244 return m_numParametersForCall >= 0;
247 bool hasJITCodeForConstruct() const
249 return m_numParametersForConstruct >= 0;
252 bool hasJITCodeFor(CodeSpecializationKind kind) const
254 if (kind == CodeForCall)
255 return hasJITCodeForCall();
256 ASSERT(kind == CodeForConstruct);
257 return hasJITCodeForConstruct();
260 // Intrinsics are only for calls, currently.
261 Intrinsic intrinsic() const;
263 Intrinsic intrinsicFor(CodeSpecializationKind kind) const
270 void dump(PrintStream&) const;
273 RefPtr<JITCode> m_jitCodeForCall;
274 RefPtr<JITCode> m_jitCodeForConstruct;
275 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
276 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
277 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheckAndPreserveRegs;
278 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheckAndPreserveRegs;
281 class NativeExecutable final : public ExecutableBase {
283 friend class LLIntOffsetsExtractor;
285 typedef ExecutableBase Base;
286 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
288 static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic)
290 NativeExecutable* executable;
291 executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
292 executable->finishCreation(vm, callThunk, constructThunk, intrinsic);
296 static void destroy(JSCell*);
298 CodeBlockHash hashFor(CodeSpecializationKind) const;
300 NativeFunction function() { return m_function; }
301 NativeFunction constructor() { return m_constructor; }
303 NativeFunction nativeFunctionFor(CodeSpecializationKind kind)
305 if (kind == CodeForCall)
307 ASSERT(kind == CodeForConstruct);
308 return constructor();
311 static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind)
313 if (kind == CodeForCall)
314 return OBJECT_OFFSETOF(NativeExecutable, m_function);
315 ASSERT(kind == CodeForConstruct);
316 return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
319 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
323 Intrinsic intrinsic() const;
326 void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic)
328 Base::finishCreation(vm);
329 m_jitCodeForCall = callThunk;
330 m_jitCodeForConstruct = constructThunk;
331 m_intrinsic = intrinsic;
335 NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
336 : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
337 , m_function(function)
338 , m_constructor(constructor)
342 NativeFunction m_function;
343 NativeFunction m_constructor;
345 Intrinsic m_intrinsic;
348 class ScriptExecutable : public ExecutableBase {
350 typedef ExecutableBase Base;
351 static const unsigned StructureFlags = Base::StructureFlags;
353 static void destroy(JSCell*);
355 CodeBlockHash hashFor(CodeSpecializationKind) const;
357 const SourceCode& source() const { return m_source; }
358 intptr_t sourceID() const { return m_source.providerID(); }
359 const String& sourceURL() const { return m_source.provider()->url(); }
360 int firstLine() const { return m_firstLine; }
361 void setOverrideLineNumber(int overrideLineNumber) { m_overrideLineNumber = overrideLineNumber; }
362 bool hasOverrideLineNumber() const { return m_overrideLineNumber != -1; }
363 int overrideLineNumber() const { return m_overrideLineNumber; }
364 int lastLine() const { return m_lastLine; }
365 unsigned startColumn() const { return m_startColumn; }
366 unsigned endColumn() const { return m_endColumn; }
367 unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; }
368 unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
370 bool usesEval() const { return m_features & EvalFeature; }
371 bool usesArguments() const { return m_features & ArgumentsFeature; }
372 bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
373 bool isStrictMode() const { return m_features & StrictModeFeature; }
374 ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
376 void setNeverInline(bool value) { m_neverInline = value; }
377 void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; }
378 bool neverInline() const { return m_neverInline; }
379 bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; }
380 bool isInliningCandidate() const { return !neverInline(); }
382 bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; }
386 CodeFeatures features() const { return m_features; }
390 void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn, unsigned endColumn)
392 m_features = features;
393 m_hasCapturedVariables = hasCapturedVariables;
394 m_firstLine = firstLine;
395 m_lastLine = lastLine;
396 ASSERT(startColumn != UINT_MAX);
397 m_startColumn = startColumn;
398 ASSERT(endColumn != UINT_MAX);
399 m_endColumn = endColumn;
402 void installCode(CodeBlock*);
403 RefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
404 PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind);
406 JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
408 if (hasJITCodeFor(kind))
410 return prepareForExecutionImpl(exec, function, scope, kind);
413 template <typename Functor> void forEachCodeBlock(Functor&&);
416 JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind);
419 ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext);
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;
436 bool m_didTryToEnterInLoop;
437 int m_overrideLineNumber;
440 unsigned m_startColumn;
441 unsigned m_endColumn;
442 unsigned m_typeProfilingStartOffset;
443 unsigned m_typeProfilingEndOffset;
446 class EvalExecutable final : public ScriptExecutable {
447 friend class LLIntOffsetsExtractor;
449 typedef ScriptExecutable Base;
450 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
452 static void destroy(JSCell*);
454 EvalCodeBlock* codeBlock()
456 return m_evalCodeBlock.get();
459 static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode, const VariableEnvironment*);
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, false, ConstructorKind::None, false); }
479 unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
480 unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
483 friend class ScriptExecutable;
484 EvalExecutable(ExecState*, const SourceCode&, bool);
486 static void visitChildren(JSCell*, SlotVisitor&);
488 RefPtr<EvalCodeBlock> m_evalCodeBlock;
489 WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
492 class ProgramExecutable final : public ScriptExecutable {
493 friend class LLIntOffsetsExtractor;
495 typedef ScriptExecutable Base;
496 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
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*);
510 ProgramCodeBlock* codeBlock()
512 return m_programCodeBlock.get();
515 JSObject* checkSyntax(ExecState*);
517 PassRefPtr<JITCode> generatedJITCode()
519 return generatedJITCodeForCall();
522 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
524 return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), info());
533 ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
536 friend class ScriptExecutable;
538 ProgramExecutable(ExecState*, const SourceCode&);
540 static void visitChildren(JSCell*, SlotVisitor&);
542 WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
543 RefPtr<ProgramCodeBlock> m_programCodeBlock;
546 class FunctionExecutable final : public ScriptExecutable {
548 friend class LLIntOffsetsExtractor;
550 typedef ScriptExecutable Base;
551 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
553 static FunctionExecutable* create(
554 VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable,
555 unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn)
557 FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn);
558 executable->finishCreation(vm);
561 static FunctionExecutable* fromGlobalCode(
562 const Identifier& name, ExecState&, const SourceCode&,
563 JSObject*& exception, int overrideLineNumber);
565 static void destroy(JSCell*);
567 UnlinkedFunctionExecutable* unlinkedExecutable()
569 return m_unlinkedExecutable.get();
572 // Returns either call or construct bytecode. This can be appropriate
573 // for answering questions that that don't vary between call and construct --
574 // for example, argumentsRegister().
575 FunctionCodeBlock* eitherCodeBlock()
577 if (m_codeBlockForCall)
578 return m_codeBlockForCall.get();
579 return m_codeBlockForConstruct.get();
582 bool isGeneratedForCall() const
584 return m_codeBlockForCall;
587 FunctionCodeBlock* codeBlockForCall()
589 return m_codeBlockForCall.get();
592 bool isGeneratedForConstruct() const
594 return m_codeBlockForConstruct;
597 FunctionCodeBlock* codeBlockForConstruct()
599 return m_codeBlockForConstruct.get();
602 bool isGeneratedFor(CodeSpecializationKind kind)
604 if (kind == CodeForCall)
605 return isGeneratedForCall();
606 ASSERT(kind == CodeForConstruct);
607 return isGeneratedForConstruct();
610 FunctionCodeBlock* codeBlockFor(CodeSpecializationKind kind)
612 if (kind == CodeForCall)
613 return codeBlockForCall();
614 ASSERT(kind == CodeForConstruct);
615 return codeBlockForConstruct();
618 FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
620 FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
622 return baselineCodeBlockFor(kind);
625 RefPtr<TypeSet> returnStatementTypeSet()
627 if (!m_returnStatementTypeSet)
628 m_returnStatementTypeSet = TypeSet::create();
630 return m_returnStatementTypeSet;
633 FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
634 bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
635 ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
636 bool isArrowFunction() const { return m_unlinkedExecutable->isArrowFunction(); }
637 bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
638 const Identifier& name() { return m_unlinkedExecutable->name(); }
639 const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
640 JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); }
641 size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
643 void clearUnlinkedCodeForRecompilation();
644 static void visitChildren(JSCell*, SlotVisitor&);
645 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
647 return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
650 unsigned parametersStartOffset() const { return m_parametersStartOffset; }
652 void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset)
654 m_parametersStartOffset = parametersStartOffset;
655 m_typeProfilingStartOffset = typeProfilingStartOffset;
656 m_typeProfilingEndOffset = typeProfilingEndOffset;
665 InferredValue* singletonFunction() { return m_singletonFunction.get(); }
669 VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine,
670 unsigned lastLine, unsigned startColumn, unsigned endColumn);
672 void finishCreation(VM&);
674 friend class ScriptExecutable;
676 WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
677 RefPtr<FunctionCodeBlock> m_codeBlockForCall;
678 RefPtr<FunctionCodeBlock> m_codeBlockForConstruct;
679 RefPtr<TypeSet> m_returnStatementTypeSet;
680 unsigned m_parametersStartOffset;
681 WriteBarrier<InferredValue> m_singletonFunction;
684 inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
686 switch (executable->type()) {
687 case EvalExecutableType:
688 return jsCast<EvalExecutable*>(executable)->clearCode();
689 case ProgramExecutableType:
690 return jsCast<ProgramExecutable*>(executable)->clearCode();
691 case FunctionExecutableType:
692 return jsCast<FunctionExecutable*>(executable)->clearCode();
694 return jsCast<NativeExecutable*>(executable)->clearCode();
698 inline void ScriptExecutable::unlinkCalls()
701 case EvalExecutableType:
702 return jsCast<EvalExecutable*>(this)->unlinkCalls();
703 case ProgramExecutableType:
704 return jsCast<ProgramExecutable*>(this)->unlinkCalls();
705 case FunctionExecutableType:
706 return jsCast<FunctionExecutable*>(this)->unlinkCalls();
708 RELEASE_ASSERT_NOT_REACHED();