Commit cd11e1d5 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Make the GC-header managed by the GC

Previously the gc header had to be set and managed by the user of the GC,
which didn't make much sense.

Also took this opportunity to clean up a bunch of old cruft.

Also got rid of ObjectFlavors and AllocationKinds, in preference for
a GCKind which I think makes more sense.  Right now there are only three
different GCKinds, but I'm not sure if the previous AllocationKinds
should each get their own GCKind.
parent e891c285
......@@ -105,7 +105,9 @@ void Assembler::emitByte(uint8_t b) {
void Assembler::emitInt(int64_t n, int bytes) {
assert(bytes > 0 && bytes <= 8);
assert((-1L << (8 * bytes - 1)) <= n && n <= ((1L << (8 * bytes - 1)) - 1));
if (bytes < 8)
assert((-1L << (8 * bytes - 1)) <= n && n <= ((1L << (8 * bytes - 1)) - 1));
for (int i = 0; i < bytes; i++) {
emitByte(n & 0xff);
n >>= 8;
......
......@@ -67,7 +67,6 @@ struct GlobalState {
FunctionAddressRegistry func_addr_registry;
llvm::Type* llvm_value_type, *llvm_value_type_ptr, *llvm_value_type_ptr_ptr;
llvm::Type* llvm_class_type, *llvm_class_type_ptr;
llvm::Type* llvm_flavor_type, *llvm_flavor_type_ptr;
llvm::Type* llvm_opaque_type;
llvm::Type* llvm_str_type_ptr;
llvm::Type* llvm_clfunction_type_ptr, *llvm_closure_type_ptr, *llvm_generator_type_ptr;
......
......@@ -242,8 +242,11 @@ public:
virtual llvm::Value* makeClassCheck(IREmitter& emitter, ConcreteCompilerVariable* var, BoxedClass* cls) {
assert(var->getValue()->getType() == g.llvm_value_type_ptr);
// TODO this is brittle: directly embeds the position of the class object:
llvm::Value* cls_ptr = emitter.getBuilder()->CreateConstInBoundsGEP2_32(var->getValue(), 0, 1);
static_assert(offsetof(Box, cls) % sizeof(void*) == 0, "");
llvm::Value* cls_ptr
= emitter.getBuilder()->CreateConstInBoundsGEP2_32(var->getValue(), 0, offsetof(Box, cls) / sizeof(void*));
llvm::Value* cls_value = emitter.getBuilder()->CreateLoad(cls_ptr);
assert(cls_value->getType() == g.llvm_class_type_ptr);
llvm::Value* rtn = emitter.getBuilder()->CreateICmpEQ(cls_value, embedConstantPtr(cls, g.llvm_class_type_ptr));
......
......@@ -35,7 +35,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "core/util.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......
......@@ -49,8 +49,6 @@ private:
}
BoxedClass* getClassFromGV(GlobalVariable* gv) { return *(BoxedClass**)getGVAddr(gv); }
ObjectFlavor* getFlavorFromGV(GlobalVariable* gv) { return (ObjectFlavor*)getGVAddr(gv); }
void replaceUsesWithConstant(llvm::Value* v, uintptr_t val) {
if (isa<PointerType>(v->getType()))
v->replaceAllUsesWith(embedConstantPtr((void*)val, v->getType()));
......@@ -69,31 +67,6 @@ private:
return true;
}
bool handleFlavor(LoadInst* li, ConstantExpr* gepce) {
if (VERBOSITY("opt") >= 1) {
errs() << "\nFound this load of a flavor attr:\n" << *li << '\n';
}
GetElementPtrInst* gep = cast<GetElementPtrInst>(gepce->getAsInstruction());
APInt ap_offset(64, 0, true);
bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset);
delete gep;
assert(success);
int64_t offset = ap_offset.getSExtValue();
if (offset == offsetof(ObjectFlavor, kind_id)) {
ObjectFlavor* flavor = getFlavorFromGV(cast<GlobalVariable>(gepce->getOperand(0)));
replaceUsesWithConstant(li, flavor->kind_id);
return true;
} else {
ASSERT(0, "%ld", offset);
return false;
}
assert(0);
return false;
}
bool handleCls(LoadInst* li, GlobalVariable* gv) {
bool changed = true;
......@@ -190,9 +163,6 @@ public:
ConstantExpr* ce = dyn_cast<ConstantExpr>(li->getOperand(0));
// Not 100% sure what the isGEPWithNoNotionalOverIndexing() means, but
// at least it checks if it's a gep:
if (ce && ce->isGEPWithNoNotionalOverIndexing() && ce->getOperand(0)->getType() == g.llvm_flavor_type_ptr) {
changed = handleFlavor(li, ce);
}
GlobalVariable* gv = dyn_cast<GlobalVariable>(li->getOperand(0));
if (!gv)
......
......@@ -33,7 +33,6 @@
#include "core/threading.h"
#include "core/types.h"
#include "runtime/float.h"
#include "runtime/gc_runtime.h"
#include "runtime/generator.h"
#include "runtime/inline/boxing.h"
#include "runtime/int.h"
......@@ -129,10 +128,6 @@ void initGlobalFuncs(GlobalState& g) {
assert(g.llvm_class_type);
g.llvm_class_type_ptr = g.llvm_class_type->getPointerTo();
g.llvm_flavor_type = g.stdlib_module->getTypeByName("class.pyston::ObjectFlavor");
assert(g.llvm_flavor_type);
g.llvm_flavor_type_ptr = g.llvm_flavor_type->getPointerTo();
g.llvm_str_type_ptr = lookupFunction("boxStringPtr")->arg_begin()->getType();
// The LLVM vector type for the arguments that we pass to runtimeCall and related functions.
......
......@@ -71,37 +71,6 @@ public:
virtual void visitPotentialRange(void* const* start, void* const* end) = 0;
};
typedef int kindid_t;
class AllocationKind;
extern "C" kindid_t registerKind(const AllocationKind*);
class AllocationKind {
public:
#ifndef NDEBUG
static const int64_t COOKIE = 0x1234abcd0c00c1e;
const int64_t _cookie = COOKIE;
#endif
typedef void (*GCHandler)(GCVisitor*, void*);
GCHandler gc_handler;
typedef void (*FinalizationFunc)(void*);
FinalizationFunc finalizer;
const kindid_t kind_id;
public:
AllocationKind(GCHandler gc_handler, FinalizationFunc finalizer) __attribute__((visibility("default")))
: gc_handler(gc_handler), finalizer(finalizer), kind_id(registerKind(this)) {}
};
extern "C" const AllocationKind untracked_kind, conservative_kind;
class ObjectFlavor;
class ObjectFlavor : public AllocationKind {
public:
ObjectFlavor(GCHandler gc_handler, FinalizationFunc finalizer) __attribute__((visibility("default")))
: AllocationKind(gc_handler, finalizer) {}
};
namespace EffortLevel {
......@@ -302,56 +271,11 @@ EffortLevel::EffortLevel initialEffort();
typedef bool i1;
typedef int64_t i64;
extern "C" void* rt_alloc(size_t);
extern "C" void rt_free(void*);
extern "C" void* rt_realloc(void* ptr, size_t new_size);
extern "C" const std::string* getNameOfClass(BoxedClass* cls);
class Rewriter;
class RewriterVar;
struct GCObjectHeader {
kindid_t kind_id;
uint16_t kind_data; // this part of the header is free for the kind to set as it wishes.
uint8_t gc_flags;
constexpr GCObjectHeader(const AllocationKind* kind) : kind_id(kind->kind_id), kind_data(0), gc_flags(0) {}
};
static_assert(sizeof(GCObjectHeader) <= sizeof(void*), "");
class GCObject {
public:
GCObjectHeader gc_header;
constexpr GCObject(const AllocationKind* kind) : gc_header(kind) {}
void* operator new(size_t size) __attribute__((visibility("default"))) { return rt_alloc(size); }
void operator delete(void* ptr) __attribute__((visibility("default"))) { rt_free(ptr); }
};
extern "C" const AllocationKind hc_kind;
class HiddenClass : public GCObject {
private:
HiddenClass() : GCObject(&hc_kind) {}
HiddenClass(const HiddenClass* parent) : GCObject(&hc_kind), attr_offsets(parent->attr_offsets) {}
public:
static HiddenClass* getRoot();
std::unordered_map<std::string, int> attr_offsets;
std::unordered_map<std::string, HiddenClass*> children;
HiddenClass* getOrMakeChild(const std::string& attr);
int getOffset(const std::string& attr) {
std::unordered_map<std::string, int>::iterator it = attr_offsets.find(attr);
if (it == attr_offsets.end())
return -1;
return it->second;
}
HiddenClass* delAttrToMakeHC(const std::string& attr);
};
class Box;
class BoxIterator {
public:
......@@ -375,6 +299,43 @@ private:
Box* value;
};
namespace gc {
enum class GCKind : uint8_t {
PYTHON = 1,
CONSERVATIVE = 2,
UNTRACKED = 3,
};
void* gc_alloc(size_t nbytes, GCKind kind);
}
class PythonGCObject {
public:
void* operator new(size_t size) __attribute__((visibility("default"))) {
return gc_alloc(size, gc::GCKind::PYTHON);
}
void operator delete(void* ptr) __attribute__((visibility("default"))) { abort(); }
};
class ConservativeGCObject {
public:
void* operator new(size_t size) __attribute__((visibility("default"))) {
return gc_alloc(size, gc::GCKind::CONSERVATIVE);
}
void operator delete(void* ptr) __attribute__((visibility("default"))) { abort(); }
};
class UntrackedGCObject {
public:
void* operator new(size_t size) __attribute__((visibility("default"))) {
return gc_alloc(size, gc::GCKind::UNTRACKED);
}
void operator delete(void* ptr) __attribute__((visibility("default"))) { abort(); }
};
class HiddenClass;
extern HiddenClass* root_hcls;
class SetattrRewriteArgs;
class GetattrRewriteArgs;
......@@ -382,23 +343,23 @@ class DelattrRewriteArgs;
struct HCAttrs {
public:
struct AttrList : GCObject {
struct AttrList : ConservativeGCObject {
Box* attrs[0];
};
HiddenClass* hcls;
AttrList* attr_list;
HCAttrs() : hcls(HiddenClass::getRoot()), attr_list(nullptr) {}
HCAttrs() : hcls(root_hcls), attr_list(nullptr) {}
};
class Box : public GCObject {
class Box : public PythonGCObject {
public:
BoxedClass* cls;
llvm::iterator_range<BoxIterator> pyElements();
Box(const ObjectFlavor* flavor, BoxedClass* cls);
Box(BoxedClass* cls);
HCAttrs* getAttrsPtr();
......@@ -412,6 +373,7 @@ public:
Box* getattr(const std::string& attr) { return getattr(attr, NULL); }
void delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args);
};
extern "C" const std::string* getTypeName(Box* o);
......@@ -429,6 +391,9 @@ public:
// Is NULL iff this is object_cls
BoxedClass* const base;
typedef void (*gcvisit_func)(GCVisitor*, Box*);
gcvisit_func gc_visit;
// Offset of the HCAttrs object or 0 if there are no hcattrs.
// Analogous to tp_dictoffset
const int attrs_offset;
......@@ -450,7 +415,7 @@ public:
// will need to update this once we support tp_getattr-style overriding:
bool hasGenericGetattr() { return true; }
BoxedClass(BoxedClass* base, int attrs_offset, int instance_size, bool is_user_defined);
BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size, bool is_user_defined);
void freeze() {
assert(!is_constant);
is_constant = true;
......
......@@ -54,17 +54,15 @@ StaticRootHandle::~StaticRootHandle() {
getRootHandles()->erase(this);
}
bool TraceStackGCVisitor::isValid(void* p) {
return global_heap.getAllocationFromInteriorPointer(p);
}
inline void TraceStackGCVisitor::_visit(void* p) {
assert(isValid(p));
stack->push(p);
bool TraceStackGCVisitor::isValid(void* p) {
return global_heap.getAllocationFromInteriorPointer(p) != NULL;
}
void TraceStackGCVisitor::visit(void* p) {
_visit(p);
assert(global_heap.getAllocationFromInteriorPointer(p)->user_data == p);
stack->push(p);
}
void TraceStackGCVisitor::visitRange(void* const* start, void* const* end) {
......@@ -79,9 +77,9 @@ void TraceStackGCVisitor::visitRange(void* const* start, void* const* end) {
}
void TraceStackGCVisitor::visitPotential(void* p) {
void* a = global_heap.getAllocationFromInteriorPointer(p);
GCAllocation* a = global_heap.getAllocationFromInteriorPointer(p);
if (a) {
visit(a);
visit(a->user_data);
}
}
......@@ -92,19 +90,6 @@ void TraceStackGCVisitor::visitPotentialRange(void* const* start, void* const* e
}
}
#define MAX_KINDS 1024
#define KIND_OFFSET 0x111
static kindid_t num_kinds = 0;
static AllocationKind::GCHandler handlers[MAX_KINDS];
extern "C" kindid_t registerKind(const AllocationKind* kind) {
assert(kind == &untracked_kind || kind->gc_handler);
assert(num_kinds < MAX_KINDS);
assert(handlers[num_kinds] == NULL);
handlers[num_kinds] = kind->gc_handler;
return KIND_OFFSET + num_kinds++;
}
static void markPhase() {
#ifndef NVALGRIND
// Have valgrind close its eyes while we do the conservative stack and data scanning,
......@@ -124,37 +109,37 @@ static void markPhase() {
// if (VERBOSITY()) printf("Found %d roots\n", stack.size());
while (void* p = stack.pop()) {
assert(((intptr_t)p) % 8 == 0);
GCObjectHeader* header = headerFromObject(p);
GCAllocation* al = GCAllocation::fromUserData(p);
if (isMarked(header)) {
if (isMarked(al)) {
continue;
}
// printf("Marking + scanning %p\n", p);
setMark(header);
setMark(al);
// is being made
if (header->kind_id == 0)
GCKind kind_id = al->kind_id;
if (kind_id == GCKind::UNTRACKED) {
continue;
ASSERT(KIND_OFFSET <= header->kind_id && header->kind_id < KIND_OFFSET + num_kinds, "%p %d", header,
header->kind_id);
if (header->kind_id == untracked_kind.kind_id)
continue;
// ASSERT(kind->_cookie == AllocationKind::COOKIE, "%lx %lx", kind->_cookie, AllocationKind::COOKIE);
// AllocationKind::GCHandler gcf = kind->gc_handler;
AllocationKind::GCHandler gcf = handlers[header->kind_id - KIND_OFFSET];
assert(gcf);
// if (!gcf) {
// std::string name = g.func_addr_registry.getFuncNameAtAddress((void*)kind, true);
// ASSERT(gcf, "%p %s", kind, name.c_str());
//}
gcf(&visitor, p);
} else if (kind_id == GCKind::CONSERVATIVE) {
uint32_t bytes = al->kind_data;
visitor.visitPotentialRange((void**)p, (void**)((char*)p + bytes));
} else if (kind_id == GCKind::PYTHON) {
Box* b = reinterpret_cast<Box*>(p);
BoxedClass* cls = b->cls;
if (cls) {
// The cls can be NULL since we use 'new' to construct them.
// An arbitrary amount of stuff can happen between the 'new' and
// the call to the constructor (ie the args get evaluated), which
// can trigger a collection.
ASSERT(cls->gc_visit, "%s", getTypeName(b)->c_str());
cls->gc_visit(&visitor, b);
}
} else {
RELEASE_ASSERT(0, "Unhandled kind: %d", (int)kind_id);
}
}
#ifndef NVALGRIND
......
......@@ -22,22 +22,6 @@
namespace pyston {
namespace gc {
#define MARK_BIT 0x1
inline void setMark(GCObjectHeader* header) {
header->gc_flags |= MARK_BIT;
}
inline void clearMark(GCObjectHeader* header) {
header->gc_flags &= ~MARK_BIT;
}
inline bool isMarked(GCObjectHeader* header) {
return (header->gc_flags & MARK_BIT) != 0;
}
#undef MARK_BIT
class TraceStack {
private:
std::vector<void*> v;
......@@ -65,12 +49,11 @@ class TraceStackGCVisitor : public GCVisitor {
private:
bool isValid(void* p);
void _visit(void* p);
public:
TraceStack* stack;
TraceStackGCVisitor(TraceStack* stack) : stack(stack) {}
// These all work on *user* pointers, ie pointers to the user_data section of GCAllocations
void visit(void* p) override;
void visitRange(void* const* start, void* const* end) override;
void visitPotential(void* p) override;
......
......@@ -27,8 +27,9 @@
namespace pyston {
namespace gc {
inline void* gc_alloc(size_t bytes) __attribute__((visibility("default")));
inline void* gc_alloc(size_t bytes) {
inline void* gc_alloc(size_t bytes, GCKind kind_id) __attribute__((visibility("default")));
inline void* gc_alloc(size_t bytes, GCKind kind_id) {
bytes += sizeof(GCAllocation);
#ifndef NVALGRIND
// Adding a redzone will confuse the allocator, so disable it for now.
......@@ -37,19 +38,33 @@ inline void* gc_alloc(size_t bytes) {
// valgrind is actively running, but I think it's better to just always turn them on.
// They're broken and have 0 size anyway.
#define ENABLE_REDZONES 1
void* r;
if (ENABLE_REDZONES)
bytes += REDZONE_SIZE * 2;
#endif
GCAllocation* alloc = global_heap.alloc(bytes);
alloc->kind_id = kind_id;
alloc->gc_flags = 0;
if (kind_id == GCKind::CONSERVATIVE) {
assert(bytes < (1 << 31));
alloc->kind_data = bytes;
}
void* r = alloc->user_data;
#ifndef NVALGRIND
if (ENABLE_REDZONES) {
void* base = global_heap.alloc(bytes + REDZONE_SIZE * 2);
r = ((char*)base) + REDZONE_SIZE;
// printf("alloc base = %p\n", base);
} else {
r = global_heap.alloc(bytes);
r = ((char*)r) + REDZONE_SIZE;
}
VALGRIND_MALLOCLIKE_BLOCK(r, bytes, REDZONE_SIZE, false);
#else
void* r = global_heap.alloc(bytes);
#endif
// TODO This doesn't belong here (probably in PythonGCObject?)...
if (kind_id == GCKind::PYTHON) {
((Box*)r)->cls = NULL;
}
#ifndef NDEBUG
// I think I have a suspicion: the gc will see the constant and treat it as a
// root. So instead, shift to hide the pointer
......@@ -68,21 +83,23 @@ inline void* gc_alloc(size_t bytes) {
inline void* gc_realloc(void* ptr, size_t bytes) __attribute__((visibility("default")));
inline void* gc_realloc(void* ptr, size_t bytes) {
bytes += sizeof(GCAllocation);
#ifndef NVALGRIND
void* rtn;
if (ENABLE_REDZONES) {
void* base = (char*)ptr - REDZONE_SIZE;
void* rtn_base = global_heap.realloc(base, bytes + 2 * REDZONE_SIZE);
void* rtn_base = global_heap.realloc(GCAllocation::fromUserData(base), bytes + 2 * REDZONE_SIZE)->user_data;
rtn = (char*)rtn_base + REDZONE_SIZE;
} else {
rtn = global_heap.realloc(ptr, bytes);
rtn = global_heap.realloc(GCAllocation::fromUserData(ptr), bytes)->user_data;
}
VALGRIND_FREELIKE_BLOCK(ptr, REDZONE_SIZE);
VALGRIND_MALLOCLIKE_BLOCK(rtn, bytes, REDZONE_SIZE, true);
return rtn;
#else
return global_heap.realloc(ptr, bytes);
return global_heap.realloc(GCAllocation::fromUserData(ptr), bytes)->user_data;
#endif
}
......@@ -91,13 +108,13 @@ inline void gc_free(void* ptr) {
#ifndef NVALGRIND
if (ENABLE_REDZONES) {
void* base = (char*)ptr - REDZONE_SIZE;
global_heap.free(base);
global_heap.free(GCAllocation::fromUserData(base));
} else {
global_heap.free(ptr);
global_heap.free(GCAllocation::fromUserData(ptr));
}
VALGRIND_FREELIKE_BLOCK(ptr, REDZONE_SIZE);
#else
global_heap.free(ptr);
global_heap.free(GCAllocation::fromUserData(ptr));
#endif
}
}
......
......@@ -83,13 +83,13 @@ public:
bool contains(void* addr) { return start <= addr && addr < cur; }
};
Arena small_arena((void*)0x1270000000L);
Arena large_arena((void*)0x2270000000L);
static Arena small_arena((void*)0x1270000000L);
static Arena large_arena((void*)0x2270000000L);
struct LargeObj {
LargeObj* next, **prev;
size_t obj_size;
char data[0];
GCAllocation data[0];
int mmap_size() {
size_t total_size = obj_size + sizeof(LargeObj);
......@@ -99,14 +99,14 @@ struct LargeObj {
int capacity() { return mmap_size() - sizeof(LargeObj); }
static LargeObj* fromPointer(void* ptr) {
char* rtn = (char*)ptr + ((char*)NULL - ((LargeObj*)(NULL))->data);
static LargeObj* fromAllocation(GCAllocation* alloc) {
char* rtn = (char*)alloc - offsetof(LargeObj, data);
assert((uintptr_t)rtn % PAGE_SIZE == 0);
return reinterpret_cast<LargeObj*>(rtn);
}
};
void* Heap::allocLarge(size_t size) {
GCAllocation* Heap::allocLarge(size_t size) {
_collectIfNeeded(size);
LOCK_REGION(lock);
......@@ -122,7 +122,7 @@ void* Heap::allocLarge(size_t size) {
rtn->prev = &large_head;
large_head = rtn;
return &rtn->data;
return rtn->data;
}
static Block* alloc_block(uint64_t size, Block** prev) {
......@@ -197,7 +197,7 @@ Heap::ThreadBlockCache::~ThreadBlockCache() {
}
}
static void* allocFromBlock(Block* b) {
static GCAllocation* allocFromBlock(Block* b) {
int i = 0;
uint64_t mask = 0;
for (; i < BITFIELD_ELTS; i++) {
......@@ -220,7 +220,7 @@ static void* allocFromBlock(Block* b) {
int idx = first + i * 64;
void* rtn = &b->atoms[idx];
return rtn;
return reinterpret_cast<GCAllocation*>(rtn);
}
static Block* claimBlock(size_t rounded_size, Block** free_head) {
......@@ -233,7 +233,7 @@ static Block* claimBlock(size_t rounded_size, Block** free_head) {
return alloc_block(rounded_size, NULL);
}
void* Heap::allocSmall(size_t rounded_size, int bucket_idx) {
GCAllocation* Heap::allocSmall(size_t rounded_size, int bucket_idx) {
_collectIfNeeded(rounded_size);
Block** free_head = &heads[bucket_idx];
......@@ -252,7 +252,7 @@ void* Heap::allocSmall(size_t rounded_size, int bucket_idx) {
while (true) {
while (Block* cache_block = *cache_head) {
void* rtn = allocFromBlock(cache_block);
GCAllocation* rtn = allocFromBlock(cache_block);
if (rtn)
return rtn;
......@@ -280,11 +280,11 @@ void* Heap::allocSmall(size_t rounded_size, int bucket_idx) {
}
}
void _freeFrom(void* ptr, Block* b) {
assert(b == Block::forPointer(ptr));
void _freeFrom(GCAllocation* alloc, Block* b) {
assert(b == Block::forPointer(alloc));
size_t size = b->size;
int offset = (char*)ptr - (char*)b;
int offset = (char*)alloc - (char*)b;
assert(offset % size == 0);
int atom_idx = offset / ATOM_SIZE;
......@@ -308,56 +308,56 @@ static void _freeLargeObj(LargeObj* lobj) {
assert(r == 0);
}
void Heap::free(void* ptr) {
if (large_arena.contains(ptr)) {
LargeObj* lobj = LargeObj::fromPointer(ptr);
void Heap::free(GCAllocation* al) {
if (large_arena.contains(al)) {
LargeObj* lobj = LargeObj::fromAllocation(al);
_freeLargeObj(lobj);
return;
}
assert(small_arena.contains(ptr));
Block* b = Block::forPointer(ptr);
_freeFrom(ptr, b);
assert(small_arena.contains(al));
Block* b = Block::forPointer(al);
_freeFrom(al, b);
}
void* Heap::realloc(void* ptr, size_t bytes) {
if (large_arena.contains(ptr)) {
LargeObj* lobj = LargeObj::fromPointer(ptr);
GCAllocation* Heap::realloc(GCAllocation* al, size_t bytes) {
if (large_arena.contains(al)) {
LargeObj* lobj = LargeObj::fromAllocation(al);
int capacity = lobj->capacity();
if (capacity >= bytes && capacity < bytes * 2)
return ptr;
return al;
void* rtn = alloc(bytes);
memcpy(rtn, ptr, std::min(bytes, lobj->obj_size));
GCAllocation* rtn = alloc(bytes);
memcpy(rtn, al, std::min(bytes, lobj->obj_size));
_freeLargeObj(lobj);
return rtn;
}
assert(small_arena.contains(ptr));
Block* b = Block::forPointer(ptr);
assert(small_arena.contains(al));
Block* b = Block::forPointer(al);
size_t size = b->size;
if (size >= bytes && size < bytes * 2)
return ptr;
return al;
void* rtn = alloc(bytes);
GCAllocation* rtn = alloc(bytes);
#ifndef NVALGRIND
VALGRIND_DISABLE_ERROR_REPORTING;
memcpy(rtn, ptr, std::min(bytes, size));
memcpy(rtn, al, std::min(bytes, size));
VALGRIND_ENABLE_ERROR_REPORTING;
#else
memcpy(rtn, ptr, std::min(bytes, size));
memcpy(rtn, al, std::min(bytes, size));
#endif
_freeFrom(ptr, b);
_freeFrom(al, b);
return rtn;
}
void* Heap::getAllocationFromInteriorPointer(void* ptr) {
GCAllocation* Heap::getAllocationFromInteriorPointer(void* ptr) {
if (large_arena.contains(ptr)) {
LargeObj* cur = large_head;
while (cur) {
......@@ -387,7 +387,7 @@ void* Heap::getAllocationFromInteriorPointer(void* ptr) {
if (b->isfree[bitmap_idx] & mask)
return NULL;
return &b->atoms[atom_idx];
return reinterpret_cast<GCAllocation*>(&b->atoms[atom_idx]);
}
static Block** freeChain(Block** head) {
......@@ -406,11 +406,14 @@ static Block** freeChain(Block** head) {
continue;
void* p = &b->atoms[atom_idx];
GCObjectHeader* header = headerFromObject(p);
GCAllocation* al = reinterpret_cast<GCAllocation*>(p);
if (isMarked(header)) {
clearMark(header);
if (isMarked(al)) {
clearMark(al);
} else {
if (VERBOSITY() >= 2)
printf("Freeing %p\n", al->user_data);
// assert(p != (void*)0x127000d960); // the main module
b->isfree[bitmap_idx] |= mask;
}
......@@ -464,13 +467,12 @@ void Heap::freeUnmarked() {
LargeObj* cur = large_head;
while (cur) {
void* p = cur->data;
GCObjectHeader* header = headerFromObject(p);
if (isMarked(header)) {
clearMark(header);
GCAllocation* al = cur->data;
if (isMarked(al)) {
clearMark(al);
} else {
if (VERBOSITY() >= 2)
printf("Freeing %p\n", p);
printf("Freeing %p\n", al->user_data);
*cur->prev = cur->next;
if (cur->next)
......
......@@ -15,6 +15,7 @@
#ifndef PYSTON_GC_HEAP_H
#define PYSTON_GC_HEAP_H
#include <cstddef>
#include <cstdint>
#include "core/common.h"
......@@ -23,14 +24,41 @@
namespace pyston {
namespace gc {
inline GCObjectHeader* headerFromObject(void* obj) {
#ifndef NVALGRIND
return static_cast<GCObjectHeader*>((void*)((char*)obj + 0));
#else
return static_cast<GCObjectHeader*>(obj);
#endif
typedef uint8_t kindid_t;
struct GCAllocation {
unsigned int gc_flags : 8;
GCKind kind_id : 8;
unsigned int _reserved1 : 16;
unsigned int kind_data : 32;
char user_data[0];
static GCAllocation* fromUserData(void* user_data) {
char* d = reinterpret_cast<char*>(user_data);
return reinterpret_cast<GCAllocation*>(d - offsetof(GCAllocation, user_data));
}
};
static_assert(sizeof(GCAllocation) <= sizeof(void*),
"we should try to make sure the gc header is word-sized or smaller");
#define MARK_BIT 0x1
inline void setMark(GCAllocation* header) {
header->gc_flags |= MARK_BIT;
}
inline void clearMark(GCAllocation* header) {
header->gc_flags &= ~MARK_BIT;
}
inline bool isMarked(GCAllocation* header) {
return (header->gc_flags & MARK_BIT) != 0;
}
#undef MARK_BIT
#define BLOCK_SIZE (4 * 4096)
#define ATOM_SIZE 16
static_assert(BLOCK_SIZE % ATOM_SIZE == 0, "");
......@@ -80,8 +108,8 @@ private:
Block* full_heads[NUM_BUCKETS];
LargeObj* large_head = NULL;
void* allocSmall(size_t rounded_size, int bucket_idx);
void* allocLarge(size_t bytes);
GCAllocation* allocSmall(size_t rounded_size, int bucket_idx);
GCAllocation* allocLarge(size_t bytes);
// DS_DEFINE_MUTEX(lock);
DS_DEFINE_SPINLOCK(lock);
......@@ -104,10 +132,10 @@ private:
public:
Heap() : thread_caches(this) {}
void* realloc(void* ptr, size_t bytes);
GCAllocation* realloc(GCAllocation* alloc, size_t bytes);
void* alloc(size_t bytes) {
void* rtn;
GCAllocation* alloc(size_t bytes) {
GCAllocation* rtn;
// assert(bytes >= 16);
if (bytes <= 16)
rtn = allocSmall(16, 0);
......@@ -125,16 +153,13 @@ public:
}
}
// assert(rtn);
GCObjectHeader* header = headerFromObject(rtn);
*reinterpret_cast<intptr_t*>(header) = 0;
return rtn;
}
void free(void* ptr);
void free(GCAllocation* alloc);
// not thread safe:
void* getAllocationFromInteriorPointer(void* ptr);
GCAllocation* getAllocationFromInteriorPointer(void* ptr);
// not thread safe:
void freeUnmarked();
};
......
......@@ -16,7 +16,6 @@
#include "core/common.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......
......@@ -16,7 +16,6 @@
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
......
......@@ -20,7 +20,6 @@
#include "core/ast.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/xrange.h"
#include "runtime/list.h"
#include "runtime/long.h"
......@@ -392,7 +391,6 @@ Box* zip2(Box* container1, Box* container2) {
return rtn;
}
extern "C" const ObjectFlavor notimplemented_flavor(&boxGCHandler, NULL);
BoxedClass* notimplemented_cls;
BoxedModule* builtins_module;
......@@ -401,7 +399,6 @@ BoxedClass* Exception, *AssertionError, *AttributeError, *GeneratorExit, *TypeEr
*IOError, *OSError, *ZeroDivisionError, *ValueError, *UnboundLocalError, *RuntimeError, *ImportError,
*StopIteration, *Warning, *SyntaxError;
const ObjectFlavor exception_flavor(&boxGCHandler, NULL);
Box* exceptionNew1(BoxedClass* cls) {
return exceptionNew2(cls, boxStrConstant(""));
}
......@@ -409,7 +406,7 @@ Box* exceptionNew1(BoxedClass* cls) {
class BoxedException : public Box {
public:
HCAttrs attrs;
BoxedException(BoxedClass* cls) : Box(&exception_flavor, cls) {}
BoxedException(BoxedClass* cls) : Box(cls) {}
};
Box* exceptionNew2(BoxedClass* cls, Box* message) {
......@@ -441,7 +438,7 @@ Box* exceptionRepr(Box* b) {
}
static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name) {
BoxedClass* cls = new BoxedClass(base, offsetof(BoxedException, attrs), sizeof(BoxedException), false);
BoxedClass* cls = new BoxedClass(base, NULL, offsetof(BoxedException, attrs), sizeof(BoxedException), false);
cls->giveAttr("__name__", boxStrConstant(name));
// TODO these should be on the base Exception class:
......@@ -455,14 +452,13 @@ static BoxedClass* makeBuiltinException(BoxedClass* base, const char* name) {
}
BoxedClass* enumerate_cls;
extern const ObjectFlavor enumerate_flavor;
class BoxedEnumerate : public Box {
private:
Box* iterator;
int64_t idx;
public:
BoxedEnumerate(Box* iterator, int64_t idx) : Box(&enumerate_flavor, enumerate_cls), iterator(iterator), idx(idx) {}
BoxedEnumerate(Box* iterator, int64_t idx) : Box(enumerate_cls), iterator(iterator), idx(idx) {}
static Box* new_(Box* cls, Box* obj, Box* start) {
RELEASE_ASSERT(cls == enumerate_cls, "");
......@@ -508,25 +504,24 @@ public:
return r;
}
static void gcHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
static void gcHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedEnumerate* it = (BoxedEnumerate*)p;
BoxedEnumerate* it = (BoxedEnumerate*)b;
v->visit(it->iterator);
}
};
const ObjectFlavor enumerate_flavor(&BoxedEnumerate::gcHandler, NULL);
void setupBuiltins() {
builtins_module = createModule("__builtin__", "__builtin__");
builtins_module->giveAttr("None", None);
notimplemented_cls = new BoxedClass(object_cls, 0, sizeof(Box), false);
notimplemented_cls = new BoxedClass(object_cls, NULL, 0, sizeof(Box), false);
notimplemented_cls->giveAttr("__name__", boxStrConstant("NotImplementedType"));
notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, STR, 1)));
notimplemented_cls->freeze();
NotImplemented = new Box(&notimplemented_flavor, notimplemented_cls);
NotImplemented = new Box(notimplemented_cls);
gc::registerStaticRootObj(NotImplemented);
builtins_module->giveAttr("NotImplemented", NotImplemented);
......@@ -598,7 +593,7 @@ void setupBuiltins() {
builtins_module->giveAttr("issubclass", issubclass_obj);
enumerate_cls = new BoxedClass(object_cls, 0, sizeof(BoxedEnumerate), false);
enumerate_cls = new BoxedClass(object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate), false);
enumerate_cls->giveAttr("__name__", boxStrConstant("enumerate"));
enumerate_cls->giveAttr(
"__new__",
......
......@@ -16,7 +16,6 @@
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
......
......@@ -17,7 +17,6 @@
#include "codegen/compvars.h"
#include "core/types.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
......
......@@ -16,7 +16,6 @@
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
......
......@@ -17,7 +17,6 @@
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/int.h"
#include "runtime/types.h"
......
......@@ -20,7 +20,6 @@
#include "codegen/compvars.h"
#include "core/threading.h"
#include "core/types.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......
......@@ -27,7 +27,6 @@ namespace pyston {
static BoxedModule* test_module = NULL;
extern "C" const ObjectFlavor capifunc_flavor(&boxGCHandler, NULL);
BoxedClass* capifunc_cls;
class BoxedCApiFunction : public Box {
private:
......@@ -35,8 +34,7 @@ private:
PyCFunction func;
public:
BoxedCApiFunction(const char* name, PyCFunction func)
: Box(&capifunc_flavor, capifunc_cls), name(name), func(func) {}
BoxedCApiFunction(const char* name, PyCFunction func) : Box(capifunc_cls), name(name), func(func) {}
static BoxedString* __repr__(BoxedCApiFunction* self) {
assert(self->cls == capifunc_cls);
......@@ -124,7 +122,7 @@ BoxedModule* getTestModule() {
}
void setupCAPI() {
capifunc_cls = new BoxedClass(object_cls, 0, sizeof(BoxedCApiFunction), false);
capifunc_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedCApiFunction), false);
capifunc_cls->giveAttr("__name__", boxStrConstant("capifunc"));
capifunc_cls->giveAttr("__repr__",
......
......@@ -19,7 +19,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -165,16 +164,15 @@ extern "C" Box* dictNew(Box* _cls) {
}
BoxedClass* dict_iterator_cls = NULL;
extern "C" void dictIteratorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
BoxedDictIterator* it = (BoxedDictIterator*)p;
extern "C" void dictIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedDictIterator* it = static_cast<BoxedDictIterator*>(b);
v->visit(it->d);
}
extern "C" const ObjectFlavor dict_iterator_flavor(&dictIteratorGCHandler, NULL);
void setupDict() {
dict_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedDict), false);
dict_iterator_cls = new BoxedClass(object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false);
dict_cls->giveAttr("__name__", boxStrConstant("dict"));
// dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, NULL, 1)));
......
......@@ -33,7 +33,6 @@ public:
BoxedDictIterator(BoxedDict* d, IteratorType type);
};
extern "C" const ObjectFlavor dict_iterator_flavor;
Box* dictIterKeys(Box* self);
Box* dictIterValues(Box* self);
Box* dictIterItems(Box* self);
......
......@@ -19,7 +19,6 @@
#include "core/common.h"
#include "core/stats.h"
#include "core/types.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......
......@@ -17,7 +17,6 @@
#include "codegen/compvars.h"
#include "core/types.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......
// Copyright (c) 2014 Dropbox, Inc.
//
// 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 PYSTON_RUNTIME_GCRUNTIME_H
#define PYSTON_RUNTIME_GCRUNTIME_H
#include "core/common.h"
#include "core/options.h"
#include "core/types.h"
namespace pyston {
class Box;
void gc_teardown();
extern "C" void* rt_alloc(size_t size);
extern "C" void* rt_realloc(void* ptr, size_t new_size);
extern "C" void rt_free(void* ptr);
}
#endif
......@@ -26,7 +26,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -128,8 +127,8 @@ extern "C" BoxedGenerator* createGenerator(BoxedFunction* function, Box* arg1, B
extern "C" BoxedGenerator::BoxedGenerator(BoxedFunction* function, Box* arg1, Box* arg2, Box* arg3, Box** args)
: Box(&generator_flavor, generator_cls), function(function), arg1(arg1), arg2(arg2), arg3(arg3), args(nullptr),
entryExited(false), returnValue(nullptr), exception(nullptr) {
: Box(generator_cls), function(function), arg1(arg1), arg2(arg2), arg3(arg3), args(nullptr), entryExited(false),
returnValue(nullptr), exception(nullptr) {
giveAttr("__name__", boxString(function->f->source->getName()));
......@@ -147,9 +146,37 @@ extern "C" BoxedGenerator::BoxedGenerator(BoxedFunction* function, Box* arg1, Bo
makecontext(&context, (void (*)(void))generatorEntry, 1, this);
}
extern "C" void generatorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedGenerator* g = (BoxedGenerator*)b;
v->visit(g->function);
int num_args = g->function->f->num_args;
if (num_args >= 1)
v->visit(g->arg1);
if (num_args >= 2)
v->visit(g->arg2);
if (num_args >= 3)
v->visit(g->arg3);
if (num_args > 3)
v->visitPotentialRange(reinterpret_cast<void* const*>(&g->args->elts[0]),
reinterpret_cast<void* const*>(&g->args->elts[num_args - 3]));
if (g->returnValue)
v->visit(g->returnValue);
if (g->exception)
v->visit(g->exception);
v->visitPotentialRange((void**)&g->context, ((void**)&g->context) + sizeof(g->context) / sizeof(void*));
v->visitPotentialRange((void**)&g->returnContext,
((void**)&g->returnContext) + sizeof(g->returnContext) / sizeof(void*));
v->visitPotentialRange((void**)&g->stack[0], (void**)&g->stack[BoxedGenerator::STACK_SIZE]);
}
void setupGenerator() {
generator_cls = new BoxedClass(object_cls, offsetof(BoxedGenerator, attrs), sizeof(BoxedGenerator), false);
generator_cls = new BoxedClass(object_cls, &generatorGCHandler, offsetof(BoxedGenerator, attrs),
sizeof(BoxedGenerator), false);
generator_cls->giveAttr("__name__", boxStrConstant("generator"));
generator_cls->giveAttr("__iter__",
new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1)));
......
......@@ -21,7 +21,6 @@
namespace pyston {
extern BoxedClass* generator_cls;
extern "C" const ObjectFlavor generator_flavor;
void setupGenerator();
......
......@@ -14,7 +14,6 @@
#include "runtime/inline/boxing.h"
#include "runtime/gc_runtime.h"
#include "runtime/int.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......
......@@ -15,7 +15,6 @@
#ifndef PYSTON_RUNTIME_INLINE_BOXING_H
#define PYSTON_RUNTIME_INLINE_BOXING_H
#include "runtime/gc_runtime.h"
#include "runtime/int.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......
......@@ -15,12 +15,11 @@
#include <cstring>
#include "runtime/dict.h"
#include "runtime/gc_runtime.h"
namespace pyston {
BoxedDictIterator::BoxedDictIterator(BoxedDict* d, IteratorType type)
: Box(&dict_iterator_flavor, dict_iterator_cls), d(d), it(d->d.begin()), itEnd(d->d.end()), type(type) {
: Box(dict_iterator_cls), d(d), it(d->d.begin()), itEnd(d->d.end()), type(type) {
}
Box* dictIterKeys(Box* s) {
......
// Copyright (c) 2014 Dropbox, Inc.
//
// 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.
#include <cstdio>
#include <cstdlib>
#include "core/common.h"
#include "core/options.h"
#include "core/types.h"
#include "gc/gc_alloc.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#define USE_CUSTOM_ALLOC
namespace pyston {
//#define DEBUG_GC
#ifdef DEBUG_GC
typedef std::unordered_set<void*> AliveSet;
static AliveSet* getAlive() {
static AliveSet* alive = new AliveSet();
return alive;
}
#endif
void* rt_alloc(size_t size) {
#ifdef USE_CUSTOM_ALLOC
void* ptr = gc::gc_alloc(size);
#else
void* ptr = malloc(size);
#endif
#ifndef NDEBUG
// nallocs++;
#endif
#ifdef DEBUG_GC
getAlive()->insert(ptr);
#endif
return ptr;
}
void* rt_realloc(void* ptr, size_t new_size) {
#ifdef USE_CUSTOM_ALLOC
void* rtn = gc::gc_realloc(ptr, new_size);
#else
void* rtn = realloc(ptr, new_size);
#endif
#ifdef DEBUG_GC
getAlive()->erase(ptr);
getAlive()->insert(rtn);
#endif
return rtn;
}
void rt_free(void* ptr) {
#ifndef NDEBUG
// nallocs--;
#endif
#ifdef DEBUG_GC
getAlive()->erase(ptr);
#endif
#ifdef USE_CUSTOM_ALLOC
gc::gc_free(ptr);
#else
free(ptr);
#endif
// assert(nallocs >= 0);
}
void gc_teardown() {
/*
if (nallocs != 0) {
printf("Error: %d alloc's not freed\n", nallocs);
#ifdef DEBUG_GC
AliveSet *alive = getAlive();
assert(nallocs == alive->size());
for (void* p : alive) {
printf("%p\n", p);
}
#endif
// This will scan through the heap and alert us about things that
// aren't marked (which should be all alive objects):
gc::global_heap.freeUnmarked();
abort();
}
*/
}
}
......@@ -18,7 +18,6 @@
#include "core/types.h"
#include "gc/heap.h"
#include "runtime/float.h"
#include "runtime/gc_runtime.h"
#include "runtime/generator.h"
#include "runtime/inline/boxing.h"
#include "runtime/int.h"
......
......@@ -15,13 +15,12 @@
#include <cstring>
#include "runtime/gc_runtime.h"
#include "runtime/list.h"
#include "runtime/objmodel.h"
namespace pyston {
BoxedListIterator::BoxedListIterator(BoxedList* l) : Box(&list_iterator_flavor, list_iterator_cls), l(l), pos(0) {
BoxedListIterator::BoxedListIterator(BoxedList* l) : Box(list_iterator_cls), l(l), pos(0) {
}
......@@ -72,7 +71,7 @@ void BoxedList::shrink() {
elts = GCdArray::realloc(elts, new_capacity);
capacity = new_capacity;
} else if (size == 0) {
rt_free(elts);
delete elts;
capacity = 0;
}
}
......
......@@ -14,13 +14,12 @@
#include <cstring>
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/tuple.h"
namespace pyston {
BoxedTupleIterator::BoxedTupleIterator(BoxedTuple* t) : Box(&tuple_iterator_flavor, tuple_iterator_cls), t(t), pos(0) {
BoxedTupleIterator::BoxedTupleIterator(BoxedTuple* t) : Box(tuple_iterator_cls), t(t), pos(0) {
}
Box* tupleIterIter(Box* s) {
......
......@@ -14,15 +14,11 @@
#include "codegen/compvars.h"
#include "core/types.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
namespace pyston {
extern "C" const ObjectFlavor xrange_flavor(&boxGCHandler, NULL);
extern "C" const ObjectFlavor xrange_iterator_flavor;
BoxedClass* xrange_cls, *xrange_iterator_cls;
class BoxedXrangeIterator;
......@@ -31,8 +27,7 @@ private:
const int64_t start, stop, step;
public:
BoxedXrange(i64 start, i64 stop, i64 step)
: Box(&xrange_flavor, xrange_cls), start(start), stop(stop), step(step) {}
BoxedXrange(i64 start, i64 stop, i64 step) : Box(xrange_cls), start(start), stop(stop), step(step) {}
friend class BoxedXrangeIterator;
};
......@@ -43,8 +38,7 @@ private:
int64_t cur;
public:
BoxedXrangeIterator(BoxedXrange* xrange)
: Box(&xrange_iterator_flavor, xrange_iterator_cls), xrange(xrange), cur(xrange->start) {}
BoxedXrangeIterator(BoxedXrange* xrange) : Box(xrange_iterator_cls), xrange(xrange), cur(xrange->start) {}
static bool xrangeIteratorHasnextUnboxed(Box* s) __attribute__((visibility("default"))) {
assert(s->cls == xrange_iterator_cls);
......@@ -70,14 +64,13 @@ public:
return boxInt(xrangeIteratorNextUnboxed(s));
}
static void xrangeIteratorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
static void xrangeIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedXrangeIterator* it = (BoxedXrangeIterator*)p;
BoxedXrangeIterator* it = (BoxedXrangeIterator*)b;
v->visit(it->xrange);
}
};
extern "C" const ObjectFlavor xrange_iterator_flavor(&BoxedXrangeIterator::xrangeIteratorGCHandler, NULL);
Box* xrange(Box* cls, Box* start, Box* stop, Box** args) {
assert(cls == xrange_cls);
......@@ -117,9 +110,10 @@ Box* xrangeIter(Box* self) {
}
void setupXrange() {
xrange_cls = new BoxedClass(object_cls, 0, sizeof(BoxedXrange), false);
xrange_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedXrange), false);
xrange_cls->giveAttr("__name__", boxStrConstant("xrange"));
xrange_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedXrangeIterator), false);
xrange_iterator_cls = new BoxedClass(object_cls, &BoxedXrangeIterator::xrangeIteratorGCHandler, 0,
sizeof(BoxedXrangeIterator), false);
xrange_iterator_cls->giveAttr("__name__", boxStrConstant("rangeiterator"));
xrange_cls->giveAttr(
......
......@@ -23,7 +23,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/long.h"
#include "runtime/objmodel.h"
......@@ -590,7 +589,7 @@ extern "C" Box* intNew(Box* _cls, Box* val) {
getNameOfClass(cls)->c_str());
assert(cls->instance_size >= sizeof(BoxedInt));
void* mem = rt_alloc(cls->instance_size);
void* mem = gc_alloc(cls->instance_size, gc::GCKind::PYTHON);
BoxedInt* rtn = ::new (mem) BoxedInt(cls, 0);
initUserAttrs(rtn, cls);
......
......@@ -24,7 +24,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -448,14 +447,12 @@ Box* listReverse(BoxedList* self) {
}
BoxedClass* list_iterator_cls = NULL;
extern "C" void listIteratorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
BoxedListIterator* it = (BoxedListIterator*)p;
extern "C" void listIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedListIterator* it = (BoxedListIterator*)b;
v->visit(it->l);
}
extern "C" const ObjectFlavor list_iterator_flavor(&listIteratorGCHandler, NULL);
extern "C" Box* listNew(Box* cls, Box* container) {
assert(cls == list_cls);
......@@ -521,7 +518,7 @@ Box* listEq(BoxedList* self, Box* rhs) {
}
void setupList() {
list_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedList), false);
list_iterator_cls = new BoxedClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList), false);
list_cls->giveAttr("__name__", boxStrConstant("list"));
......
......@@ -28,7 +28,6 @@ public:
BoxedListIterator(BoxedList* l);
};
extern "C" const ObjectFlavor list_iterator_flavor;
Box* listIter(Box* self);
Box* listIterIter(Box* self);
Box* listiterHasnext(Box* self);
......
......@@ -24,7 +24,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......@@ -33,7 +32,6 @@
namespace pyston {
BoxedClass* long_cls;
const ObjectFlavor long_flavor(&boxGCHandler, NULL);
extern "C" Box* createLong(const std::string* s) {
BoxedLong* rtn = new BoxedLong(long_cls);
......@@ -58,7 +56,7 @@ extern "C" Box* longNew(Box* _cls, Box* val) {
getNameOfClass(cls)->c_str());
assert(cls->instance_size >= sizeof(BoxedInt));
void* mem = rt_alloc(cls->instance_size);
void* mem = gc_alloc(cls->instance_size, gc::GCKind::PYTHON);
BoxedLong* rtn = ::new (mem) BoxedLong(cls);
initUserAttrs(rtn, cls);
......
......@@ -25,13 +25,12 @@ namespace pyston {
void setupLong();
extern BoxedClass* long_cls;
extern const ObjectFlavor long_flavor;
class BoxedLong : public Box {
public:
mpz_t n;
BoxedLong(BoxedClass* cls) __attribute__((visibility("default"))) : Box(&long_flavor, cls) {}
BoxedLong(BoxedClass* cls) __attribute__((visibility("default"))) : Box(cls) {}
};
extern "C" Box* createLong(const std::string* s);
......
......@@ -39,7 +39,6 @@
#include "gc/heap.h"
#include "runtime/capi.h"
#include "runtime/float.h"
#include "runtime/gc_runtime.h"
#include "runtime/generator.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -360,10 +359,17 @@ extern "C" void checkUnpackingLength(i64 expected, i64 given) {
}
}
BoxedClass::BoxedClass(BoxedClass* base, int attrs_offset, int instance_size, bool is_user_defined)
: Box(&type_flavor, type_cls), base(base), attrs_offset(attrs_offset), instance_size(instance_size),
BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int instance_size,
bool is_user_defined)
: Box(type_cls), base(base), gc_visit(gc_visit), attrs_offset(attrs_offset), instance_size(instance_size),
is_constant(false), is_user_defined(is_user_defined) {
if (gc_visit == NULL) {
assert(base);
this->gc_visit = base->gc_visit;
}
assert(this->gc_visit);
if (!base) {
assert(object_cls == nullptr);
// we're constructing 'object'
......@@ -432,19 +438,14 @@ HiddenClass* HiddenClass::delAttrToMakeHC(const std::string& attr) {
// TODO we can first locate the parent HiddenClass of the deleted
// attribute and hence avoid creation of its ancestors.
HiddenClass* cur = getRoot();
HiddenClass* cur = root_hcls;
for (const auto& attr : new_attrs) {
cur = cur->getOrMakeChild(attr);
}
return cur;
}
HiddenClass* HiddenClass::getRoot() {
static HiddenClass* root = new HiddenClass();
return root;
}
Box::Box(const ObjectFlavor* flavor, BoxedClass* cls) : GCObject(flavor), cls(cls) {
Box::Box(BoxedClass* cls) : cls(cls) {
// if (TRACK_ALLOCATIONS) {
// int id = Stats::getStatId("allocated_" + *getNameOfClass(c));
// Stats::log(id);
......@@ -613,22 +614,22 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite
RewriterVarUsage r_new_array2(RewriterVarUsage::empty());
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (numattrs + 1);
if (numattrs == 0) {
attrs->attr_list = (HCAttrs::AttrList*)rt_alloc(new_size);
attrs->attr_list->gc_header.kind_id = untracked_kind.kind_id;
attrs->attr_list = (HCAttrs::AttrList*)gc_alloc(new_size, gc::GCKind::UNTRACKED);
if (rewrite_args) {
RewriterVarUsage r_newsize = rewrite_args->rewriter->loadConst(new_size, Location::forArg(0));
r_new_array2 = rewrite_args->rewriter->call(false, (void*)rt_alloc, std::move(r_newsize));
RewriterVarUsage r_flavor = rewrite_args->rewriter->loadConst((int64_t)untracked_kind.kind_id);
r_new_array2.setAttr(ATTRLIST_KIND_OFFSET, std::move(r_flavor));
RewriterVarUsage r_kind
= rewrite_args->rewriter->loadConst((int)gc::GCKind::UNTRACKED, Location::forArg(1));
r_new_array2
= rewrite_args->rewriter->call(false, (void*)gc::gc_alloc, std::move(r_newsize), std::move(r_kind));
}
} else {
attrs->attr_list = (HCAttrs::AttrList*)rt_realloc(attrs->attr_list, new_size);
attrs->attr_list = (HCAttrs::AttrList*)gc::gc_realloc(attrs->attr_list, new_size);
if (rewrite_args) {
RewriterVarUsage r_oldarray = rewrite_args->obj.getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET,
RewriterVarUsage::NoKill, Location::forArg(0));
RewriterVarUsage r_newsize = rewrite_args->rewriter->loadConst(new_size, Location::forArg(1));
r_new_array2
= rewrite_args->rewriter->call(false, (void*)rt_realloc, std::move(r_oldarray), std::move(r_newsize));
r_new_array2 = rewrite_args->rewriter->call(false, (void*)gc::gc_realloc, std::move(r_oldarray),
std::move(r_newsize));
}
}
// Don't set the new hcls until after we do the allocation for the new attr_list;
......@@ -1273,28 +1274,28 @@ extern "C" void dump(void* p) {
return;
}
GCObjectHeader* header = gc::headerFromObject(p);
if (header->kind_id == hc_kind.kind_id) {
printf("hcls object\n");
gc::GCAllocation* al = gc::GCAllocation::fromUserData(p);
if (al->kind_id == gc::GCKind::UNTRACKED) {
printf("gc-untracked object\n");
return;
}
if (header->kind_id == untracked_kind.kind_id) {
printf("untracked object\n");
if (al->kind_id == gc::GCKind::CONSERVATIVE) {
printf("conservatively-scanned object object\n");
return;
}
if (header->kind_id == conservative_kind.kind_id) {
printf("untracked object\n");
if (al->kind_id == gc::GCKind::PYTHON) {
printf("Python object\n");
Box* b = (Box*)p;
printf("Class: %s\n", getTypeName(b)->c_str());
if (isSubclass(b->cls, type_cls)) {
printf("Type name: %s\n", getNameOfClass(static_cast<BoxedClass*>(b))->c_str());
}
return;
}
printf("Assuming it's a Box*\n");
Box* b = (Box*)p;
printf("Class: %s\n", getTypeName(b)->c_str());
if (isSubclass(b->cls, type_cls)) {
printf("Type name: %s\n", getNameOfClass(static_cast<BoxedClass*>(b))->c_str());
}
RELEASE_ASSERT(0, "%d", (int)al->kind_id);
}
// For rewriting purposes, this function assumes that nargs will be constant.
......@@ -2745,7 +2746,7 @@ void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) {
// guarantee the size of the attr_list equals the number of attrs
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1);
attrs->attr_list = (HCAttrs::AttrList*)rt_realloc(attrs->attr_list, new_size);
attrs->attr_list = (HCAttrs::AttrList*)gc::gc_realloc(attrs->attr_list, new_size);
}
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
......
......@@ -37,7 +37,6 @@ void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
// helper function for raising from the runtime:
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__));
extern "C" const std::string* getTypeName(Box* o);
extern "C" const std::string* getNameOfClass(BoxedClass* cls);
// TODO sort this
......
......@@ -25,12 +25,6 @@ namespace pyston {
BoxedClass* set_cls, *set_iterator_cls;
BoxedClass* frozenset_cls;
extern "C" void setGCHandler(GCVisitor* v, void* p);
extern "C" void setIteratorGCHandler(GCVisitor* v, void* p);
const ObjectFlavor set_flavor(&setGCHandler, NULL);
const ObjectFlavor set_iterator_flavor(&setIteratorGCHandler, NULL);
extern "C" Box* createSet() {
return new BoxedSet(set_cls);
}
......@@ -42,7 +36,7 @@ public:
BoxedSet* s;
decltype(BoxedSet::s)::iterator it;
BoxedSetIterator(BoxedSet* s) : Box(&set_iterator_flavor, set_iterator_cls), s(s), it(s->s.begin()) {}
BoxedSetIterator(BoxedSet* s) : Box(set_iterator_cls), s(s), it(s->s.begin()) {}
bool hasNext() { return it != s->s.end(); }
......@@ -53,25 +47,10 @@ public:
}
};
extern "C" void setGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
BoxedSet* s = (BoxedSet*)p;
// This feels like a cludge, but we need to find anything that
// the unordered_map might have allocated.
// Another way to handle this would be to rt_alloc the unordered_map
// as well, though that incurs extra memory dereferences which would
// be nice to avoid.
void** start = (void**)&s->s;
void** end = start + (sizeof(s->s) / 8);
v->visitPotentialRange(start, end);
}
extern "C" void setIteratorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
extern "C" void setIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedSetIterator* it = (BoxedSetIterator*)p;
BoxedSetIterator* it = (BoxedSetIterator*)b;
v->visit(it->s);
}
......@@ -228,7 +207,7 @@ void setupSet() {
set_cls->giveAttr("__name__", boxStrConstant("set"));
frozenset_cls->giveAttr("__name__", boxStrConstant("frozenset"));
set_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedSet), false);
set_iterator_cls = new BoxedClass(object_cls, &setIteratorGCHandler, 0, sizeof(BoxedSet), false);
set_iterator_cls->giveAttr("__name__", boxStrConstant("setiterator"));
set_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1)));
......
......@@ -26,7 +26,6 @@ void setupSet();
void teardownSet();
extern BoxedClass* set_cls, *frozenset_cls;
extern const ObjectFlavor set_flavor, frozenset_flavor;
extern "C" Box* createSet();
......@@ -34,7 +33,7 @@ class BoxedSet : public Box {
public:
std::unordered_set<Box*, PyHasher, PyEq, StlCompatAllocator<Box*> > s;
BoxedSet(BoxedClass* cls) __attribute__((visibility("default"))) : Box(&set_flavor, cls) {}
BoxedSet(BoxedClass* cls) __attribute__((visibility("default"))) : Box(cls) {}
};
}
......
......@@ -24,7 +24,6 @@
#include "core/common.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -579,16 +578,13 @@ extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
// Should probably implement that, and maybe once that's implemented get
// rid of the striterator class?
BoxedClass* str_iterator_cls = NULL;
extern "C" void strIteratorGCHandler(GCVisitor* v, void* p);
extern "C" const ObjectFlavor str_iterator_flavor(&strIteratorGCHandler, NULL);
class BoxedStringIterator : public Box {
public:
BoxedString* s;
std::string::const_iterator it, end;
BoxedStringIterator(BoxedString* s)
: Box(&str_iterator_flavor, str_iterator_cls), s(s), it(s->s.begin()), end(s->s.end()) {}
BoxedStringIterator(BoxedString* s) : Box(str_iterator_cls), s(s), it(s->s.begin()), end(s->s.end()) {}
static bool hasnextUnboxed(BoxedStringIterator* self) {
assert(self->cls == str_iterator_cls);
......@@ -610,9 +606,9 @@ public:
}
};
extern "C" void strIteratorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
BoxedStringIterator* it = (BoxedStringIterator*)p;
extern "C" void strIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedStringIterator* it = (BoxedStringIterator*)b;
v->visit(it->s);
}
......@@ -648,7 +644,7 @@ Box* strCount2(BoxedString* self, Box* elt) {
}
void setupStr() {
str_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedString), false);
str_iterator_cls = new BoxedClass(object_cls, &strIteratorGCHandler, 0, sizeof(BoxedString), false);
gc::registerStaticRootObj(str_iterator_cls);
str_iterator_cls->giveAttr("__name__", boxStrConstant("striterator"));
str_iterator_cls->giveAttr("__hasnext__",
......
......@@ -22,7 +22,6 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -203,17 +202,15 @@ Box* tupleHash(BoxedTuple* self) {
}
BoxedClass* tuple_iterator_cls = NULL;
extern "C" void tupleIteratorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p);
BoxedTupleIterator* it = (BoxedTupleIterator*)p;
extern "C" void tupleIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedTupleIterator* it = (BoxedTupleIterator*)b;
v->visit(it->t);
}
extern "C" const ObjectFlavor tuple_iterator_flavor(&tupleIteratorGCHandler, NULL);
void setupTuple() {
tuple_iterator_cls = new BoxedClass(object_cls, 0, sizeof(BoxedTuple), false);
tuple_iterator_cls = new BoxedClass(object_cls, &tupleIteratorGCHandler, 0, sizeof(BoxedTuple), false);
tuple_cls->giveAttr("__name__", boxStrConstant("tuple"));
......
......@@ -28,7 +28,6 @@ public:
BoxedTupleIterator(BoxedTuple* t);
};
extern "C" const ObjectFlavor tuple_iterator_flavor;
Box* tupleIter(Box* self);
Box* tupleIterIter(Box* self);
Box* tupleiterHasnext(Box* self);
......
This diff is collapsed.
......@@ -19,6 +19,7 @@
#include "core/threading.h"
#include "core/types.h"
#include "gc/gc_alloc.h"
namespace pyston {
......@@ -74,11 +75,6 @@ extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *float_cls, *str_
*instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *xrange_cls, *member_cls,
*closure_cls, *generator_cls;
}
extern "C" {
extern const ObjectFlavor object_flavor, type_flavor, bool_flavor, int_flavor, float_flavor, str_flavor,
function_flavor, none_flavor, instancemethod_flavor, list_flavor, slice_flavor, module_flavor, dict_flavor,
tuple_flavor, file_flavor, xrange_flavor, member_flavor, closure_flavor, generator_flavor;
}
extern "C" { extern Box* None, *NotImplemented, *True, *False; }
extern "C" {
extern Box* repr_obj, *len_obj, *hash_obj, *range_obj, *abs_obj, *min_obj, *max_obj, *open_obj, *id_obj, *chr_obj,
......@@ -108,27 +104,6 @@ extern "C" Box* createTuple(int64_t nelts, Box** elts);
extern "C" void printFloat(double d);
class ConservativeWrapper : public GCObject {
public:
void* data[0];
ConservativeWrapper(size_t data_size) : GCObject(&conservative_kind), data() {
assert(data_size % sizeof(void*) == 0);
gc_header.kind_data = data_size;
}
void* operator new(size_t size, size_t data_size) {
assert(size == sizeof(ConservativeWrapper));
return rt_alloc(data_size + size);
}
static ConservativeWrapper* fromPointer(void* p) {
ConservativeWrapper* o = (ConservativeWrapper*)((void**)p - 1);
assert(&o->data == p);
return o;
}
};
template <class T> class StlCompatAllocator {
public:
typedef size_t size_type;
......@@ -148,14 +123,10 @@ public:
size_t to_allocate = n * sizeof(value_type);
// assert(to_allocate < (1<<16));
ConservativeWrapper* rtn = new (to_allocate) ConservativeWrapper(to_allocate);
return (pointer)&rtn->data[0];
return reinterpret_cast<pointer>(gc_alloc(to_allocate, gc::GCKind::CONSERVATIVE));
}
void deallocate(pointer p, size_t n) {
ConservativeWrapper* o = ConservativeWrapper::fromPointer(p);
rt_free(o);
}
void deallocate(pointer p, size_t n) { gc::gc_free(p); }
// I would never be able to come up with this on my own:
// http://en.cppreference.com/w/cpp/memory/allocator/construct
......@@ -169,26 +140,59 @@ public:
bool operator!=(const StlCompatAllocator<T>& rhs) const { return false; }
};
template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K> >
class conservative_unordered_map
: public std::unordered_map<K, V, Hash, KeyEqual, StlCompatAllocator<std::pair<const K, V> > > {};
class HiddenClass : public ConservativeGCObject {
private:
HiddenClass() {}
HiddenClass(const HiddenClass* parent) : attr_offsets(parent->attr_offsets) {}
public:
static HiddenClass* makeRoot() {
#ifndef NDEBUG
static bool made = false;
assert(!made);
made = true;
#endif
return new HiddenClass();
}
conservative_unordered_map<std::string, int> attr_offsets;
conservative_unordered_map<std::string, HiddenClass*> children;
HiddenClass* getOrMakeChild(const std::string& attr);
int getOffset(const std::string& attr) {
auto it = attr_offsets.find(attr);
if (it == attr_offsets.end())
return -1;
return it->second;
}
HiddenClass* delAttrToMakeHC(const std::string& attr);
};
class BoxedInt : public Box {
public:
int64_t n;
BoxedInt(BoxedClass* cls, int64_t n) __attribute__((visibility("default"))) : Box(&int_flavor, cls), n(n) {}
BoxedInt(BoxedClass* cls, int64_t n) __attribute__((visibility("default"))) : Box(cls), n(n) {}
};
class BoxedFloat : public Box {
public:
double d;
BoxedFloat(double d) __attribute__((visibility("default"))) : Box(&float_flavor, float_cls), d(d) {}
BoxedFloat(double d) __attribute__((visibility("default"))) : Box(float_cls), d(d) {}
};
class BoxedBool : public Box {
public:
bool b;
BoxedBool(bool b) __attribute__((visibility("default"))) : Box(&bool_flavor, bool_cls), b(b) {}
BoxedBool(bool b) __attribute__((visibility("default"))) : Box(bool_cls), b(b) {}
};
class BoxedString : public Box {
......@@ -196,9 +200,8 @@ public:
// const std::basic_string<char, std::char_traits<char>, StlCompatAllocator<char> > s;
const std::string s;
BoxedString(const std::string&& s) __attribute__((visibility("default")))
: Box(&str_flavor, str_cls), s(std::move(s)) {}
BoxedString(const std::string& s) __attribute__((visibility("default"))) : Box(&str_flavor, str_cls), s(s) {}
BoxedString(const std::string&& s) __attribute__((visibility("default"))) : Box(str_cls), s(std::move(s)) {}
BoxedString(const std::string& s) __attribute__((visibility("default"))) : Box(str_cls), s(s) {}
};
class BoxedInstanceMethod : public Box {
......@@ -206,22 +209,22 @@ public:
Box* obj, *func;
BoxedInstanceMethod(Box* obj, Box* func) __attribute__((visibility("default")))
: Box(&instancemethod_flavor, instancemethod_cls), obj(obj), func(func) {}
: Box(instancemethod_cls), obj(obj), func(func) {}
};
class GCdArray : public GCObject {
class GCdArray {
public:
Box* elts[0];
GCdArray() : GCObject(&untracked_kind) {}
void* operator new(size_t size, int capacity) {
assert(size == sizeof(GCdArray));
return rt_alloc(capacity * sizeof(Box*) + size);
return gc_alloc(capacity * sizeof(Box*) + size, gc::GCKind::UNTRACKED);
}
void operator delete(void* p) { gc::gc_free(p); }
static GCdArray* realloc(GCdArray* array, int capacity) {
return (GCdArray*)rt_realloc(array, capacity * sizeof(Box*) + sizeof(GCdArray));
return (GCdArray*)gc::gc_realloc(array, capacity * sizeof(Box*) + sizeof(GCdArray));
}
};
......@@ -232,7 +235,7 @@ public:
DS_DEFINE_MUTEX(lock);
BoxedList() __attribute__((visibility("default"))) : Box(&list_flavor, list_cls), size(0), capacity(0) {}
BoxedList() __attribute__((visibility("default"))) : Box(list_cls), size(0), capacity(0) {}
void ensure(int space);
void shrink();
......@@ -245,9 +248,9 @@ public:
const GCVector elts;
BoxedTuple(std::vector<Box*, StlCompatAllocator<Box*> >& elts) __attribute__((visibility("default")))
: Box(&tuple_flavor, tuple_cls), elts(elts) {}
: Box(tuple_cls), elts(elts) {}
BoxedTuple(std::vector<Box*, StlCompatAllocator<Box*> >&& elts) __attribute__((visibility("default")))
: Box(&tuple_flavor, tuple_cls), elts(std::move(elts)) {}
: Box(tuple_cls), elts(std::move(elts)) {}
};
extern "C" BoxedTuple* EmptyTuple;
......@@ -255,7 +258,7 @@ class BoxedFile : public Box {
public:
FILE* f;
bool closed;
BoxedFile(FILE* f) __attribute__((visibility("default"))) : Box(&file_flavor, file_cls), f(f), closed(false) {}
BoxedFile(FILE* f) __attribute__((visibility("default"))) : Box(file_cls), f(f), closed(false) {}
};
struct PyHasher {
......@@ -276,7 +279,7 @@ public:
DictMap d;
BoxedDict() __attribute__((visibility("default"))) : Box(&dict_flavor, dict_cls) {}
BoxedDict() __attribute__((visibility("default"))) : Box(dict_cls) {}
};
class BoxedFunction : public Box {
......@@ -306,8 +309,7 @@ public:
class BoxedSlice : public Box {
public:
Box* start, *stop, *step;
BoxedSlice(Box* lower, Box* upper, Box* step)
: Box(&slice_flavor, slice_cls), start(lower), stop(upper), step(step) {}
BoxedSlice(Box* lower, Box* upper, Box* step) : Box(slice_cls), start(lower), stop(upper), step(step) {}
};
class BoxedMemberDescriptor : public Box {
......@@ -318,7 +320,7 @@ public:
int offset;
BoxedMemberDescriptor(MemberType type, int offset) : Box(&member_flavor, member_cls), type(type), offset(offset) {}
BoxedMemberDescriptor(MemberType type, int offset) : Box(member_cls), type(type), offset(offset) {}
};
// TODO is there any particular reason to make this a Box, ie a python-level object?
......@@ -327,7 +329,7 @@ public:
HCAttrs attrs;
BoxedClosure* parent;
BoxedClosure(BoxedClosure* parent) : Box(&closure_flavor, closure_cls), parent(parent) {}
BoxedClosure(BoxedClosure* parent) : Box(closure_cls), parent(parent) {}
};
class BoxedGenerator : public Box {
......@@ -349,7 +351,7 @@ public:
BoxedGenerator(BoxedFunction* function, Box* arg1, Box* arg2, Box* arg3, Box** args);
};
extern "C" void boxGCHandler(GCVisitor* v, void* p);
extern "C" void boxGCHandler(GCVisitor* v, Box* b);
Box* exceptionNew1(BoxedClass* cls);
Box* exceptionNew2(BoxedClass* cls, Box* message);
......
......@@ -2,22 +2,22 @@
#include <cstdio>
#include "stdint.h"
void set64(int64_t* ptr) {
*ptr = 0x1234;
}
class C {
public:
C(int i) {
printf("ctor\n");
}
void* operator new(size_t bytes) {
printf("operator new\n");
return NULL;
}
};
void set64full(int64_t* ptr) {
*ptr = 0x1234567890;
int f() {
printf("f()");
return 1;
}
namespace pyston {
class Box {};
int throw_catch(Box* b) {
try {
throw b;
} catch (int e) {
return e;
}
}
extern "C" C* c() {
return new C(f());
}
# expected: fail
# - the GC will crash if any thread is inside a generator during a collection
# Allocate a few-dozen megabytes of memory inside a generator,
# to try to force a collection.
def f():
l = range(1000)
for i in xrange(10000):
l = list(l)
yield 0
print list(f())
......@@ -13,10 +13,16 @@ using namespace pyston;
using namespace pyston::gc;
struct S {
GCObjectHeader header;
int data[0];
};
TEST(alloc, basic) {
void* p1 = gc_alloc(16, GCKind::UNTRACKED);
void* p2 = gc_alloc(16, GCKind::UNTRACKED);
ASSERT_TRUE(p1 != p2);
}
void testAlloc(int B) {
std::unique_ptr<int> masks(new int[B/4]);
masks.get()[0] = 0;
......@@ -32,8 +38,7 @@ void testAlloc(int B) {
if (B > 1024)
N /= 10;
for (int i = 0; i < N; i++) {
S* t = static_cast<S*>(gc_alloc(B));
t->header.kind_id = untracked_kind.kind_id;
S* t = static_cast<S*>(gc_alloc(B, GCKind::UNTRACKED));
ASSERT_TRUE(t != NULL);
ASSERT_EQ(0, seen.count(t));
......@@ -66,18 +71,15 @@ TEST(alloc, alloc3584) { testAlloc(3584); }
TEST(alloc, largeallocs) {
int s1 = 1 << 20;
S* d1 = (S*)gc_alloc(s1);
d1->header.kind_id = untracked_kind.kind_id;
S* d1 = (S*)gc_alloc(s1, GCKind::UNTRACKED);
memset(d1->data, 1, s1 - sizeof(S));
int s2 = 2 << 20;
S* d2 = (S*)gc_alloc(s2);
d2->header.kind_id = untracked_kind.kind_id;
S* d2 = (S*)gc_alloc(s2, GCKind::UNTRACKED);
memset(d2->data, 2, s2 - sizeof(S));
int s3 = 4 << 20;
S* d3 = (S*)gc_alloc(s3);
d3->header.kind_id = untracked_kind.kind_id;
S* d3 = (S*)gc_alloc(s3, GCKind::UNTRACKED);
memset(d3->data, 3, s3 - sizeof(S));
for (int i = sizeof(S); i < s1; i++) {
......@@ -96,14 +98,14 @@ TEST(alloc, largeallocs) {
TEST(alloc, freeing) {
// Not sure this is enough to crash if it doesn't get freed:
for (int i = 0; i < 100000; i++) {
void* a = gc_alloc(1024);
void* a = gc_alloc(1024, GCKind::UNTRACKED);
gc_free(a);
}
}
TEST(alloc, freeingLarge) {
for (int i = 0; i < 200; i++) {
void* a = gc_alloc(1<<26);
void* a = gc_alloc(1<<26, GCKind::UNTRACKED);
gc_free(a);
}
}
......
......@@ -100,6 +100,9 @@ bool makeVisible(llvm::GlobalValue* gv) {
bool isConstant(MDNode* parent_type, int offset) {
MDString *s = cast<MDString>(parent_type->getOperand(0));
// TODO: these were somewhat helpful, but this code is broken since
// it hard-codes the attribute offsets.
/*
if (s->getString() == "_ZTSN6pyston19BoxedXrangeIteratorE") {
return (offset == 16);
}
......@@ -115,6 +118,7 @@ bool isConstant(MDNode* parent_type, int offset) {
if (s->getString() == "_ZTSN6pyston11BoxedXrangeE") {
return offset == 16 || offset == 24 || offset == 32;
}
*/
return false;
}
......
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