diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecode/InlineCallFrame.h')
-rw-r--r-- | Source/JavaScriptCore/bytecode/InlineCallFrame.h | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/InlineCallFrame.h b/Source/JavaScriptCore/bytecode/InlineCallFrame.h new file mode 100644 index 000000000..eaa943cfe --- /dev/null +++ b/Source/JavaScriptCore/bytecode/InlineCallFrame.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef InlineCallFrame_h +#define InlineCallFrame_h + +#include "CodeBlock.h" +#include "CodeBlockHash.h" +#include "CodeOrigin.h" +#include "ValueRecovery.h" +#include "WriteBarrier.h" +#include <wtf/BitVector.h> +#include <wtf/HashMap.h> +#include <wtf/PrintStream.h> +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +namespace JSC { + +struct InlineCallFrame; +class ExecState; +class JSFunction; + +struct InlineCallFrame { + enum Kind { + Call, + Construct, + TailCall, + CallVarargs, + ConstructVarargs, + TailCallVarargs, + + // For these, the stackOffset incorporates the argument count plus the true return PC + // slot. + GetterCall, + SetterCall + }; + + static CallMode callModeFor(Kind kind) + { + switch (kind) { + case Call: + case CallVarargs: + case GetterCall: + case SetterCall: + return CallMode::Regular; + case TailCall: + case TailCallVarargs: + return CallMode::Tail; + case Construct: + case ConstructVarargs: + return CallMode::Construct; + } + RELEASE_ASSERT_NOT_REACHED(); + } + + static Kind kindFor(CallMode callMode) + { + switch (callMode) { + case CallMode::Regular: + return Call; + case CallMode::Construct: + return Construct; + case CallMode::Tail: + return TailCall; + } + RELEASE_ASSERT_NOT_REACHED(); + } + + static Kind varargsKindFor(CallMode callMode) + { + switch (callMode) { + case CallMode::Regular: + return CallVarargs; + case CallMode::Construct: + return ConstructVarargs; + case CallMode::Tail: + return TailCallVarargs; + } + RELEASE_ASSERT_NOT_REACHED(); + } + + static CodeSpecializationKind specializationKindFor(Kind kind) + { + switch (kind) { + case Call: + case CallVarargs: + case TailCall: + case TailCallVarargs: + case GetterCall: + case SetterCall: + return CodeForCall; + case Construct: + case ConstructVarargs: + return CodeForConstruct; + } + RELEASE_ASSERT_NOT_REACHED(); + } + + static bool isVarargs(Kind kind) + { + switch (kind) { + case CallVarargs: + case TailCallVarargs: + case ConstructVarargs: + return true; + default: + return false; + } + } + + static bool isTail(Kind kind) + { + switch (kind) { + case TailCall: + case TailCallVarargs: + return true; + default: + return false; + } + } + bool isTail() const + { + return isTail(static_cast<Kind>(kind)); + } + + static CodeOrigin* computeCallerSkippingTailCalls(InlineCallFrame* inlineCallFrame, Kind* callerCallKind = nullptr) + { + CodeOrigin* codeOrigin; + bool tailCallee; + int callKind; + do { + tailCallee = inlineCallFrame->isTail(); + callKind = inlineCallFrame->kind; + codeOrigin = &inlineCallFrame->directCaller; + inlineCallFrame = codeOrigin->inlineCallFrame; + } while (inlineCallFrame && tailCallee); + + if (tailCallee) + return nullptr; + + if (callerCallKind) + *callerCallKind = static_cast<Kind>(callKind); + + return codeOrigin; + } + + CodeOrigin* getCallerSkippingTailCalls(Kind* callerCallKind = nullptr) + { + return computeCallerSkippingTailCalls(this, callerCallKind); + } + + InlineCallFrame* getCallerInlineFrameSkippingTailCalls() + { + CodeOrigin* caller = getCallerSkippingTailCalls(); + return caller ? caller->inlineCallFrame : nullptr; + } + + Vector<ValueRecovery> arguments; // Includes 'this'. + WriteBarrier<CodeBlock> baselineCodeBlock; + ValueRecovery calleeRecovery; + CodeOrigin directCaller; + + signed stackOffset : 28; + unsigned kind : 3; // real type is Kind + bool isClosureCall : 1; // If false then we know that callee/scope are constants and the DFG won't treat them as variables, i.e. they have to be recovered manually. + VirtualRegister argumentCountRegister; // Only set when we inline a varargs call. + + // There is really no good notion of a "default" set of values for + // InlineCallFrame's fields. This constructor is here just to reduce confusion if + // we forgot to initialize explicitly. + InlineCallFrame() + : stackOffset(0) + , kind(Call) + , isClosureCall(false) + { + } + + bool isVarargs() const + { + return isVarargs(static_cast<Kind>(kind)); + } + + CodeSpecializationKind specializationKind() const { return specializationKindFor(static_cast<Kind>(kind)); } + + JSFunction* calleeConstant() const; + + // Get the callee given a machine call frame to which this InlineCallFrame belongs. + JSFunction* calleeForCallFrame(ExecState*) const; + + CString inferredName() const; + CodeBlockHash hash() const; + CString hashAsStringIfPossible() const; + + void setStackOffset(signed offset) + { + stackOffset = offset; + RELEASE_ASSERT(static_cast<signed>(stackOffset) == offset); + } + + ptrdiff_t callerFrameOffset() const { return stackOffset * sizeof(Register) + CallFrame::callerFrameOffset(); } + ptrdiff_t returnPCOffset() const { return stackOffset * sizeof(Register) + CallFrame::returnPCOffset(); } + + bool isStrictMode() const { return baselineCodeBlock->isStrictMode(); } + + void dumpBriefFunctionInformation(PrintStream&) const; + void dump(PrintStream&) const; + void dumpInContext(PrintStream&, DumpContext*) const; + + MAKE_PRINT_METHOD(InlineCallFrame, dumpBriefFunctionInformation, briefFunctionInformation); + +}; + +inline CodeBlock* baselineCodeBlockForInlineCallFrame(InlineCallFrame* inlineCallFrame) +{ + RELEASE_ASSERT(inlineCallFrame); + return inlineCallFrame->baselineCodeBlock.get(); +} + +inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock) +{ + if (codeOrigin.inlineCallFrame) + return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame); + return baselineCodeBlock; +} + +template <typename Function> +inline void CodeOrigin::walkUpInlineStack(const Function& function) +{ + CodeOrigin codeOrigin = *this; + while (true) { + function(codeOrigin); + if (!codeOrigin.inlineCallFrame) + break; + codeOrigin = codeOrigin.inlineCallFrame->directCaller; + } +} + +} // namespace JSC + +namespace WTF { + +void printInternal(PrintStream&, JSC::InlineCallFrame::Kind); + +} // namespace WTF + +#endif // InlineCallFrame_h |