Skip to content

Commit

Permalink
Fix bug of dtor calls with wrong addresses. (#309)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored Aug 23, 2023
1 parent 11e13c1 commit 1b1ed41
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 63 deletions.
2 changes: 1 addition & 1 deletion .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="build -d -O2 -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="build -d -O0 -g -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<envs>
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
</envs>
Expand Down
43 changes: 16 additions & 27 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
import "std/io/cli-parser";
import "std/os/thread-pool";

type CliOptions struct {
bool sayHi = false
}

p callback(bool& value) {
printf("Callback called with value %d\n", value);
}

f<int> main(int argc, string[] argv) {
CliParser parser = CliParser("Test Program", "This is a simple test program");
parser.setVersion("v0.1.0");
parser.setFooter("Copyright (c) Marc Auberer 2021-2023");

CliOptions options;
parser.addFlag("--hi", options.sayHi, "Say hi to the user");
parser.addFlag("--callback", callback, "Call a callback function");
parser.addFlag("-cb", p(bool& value) {
printf("CB called with value %d\n", value);
}, "Call a callback function");

parser.parse(argc, argv);

// Print hi if requested
if options.sayHi {
printf("Hi!\n");
}
f<int> main() {
ThreadPool tp = ThreadPool(3s);
tp.enqueue(p() {
printf("Hello from task 1\n");
});
tp.enqueue(p() {
printf("Hello from task 2\n");
});
tp.enqueue(p() {
printf("Hello from task 3\n");
});
tp.enqueue(p() {
printf("Hello from task 4\n");
});
tp.start();
}

/*import "std/os/thread-pool";
Expand Down
2 changes: 1 addition & 1 deletion src/ast/ASTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ASTNode;
class ConstantNode;

#define ERROR_MESSAGE_CONTEXT 20
const char *const RESERVED_KEYWORDS[8] = {"new", "switch", "case", "yield", "stash", "pick", "sync", "class"};
const char *const RESERVED_KEYWORDS[] = {"new", "switch", "case", "stash", "pick", "sync", "class"};
const char *const MEMBER_ACCESS_TOKEN = ".";
const char *const SCOPE_ACCESS_TOKEN = "::";

Expand Down
9 changes: 5 additions & 4 deletions src/irgenerator/IRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,13 +463,14 @@ void IRGenerator::generateDtorCall(SymbolTableEntry *entry, Function *dtor, cons
llvm::Value *structPtr;
if (entry->isField()) {
// Take 'this' var as base pointer
SymbolTableEntry *thisVar = currentScope->lookupStrict(THIS_VARIABLE_NAME);
const SymbolTableEntry *thisVar = currentScope->lookupStrict(THIS_VARIABLE_NAME);
assert(thisVar != nullptr);
llvm::Value *baseAddress = thisVar->getAddress();
assert(thisVar->getType().isPtr() && thisVar->getType().getContainedTy().is(TY_STRUCT));
llvm::Type *thisType = thisVar->getType().getContainedTy().toLLVMType(context, currentScope);
llvm::Value *thisPtr = builder.CreateLoad(builder.getPtrTy(), thisVar->getAddress());
// Add field offset
llvm::Type *fieldType = entry->getType().toLLVMType(context, currentScope);
llvm::ArrayRef<llvm::Value *> indices = {builder.getInt32(0), builder.getInt32(entry->orderIndex)};
structPtr = builder.CreateInBoundsGEP(fieldType, baseAddress, indices);
structPtr = builder.CreateInBoundsGEP(thisType, thisPtr, indices);
} else {
structPtr = entry->getAddress();
}
Expand Down
2 changes: 2 additions & 0 deletions std/data/vector.spice
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public type Vector<T> struct {
public p Vector.ctor(unsigned long initAllocItems = INITIAL_ALLOC_COUNT) {
// Allocate space for the initial number of elements
const long itemSize = sizeof(type T) / 8l;
assert itemSize != 0l;
unsafe {
this.contents = (T*) malloc(itemSize * initAllocItems);
}
Expand Down Expand Up @@ -194,6 +195,7 @@ public p Vector.pack() {
p Vector.resize(unsigned long itemCount) {
// Allocate the new memory
const long itemSize = sizeof(type T) / 8l;
assert itemSize != 0l;
unsafe {
byte* oldAddress = (byte*) this.contents;
int newSize = (int) (itemSize * itemCount);
Expand Down
22 changes: 22 additions & 0 deletions std/math/fct.spice
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,28 @@ public inline f<Numeric> abs<Numeric>(Numeric input) {
return input < 0 ? -input : input;
}

/**
* Calculate the maximum of two inputs
*
* @param input1 First input
* @param input2 Second input
* @return Maximum of inputs
*/
public inline f<Numeric> max<Numeric>(Numeric input1, Numeric input2) {
return input1 > input2 ? input1 : input2;
}

/**
* Calculate the minimum of two inputs
*
* @param input1 First input
* @param input2 Second input
* @return Minimum of inputs
*/
public inline f<Numeric> min<Numeric>(Numeric input1, Numeric input2) {
return input1 < input2 ? input1 : input2;
}

/**
* Round the input number down
*
Expand Down
2 changes: 1 addition & 1 deletion std/os/cpu.spice
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ ext f<int> sched_yield();
* Causes the calling thread to relinquish the CPU.
* The thread is moved to the end of the scheduling queue and the next thread gets to run.
*/
p yield() {
public p yield() {
sched_yield();
}
48 changes: 28 additions & 20 deletions std/os/thread-pool.spice
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import "std/os/thread";
import "std/data/queue";
import "std/data/vector";
import "std/os/system";
import "std/os/cpu";
import "std/runtime/iterator_rt";

/**
* A thread pool that can be used to run multiple jobs in parallel.
Expand All @@ -25,17 +26,30 @@ public p ThreadPool.ctor(unsigned short workerThreadCount = 0s) {
this.queuedJobs = Queue<p()>();
this.workerThreadCount = workerThreadCount > 0s ? workerThreadCount : (unsigned short) getCPUCoreCount();
this.runningJobs = 0s;
}

/**
* Destroy the thread pool.
*/
public p ThreadPool.dtor() {
this.join();
}

/**
* Start the thread pool.
*/
public p ThreadPool.start() {
p() workerRoutine = p() {
p() task;
while (true) {
if !this.stopRequested { break; }
/*if this.paused { continue; }
task = this.queuedJobs.pop();
this.runningJobs++;
task();
this.runningJobs--;*/
}
do {
if !this.paused & !this.queuedJobs.isEmpty() {
p() task = this.queuedJobs.pop();
printf("Worker %d took job\n", getThreadId());
this.runningJobs++;
task();
this.runningJobs--;
}
yield();
} while (!this.stopRequested);
};

// Create worker threads
Expand All @@ -46,20 +60,14 @@ public p ThreadPool.ctor(unsigned short workerThreadCount = 0s) {
}
}

/**
* Destroy the thread pool.
*/
public p ThreadPool.dtor() {
this.join();
}

/**
* Stop the thread pool. This will wait for all running jobs to finish.
*/
public p ThreadPool.join() {
// Join worker threads
for (unsigned short i = 0s; i < this.workerThreadCount; i++) {
Thread& workerThread = this.workerThreads.get((unsigned int) i);
// Stop worker threads
this.stopRequested = true;
// Wait for all worker threads to terminate
foreach (const Thread& workerThread : iterate(this.workerThreads)) {
workerThread.join();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,64 @@ target triple = "x86_64-w64-windows-gnu"
%struct.Vector = type { i1, ptr }

@printf.str.0 = private unnamed_addr constant [19 x i8] c"Destructor called!\00", align 1
@anon.string.0 = private unnamed_addr constant [5 x i8] c"Test\00", align 1
@anon.struct.0 = private unnamed_addr constant %struct.Vector { i1 true, ptr @anon.string.0 }
@anon.string.0 = private unnamed_addr constant [70 x i8] c"Assertion failed: Condition 'this.field1 == true' evaluated to false.\00", align 1
@anon.string.1 = private unnamed_addr constant [5 x i8] c"Test\00", align 1
@anon.string.2 = private unnamed_addr constant [72 x i8] c"Assertion failed: Condition 'this.field2 == \22Test\22' evaluated to false.\00", align 1
@anon.string.3 = private unnamed_addr constant [5 x i8] c"Test\00", align 1
@anon.struct.0 = private unnamed_addr constant %struct.Vector { i1 true, ptr @anon.string.3 }
@printf.str.1 = private unnamed_addr constant [16 x i8] c"Fields: %d, %s\0A\00", align 1

define private void @_ZN6Vector4dtorEv(ptr noundef nonnull %0) {
%this = alloca ptr, align 8
%2 = alloca i1, align 1
store ptr %0, ptr %this, align 8
%2 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.0)
%3 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.0)
%4 = load ptr, ptr %this, align 8
%field1_addr = getelementptr inbounds %struct.Vector, ptr %4, i32 0, i32 0
store i1 true, ptr %2, align 1
%5 = call i32 @memcmp(ptr %field1_addr, ptr %2, i64 0)
%6 = icmp eq i32 %5, 0
br i1 %6, label %assert.exit.L8, label %assert.then.L8, !prof !0

assert.then.L8: ; preds = %1
%7 = call i32 (ptr, ...) @printf(ptr @anon.string.0)
call void @exit(i32 1)
unreachable

assert.exit.L8: ; preds = %1
%8 = load ptr, ptr %this, align 8
%field2_addr = getelementptr inbounds %struct.Vector, ptr %8, i32 0, i32 1
%9 = load ptr, ptr %field2_addr, align 8
%10 = call i1 @_Z10isRawEqualPcPc(ptr %9, ptr @anon.string.1)
br i1 %10, label %assert.exit.L9, label %assert.then.L9, !prof !0

assert.then.L9: ; preds = %assert.exit.L8
%11 = call i32 (ptr, ...) @printf(ptr @anon.string.2)
call void @exit(i32 1)
unreachable

assert.exit.L9: ; preds = %assert.exit.L8
ret void
}

; Function Attrs: nofree nounwind
declare noundef i32 @printf(ptr nocapture noundef readonly, ...) #0

; Function Attrs: nounwind
declare i32 @memcmp(ptr, ptr, i64) #1

; Function Attrs: cold noreturn nounwind
declare void @exit(i32) #2

declare i1 @_Z10isRawEqualPcPc(ptr, ptr)

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #1 {
define dso_local i32 @main() #3 {
%result = alloca i32, align 4
%vec = alloca %struct.Vector, align 8
store i32 0, ptr %result, align 4
call void @llvm.memcpy.p0.p0.i64(ptr %vec, ptr @anon.struct.0, i64 16, i1 false)
store %struct.Vector { i1 true, ptr @anon.string.0 }, ptr %vec, align 8
store %struct.Vector { i1 true, ptr @anon.string.3 }, ptr %vec, align 8
%field1_addr = getelementptr inbounds %struct.Vector, ptr %vec, i32 0, i32 0
%1 = load i1, ptr %field1_addr, align 1
%2 = zext i1 %1 to i32
Expand All @@ -39,8 +76,12 @@ define dso_local i32 @main() #1 {
}

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #2
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #4

attributes #0 = { nofree nounwind }
attributes #1 = { noinline nounwind optnone uwtable }
attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #1 = { nounwind }
attributes #2 = { cold noreturn nounwind }
attributes #3 = { noinline nounwind optnone uwtable }
attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }

!0 = !{!"branch_weights", i32 2000, i32 1}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ type Vector struct {

p Vector.dtor() {
printf("Destructor called!");
assert this.field1 == true;
assert this.field2 == "Test";
}

f<int> main() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ target triple = "x86_64-w64-windows-gnu"
@anon.struct.0 = private unnamed_addr constant %struct.Vector { i1 true, ptr @anon.string.0 }
@printf.str.0 = private unnamed_addr constant [16 x i8] c"Fields: %d, %s\0A\00", align 1
@printf.str.1 = private unnamed_addr constant [19 x i8] c"Destructor called!\00", align 1
@anon.string.1 = private unnamed_addr constant [70 x i8] c"Assertion failed: Condition 'this.field1 == true' evaluated to false.\00", align 1
@anon.string.2 = private unnamed_addr constant [5 x i8] c"Test\00", align 1
@anon.string.3 = private unnamed_addr constant [72 x i8] c"Assertion failed: Condition 'this.field2 == \22Test\22' evaluated to false.\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
Expand Down Expand Up @@ -36,11 +39,49 @@ declare noundef i32 @printf(ptr nocapture noundef readonly, ...) #2

define private void @_ZN6Vector4dtorEv(ptr noundef nonnull %0) {
%this = alloca ptr, align 8
%2 = alloca i1, align 1
store ptr %0, ptr %this, align 8
%2 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.1)
%3 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.1)
%4 = load ptr, ptr %this, align 8
%field1_addr = getelementptr inbounds %struct.Vector, ptr %4, i32 0, i32 0
store i1 true, ptr %2, align 1
%5 = call i32 @memcmp(ptr %field1_addr, ptr %2, i64 0)
%6 = icmp eq i32 %5, 0
br i1 %6, label %assert.exit.L13, label %assert.then.L13, !prof !0

assert.then.L13: ; preds = %1
%7 = call i32 (ptr, ...) @printf(ptr @anon.string.1)
call void @exit(i32 1)
unreachable

assert.exit.L13: ; preds = %1
%8 = load ptr, ptr %this, align 8
%field2_addr = getelementptr inbounds %struct.Vector, ptr %8, i32 0, i32 1
%9 = load ptr, ptr %field2_addr, align 8
%10 = call i1 @_Z10isRawEqualPcPc(ptr %9, ptr @anon.string.2)
br i1 %10, label %assert.exit.L14, label %assert.then.L14, !prof !0

assert.then.L14: ; preds = %assert.exit.L13
%11 = call i32 (ptr, ...) @printf(ptr @anon.string.3)
call void @exit(i32 1)
unreachable

assert.exit.L14: ; preds = %assert.exit.L13
ret void
}

; Function Attrs: nounwind
declare i32 @memcmp(ptr, ptr, i64) #3

; Function Attrs: cold noreturn nounwind
declare void @exit(i32) #4

declare i1 @_Z10isRawEqualPcPc(ptr, ptr)

attributes #0 = { noinline nounwind optnone uwtable }
attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #2 = { nofree nounwind }
attributes #3 = { nounwind }
attributes #4 = { cold noreturn nounwind }

!0 = !{!"branch_weights", i32 2000, i32 1}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ f<int> main() {

p Vector.dtor() {
printf("Destructor called!");
assert this.field1 == true;
assert this.field2 == "Test";
}

0 comments on commit 1b1ed41

Please sign in to comment.