Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ollef committed Dec 30, 2023
1 parent 485e854 commit 6ad14e4
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 555 deletions.
125 changes: 125 additions & 0 deletions rts/reference_counting.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "reference_counting.h"
#include <mimalloc.h>

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define debug_printf(...) // printf(__VA_ARGS__)

const uintptr_t INLINE_SIZE_MASK = 0xFF << 3;

// heap pointer: | 45 bits pointer data | 8 bits constructor tag | 8 bits word size | 2 bits object type | 1 |

static
void print_heap_object(uintptr_t heap_object) {
char* pointer = sixten_heap_object_pointer(heap_object);
debug_printf("pointer: 0x%" PRIxPTR, (uintptr_t)pointer);
uintptr_t constructor_tag = heap_object_constructor_tag(heap_object);
debug_printf(", constructor_tag: %" PRIuPTR, constructor_tag);
uintptr_t inline_size = heap_object & INLINE_SIZE_MASK;
debug_printf(", inline_size: %" PRIuPTR, inline_size);
uintptr_t object_type = heap_object & ~(~0ul << 3);
debug_printf(", object_type: %" PRIuPTR, object_type);
}

int sixten_is_heap_object(uintptr_t word) {
return word & 0x1;
}

uintptr_t sixten_heap_object_size(uintptr_t word) {
uintptr_t inline_size = word & INLINE_SIZE_MASK;
if (unlikely(inline_size == INLINE_SIZE_MASK)) {
return *(uintptr_t*)(sixten_heap_object_pointer(word) - sizeof(char*));
}
return inline_size;
}

char* sixten_heap_object_pointer(uintptr_t word) {
return (char*)((uintptr_t)((intptr_t)word >> 19) << 3);
}

// If we know that the constructor tag is <= 5 bits, we can get the pointer
// with one instead of two shifts.
char* sixten_heap_object_pointer_5bit_tag(uintptr_t word) {
return (char*)((intptr_t)word >> 16);
}

uintptr_t sixten_heap_object_constructor_tag(uintptr_t word) {
return (word >> 11) & 0xFF;
}

uintptr_t sixten_allocate(uintptr_t constructor_tag, uintptr_t size){
debug_printf("heap allocating %" PRIuPTR " bytes \n", size);
uintptr_t inline_size = size;
uintptr_t object_size = size;
uintptr_t object_pointer_offset = 0;
char* object_pointer = heap_pointer;

// If size is too large to be stored in free bits in the pointer, make room
// for it to be stored just before the heap object's data.
if (unlikely(size >= INLINE_SIZE_MASK)) {
inline_size = INLINE_SIZE_MASK;
object_size = size + sizeof(char*);
object_pointer_offset = sizeof(char*);
}

// Make space for reference count.
uintptr_t alloc_size = object_size + sizeof(char*);

char* heap_pointer = mi_malloc(alloc_size);
char* object_pointer = heap_pointer + object_pointer_offset;

// Store initial reference count.
*(uintptr_t*)object_pointer = 1;

// Actually store the size before the heap object if the size was too large
// to be inline.
if (unlikely(size >= INLINE_SIZE_MASK)) {
*(uintptr_t*)heap_pointer = size;
}

uintptr_t result
= ((uintptr_t)object_pointer << 16)
| ((uintptr_t)constructor_tag << 11)
| (uintptr_t)inline_size
| 1;

debug_printf("heap allocated object ");
print_heap_object(result);
debug_printf("\n");

return result;
}

void sixten_retain(uintptr_t word) {
if (!sixten_is_heap_object(word))
return;
char* pointer = sixten_heap_object_pointer(word);
*(uintptr_t*)pointer += 1;
}

void sixten_retains(char* pointer, uintptr_t size) {
for (char* p = pointer, end = pointer + size; p < end; p += sizeof(char*)) {
sixten_retain(*(uintptr_t*)p);
}
}

