Commit dffaf33c authored by Rudi Chen's avatar Rudi Chen

Scan pointers used in inline caches and scan relocatable symbols.

parent 1c9ebd80
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Memory.h" #include "llvm/Support/Memory.h"
#include "asm_writing/assembler.h" #include "asm_writing/assembler.h"
...@@ -25,6 +26,9 @@ ...@@ -25,6 +26,9 @@
#include "core/common.h" #include "core/common.h"
#include "core/options.h" #include "core/options.h"
#include "core/types.h" #include "core/types.h"
#include "gc/gc.h"
#include "gc/heap.h"
#include "runtime/types.h"
namespace pyston { namespace pyston {
...@@ -82,7 +86,7 @@ uint8_t* ICSlotRewrite::getSlotStart() { ...@@ -82,7 +86,7 @@ uint8_t* ICSlotRewrite::getSlotStart() {
return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize(); return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize();
} }
void ICSlotRewrite::commit(CommitHook* hook) { void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) {
bool still_valid = true; bool still_valid = true;
for (int i = 0; i < dependencies.size(); i++) { for (int i = 0; i < dependencies.size(); i++) {
int orig_version = dependencies[i].second; int orig_version = dependencies[i].second;
...@@ -118,6 +122,8 @@ void ICSlotRewrite::commit(CommitHook* hook) { ...@@ -118,6 +122,8 @@ void ICSlotRewrite::commit(CommitHook* hook) {
// if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size); // if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size);
memcpy(slot_start, buf, ic->getSlotSize()); memcpy(slot_start, buf, ic->getSlotSize());
ic_entry->gc_references = std::move(gc_references);
ic->times_rewritten++; ic->times_rewritten++;
if (ic->times_rewritten == IC_MEGAMORPHIC_THRESHOLD) { if (ic->times_rewritten == IC_MEGAMORPHIC_THRESHOLD) {
...@@ -187,6 +193,25 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) { ...@@ -187,6 +193,25 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) {
return NULL; return NULL;
} }
// Keep track of all ICInfo(s) that we create because they contain pointers to Pyston heap objects
// that we have written into the generated code and we may need to scan those.
static llvm::DenseSet<ICInfo*> ics_list;
static llvm::DenseMap<void*, ICInfo*> ics_by_return_addr;
void registerGCTrackedICInfo(ICInfo* ic) {
#if MOVING_GC
assert(ics_list.count(ic) == 0);
ics_list.insert(ic);
#endif
}
void deregisterGCTrackedICInfo(ICInfo* ic) {
#if MOVING_GC
assert(ics_list.count(ic) == 1);
ics_list.erase(ic);
#endif
}
ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots, ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs, int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs,
assembler::GenericRegister return_register, TypeRecorder* type_recorder) assembler::GenericRegister return_register, TypeRecorder* type_recorder)
...@@ -207,9 +232,18 @@ ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, S ...@@ -207,9 +232,18 @@ ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, S
for (int i = 0; i < num_slots; i++) { for (int i = 0; i < num_slots; i++) {
slots.emplace_back(this, i); slots.emplace_back(this, i);
} }
#if MOVING_GC
assert(ics_list.count(this) == 0);
#endif
}
ICInfo::~ICInfo() {
#if MOVING_GC
assert(ics_list.count(this) == 0);
#endif
} }
static llvm::DenseMap<void*, ICInfo*> ics_by_return_addr;
std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr, std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr,
uint8_t* continue_addr, uint8_t* slowpath_rtn_addr, uint8_t* continue_addr, uint8_t* slowpath_rtn_addr,
const ICSetupInfo* ic, StackInfo stack_info, LiveOutSet live_outs) { const ICSetupInfo* ic, StackInfo stack_info, LiveOutSet live_outs) {
...@@ -251,14 +285,19 @@ std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* ...@@ -251,14 +285,19 @@ std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t*
ICInfo* icinfo = new ICInfo(start_addr, slowpath_rtn_addr, continue_addr, stack_info, ic->num_slots, ic->slot_size, ICInfo* icinfo = new ICInfo(start_addr, slowpath_rtn_addr, continue_addr, stack_info, ic->num_slots, ic->slot_size,
ic->getCallingConvention(), std::move(live_outs), return_register, ic->type_recorder); ic->getCallingConvention(), std::move(live_outs), return_register, ic->type_recorder);
assert(!ics_by_return_addr.count(slowpath_rtn_addr));
ics_by_return_addr[slowpath_rtn_addr] = icinfo; ics_by_return_addr[slowpath_rtn_addr] = icinfo;
registerGCTrackedICInfo(icinfo);
return std::unique_ptr<ICInfo>(icinfo); return std::unique_ptr<ICInfo>(icinfo);
} }
void deregisterCompiledPatchpoint(ICInfo* ic) { void deregisterCompiledPatchpoint(ICInfo* ic) {
assert(ics_by_return_addr.count(ic->slowpath_rtn_addr)); assert(ics_by_return_addr.count(ic->slowpath_rtn_addr));
ics_by_return_addr.erase(ic->slowpath_rtn_addr); ics_by_return_addr.erase(ic->slowpath_rtn_addr);
deregisterGCTrackedICInfo(ic);
} }
ICInfo* getICInfo(void* rtn_addr) { ICInfo* getICInfo(void* rtn_addr) {
...@@ -305,4 +344,12 @@ bool ICInfo::shouldAttempt() { ...@@ -305,4 +344,12 @@ bool ICInfo::shouldAttempt() {
bool ICInfo::isMegamorphic() { bool ICInfo::isMegamorphic() {
return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD; return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD;
} }
void ICInfo::visitGCReferences(gc::GCVisitor* v) {
for (const auto& p : ics_list) {
for (auto& slot : p->slots) {
v->visitNonRelocatableRange(&slot.gc_references[0], &slot.gc_references[slot.gc_references.size()]);
}
}
}
} }
...@@ -27,6 +27,10 @@ ...@@ -27,6 +27,10 @@
namespace pyston { namespace pyston {
namespace gc {
class GCVisitor;
}
class TypeRecorder; class TypeRecorder;
class ICInfo; class ICInfo;
...@@ -43,6 +47,8 @@ public: ...@@ -43,6 +47,8 @@ public:
int idx; // the index inside the ic int idx; // the index inside the ic
int num_inside; // the number of stack frames that are currently inside this slot int num_inside; // the number of stack frames that are currently inside this slot
std::vector<void*> gc_references;
void clear(); void clear();
}; };
...@@ -85,7 +91,7 @@ public: ...@@ -85,7 +91,7 @@ public:
void gc_visit(gc::GCVisitor* visitor); void gc_visit(gc::GCVisitor* visitor);
void addDependenceOn(ICInvalidator&); void addDependenceOn(ICInvalidator&);
void commit(CommitHook* hook); void commit(CommitHook* hook, std::vector<void*> gc_references);
void abort(); void abort();
const ICInfo* getICInfo() { return ic; } const ICInfo* getICInfo() { return ic; }
...@@ -124,6 +130,7 @@ public: ...@@ -124,6 +130,7 @@ public:
ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots, ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet live_outs, int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet live_outs,
assembler::GenericRegister return_register, TypeRecorder* type_recorder); assembler::GenericRegister return_register, TypeRecorder* type_recorder);
~ICInfo();
void* const start_addr, *const slowpath_rtn_addr, *const continue_addr; void* const start_addr, *const slowpath_rtn_addr, *const continue_addr;
int getSlotSize() { return slot_size; } int getSlotSize() { return slot_size; }
...@@ -142,8 +149,12 @@ public: ...@@ -142,8 +149,12 @@ public:
int percentBackedoff() const { return retry_backoff; } int percentBackedoff() const { return retry_backoff; }
friend class ICSlotRewrite; friend class ICSlotRewrite;
static void visitGCReferences(gc::GCVisitor* visitor);
}; };
void registerGCTrackedICInfo(ICInfo* ic);
void deregisterGCTrackedICInfo(ICInfo* ic);
class ICSetupInfo; class ICSetupInfo;
struct CompiledFunction; struct CompiledFunction;
std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr, std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr,
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "codegen/unwinding.h" #include "codegen/unwinding.h"
#include "core/common.h" #include "core/common.h"
#include "core/stats.h" #include "core/stats.h"
#include "gc/heap.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
...@@ -350,6 +351,7 @@ void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) { ...@@ -350,6 +351,7 @@ void RewriterVar::addAttrGuard(int offset, uint64_t val, bool negate) {
if (!attr_guards.insert(std::make_tuple(offset, val, negate)).second) if (!attr_guards.insert(std::make_tuple(offset, val, negate)).second)
return; // duplicate guard detected return; // duplicate guard detected
RewriterVar* val_var = rewriter->loadConst(val); RewriterVar* val_var = rewriter->loadConst(val);
rewriter->addAction([=]() { rewriter->_addAttrGuard(this, offset, val_var, negate); }, { this, val_var }, rewriter->addAction([=]() { rewriter->_addAttrGuard(this, offset, val_var, negate); }, { this, val_var },
ActionType::GUARD); ActionType::GUARD);
...@@ -717,6 +719,15 @@ void Rewriter::_trap() { ...@@ -717,6 +719,15 @@ void Rewriter::_trap() {
RewriterVar* Rewriter::loadConst(int64_t val, Location dest) { RewriterVar* Rewriter::loadConst(int64_t val, Location dest) {
STAT_TIMER(t0, "us_timer_rewriter", 10); STAT_TIMER(t0, "us_timer_rewriter", 10);
#if MOVING_GC
// Moving GCs need to know all existing references in the program, including those that end
// up in compiled code.
auto al = gc::global_heap.getAllocationFromInteriorPointer((void*)val);
if (al) {
gc_references.push_back(al->user_data);
}
#endif
for (auto& p : const_loader.consts) { for (auto& p : const_loader.consts) {
if (p.first != val) if (p.first != val)
continue; continue;
...@@ -1328,7 +1339,7 @@ void Rewriter::commit() { ...@@ -1328,7 +1339,7 @@ void Rewriter::commit() {
} }
#endif #endif
rewrite->commit(this); rewrite->commit(this, std::move(gc_references));
if (assembler->hasFailed()) { if (assembler->hasFailed()) {
on_assemblyfail(); on_assemblyfail();
......
...@@ -442,6 +442,7 @@ protected: ...@@ -442,6 +442,7 @@ protected:
} }
bool added_changing_action; bool added_changing_action;
bool marked_inside_ic; bool marked_inside_ic;
std::vector<void*> gc_references;
bool done_guarding; bool done_guarding;
bool isDoneGuarding() { bool isDoneGuarding() {
......
...@@ -624,6 +624,15 @@ int JitFragmentWriter::finishCompilation() { ...@@ -624,6 +624,15 @@ int JitFragmentWriter::finishCompilation() {
void* next_fragment_start = (uint8_t*)block->code + assembler->bytesWritten(); void* next_fragment_start = (uint8_t*)block->code + assembler->bytesWritten();
code_block.fragmentFinished(assembler->bytesWritten(), num_bytes_overlapping, next_fragment_start); code_block.fragmentFinished(assembler->bytesWritten(), num_bytes_overlapping, next_fragment_start);
#if MOVING_GC
// If JitFragmentWriter is destroyed, we don't necessarily want the ICInfo to be destroyed also,
// because it may contain a list of references to pointers in generated code that still exists
// and we need to keep those around.
// TODO: When should these ICInfo be freed?
registerGCTrackedICInfo(ic_info.release());
#endif
return num_bytes_exit; return num_bytes_exit;
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "codegen/codegen.h" #include "codegen/codegen.h"
#include "codegen/patchpoints.h" #include "codegen/patchpoints.h"
#include "core/common.h" #include "core/common.h"
#include "gc/gc.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
...@@ -97,7 +98,7 @@ llvm::Constant* getStringConstantPtr(llvm::StringRef str) { ...@@ -97,7 +98,7 @@ llvm::Constant* getStringConstantPtr(llvm::StringRef str) {
// It's slightly easier to emit them as integers (there are primitive integer constants but not pointer constants), // It's slightly easier to emit them as integers (there are primitive integer constants but not pointer constants),
// but doing it this way makes it clearer what's going on. // but doing it this way makes it clearer what's going on.
static llvm::StringMap<const void*> relocatable_syms; llvm::StringMap<const void*> relocatable_syms;
void clearRelocatableSymsMap() { void clearRelocatableSymsMap() {
relocatable_syms.clear(); relocatable_syms.clear();
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <string> #include <string>
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
namespace llvm { namespace llvm {
...@@ -25,6 +26,10 @@ class Function; ...@@ -25,6 +26,10 @@ class Function;
class Type; class Type;
} }
namespace gc {
class GCVisitor;
}
namespace pyston { namespace pyston {
llvm::Constant* embedRelocatablePtr(const void* addr, llvm::Type*, llvm::StringRef shared_name = llvm::StringRef()); llvm::Constant* embedRelocatablePtr(const void* addr, llvm::Type*, llvm::StringRef shared_name = llvm::StringRef());
...@@ -37,6 +42,8 @@ llvm::Constant* getNullPtr(llvm::Type* t); ...@@ -37,6 +42,8 @@ llvm::Constant* getNullPtr(llvm::Type* t);
void clearRelocatableSymsMap(); void clearRelocatableSymsMap();
const void* getValueOfRelocatableSym(const std::string& str); const void* getValueOfRelocatableSym(const std::string& str);
void visitRelocatableSymsMap(gc::GCVisitor* visitor);
void dumpPrettyIR(llvm::Function* f); void dumpPrettyIR(llvm::Function* f);
} }
......
...@@ -18,8 +18,10 @@ ...@@ -18,8 +18,10 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include "asm_writing/icinfo.h"
#include "codegen/ast_interpreter.h" #include "codegen/ast_interpreter.h"
#include "codegen/codegen.h" #include "codegen/codegen.h"
#include "codegen/irgen/util.h"
#include "core/common.h" #include "core/common.h"
#include "core/threading.h" #include "core/threading.h"
#include "core/types.h" #include "core/types.h"
...@@ -429,6 +431,11 @@ static void markRoots(GCVisitor& visitor) { ...@@ -429,6 +431,11 @@ static void markRoots(GCVisitor& visitor) {
for (auto weakref : weakrefs_needing_callback_list) { for (auto weakref : weakrefs_needing_callback_list) {
visitor.visit(weakref); visitor.visit(weakref);
} }
GC_TRACE_LOG("Looking at generated code pointers\n");
#if MOVING_GC
ICInfo::visitGCReferences(&visitor);
#endif
} }
static void finalizationOrderingFindReachable(Box* obj) { static void finalizationOrderingFindReachable(Box* obj) {
......
...@@ -86,6 +86,14 @@ public: ...@@ -86,6 +86,14 @@ public:
virtual void visitRedundantRange(void** start, void** end) {} virtual void visitRedundantRange(void** start, void** end) {}
virtual void visitPotentialRedundant(void* p) {} virtual void visitPotentialRedundant(void* p) {}
virtual void visitPotentialRangeRedundant(void* const* start, void* const* end) {} virtual void visitPotentialRangeRedundant(void* const* start, void* const* end) {}
// Visit pointers to objects that we know cannot be moved.
// This is often used to scan a pointer that's a copy of a pointer stored in a place that
// we cannot easily scanned (like generated code).
// This default to visitPotential for now (which also cannot be moved) but we may want to
// change that later for performance.
void visitNonRelocatable(void* p) { visitPotential(p); }
void visitNonRelocatableRange(void** start, void** end) { visitPotentialRange(start, end); }
}; };
enum class GCKind : uint8_t { enum class GCKind : uint8_t {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment