blob: 73d237e27191319eb8cd93177951a6eaab954eae [file]
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_MM_SHADOW_STACK
#define RUNTIME_MM_SHADOW_STACK
#include "Memory.h"
#include "Utils.hpp"
struct FrameOverlay;
struct ObjHeader;
namespace kotlin {
namespace mm {
// Accessing current stack as provided by K/N compiler. The compiler calls `EnterFrame` when
// it has allocated and zeroed stack space in the function prologue. And it calls `LeaveFrame` in
// the function epilogue (both for regular return and for exception unwinding).
//
// Stack scanning does not lock anything and so must either be done while the mutator is stopped (or is
// running code outside Kotlin), or by the mutator itself. So, in concurrent collection case, make sure
// to do as little as possible while scanning the stack to free the mutator as soon as possible.
//
// TODO: This is currently incompatible with stack-allocated objects. Fix it.
class ShadowStack : private Pinned {
public:
class Iterator {
public:
using difference_type = ptrdiff_t;
using value_type = ObjHeader*;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = std::forward_iterator_tag;
explicit Iterator(FrameOverlay* frame) noexcept : frame_(frame), object_(begin()), end_(end()) { Init(); }
ObjHeader*& operator*() noexcept { return *object_; }
Iterator& operator++() noexcept;
bool operator==(const Iterator& rhs) const noexcept { return frame_ == rhs.frame_ && object_ == rhs.object_; }
bool operator!=(const Iterator& rhs) const noexcept { return !(*this == rhs); }
private:
void Init() noexcept;
// TODO: This copies the approach in the old MM. Do we need to also traverse function parameters in the new MM?
ObjHeader** begin() noexcept { return frame_ ? reinterpret_cast<ObjHeader**>(frame_ + 1) + frame_->parameters : nullptr; }
ObjHeader** end() noexcept {
constexpr int kFrameOverlaySlots = sizeof(FrameOverlay) / sizeof(ObjHeader**);
return frame_ ? begin() + frame_->count - kFrameOverlaySlots - frame_->parameters : nullptr;
}
FrameOverlay* frame_;
ObjHeader** object_ = nullptr;
ObjHeader** end_ = nullptr;
};
void EnterFrame(ObjHeader** start, int parameters, int count) noexcept;
void LeaveFrame(ObjHeader** start, int parameters, int count) noexcept;
void SetCurrentFrame(ObjHeader** start) noexcept;
FrameOverlay* getCurrentFrame() noexcept;
ALWAYS_INLINE void checkCurrentFrame(FrameOverlay* frame) noexcept;
Iterator begin() noexcept { return Iterator(currentFrame_); }
Iterator end() noexcept { return Iterator(nullptr); }
private:
FrameOverlay* currentFrame_ = nullptr;
};
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_SHADOW_STACK