From 481341409be09434c62b6aa167068d422e850c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 16 Mar 2025 23:25:34 -0300 Subject: [PATCH 01/10] [cpp:vscode] add a couple settings to enable building, and to support includes in intellisense --- .vscode/c_cpp_properties.json | 21 +++++++++++++++++++++ .vscode/settings.json | 7 +++++++ 2 files changed, 28 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..2c2b5854 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**", + "~/.conan2/**" + ], + "defines": [], + "macFrameworkPath": [ + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/usr/bin/clang", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "macos-clang-arm64", + "configurationProvider": "ms-vscode.makefile-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..429a413b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cmake.sourceDirectory": "${workspaceFolder}/runtime/cpp", + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/runtime/cpp/build/conan_toolchain.cmake", + "-DCMAKE_PREFIX_PATH=${workspaceFolder}/runtime/cpp/build" + ] +} \ No newline at end of file From fcc3f27a98b36d8e47f4c5a5a3cb2725f40dea59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 16 Mar 2025 23:54:36 -0300 Subject: [PATCH 02/10] [cpp:vscode] Update debug configuration with proper exe path and support for macos --- .vscode/launch.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index cdde698a..ab19ab2f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,13 +15,21 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/cpp/egg", - "args": ["${workspaceFolder}/image-segments/Kernel.ems"], + "program": "${workspaceFolder}/runtime/cpp/build/egg", + "args": ["TinyBenchmarks"], "stopAtEntry": false, - "cwd": "${fileDirname}", + "cwd": "${workspaceFolder}/image-segments/", "environment": [], "externalConsole": false, - "MIMode": "gdb", + "linux" : { + "MIMode": "gdb", + }, + "osx" : { + "MIMode": "lldb" + }, + "windows": { + "MIMode": "gdb" + }, "setupCommands": [ { "description": "Enable pretty-printing for gdb", From 58a9f5e2b1c20333c61b19f584de6e05df7620a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 16 Mar 2025 23:55:57 -0300 Subject: [PATCH 03/10] [cpp:git] ignore build and clion files --- runtime/cpp/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 runtime/cpp/.gitignore diff --git a/runtime/cpp/.gitignore b/runtime/cpp/.gitignore new file mode 100644 index 00000000..baadeb1b --- /dev/null +++ b/runtime/cpp/.gitignore @@ -0,0 +1,3 @@ +build/* +.idea/* +CMakeUserPresets.json \ No newline at end of file From 825aeab72bbe2282a75212f12041c674ea028f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:11:17 -0300 Subject: [PATCH 04/10] [git] ignore mac hidden files and release build dir --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 771a57ac..50a4fba6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -image-segments \ No newline at end of file +.DS_Store +release/* From f96cedddff61492d881e372f3ab1ad47eab14ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:17:28 -0300 Subject: [PATCH 05/10] [cppvm][kernel] add a primitive to do very basic logging --- modules/Kernel/HostSystem.st | 32 +++++++++++++++++- modules/Kernel/KernelModule.st | 5 +++ runtime/cpp/Evaluator/Evaluator.cpp | 23 +++++++++++++ runtime/cpp/Evaluator/Evaluator.h | 1 + runtime/cpp/Evaluator/Runtime.cpp | 46 +++++++++++++++++++++++++ runtime/cpp/Evaluator/Runtime.h | 1 + runtime/cpp/Utils/CRLFStream.h | 52 +++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 runtime/cpp/Utils/CRLFStream.h diff --git a/modules/Kernel/HostSystem.st b/modules/Kernel/HostSystem.st index 1379d2e0..7a61e24c 100644 --- a/modules/Kernel/HostSystem.st +++ b/modules/Kernel/HostSystem.st @@ -40,11 +40,41 @@ HostSystem >> load: aSymbol [ ^module justLoaded ] +{ #category : #logging } +HostSystem >> log: aString level: anInteger [ + +] + +{ #category : #logging } +HostSystem >> logTrace: aString [ + self log: aString level: 0 +] + +{ #category : #logging } +HostSystem >> logDebug: aString [ + self log: aString level: 1 +] + +{ #category : #logging } +HostSystem >> logInfo: aString [ + self log: aString level: 2 +] + +{ #category : #logging } +HostSystem >> logWarning: aString [ + self log: aString level: 3 +] + { #category : #logging } HostSystem >> logError: aString [ - + self log: aString level: 4 ] +{ #category : #logging } +HostSystem >> logFatal: aString [ + self log: aString level: 5 + +] { #category : #loading } HostSystem >> platformName [ diff --git a/modules/Kernel/KernelModule.st b/modules/Kernel/KernelModule.st index 29448544..81f5f43e 100644 --- a/modules/Kernel/KernelModule.st +++ b/modules/Kernel/KernelModule.st @@ -151,6 +151,11 @@ KernelModule >> loadedModuleNamed: aSymbol [ ^loadedModules at: aSymbol ifAbsent: [] ] +{ #category : #logging } +KernelModule >> log: aString [ + ^host log: aString level: 2 +] + { #category : #accessing } KernelModule >> memory [ ^memory diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index b8e7d47f..df8cd9b8 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -161,6 +161,8 @@ void Evaluator::initializePrimitives() this->addPrimitive("HostInitializeFFI", &Evaluator::primitiveHostInitializeFFI); this->addPrimitive("HostPlatformName", &Evaluator::primitiveHostPlatformName); this->addPrimitive("HostCurrentMilliseconds", &Evaluator::primitiveHostCurrentMilliseconds); + this->addPrimitive("HostLog", &Evaluator::primitiveHostLog); + /*this->addPrimitive("PrepareForExecution", &Evaluator::primitivePrepareForExecution); this->addPrimitive("ProcessVMStackInitialize", &Evaluator::primitiveProcessVMStackInitialize); this->addPrimitive("ProcessVMStackAt", &Evaluator::primitiveProcessVMStackAt); @@ -675,6 +677,27 @@ Object* Evaluator::primitiveHostPlatformName() { return (Object*)this->_runtime->newString_(PlatformName()); } +Object* Evaluator::primitiveHostLog() { + auto arg = this->_context->firstArgument(); + auto code = this->_context->secondArgument()->asSmallInteger()->asNative(); + + std::string message; + if (arg->isSmallInteger()) + message = arg->printString(); + else + { + auto harg = arg->asHeapObject(); + auto species = _runtime->behaviorClass_(harg->behavior()); + if (species == _runtime->_stringClass) + message = harg->asLocalString(); + else + message = harg->printString(); + } + + _runtime->log_code_(message, code); + return this->_regR; +} + Object* Evaluator::primitiveHostInitializeFFI() { auto library = this->_context->firstArgument()->asHeapObject(); auto handle = library->slotAt_(1); diff --git a/runtime/cpp/Evaluator/Evaluator.h b/runtime/cpp/Evaluator/Evaluator.h index ba52bb03..9bdd877a 100644 --- a/runtime/cpp/Evaluator/Evaluator.h +++ b/runtime/cpp/Evaluator/Evaluator.h @@ -204,6 +204,7 @@ class Evaluator : public SExpressionVisitor { Object* primitiveHostFixOverrides(); Object* primitiveHostInitializeFFI(); Object* primitiveHostLoadModule(); + Object* primitiveHostLog(); Object* primitiveHostPlatformName(); Object* primitiveNew(); Object* primitiveNewBytes(); diff --git a/runtime/cpp/Evaluator/Runtime.cpp b/runtime/cpp/Evaluator/Runtime.cpp index 2601b899..423943b5 100644 --- a/runtime/cpp/Evaluator/Runtime.cpp +++ b/runtime/cpp/Evaluator/Runtime.cpp @@ -11,6 +11,7 @@ #include "KnownConstants.h" #include "GCedRef.h" #include "StackGCedRef.h" +#include "Utils/CRLFStream.h" using namespace Egg; @@ -421,3 +422,48 @@ std::string Egg::Runtime::print_(HeapObject *obj) { return "a " + name + ""; } + + +// Color codes for different log levels +#define RESET "\033[0m" +#define RED "\033[31m" +#define YELLOW "\033[33m" +#define GREEN "\033[32m" +#define BLUE "\033[34m" +#define MAGENTA "\033[35m" +#define CYAN "\033[36m" + +void Runtime::log_code_(std::string &message, uintptr_t level) +{ + std::ofstream logFile("error-log.txt", std::ios_base::app); // Open log file in append mode + + CRLFStream lfout(std::cout); + + switch(level) { + case 0: // TRACE + lfout << BLUE << "[trace] " + message; break; + case 1: // DEBUG + lfout << GREEN << message; break; + case 2: // INFO + lfout << message; break; + case 3: // WARN + lfout << YELLOW << "[warn] " + message; + break; + case 4: // ERROR + lfout.setStream(std::cerr); + lfout << RED << "[error] " + message; + break; + case 5: // FATAL + lfout.setStream(std::cerr); + lfout << MAGENTA << "[FATAL] " + message; + break; + default: + return; // Invalid level + } + + // Also write to file for all error levels + if (level > 4) { + logFile << "[LEVEL " << level << "] " << message; + } +} + diff --git a/runtime/cpp/Evaluator/Runtime.h b/runtime/cpp/Evaluator/Runtime.h index 5a6211e4..682410cd 100644 --- a/runtime/cpp/Evaluator/Runtime.h +++ b/runtime/cpp/Evaluator/Runtime.h @@ -47,6 +47,7 @@ class Runtime { Runtime(Bootstrapper *bootstrapper, ImageSegment *kernel); std::string print_(HeapObject* obj); + void log_code_(std::string &string, uintptr_t code); void initializeEvaluator(); diff --git a/runtime/cpp/Utils/CRLFStream.h b/runtime/cpp/Utils/CRLFStream.h new file mode 100644 index 00000000..b9d21b03 --- /dev/null +++ b/runtime/cpp/Utils/CRLFStream.h @@ -0,0 +1,52 @@ + +#ifndef _CRLF_STREAM_H_ +#define _CRLF_STREAM_H_ + +#include +#include +#include + +class CRLFStreamBuf : public std::streambuf { + std::streambuf* dest; + bool lastWasCR = false; + +public: + explicit CRLFStreamBuf(std::streambuf* dest) : dest(dest) {} + + void setStreamBuf(std::streambuf* dest) { + this->dest = dest; + } + +protected: + int overflow(int c) override { + if (c == '\r') { + lastWasCR = true; + return dest->sputc('\n'); // Convert CR to LF + } + if (c == '\n') { + if (lastWasCR) { + lastWasCR = false; // Ignore this LF since we already wrote one + return 0; + } + return dest->sputc('\n'); // Normal LF + } + lastWasCR = false; + return dest->sputc(c); + } + + int sync() override { + return dest->pubsync(); + } +}; + +class CRLFStream : public std::ostream { + CRLFStreamBuf buf; + +public: + explicit CRLFStream(std::ostream& out) : std::ostream(&buf), buf(out.rdbuf()) {} + void setStream(std::ostream &out) { + buf.setStreamBuf(out.rdbuf()); + } +}; + +#endif // ~ _CRLF_STREAM_H_ From 9ca3a70462b97abe726bbb63d34e2bcd43256b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:20:00 -0300 Subject: [PATCH 06/10] [examples] add a hello world module --- modules/Examples/HelloWorld/HelloWorldModule.st | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/Examples/HelloWorld/HelloWorldModule.st b/modules/Examples/HelloWorld/HelloWorldModule.st index d625565d..a87bae03 100644 --- a/modules/Examples/HelloWorld/HelloWorldModule.st +++ b/modules/Examples/HelloWorld/HelloWorldModule.st @@ -1,21 +1,16 @@ Class { #name : #HelloWorldModule, #superclass : #Module, - #instVars : [ - '' - ], #category : #'Examples-HelloWorld' } { #category : #spec } HelloWorldModule >> imports [ - ^{ - #Kernel -> #(Transcript) - } + ^{} ] { #category : #services } HelloWorldModule >> main: arguments [ - Transcript show: 'Hello, World!'. + Kernel log: 'Hello, World!', String cr. ^0 ] From a72af8d452d3673232f61827bced877a37d5f30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:25:24 -0300 Subject: [PATCH 07/10] [devops] image-segment Makefile always rebuild target file --- image-segments/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/image-segments/Makefile b/image-segments/Makefile index c47ca114..72f95abd 100644 --- a/image-segments/Makefile +++ b/image-segments/Makefile @@ -4,12 +4,16 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) IMAGE_SEGMENTS_DIR=$(ROOT_DIR)/image-segments PHARO_DIR=$(GIT_PATH)/runtime/pharo +.PHONY: always_rebuild -%.json: +always_rebuild: + @true # Always succeed, forces rebuild + +%.json: always_rebuild export IMAGE_SEGMENTS_DIR cd $(PHARO_DIR) && ./pharo eggjs.image eval "EggBuilder forJSPlatform generateSegmentFromModuleNamed: '$*'" -%.ems: +%.ems: always_rebuild export IMAGE_SEGMENTS_DIR cd $(PHARO_DIR) && ./pharo eggjs.image eval "EggBuilder forNativePlatform generateSegmentFromModuleNamed: '$*'" From 8c492df3004851d540bae569dcfd12206280e746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:26:21 -0300 Subject: [PATCH 08/10] [cppvm] update CMakeLists.txt to add Utils dir --- runtime/cpp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/cpp/CMakeLists.txt b/runtime/cpp/CMakeLists.txt index 0d14afb3..965a10c7 100644 --- a/runtime/cpp/CMakeLists.txt +++ b/runtime/cpp/CMakeLists.txt @@ -34,7 +34,7 @@ find_package(cxxopts REQUIRED) # ************************************************* -file(GLOB ALL_SRC "*.cpp" "Evaluator/*.cpp" "Allocator/*.cpp" "${PLATFORM}/*.cpp") +file(GLOB ALL_SRC "*.cpp" "Evaluator/*.cpp" "Allocator/*.cpp" "Utils/*.cpp" "${PLATFORM}/*.cpp") add_executable(${EXE} ${ALL_SRC}) target_link_libraries(${EXE} libffi::libffi cxxopts::cxxopts) # link agains libffi From ad5031444070776a6ce6d08f59020690fb216d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:30:08 -0300 Subject: [PATCH 09/10] [cppvm] improve #includes order and format --- runtime/cpp/Bootstrapper.h | 12 +++++------- runtime/cpp/Evaluator/Runtime.cpp | 6 ++---- runtime/cpp/Launcher.cpp | 6 ++---- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/runtime/cpp/Bootstrapper.h b/runtime/cpp/Bootstrapper.h index 0eebb6c7..d3e6b420 100644 --- a/runtime/cpp/Bootstrapper.h +++ b/runtime/cpp/Bootstrapper.h @@ -1,17 +1,15 @@ -#include "Evaluator/Runtime.h" -#include "ImageSegment.h" -#include "HeapObject.h" #include #include #include #include #include -#include -#include -#include -#include + +#include "Allocator/GCHeap.h" +#include "Allocator/GCSpace.h" +#include "Evaluator/Evaluator.h" +#include "Evaluator/SAssociationBinding.h" namespace Egg { diff --git a/runtime/cpp/Evaluator/Runtime.cpp b/runtime/cpp/Evaluator/Runtime.cpp index 423943b5..83584936 100644 --- a/runtime/cpp/Evaluator/Runtime.cpp +++ b/runtime/cpp/Evaluator/Runtime.cpp @@ -1,10 +1,8 @@ - -#include "Runtime.h" - -#include #include #include +#include "Runtime.h" +#include "Bootstrapper.h" #include "Evaluator.h" #include "Allocator/GCHeap.h" #include "SAbstractMessage.h" diff --git a/runtime/cpp/Launcher.cpp b/runtime/cpp/Launcher.cpp index fd46f17b..f22d6456 100644 --- a/runtime/cpp/Launcher.cpp +++ b/runtime/cpp/Launcher.cpp @@ -6,16 +6,14 @@ #include #include #include - -#include "Launcher.h" - #include -#include +#include "Launcher.h" #include "ImageSegment.h" #include "Util.h" #include "Bootstrapper.h" +#include "Evaluator/Evaluator.h" #include "Evaluator/Runtime.h" using namespace Egg; From 85f52fabbbce81c452ef3886ee1ea171fd5c8fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 25 Mar 2025 01:36:24 -0300 Subject: [PATCH 10/10] [cppvm] fix subtle error with truncation of behavior addr while relocating image segments --- runtime/cpp/ImageSegment.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/runtime/cpp/ImageSegment.cpp b/runtime/cpp/ImageSegment.cpp index e86c8348..2882a880 100644 --- a/runtime/cpp/ImageSegment.cpp +++ b/runtime/cpp/ImageSegment.cpp @@ -50,14 +50,11 @@ ImageSegment::load(std::istream *data) this->readImportDescriptors(data); this->readExports(data); } - +#include void ImageSegment::fixPointerSlots(const std::vector& imports) { intptr_t delta = this->_currentBase - this->header.baseAddress; - - constexpr auto mask = static_cast(-1LL << 32); // discards lower 32 bits - uintptr_t oldBehaviorBase = this->header.baseAddress & mask; - + uintptr_t oldBehaviorBase = this->header.baseAddress & (((intptr_t)-1) << 32); // discards lower 32 bits auto spaceStart = this->spaceStart(); auto current = ((HeapObject::ObjectHeader*)spaceStart)->object(); auto end = (HeapObject*)this->spaceEnd(); @@ -66,7 +63,8 @@ void ImageSegment::fixPointerSlots(const std::vector& imports) auto behavior = current->basicBehavior(); if (((uintptr_t)behavior & 0x3) == 0x0) // if an oop { - current->behavior((HeapObject*)(oldBehaviorBase + behavior + delta)); + auto newBehavior = oldBehaviorBase + (intptr_t)behavior + delta; + current->behavior((HeapObject*)newBehavior); } else if (((uintptr_t)behavior & 0x3) == 0x2) // if an import {