void sixten_release(uintptr_t word) {
if (!sixten_is_heap_object(word))
return;
char* pointer = sixten_heap_object_pointer(word);
*(uintptr_t)pointer -= 1;
uintptr_t rc = *(uintptr_t*)pointer;
if (rc > 0)
return;
uintptr_t size = sixten_heap_object_size(word);
sixten_releases(pointer + sizeof(char*), size);
if (unlikely(size >= INLINE_SIZE_MASK))
pointer -= sizeof(char*);
mi_free(pointer);
}

void sixten_releases(char* pointer, uintptr_t size) {
for (char* p = pointer, end = p + size; p < end; p += sizeof(char*)) {
sixten_release(*(uintptr_t*)p);
}
};
15 changes: 15 additions & 0 deletions rts/reference_counting.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <stdint.h>

int sixten_is_heap_object(uintptr_t word);
uintptr_t sixten_heap_object_size(uintptr_t word);
char* sixten_heap_object_pointer(uintptr_t word);
char* sixten_heap_object_pointer_5bit_tag(uintptr_t word);
uintptr_t sixten_heap_object_constructor_tag(uintptr_t word);

uintptr_t sixten_allocate(uintptr_t constructor_tag, uintptr_t size);
void sixten_retain(uintptr_t word);
void sixten_retains(char* pointer, uintptr_t size);
void sixten_release(uintptr_t word);
void sixten_releases(char* pointer, uintptr_t size);
25 changes: 14 additions & 11 deletions src/Assembly.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ data Operand
= LocalOperand !Local
| GlobalConstant !Name.Lifted !Type
| GlobalFunction !Name.Lifted !(Return Type) [Type]
| StructOperand [Operand]
| Lit !Literal
deriving (Eq, Show, Generic, Hashable)

Expand Down Expand Up @@ -55,15 +54,17 @@ data Instruction
| RestoreStack !Operand
| HeapAllocate
{ destination :: !Local
, shadowStack :: !Operand
, heapPointer :: !Operand
, heapLimit :: !Operand
, constructorTag :: !Word8
, size :: !Operand
}
| Retains !Operand !Operand
| Releases !Operand !Operand
| AllocateGlobal
{ destination :: !Local
, size :: !Operand
}
| ExtractHeapPointer !Local !Operand
| ExtractHeapPointerConstructorTag !Local !Operand
| ExtractValue !Local !Operand !Int
| Switch !(Return (Type, Local)) !Operand [(Integer, BasicBlock)] BasicBlock
deriving (Eq, Show, Generic, Hashable)

Expand Down Expand Up @@ -111,8 +112,6 @@ instance Pretty Operand where
"(" <> pretty type_ <+> "constant" <+> pretty global <> ")"
GlobalFunction global return_ arity ->
"(function " <> pretty return_ <> " (" <> pretty arity <> ")" <+> pretty global <> ")"
StructOperand operands ->
"{" <> hsep (punctuate comma $ pretty <$> operands) <> "}"
Lit lit ->
pretty lit

Expand Down Expand Up @@ -153,14 +152,18 @@ instance Pretty Instruction where
returningInstr dst "savestack" ([] :: [Operand])
RestoreStack o ->
voidInstr "restorestack" [o]
HeapAllocate dst a b c d e ->
returningInstr dst "gcmalloc" [a, b, c, Lit $ Literal.Integer $ fromIntegral d, e]
HeapAllocate dst a b ->
returningInstr dst "gcmalloc" [Lit $ Literal.Integer $ fromIntegral a, b]
Retains pointer size ->
voidInstr "retains" [pointer, size]
Releases pointer size ->
voidInstr "releases" [pointer, size]
AllocateGlobal dst size_ ->
returningInstr dst "malloc" [size_]
ExtractHeapPointer dst a ->
returningInstr dst "extract heap pointer" [a]
ExtractHeapPointerConstructorTag dst a ->
returningInstr dst "extract heap pointer" [a]
ExtractValue dst struct index ->
pretty dst <+> "=" <+> "extractvalue" <+> hsep [pretty struct, pretty index]
Switch result scrutinee branches default_ ->
case result of
Void -> ""
Expand Down
72 changes: 0 additions & 72 deletions src/Assembly/HeapAllocates.hs

This file was deleted.

