diff --git a/.run/spice.run.xml b/.run/spice.run.xml index efc46a910..a3a1adb7a 100644 --- a/.run/spice.run.xml +++ b/.run/spice.run.xml @@ -1,5 +1,5 @@ - + diff --git a/media/test-project/test.spice b/media/test-project/test.spice index f919a118c..f24ede80e 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,42 +1,13 @@ -import "std/os/thread"; - -f fib(int n) { - if n <= 2 { return 1; } - return fib(n - 1) + fib(n - 2); -} - -f main() { - int threadCount = 8; - Thread[8] threads = []; - for unsigned int i = 0; i < threadCount; i++ { - threads[i] = Thread(p() { - int res = fib(30); - printf("Thread returned with result: %d\n", res); - }); - Thread& thread = threads[i]; - thread.run(); - } - printf("Started all threads. Waiting for results ...\n"); - for unsigned int i = 0; i < threadCount; i++ { - Thread& thread = threads[i]; - thread.join(); - } - printf("Program finished"); -} - -/*import "bootstrap/util/block-allocator"; -import "bootstrap/util/memory"; - -type ASTNode struct { - int value -} - -public p ASTNode.dtor() { - printf("Dtor called!"); -} +import "std/os/env"; +import "bootstrap/ast/ast-nodes"; +import "bootstrap/lexer/lexer"; +import "bootstrap/parser/parser"; f main() { - DefaultMemoryManager defaultMemoryManager; - IMemoryManager* memoryManager = &defaultMemoryManager; - BlockAllocator allocator = BlockAllocator(memoryManager, 10l); -}*/ \ No newline at end of file + String filePath = getEnv("SPICE_STD_DIR") + "/../test/test-files/bootstrap-compiler/standalone-parser-test/test-file.spice"; + Lexer lexer = Lexer(filePath.getRaw()); + Parser parser = Parser(lexer); + ASTEntryNode* ast = parser.parse(); + assert ast != nil; + printf("All assertions passed!\n"); +} \ No newline at end of file diff --git a/src-bootstrap/global/global-resource-manager.spice b/src-bootstrap/global/global-resource-manager.spice index fc855730d..a8e575234 100644 --- a/src-bootstrap/global/global-resource-manager.spice +++ b/src-bootstrap/global/global-resource-manager.spice @@ -3,6 +3,7 @@ import "std/type/byte"; import "std/data/vector"; import "std/data/unordered-map"; import "std/time/timer"; +import "std/io/filepath"; // Own imports import "../global/runtime-module-manager"; @@ -25,7 +26,7 @@ public const string LTO_FILE_NAME = "lto-module"; */ public type GlobalResourceManager struct { public llvm::Context context - public llvm::IRBuilder builder + public llvm::IRBuilder builder = llvm::IRBuilder(context) public llvm::Module ltoModule public llvm::TargetMachine targetMachine public DefaultMemoryManager memoryManager @@ -39,6 +40,7 @@ public type GlobalResourceManager struct { public RuntimeModuleManager runtimeModuleManager public Timer totalTimer public ErrorManager errorManager + public bool abortCompilation = false unsigned long nextCustomTypeId = BYTE_MAX_VALUE + 1 // Start at 256 because all primitive types come first } @@ -77,7 +79,9 @@ public p GlobalResourceManager.ctor(const CliOptions& cliOptions) { } public p GlobalResourceManager.dtor() { - // Shutdown LLVM + // Cleanup all statics + // ToDo: Implement + // Cleanup all LLVM statics llvm::llvm_shutdown(); } @@ -96,4 +100,12 @@ public f GlobalResourceManager.createSourceFile(SourceFile* pa public f GlobalResourceManager.getNextCustomTypeId() { return nextCustomTypeId++; +} + +public f GlobalResourceManager.getTotalLineCount() { + unsigned long totalLineCount = 0l; + foreach const SourceFile* sourceFile : sourceFiles { + totalLineCount += sourceFile.value.getLineCount(); + } + return totalLineCount; } \ No newline at end of file diff --git a/src-bootstrap/source-file.spice b/src-bootstrap/source-file.spice index fbb209b64..6472d12ee 100644 --- a/src-bootstrap/source-file.spice +++ b/src-bootstrap/source-file.spice @@ -1,6 +1,7 @@ // Imports import "std/text/print"; import "std/data/pair"; +import "std/io/filepath"; import "./driver"; import "./global/global-resource-manager"; import "./ast/ast-nodes"; @@ -11,7 +12,6 @@ type CompileStageType enum { PARSER, CST_VISUALIZER, AST_BUILDER, - AST_OPTIMIZER, AST_VISUALIZER, IMPORT_COLLECTOR, SYMBOL_TABLE_BUILDER, @@ -19,7 +19,8 @@ type CompileStageType enum { TYPE_CHECKER_POST, IR_GENERATOR, IR_OPTIMIZER, - OBJECT_EMITTER + OBJECT_EMITTER, + FINISHED } type CompileStageIOType enum { @@ -44,7 +45,6 @@ type TimerOutput struct { unsigned long irGenerator = 0l unsigned long irOptimizer = 0l unsigned long objectEmitter = 0l - unsigned long executionEngine = 0l } /** @@ -57,16 +57,17 @@ type CompilerOutput struct { String irString String irOptString String asmString + String typesString Vector warnings TimerOutput times } type NameRegistryEntry struct { String name + unsigned long typeId // Set for structs, interfaces and enums SymbolTableEntry* targetEntry Scope* targetScope - SymbolTableEntry* importEntry - String predecessorName + SymbolTableEntry* importEntry = nil } /** @@ -75,22 +76,26 @@ type NameRegistryEntry struct { public type SourceFile struct { public String name public String fileName - public String filePath + public FilePath filePath public String fileDir - public String objectFilePath public bool stdFile = false public bool mainFile = true + public bool alwaysKeepSymbolsOnNameCollision = false + public bool ignoreWarnings = false + public CompileStageType previousStage = CompileStageType::NONE public CompilerOutput compilerOutput public SourceFile* parent public String cacheKey public bool restoredFromCache = false - public EntryNode ast - public Scope globalScope + public EntryNode* ast = nil + public heap Scope* globalScope //public llvm::Module llvmModule - public Map> dependencies + public Vector dependants public Map exportedNameRegistry + public Vector testFunctions GlobalResourceManager& resourceManager + CliOptions& cliOptions unsigned short importedRuntimeModules = 0s unsigned short totalTypeCheckerRuns = 0s } diff --git a/src-bootstrap/util/block-allocator.spice b/src-bootstrap/util/block-allocator.spice index 7101acf9a..4937fb331 100644 --- a/src-bootstrap/util/block-allocator.spice +++ b/src-bootstrap/util/block-allocator.spice @@ -6,18 +6,21 @@ import "std/os/system"; import "../util/memory"; type Base dyn; +type T dyn; public type BlockAllocator struct { - IMemoryManager* memoryManager + IMemoryManager& memoryManager Vector memoryBlocks Vector allocatedObjects unsigned long blockSize unsigned long offsetInBlock = 0l } -public p BlockAllocator.ctor(IMemoryManager* memoryManager, unsigned long blockSize = 0l) { +public p BlockAllocator.ctor(IMemoryManager& memoryManager, unsigned long blockSize = 0l) { this.memoryManager = memoryManager; this.blockSize = blockSize == 0l ? (unsigned long) getPageSize() : blockSize; + // We do not allow allocating objects that exceed the block size + assert sizeof(type Base) <= this.blockSize; // Allocate the first block this.allocateNewBlock(); } @@ -30,12 +33,34 @@ public p BlockAllocator.dtor() { this.allocatedObjects.clear(); // Free all memory blocks - foreach byte* block : this.memoryBlocks { + foreach heap byte* block : this.memoryBlocks { this.memoryManager.deallocate(block); } this.memoryBlocks.clear(); } +public f BlockAllocator.allocate(const T& obj) { + // We do not allow allocating objects that exceed the block size + const unsigned long objSize = sizeof(type T); + assert objSize <= this.blockSize; + + // Check if we need a new block + if this.offsetInBlock + objSize > this.blockSize { + this.allocateNewBlock(); + } + + // Construct object at the offset address + heap byte* destAddr = this.memoryBlocks.back(); + unsafe { + destAddr += this.offsetInBlock; + } + T* ptr = sPlacementNew(destAddr, obj); + + // Update offset to be ready to store the next object + this.offsetInBlock += objSize; + return ptr; +} + public p BlockAllocator.allocateNewBlock() { // Allocate new block heap byte* ptr = this.memoryManager.allocate(this.blockSize); diff --git a/src/SourceFile.h b/src/SourceFile.h index d30eb9575..d5054ceae 100644 --- a/src/SourceFile.h +++ b/src/SourceFile.h @@ -188,7 +188,7 @@ class SourceFile { const CliOptions &cliOptions; BS::synced_stream &tout; uint8_t importedRuntimeModules = 0; - unsigned short totalTypeCheckerRuns = 0; + uint8_t totalTypeCheckerRuns = 0; // Private methods bool haveAllDependantsBeenTypeChecked() const; diff --git a/src/ast/ASTNodes.h b/src/ast/ASTNodes.h index b0000a074..cab75472d 100644 --- a/src/ast/ASTNodes.h +++ b/src/ast/ASTNodes.h @@ -90,9 +90,11 @@ class ASTNode { virtual std::vector> *getOpFctPointers() { // LCOV_EXCL_LINE assert_fail("The given node does not overload the getOpFctPointers function"); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE } // LCOV_EXCL_LINE [[nodiscard]] virtual const std::vector> *getOpFctPointers() const { // LCOV_EXCL_LINE assert_fail("The given node does not overload the getOpFctPointers function"); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE } // LCOV_EXCL_LINE virtual void customItemsInitialization(size_t) {} // Noop @@ -131,14 +133,17 @@ class ASTNode { [[nodiscard]] virtual std::vector *getFctManifestations(const std::string &) { // LCOV_EXCL_LINE assert_fail("Must be called on a FctDefNode, ProcDefNode, ExtDeclNode, StructDefNode or SignatureNode"); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE } // LCOV_EXCL_LINE [[nodiscard]] virtual std::vector *getStructManifestations() { // LCOV_EXCL_LINE assert_fail("Must be called on a StructDefNode"); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE } // LCOV_EXCL_LINE [[nodiscard]] virtual std::vector *getInterfaceManifestations() { // LCOV_EXCL_LINE assert_fail("Must be called on a InterfaceDefNode"); // LCOV_EXCL_LINE + return nullptr; // LCOV_EXCL_LINE } // LCOV_EXCL_LINE [[nodiscard]] virtual bool isFctOrProcDef() const { return false; } diff --git a/src/util/CodeLoc.h b/src/util/CodeLoc.h index a2637c487..64f068b7b 100644 --- a/src/util/CodeLoc.h +++ b/src/util/CodeLoc.h @@ -21,7 +21,7 @@ struct CodeLoc { CodeLoc(const antlr4::Token *token, size_t startIdx, size_t stopIdx, SourceFile *sourceFile = nullptr) : sourceFile(sourceFile), sourceInterval(startIdx, stopIdx), line(token->getLine()), col(token->getCharPositionInLine() + 1){}; - CodeLoc(size_t line, size_t col, SourceFile *sourceFile = nullptr) : sourceFile(sourceFile), line(line), col(col) {} + CodeLoc(uint32_t line, uint32_t col, SourceFile *sourceFile = nullptr) : sourceFile(sourceFile), line(line), col(col) {} // Public members SourceFile *sourceFile = nullptr; diff --git a/std/runtime/memory_rt.spice b/std/runtime/memory_rt.spice index 2ef7dd7ba..d921ba647 100644 --- a/std/runtime/memory_rt.spice +++ b/std/runtime/memory_rt.spice @@ -98,12 +98,12 @@ public f sNew(const T& val) { * @param val The value to put into the heap-allocated memory * @return A pointer to the heap-allocated instance */ -public f sPlacementNew(heap byte* ptr, const T& val) { +public f sPlacementNew(heap byte* ptr, const T& val) { unsafe { // Copy the value into the heap-allocated memory - sCopy((heap byte*) &val, (heap byte*) ptr, sizeof(type T)); + sCopy((heap byte*) &val, ptr, sizeof(type T)); + return (T*) ptr; } - return ptr; } /** diff --git a/test/test-files/std/os/thread-pool/source.spice b/test/test-files/std/os/thread-pool/source.spice index 97fc31637..aac51db59 100644 --- a/test/test-files/std/os/thread-pool/source.spice +++ b/test/test-files/std/os/thread-pool/source.spice @@ -4,43 +4,43 @@ import "std/time/delay"; f main() { ThreadPool tp = ThreadPool(3s); tp.enqueue(p() [[async]] { - delay(50); + delay(10); printf("Hello from task 1\n"); }); tp.enqueue(p() [[async]] { - delay(100); + delay(20); printf("Hello from task 2\n"); }); tp.enqueue(p() [[async]] { - delay(150); + delay(30); printf("Hello from task 3\n"); }); tp.enqueue(p() [[async]] { - delay(200); + delay(40); printf("Hello from task 4\n"); }); tp.enqueue(p() [[async]] { - delay(250); + delay(50); printf("Hello from task 5\n"); }); tp.enqueue(p() [[async]] { - delay(300); + delay(60); printf("Hello from task 6\n"); }); tp.enqueue(p() [[async]] { - delay(350); + delay(70); printf("Hello from task 7\n"); }); tp.enqueue(p() [[async]] { - delay(400); + delay(80); printf("Hello from task 8\n"); }); tp.enqueue(p() [[async]] { - delay(450); + delay(90); printf("Hello from task 9\n"); }); tp.enqueue(p() [[async]] { - delay(500); + delay(100); printf("Hello from task 10\n"); }); tp.start(); diff --git a/test/unittest/UnitBlockAllocator.cpp b/test/unittest/UnitBlockAllocator.cpp index 1e71dfc76..8b1034cc7 100644 --- a/test/unittest/UnitBlockAllocator.cpp +++ b/test/unittest/UnitBlockAllocator.cpp @@ -35,7 +35,7 @@ class MockMemoryManager : public MemoryManager { TEST(BlockAllocatorTest, TestBlockAllocatorLarge) { destructedDummyNodes = 0; // Reset destruction counter - constexpr size_t NODE_COUNT = 100000; // 100.000 * 176 bytes = 17.6 MB + constexpr size_t NODE_COUNT = 100000; // 100.000 * 104 bytes = 10.4 MB { // Create allocator, that can hold 5 nodes per block @@ -60,7 +60,7 @@ TEST(BlockAllocatorTest, TestBlockAllocatorLarge) { TEST(BlockAllocatorTest, TestBlockAllocatorUnevenBlockSize) { destructedDummyNodes = 0; // Reset destruction counter - constexpr size_t NODE_COUNT = 1000; // 1.000 * 176 bytes = 176 KB + constexpr size_t NODE_COUNT = 1000; // 1.000 * 104 bytes = 104 KB { // Create allocator, that can hold 4.5 nodes per block @@ -85,7 +85,7 @@ TEST(BlockAllocatorTest, TestBlockAllocatorUnevenBlockSize) { TEST(BlockAllocatorTest, TestBlockAllocatorOOM) { destructedDummyNodes = 0; // Reset destruction counter - constexpr size_t NODE_COUNT = 10; // 10 * 176 bytes = 1.76 KB + constexpr size_t NODE_COUNT = 10; // 10 * 104 bytes = 1.04 KB // Prepare mock methods MockMemoryManager mockMemoryManager;