blob: 4bf1d888be678a549d9066a5864de014272f4721 [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:
*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef asmjs_AsmJSFrameIterator_h
#define asmjs_AsmJSFrameIterator_h
#include <stdint.h>
#include "asmjs/Wasm.h"
#include "js/ProfilingFrameIterator.h"
class JSAtom;
namespace js {
class AsmJSActivation;
class AsmJSModule;
namespace jit { class MacroAssembler; class Label; }
namespace wasm { class CallSite; }
// Iterates over the frames of a single AsmJSActivation, called synchronously
// from C++ in the thread of the asm.js. The one exception is that this iterator
// may be called from the interrupt callback which may be called asynchronously
// from asm.js code; in this case, the backtrace may not be correct.
class AsmJSFrameIterator
{
const AsmJSModule* module_;
const wasm::CallSite* callsite_;
uint8_t* fp_;
// Really, a const AsmJSModule::CodeRange*, but no forward declarations of
// nested classes, so use void* to avoid pulling in all of AsmJSModule.h.
const void* codeRange_;
void settle();
public:
explicit AsmJSFrameIterator() : module_(nullptr) {}
explicit AsmJSFrameIterator(const AsmJSActivation& activation);
void operator++();
bool done() const { return !fp_; }
JSAtom* functionDisplayAtom() const;
unsigned computeLine(uint32_t* column) const;
};
// Iterates over the frames of a single AsmJSActivation, given an
// asynchrously-interrupted thread's state. If the activation's
// module is not in profiling mode, the activation is skipped.
class AsmJSProfilingFrameIterator
{
const AsmJSModule* module_;
uint8_t* callerFP_;
void* callerPC_;
void* stackAddress_;
wasm::ExitReason exitReason_;
// Really, a const AsmJSModule::CodeRange*, but no forward declarations of
// nested classes, so use void* to avoid pulling in all of AsmJSModule.h.
const void* codeRange_;
void initFromFP(const AsmJSActivation& activation);
public:
AsmJSProfilingFrameIterator() : codeRange_(nullptr) {}
explicit AsmJSProfilingFrameIterator(const AsmJSActivation& activation);
AsmJSProfilingFrameIterator(const AsmJSActivation& activation,
const JS::ProfilingFrameIterator::RegisterState& state);
void operator++();
bool done() const { return !codeRange_; }
void* stackAddress() const { MOZ_ASSERT(!done()); return stackAddress_; }
const char* label() const;
};
/******************************************************************************/
// Prologue/epilogue code generation.
struct AsmJSOffsets
{
MOZ_IMPLICIT AsmJSOffsets(uint32_t begin = 0,
uint32_t end = 0)
: begin(begin), end(end)
{}
// These define a [begin, end) contiguous range of instructions compiled
// into an AsmJSModule::CodeRange.
uint32_t begin;
uint32_t end;
};
struct AsmJSProfilingOffsets : AsmJSOffsets
{
MOZ_IMPLICIT AsmJSProfilingOffsets(uint32_t profilingReturn = 0)
: AsmJSOffsets(), profilingReturn(profilingReturn)
{}
// For CodeRanges with AsmJSProfilingOffsets, 'begin' is the offset of the
// profiling entry.
uint32_t profilingEntry() const { return begin; }
// The profiling return is the offset of the return instruction, which
// precedes the 'end' by a variable number of instructions due to
// out-of-line codegen.
uint32_t profilingReturn;
};
struct AsmJSFunctionOffsets : AsmJSProfilingOffsets
{
MOZ_IMPLICIT AsmJSFunctionOffsets(uint32_t nonProfilingEntry = 0,
uint32_t profilingJump = 0,
uint32_t profilingEpilogue = 0)
: AsmJSProfilingOffsets(),
nonProfilingEntry(nonProfilingEntry),
profilingJump(profilingJump),
profilingEpilogue(profilingEpilogue)
{}
// Function CodeRanges have an additional non-profiling entry that comes
// after the profiling entry and a non-profiling epilogue that comes before
// the profiling epilogue.
uint32_t nonProfilingEntry;
// When profiling is enabled, the 'nop' at offset 'profilingJump' is
// overwritten to be a jump to 'profilingEpilogue'.
uint32_t profilingJump;
uint32_t profilingEpilogue;
};
void
GenerateAsmJSExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, wasm::ExitReason reason,
AsmJSProfilingOffsets* offsets, jit::Label* maybeEntry = nullptr);
void
GenerateAsmJSExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, wasm::ExitReason reason,
AsmJSProfilingOffsets* offsets);
void
GenerateAsmJSFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed,
AsmJSFunctionOffsets* offsets);
void
GenerateAsmJSFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
AsmJSFunctionOffsets* offsets);
} // namespace js
#endif // asmjs_AsmJSFrameIterator_h