31 changes: 2 additions & 29 deletions src/AssemblyToLLVM.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import qualified Data.ByteString.Short as ShortByteString
import Data.HashMap.Lazy (HashMap)
import qualified Data.HashMap.Lazy as HashMap
import qualified Data.HashSet as HashSet
import qualified Data.List as List
import Data.String (fromString)
import qualified Literal
import qualified Name
Expand Down Expand Up @@ -424,11 +423,8 @@ assembleInstruction instruction =
argument' <- assembleOperandAndCastTo Assembly.WordPointer argument
declare "llvm.stackrestore" $ "declare ccc void @llvm.stackrestore" <> parens [pointer]
emitInstruction $ "call ccc void @llvm.stackrestore" <> parens [typedOperand argument']
Assembly.HeapAllocate {destination, shadowStack, heapPointer, heapLimit, constructorTag, size} -> do
Assembly.HeapAllocate {destination, constructorTag, size} -> do
destination' <- activateLocal (Assembly.Struct [Assembly.Word, Assembly.WordPointer, Assembly.WordPointer]) destination
shadowStack' <- assembleOperandAndCastTo Assembly.WordPointer shadowStack
heapPointer' <- assembleOperandAndCastTo Assembly.WordPointer heapPointer
heapLimit' <- assembleOperandAndCastTo Assembly.WordPointer heapLimit
size' <- assembleOperandAndCastTo Assembly.Word size
declare
"__regcall3__heap_alloc"
Expand All @@ -446,10 +442,7 @@ assembleInstruction instruction =
]
<> "@__regcall3__heap_alloc"
<> parens
[ typedOperand shadowStack'
, typedOperand heapPointer'
, typedOperand heapLimit'
, "i8 " <> Builder.word8Dec constructorTag
[ "i8 " <> Builder.word8Dec constructorTag
, typedOperand size'
]
Assembly.ExtractHeapPointer destination pointer_ -> do
Expand All @@ -467,14 +460,6 @@ assembleInstruction instruction =
<> wordSizedInt
<> " @heap_object_constructor_tag"
<> parens [typedOperand pointer']
Assembly.ExtractValue destination struct index -> do
(_nameSuggestion, structType, struct') <- assembleOperand struct
case structType of
Assembly.Struct types -> do
let fieldType = types List.!! index
destination' <- activateLocal fieldType destination
emitInstruction $ localName destination' <> " = extractvalue " <> typedOperand struct' <> ", " <> Builder.intDec index
_ -> panic "AssemblyToLLVM.assembleInstruction: ExtractValue of non-struct"
Assembly.Switch destination scrutinee branches (Assembly.BasicBlock defaultBranchInstructions defaultBranchResult) -> do
scrutinee' <- assembleOperandAndCastTo Assembly.Word scrutinee
branchLabels <- forM branches \(i, _) -> do
Expand Down Expand Up @@ -554,18 +539,6 @@ assembleOperand = \case
globalType = llvmType defType
declare globalName_ $ "declare fastcc " <> llvmReturnType returnType <> " " <> globalName globalName_ <> parens (llvmType <$> parameterTypes)
pure (nameSuggestion, defType, TypedOperand {type_ = globalType, operand = Global globalName_})
Assembly.StructOperand operands -> do
typedOperands <- mapM assembleOperand operands
let types = (\(_, type', _) -> type') <$> typedOperands
operands' = (\(_, _, operand') -> operand') <$> typedOperands
type_ = Assembly.Struct types
llvmType_ = llvmType type_
go (index, struct) fieldOperand = do
struct' <- freshName "struct"
emitInstruction $ localName struct' <> " = insertvalue " <> typedOperand struct <> ", " <> typedOperand fieldOperand <> ", " <> Builder.intDec index
pure (index + 1, TypedOperand {type_ = llvmType_, operand = Local struct'})
result <- snd <$> foldM go (0, TypedOperand {type_ = llvmType_, operand = Constant "undef"}) operands'
pure ("struct", type_, result)
Assembly.Lit lit ->
case lit of
Literal.Integer int ->
Expand Down
Loading

0 comments on commit 6ad14e4

Please sign in to comment.