blob: db06fdf8e693db0d0e49aee7fb75349d969483cd [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_MacroAssembler_inl_h
#define jit_MacroAssembler_inl_h
#include "jit/MacroAssembler.h"
#if defined(JS_CODEGEN_X86)
# include "jit/x86/MacroAssembler-x86-inl.h"
#elif defined(JS_CODEGEN_X64)
# include "jit/x64/MacroAssembler-x64-inl.h"
#elif defined(JS_CODEGEN_ARM)
# include "jit/arm/MacroAssembler-arm-inl.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/MacroAssembler-arm64-inl.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/MacroAssembler-mips32-inl.h"
#elif defined(JS_CODEGEN_MIPS64)
# include "jit/mips64/MacroAssembler-mips64-inl.h"
#elif !defined(JS_CODEGEN_NONE)
# error "Unknown architecture!"
#endif
namespace js {
namespace jit {
//{{{ check_macroassembler_style
// ===============================================================
// Frame manipulation functions.
uint32_t
MacroAssembler::framePushed() const
{
return framePushed_;
}
void
MacroAssembler::setFramePushed(uint32_t framePushed)
{
framePushed_ = framePushed;
}
void
MacroAssembler::adjustFrame(int32_t value)
{
MOZ_ASSERT_IF(value < 0, framePushed_ >= uint32_t(-value));
setFramePushed(framePushed_ + value);
}
void
MacroAssembler::implicitPop(uint32_t bytes)
{
MOZ_ASSERT(bytes % sizeof(intptr_t) == 0);
MOZ_ASSERT(bytes <= INT32_MAX);
adjustFrame(-int32_t(bytes));
}
// ===============================================================
// Stack manipulation functions.
CodeOffset
MacroAssembler::PushWithPatch(ImmWord word)
{
framePushed_ += sizeof(word.value);
return pushWithPatch(word);
}
CodeOffset
MacroAssembler::PushWithPatch(ImmPtr imm)
{
return PushWithPatch(ImmWord(uintptr_t(imm.value)));
}
// ===============================================================
// Simple call functions.
void
MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg)
{
CodeOffset l = call(reg);
append(desc, l, framePushed());
}
void
MacroAssembler::call(const wasm::CallSiteDesc& desc, Label* label)
{
CodeOffset l = call(label);
append(desc, l, framePushed());
}
void
MacroAssembler::call(const wasm::CallSiteDesc& desc, AsmJSInternalCallee callee)
{
CodeOffset l = callWithPatch();
append(desc, l, framePushed(), callee.index);
}
// ===============================================================
// ABI function calls.
void
MacroAssembler::passABIArg(Register reg)
{
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
}
void
MacroAssembler::passABIArg(FloatRegister reg, MoveOp::Type type)
{
passABIArg(MoveOperand(reg), type);
}
template <typename T> void
MacroAssembler::callWithABI(const T& fun, MoveOp::Type result)
{
AutoProfilerCallInstrumentation profiler(*this);
callWithABINoProfiler(fun, result);
}
void
MacroAssembler::appendSignatureType(MoveOp::Type type)
{
#ifdef JS_SIMULATOR
signature_ <<= ArgType_Shift;
switch (type) {
case MoveOp::GENERAL: signature_ |= ArgType_General; break;
case MoveOp::DOUBLE: signature_ |= ArgType_Double; break;
case MoveOp::FLOAT32: signature_ |= ArgType_Float32; break;
default: MOZ_CRASH("Invalid argument type");
}
#endif
}
ABIFunctionType
MacroAssembler::signature() const
{
#ifdef JS_SIMULATOR
#ifdef DEBUG
switch (signature_) {
case Args_General0:
case Args_General1:
case Args_General2:
case Args_General3:
case Args_General4:
case Args_General5:
case Args_General6:
case Args_General7:
case Args_General8:
case Args_Double_None:
case Args_Int_Double:
case Args_Float32_Float32:
case Args_Double_Double:
case Args_Double_Int:
case Args_Double_DoubleInt:
case Args_Double_DoubleDouble:
case Args_Double_IntDouble:
case Args_Int_IntDouble:
case Args_Int_DoubleIntInt:
case Args_Int_IntDoubleIntInt:
case Args_Double_DoubleDoubleDouble:
case Args_Double_DoubleDoubleDoubleDouble:
break;
default:
MOZ_CRASH("Unexpected type");
}
#endif // DEBUG
return ABIFunctionType(signature_);
#else
// No simulator enabled.
MOZ_CRASH("Only available for making calls within a simulator.");
#endif
}
// ===============================================================
// Jit Frames.
uint32_t
MacroAssembler::callJitNoProfiler(Register callee)
{
#ifdef JS_USE_LINK_REGISTER
// The return address is pushed by the callee.
call(callee);
#else
callAndPushReturnAddress(callee);
#endif
return currentOffset();
}
uint32_t
MacroAssembler::callJit(Register callee)
{
AutoProfilerCallInstrumentation profiler(*this);
uint32_t ret = callJitNoProfiler(callee);
return ret;
}
uint32_t
MacroAssembler::callJit(JitCode* callee)
{
AutoProfilerCallInstrumentation profiler(*this);
call(callee);
return currentOffset();
}
void
MacroAssembler::makeFrameDescriptor(Register frameSizeReg, FrameType type)
{
// See JitFrames.h for a description of the frame descriptor format.
lshiftPtr(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
// The saved-frame bit is zero for new frames. See js::SavedStacks.
orPtr(Imm32(type), frameSizeReg);
}
void
MacroAssembler::pushStaticFrameDescriptor(FrameType type)
{
uint32_t descriptor = MakeFrameDescriptor(framePushed(), type);
Push(Imm32(descriptor));
}
void
MacroAssembler::PushCalleeToken(Register callee, bool constructing)
{
if (constructing) {
orPtr(Imm32(CalleeToken_FunctionConstructing), callee);
Push(callee);
andPtr(Imm32(uint32_t(CalleeTokenMask)), callee);
} else {
static_assert(CalleeToken_Function == 0, "Non-constructing call requires no tagging");
Push(callee);
}
}
void
MacroAssembler::loadFunctionFromCalleeToken(Address token, Register dest)
{
#ifdef DEBUG
Label ok;
loadPtr(token, dest);
andPtr(Imm32(uint32_t(~CalleeTokenMask)), dest);
branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_Function), &ok);
branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_FunctionConstructing), &ok);
assumeUnreachable("Unexpected CalleeToken tag");
bind(&ok);
#endif
loadPtr(token, dest);
andPtr(Imm32(uint32_t(CalleeTokenMask)), dest);
}
uint32_t
MacroAssembler::buildFakeExitFrame(Register scratch)
{
mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
pushStaticFrameDescriptor(JitFrame_IonJS);
uint32_t retAddr = pushFakeReturnAddress(scratch);
MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
return retAddr;
}
// ===============================================================
// Exit frame footer.
void
MacroAssembler::PushStubCode()
{
// Make sure that we do not erase an existing self-reference.
MOZ_ASSERT(!hasSelfReference());
selfReferencePatch_ = PushWithPatch(ImmWord(-1));
}
void
MacroAssembler::enterExitFrame(const VMFunction* f)
{
linkExitFrame();
// Push the JitCode pointer. (Keep the code alive, when on the stack)
PushStubCode();
// Push VMFunction pointer, to mark arguments.
Push(ImmPtr(f));
}
void
MacroAssembler::enterFakeExitFrame(enum ExitFrameTokenValues token)
{
linkExitFrame();
Push(Imm32(token));
Push(ImmPtr(nullptr));
}
void
MacroAssembler::enterFakeExitFrameForNative(bool isConstructing)
{
enterFakeExitFrame(isConstructing ? ConstructNativeExitFrameLayoutToken
: CallNativeExitFrameLayoutToken);
}
void
MacroAssembler::leaveExitFrame(size_t extraFrame)
{
freeStack(ExitFooterFrame::Size() + extraFrame);
}
bool
MacroAssembler::hasSelfReference() const
{
return selfReferencePatch_.bound();
}
//}}} check_macroassembler_style
// ===============================================================
void
MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun,
Register scratch, Label* label)
{
// 16-bit loads are slow and unaligned 32-bit loads may be too so
// perform an aligned 32-bit load and adjust the bitmask accordingly.
MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0);
MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
Address address(fun, JSFunction::offsetOfNargs());
int32_t mask = IMM32_16ADJ(JSFunction::FUNCTION_KIND_MASK);
int32_t bit = IMM32_16ADJ(kind << JSFunction::FUNCTION_KIND_SHIFT);
load32(address, scratch);
and32(Imm32(mask), scratch);
branch32(cond, scratch, Imm32(bit), label);
}
} // namespace jit
} // namespace js
#endif /* jit_MacroAssembler_inl_h */