From 7a4c2ab9c33852d325559f5d774c4571617eca57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Thu, 24 Apr 2025 10:24:50 -0300 Subject: [PATCH 01/24] [cpphttp] make server agnostic on webapp implementation --- modules/HTTP/CPPHTTPServer/CPPHTTPServer.st | 25 +++++---------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/modules/HTTP/CPPHTTPServer/CPPHTTPServer.st b/modules/HTTP/CPPHTTPServer/CPPHTTPServer.st index e9984089..4a73cc78 100644 --- a/modules/HTTP/CPPHTTPServer/CPPHTTPServer.st +++ b/modules/HTTP/CPPHTTPServer/CPPHTTPServer.st @@ -7,18 +7,11 @@ Class { #name : #CPPHTTPServer, #superclass : #ExternalObject, #instVars : [ - 'library', - 'apiClass', - 'baseUri' + 'library' ], #category : #'CPPHTTPServer' } -{ #category : #accessing } -CPPHTTPServer >> apiClass: aClass [ - apiClass := aClass -] - { #category : #accessing } CPPHTTPServer >> baseUri [ ^baseUri @@ -30,14 +23,8 @@ CPPHTTPServer >> baseUri: aString [ ] { #category : #spec } -CPPHTTPServer >> handleRequest: request into: response with: selector [ - | api | - api := apiClass new - server: self; - request: request; - response: response. - api perform: selector. - "response headersAt: 'Access-Control-Allow-Origin' put: '*'." +CPPHTTPServer >> handle: request with: handler into: response with: selector [ + handler handle: request into: response with: selector. ^ response ] @@ -53,11 +40,11 @@ CPPHTTPServer >> library [ ] { #category : #spec } -CPPHTTPServer >> routeGET: uri to: selector [ +CPPHTTPServer >> routeGET: uri to: selector with: handler [ library server: self asParameter - GET: (baseUri , uri) externalCopy asParameter - callback: [ :request :response | self handleRequest: request into: response with: selector ] asCallback + GET: uri externalCopy asParameter + callback: [ :request :response | self handle: request with: handler into: response with: selector ] asCallback ] { #category : #spec } From 5dfc950afa273ed405979443beb7d11de7193461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Thu, 24 Apr 2025 10:31:04 -0300 Subject: [PATCH 02/24] [cpphttp] rename CPPHTTP* to just HTTP* --- .../{CPPHTTPServer.st => HTTPServer.st} | 22 +++++++++---------- ...PServerLibrary.st => HTTPServerLibrary.st} | 18 +++++++-------- ...TTPServerModule.st => HTTPServerModule.st} | 4 ++-- 3 files changed, 22 insertions(+), 22 deletions(-) rename modules/HTTP/CPPHTTPServer/{CPPHTTPServer.st => HTTPServer.st} (65%) rename modules/HTTP/CPPHTTPServer/{CPPHTTPServerLibrary.st => HTTPServerLibrary.st} (59%) rename modules/HTTP/CPPHTTPServer/{CPPHTTPServerModule.st => HTTPServerModule.st} (80%) diff --git a/modules/HTTP/CPPHTTPServer/CPPHTTPServer.st b/modules/HTTP/CPPHTTPServer/HTTPServer.st similarity index 65% rename from modules/HTTP/CPPHTTPServer/CPPHTTPServer.st rename to modules/HTTP/CPPHTTPServer/HTTPServer.st index 4a73cc78..6a1226e2 100644 --- a/modules/HTTP/CPPHTTPServer/CPPHTTPServer.st +++ b/modules/HTTP/CPPHTTPServer/HTTPServer.st @@ -4,43 +4,43 @@ " Class { - #name : #CPPHTTPServer, + #name : #HTTPServer, #superclass : #ExternalObject, #instVars : [ 'library' ], - #category : #'CPPHTTPServer' + #category : #'HTTPServer' } { #category : #accessing } -CPPHTTPServer >> baseUri [ +HTTPServer >> baseUri [ ^baseUri ] { #category : #accessing } -CPPHTTPServer >> baseUri: aString [ +HTTPServer >> baseUri: aString [ baseUri := aString ] { #category : #spec } -CPPHTTPServer >> handle: request with: handler into: response with: selector [ +HTTPServer >> handle: request with: handler into: response with: selector [ handler handle: request into: response with: selector. ^ response ] { #category : #spec } -CPPHTTPServer >> initialize [ - library := CPPHTTPServerLibrary new open. +HTTPServer >> initialize [ + library := HTTPServerLibrary new open. self handle: library newServer. ] { #category : #spec } -CPPHTTPServer >> library [ +HTTPServer >> library [ ^library ] { #category : #spec } -CPPHTTPServer >> routeGET: uri to: selector with: handler [ +HTTPServer >> routeGET: uri to: selector with: handler [ library server: self asParameter GET: uri externalCopy asParameter @@ -48,11 +48,11 @@ CPPHTTPServer >> routeGET: uri to: selector with: handler [ ] { #category : #spec } -CPPHTTPServer >> start [ +HTTPServer >> start [ library startServer: self asParameter ] { #category : #initializing } -CPPHTTPServer >> stop [ +HTTPServer >> stop [ library stopServer: self asParameter ] diff --git a/modules/HTTP/CPPHTTPServer/CPPHTTPServerLibrary.st b/modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st similarity index 59% rename from modules/HTTP/CPPHTTPServer/CPPHTTPServerLibrary.st rename to modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st index 97a2d675..6f8e232b 100644 --- a/modules/HTTP/CPPHTTPServer/CPPHTTPServerLibrary.st +++ b/modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st @@ -4,47 +4,47 @@ " Class { - #name : #CPPHTTPServerLibrary, + #name : #HTTPServerLibrary, #superclass : #ExternalLibrary, #category : #'CPPHTTPServer' } { #category : #accessing } -CPPHTTPServerLibrary class >> libname [ +HTTPServerLibrary class >> libname [ ^'httpserver' ] { #category : #accessing } -CPPHTTPServerLibrary class >> libpath [ +HTTPServerLibrary class >> libpath [ ^'./' ] { #category : #spec } -CPPHTTPServerLibrary >> deleteServer: aServer [ +HTTPServerLibrary >> deleteServer: aServer [ ] { #category : #spec } -CPPHTTPServerLibrary >> newServer [ +HTTPServerLibrary >> newServer [ ] { #category : #spec } -CPPHTTPServerLibrary >> server: aServer GET: url callback: aCallback [ +HTTPServerLibrary >> server: aServer GET: url callback: aCallback [ ] { #category : #spec } -CPPHTTPServerLibrary >> startServer: aServer [ +HTTPServerLibrary >> startServer: aServer [ ] { #category : #initializing } -CPPHTTPServerLibrary >> stopServer: aServer [ +HTTPServerLibrary >> stopServer: aServer [ ] { #category : #initializing } -CPPHTTPServerLibrary >> response: aResponse setContents: aString type: anotherString [ +HTTPServerLibrary >> response: aResponse setContents: aString type: anotherString [ ] diff --git a/modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st b/modules/HTTP/CPPHTTPServer/HTTPServerModule.st similarity index 80% rename from modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st rename to modules/HTTP/CPPHTTPServer/HTTPServerModule.st index 0a4f060a..ab302931 100644 --- a/modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st +++ b/modules/HTTP/CPPHTTPServer/HTTPServerModule.st @@ -4,7 +4,7 @@ " Class { - #name : #CPPHTTPServerModule, + #name : #HTTPServerModule, #superclass : #Module, #instVars : [ 'server' @@ -13,7 +13,7 @@ Class { } { #category : #spec } -CPPHTTPServerModule >> imports [ +HTTPServerModule >> imports [ ^{ #FFI -> #(ExternalLibrary ExternalObject). } From cea3d331153df241789507b1560678643639d8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Thu, 24 Apr 2025 14:19:20 -0300 Subject: [PATCH 03/24] [vm-cpp] add support for arm64 in ffi --- runtime/cpp/Posix/FFIGlue.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/runtime/cpp/Posix/FFIGlue.cpp b/runtime/cpp/Posix/FFIGlue.cpp index afb1c0c6..61e2c8a3 100644 --- a/runtime/cpp/Posix/FFIGlue.cpp +++ b/runtime/cpp/Posix/FFIGlue.cpp @@ -24,15 +24,25 @@ uintptr_t Egg::LoaderHandle() { const char* Egg::PlatformName() { #if defined(__x86_64__) -#if defined(__linux__) - return "x86_64-linux-gnu"; -#elif defined(__APPLE__) - return "x86_64-darwin"; -#elif defined(_WIN32) - return "x86_64-win32"; -#else - return "x86_64-unknown"; -#endif + #if defined(__linux__) + return "x86_64-linux-gnu"; + #elif defined(__APPLE__) + return "x86_64-darwin"; + #elif defined(_WIN32) + return "x86_64-win32"; + #else + return "x86_64-unknown"; + #endif +#elif defined(__aarch64__) || defined(_M_ARM64) + #if defined(__linux__) + return "aarch64-linux-gnu"; + #elif defined(__APPLE__) + return "aarch64-darwin"; + #elif defined(_WIN32) + return "aarch64-win32"; + #else + return "aarch64-unknown"; + #endif #elif defined(__riscv) && __riscv_xlen == 64 return "riscv64-linux-gnu"; #else From 314a52de29023e06dd6637f18ba17283c926de8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:23:23 -0300 Subject: [PATCH 04/24] [ffi] share ffi submodule for linux and mac as posix --- modules/FFI/FFIModule.st | 22 +++-- modules/FFI/Linux/LinuxLibraryLoader.st | 69 --------------- modules/FFI/{Linux => Posix}/DLLibrary.st | 0 modules/FFI/Posix/PosixLibraryLoader.st | 83 +++++++++++++++++++ .../LinuxModule.st => Posix/PosixModule.st} | 6 +- .../HTTP/CPPHTTPServer/CPPHTTPServerModule.st | 24 ++++++ 6 files changed, 126 insertions(+), 78 deletions(-) delete mode 100644 modules/FFI/Linux/LinuxLibraryLoader.st rename modules/FFI/{Linux => Posix}/DLLibrary.st (100%) create mode 100644 modules/FFI/Posix/PosixLibraryLoader.st rename modules/FFI/{Linux/LinuxModule.st => Posix/PosixModule.st} (75%) create mode 100644 modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st diff --git a/modules/FFI/FFIModule.st b/modules/FFI/FFIModule.st index 981ae49f..a46f42d1 100644 --- a/modules/FFI/FFIModule.st +++ b/modules/FFI/FFIModule.st @@ -35,7 +35,11 @@ FFIModule >> initializeFor: moduleName loader: loaderName [ at: #FFI put: self; at: #OS put: module. loaderType := module namespace at: loaderName. - loader := loaderType new. + loader := loaderType new +] + +{ #category : #private } +FFIModule >> initializeLibC [ libc := LibC new. loader bootstrapOpen: libc. defaultHeap := mallocHeap := MallocHeap new @@ -52,18 +56,24 @@ FFIModule >> initializeForCurrentPlatform [ ] { #category : #initialization } -FFIModule >> initializeForMac [ - self initializeFor: #'FFI.Mac' loader: #MacLibraryLoader +FFIModule >> initializeForLinux [ + self + initializeFor: #'FFI.Posix' loader: #PosixLibraryLoader; + initializeLibC ] { #category : #initialization } -FFIModule >> initializeForLinux [ - self initializeFor: #'FFI.Linux' loader: #LinuxLibraryLoader +FFIModule >> initializeForMac [ + self initializeFor: #'FFI.Posix' loader: #PosixLibraryLoader. + loader beMac. + self initializeLibC. ] { #category : #initialization } FFIModule >> initializeForWindows [ - self initializeFor: #'FFI.Windows' loader: #WindowsLibraryLoader + self + initializeFor: #'FFI.Windows' loader: #WindowsLibraryLoader; + initializeLibC. ] { #category : #initialization } diff --git a/modules/FFI/Linux/LinuxLibraryLoader.st b/modules/FFI/Linux/LinuxLibraryLoader.st deleted file mode 100644 index adffd9a8..00000000 --- a/modules/FFI/Linux/LinuxLibraryLoader.st +++ /dev/null @@ -1,69 +0,0 @@ -" - Copyright (c) 2024, Javier Pimás. - See (MIT) license in root directory. - - I'm an object that allows loading dynamic libraries in Linux. For that, - I call dlopen and dlsym, part of dl library. That library is initialized - when the linux process is launched. -" - -Class { - #name : #LinuxLibraryLoader, - #superclass : #LibraryLoader, - #instVars : [ - 'dl' - ], - #category : #FFI -} - -{ #category : #bootstrap } -LinuxLibraryLoader >> bootstrapOpen: anExternalLibrary [ - " - We do this because externalCopy asParameter requires libc/calloc to be already loaded - " - | path parameter handle | - path := anExternalLibrary class libpath, anExternalLibrary class linuxFilename. - parameter := Array with: path. - handle := dl dlopen: parameter flags: 1. "RTLD_LAZY" - handle = 0 ifTrue: [dl lastError]. - anExternalLibrary address: handle. -] - -{ #category : #accessing } -LinuxLibraryLoader >> close: anExternalLibrary [ - dl dlclose: anExternalLibrary asParameter. -] - -{ #category : #accessing } -LinuxLibraryLoader >> findSymbol: aSymbol in: anExternalLibrary [ - ^dl dlsym: anExternalLibrary asParameter symbol: aSymbol externalCopy asParameter. -] - -{ #category : #accessing } -LinuxLibraryLoader >> initialize [ - dl := DLLibrary new. - Kernel host initializeFFI: dl symbolFinder: DLLibrary >> #dlsym:symbol:. - self initializeDLErrorDescriptor -] - -{ #category : #accessing } -LinuxLibraryLoader >> initializeDLErrorDescriptor [ - " - Sending dlerror for the first time initializes its descriptor, through dlsym. This makes - subsequent sends of dlerror not call dlsym, which would invalidate the last error code - " - dl dlerror -] -{ #category : #accessing } -LinuxLibraryLoader >> libraryFilename: externalLibrary [ - ^externalLibrary linuxFilename -] - -{ #category : #services } -LinuxLibraryLoader >> open: anExternalLibrary [ - | path handle | - path := anExternalLibrary class libpath, anExternalLibrary class linuxFilename. - handle := dl dlopen: path externalCopy asParameter flags: 1. "RTLD_LAZY" - handle = 0 ifTrue: [dl lastError]. - anExternalLibrary address: handle. -] diff --git a/modules/FFI/Linux/DLLibrary.st b/modules/FFI/Posix/DLLibrary.st similarity index 100% rename from modules/FFI/Linux/DLLibrary.st rename to modules/FFI/Posix/DLLibrary.st diff --git a/modules/FFI/Posix/PosixLibraryLoader.st b/modules/FFI/Posix/PosixLibraryLoader.st new file mode 100644 index 00000000..7ac556be --- /dev/null +++ b/modules/FFI/Posix/PosixLibraryLoader.st @@ -0,0 +1,83 @@ +" + Copyright (c) 2024, Javier Pimás. + See (MIT) license in root directory. + + I'm an object that allows loading dynamic libraries in Linux. For that, + I call dlopen and dlsym, part of dl library. That library is initialized + when the linux process is launched. +" + +Class { + #name : #PosixLibraryLoader, + #superclass : #LibraryLoader, + #instVars : [ + 'dl', + 'linux' + ], + #category : #FFI +} + +{ #category : #accessing } +PosixLibraryLoader >> beMac [ + linux := false +] + +{ #category : #bootstrap } +PosixLibraryLoader >> bootstrapOpen: anExternalLibrary [ + " + We do this because externalCopy asParameter requires libc/calloc to be already loaded + " + | filename path parameter handle | + filename := self libraryFilename: anExternalLibrary class. + path := anExternalLibrary class libpath, filename. + parameter := Array with: path. + Kernel log: 'Loading ', filename, String cr. + handle := filename = 'libc.dylib' + ifTrue: [dl handle asInteger] + ifFalse: [dl dlopen: parameter flags: 1. "RTLD_LAZY"]. + handle = 0 ifTrue: [dl lastError]. + Kernel log: 'handle is', handle printString, String cr. + anExternalLibrary address: handle. +] + +{ #category : #accessing } +PosixLibraryLoader >> close: anExternalLibrary [ + dl dlclose: anExternalLibrary asParameter +] + +{ #category : #accessing } +PosixLibraryLoader >> findSymbol: aSymbol in: anExternalLibrary [ + ^dl dlsym: anExternalLibrary asParameter symbol: aSymbol externalCopy asParameter +] + +{ #category : #accessing } +PosixLibraryLoader >> initialize [ + linux := true. + dl := DLLibrary new. + Kernel host initializeFFI: dl symbolFinder: DLLibrary >> #dlsym:symbol:. + self initializeDLErrorDescriptor +] + +{ #category : #accessing } +PosixLibraryLoader >> initializeDLErrorDescriptor [ + " + Sending dlerror for the first time initializes libdl descriptor, through dlsym. This makes + subsequent sends of dlerror not call dlsym, which would invalidate the last error code + " + dl dlerror +] +{ #category : #accessing } +PosixLibraryLoader >> libraryFilename: externalLibrary [ + ^linux ifTrue: [ externalLibrary linuxFilename ] ifFalse: [ externalLibrary macFilename ] +] + +{ #category : #services } +PosixLibraryLoader >> open: anExternalLibrary [ + | filename path handle | + filename := self libraryFilename: anExternalLibrary class. + Kernel log: 'Loading ', filename, String cr. + path := anExternalLibrary class libpath, filename. + handle := dl dlopen: path externalCopy asParameter flags: 1. "RTLD_LAZY" + handle = 0 ifTrue: [Error signal: dl lastError]. + anExternalLibrary address: handle +] diff --git a/modules/FFI/Linux/LinuxModule.st b/modules/FFI/Posix/PosixModule.st similarity index 75% rename from modules/FFI/Linux/LinuxModule.st rename to modules/FFI/Posix/PosixModule.st index 27902079..6a551340 100644 --- a/modules/FFI/Linux/LinuxModule.st +++ b/modules/FFI/Posix/PosixModule.st @@ -4,17 +4,17 @@ " Class { - #name : #LinuxModule, + #name : #PosixModule, #superclass : #Module, #category : #FFI } { #category : #services } -LinuxModule >> externalCopyOfString: aString [ +PosixModule >> externalCopyOfString: aString [ ^Kernel utf8 externalCopyOf: aString ] { #category : #services } -LinuxModule >> imports [ +PosixModule >> imports [ ^{ #FFI -> #(ExternalLibrary ExternalMemory LibraryLoader) } ] diff --git a/modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st b/modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st new file mode 100644 index 00000000..8c8aec76 --- /dev/null +++ b/modules/HTTP/CPPHTTPServer/CPPHTTPServerModule.st @@ -0,0 +1,24 @@ +" + Copyright (c) 2024, Javier Pimás. + See (MIT) license in root directory. +" + +Class { + #name : #CPPHTTPServerModule, + #superclass : #Module, + #instVars : [ + 'library' + ], + #category : #'CPPHTTPServer' +} + +{ #category : #spec } +CPPHTTPServerModule >> imports [ + ^{ + #FFI -> #(ExternalLibrary ExternalObject). + } +] + +CPPHTTPServerModule >> library [ + ^library ifNil: [library := HTTPServerLibrary new open] +] From aaba92785175a166268a3c8e060376dad05a30aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:27:02 -0300 Subject: [PATCH 05/24] [vm-cpp][ffi] add support for getting loader handle in macos and windows --- runtime/cpp/Posix/FFIGlue.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/cpp/Posix/FFIGlue.cpp b/runtime/cpp/Posix/FFIGlue.cpp index 61e2c8a3..a35294cc 100644 --- a/runtime/cpp/Posix/FFIGlue.cpp +++ b/runtime/cpp/Posix/FFIGlue.cpp @@ -19,7 +19,13 @@ uintptr_t Egg::FindSymbol(uintptr_t libHandle, char *symbol) } uintptr_t Egg::LoaderHandle() { +#ifdef __APPLE__ + return (uintptr_t)dlopen(nullptr, RTLD_LAZY); +#elif _WIN32 + return LoadLibrary("Kernel32.dll"); +#else return (uintptr_t)dlopen("libdl.so.2", RTLD_LAZY); +#endif } const char* Egg::PlatformName() { From 71d9e53f07ca35a52820cec60106f499ef5b86fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:28:01 -0300 Subject: [PATCH 06/24] [vm-cpp] avoid signedness undefined behavior warning --- runtime/cpp/ImageSegment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/cpp/ImageSegment.cpp b/runtime/cpp/ImageSegment.cpp index 2882a880..354d3a1c 100644 --- a/runtime/cpp/ImageSegment.cpp +++ b/runtime/cpp/ImageSegment.cpp @@ -54,7 +54,7 @@ ImageSegment::load(std::istream *data) void ImageSegment::fixPointerSlots(const std::vector& imports) { intptr_t delta = this->_currentBase - this->header.baseAddress; - uintptr_t oldBehaviorBase = this->header.baseAddress & (((intptr_t)-1) << 32); // discards lower 32 bits + uintptr_t oldBehaviorBase = this->header.baseAddress & (((uintptr_t)-1) << 32); // discards lower 32 bits auto spaceStart = this->spaceStart(); auto current = ((HeapObject::ObjectHeader*)spaceStart)->object(); auto end = (HeapObject*)this->spaceEnd(); From c2b5098d3263a0f1687b6fbbae7ba54abcd7211c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:30:04 -0300 Subject: [PATCH 07/24] [vm-cpp][ffi] use libffi closure and code_location appropiately (they are not the same in macos) --- runtime/cpp/Evaluator/Evaluator.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index bd1ae921..6c250473 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -617,26 +617,29 @@ Object* Evaluator::primitiveClosureAsCallback() { } if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, count, &ffi_type_pointer, argTypes) != FFI_OK) { - delete[] argTypes; delete cif; - return nullptr; + delete[] argTypes; + ffi_closure_free(closure); + return (Object*)_runtime->_nilObj; } + auto self = this->_context->self()->asHeapObject(); - auto lambda = new std::function( - [self, this](void *ret, int argc, void *args[]) { - this->evaluateCallback_(ret, self, argc, args); - } -); + auto lambda = new std::function( + [self, this](void *ret, int argc, void *args[]) { + this->evaluateCallback_(ret, self, argc, args); + } + ); // Bind the closure - if (ffi_prep_closure_loc(closure, cif, closureCallbackWrapper, (void*)lambda, closure) != FFI_OK) { - delete[] argTypes; + if (ffi_prep_closure_loc(closure, cif, closureCallbackWrapper, (void*)lambda, code_location) != FFI_OK) { delete cif; + delete[] argTypes; ffi_closure_free(closure); - return nullptr; + delete lambda; + return (Object*)_runtime->_nilObj; } - return (Object*)this->_runtime->newInteger_(reinterpret_cast(closure)); + return (Object*)this->_runtime->newInteger_(reinterpret_cast(code_location)); } Object* Evaluator::primitiveClosureValue() { @@ -895,7 +898,7 @@ void Evaluator::initializeCIF(HeapObject *method, int argCount) { HeapObject *dll = this->_context->receiver()->asHeapObject(); Object *handle = dll->slotAt_(1); // the handle if (handle->asHeapObject()->untypedSlot(0) == nullptr) { - error("trying to execute FFI method on closed library"); + error_("trying to execute FFI method " + method->printString() + " on closed library"); } HeapObject *fnName = _runtime->ffiMethodSymbol_(method); From 3d72b1f072d429340c9c05ef87123c5082078eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:31:36 -0300 Subject: [PATCH 08/24] [vm-cpp] correct subscript error in U*AtOfffset underprims --- runtime/cpp/Evaluator/Evaluator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index 6c250473..a57443c1 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -1173,7 +1173,7 @@ Object* Evaluator::underprimitiveSmallSize(Object *receiver, std::vector &args) { - auto result = receiver->asHeapObject()->uint64offset((args[1]->asSmallInteger()->asNative())); + auto result = receiver->asHeapObject()->uint64offset((args[0]->asSmallInteger()->asNative())); return newIntObject(result); } @@ -1184,7 +1184,7 @@ Object* Evaluator::underprimitiveULargeAtOffsetPut(Object *receiver, std::vector } Object* Evaluator::underprimitiveULongAtOffset(Object *receiver, std::vector &args) { - auto result = receiver->asHeapObject()->uint32offset((args[1]->asSmallInteger()->asNative())); + auto result = receiver->asHeapObject()->uint32offset((args[0]->asSmallInteger()->asNative())); return newIntObject(result); } @@ -1195,7 +1195,7 @@ Object* Evaluator::underprimitiveULongAtOffsetPut(Object *receiver, std::vector< } Object* Evaluator::underprimitiveUShortAtOffset(Object *receiver, std::vector &args) { - auto result = receiver->asHeapObject()->uint16offset((args[1]->asSmallInteger()->asNative())); + auto result = receiver->asHeapObject()->uint16offset((args[0]->asSmallInteger()->asNative())); return newIntObject(result); } From 905421149b859c5e84047f5c0a983e02b8c09936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:32:44 -0300 Subject: [PATCH 09/24] [vm-cpp] while #dnu is still unimlemented, at least print an error when it happens --- runtime/cpp/Evaluator/Runtime.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/cpp/Evaluator/Runtime.cpp b/runtime/cpp/Evaluator/Runtime.cpp index 83584936..4c8f1e4f 100644 --- a/runtime/cpp/Evaluator/Runtime.cpp +++ b/runtime/cpp/Evaluator/Runtime.cpp @@ -227,6 +227,8 @@ HeapObject* Runtime::lookup_startingAt_(HeapObject *symbol, HeapObject *behavior } auto method = this->doLookup_startingAt_(symbol, behavior); + if (!method) + error_(this->behaviorClass_(behavior)->printString() + " does not understand " + symbol->printString()); auto key = gced_global_cache_key(new GCedRef(symbol),new GCedRef(behavior)); auto value = new GCedRef(method); _globalCache.insert({key, value}); From bdd2c7645b2473d9806c274733ad6b309fd5ce70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:35:48 -0300 Subject: [PATCH 10/24] [ffi] add support for mac dylib filenames --- modules/FFI/ExternalLibrary.st | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/FFI/ExternalLibrary.st b/modules/FFI/ExternalLibrary.st index 929922a4..93c6cf52 100644 --- a/modules/FFI/ExternalLibrary.st +++ b/modules/FFI/ExternalLibrary.st @@ -29,6 +29,11 @@ ExternalLibrary class >> linuxFilename [ ^'lib', self libname, '.so' ] +{ #category : #accessing } +ExternalLibrary class >> macFilename [ + ^'lib', self libname, '.dylib' +] + { #category : #accessing } ExternalLibrary class >> windowsFilename [ ^self libname, '.dll' From adec0c836e5df853d36296eb71b81dba857cf918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Sun, 27 Apr 2025 12:36:26 -0300 Subject: [PATCH 11/24] [ffi] ExternalHandle >> #asInteger seemed to be missing --- modules/FFI/ExternalHandle.st | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/FFI/ExternalHandle.st b/modules/FFI/ExternalHandle.st index d8421718..280f7003 100644 --- a/modules/FFI/ExternalHandle.st +++ b/modules/FFI/ExternalHandle.st @@ -15,6 +15,11 @@ ExternalHandle class >> new [ ^self new: WordSize ] +{ #category : #'accessing' } +ExternalHandle >> asInteger [ + ^self pointerAtOffset: 0 +] + { #category : #'testing' } ExternalHandle >> isValid [ ^self asInteger != 0 From 0793876183b218d0435a4b0be7414eb1ad541a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Mon, 28 Apr 2025 11:05:02 -0300 Subject: [PATCH 12/24] [vm-cpp] add missing method to set special bit in object headers --- runtime/cpp/HeapObject.cpp | 4 ++++ runtime/cpp/HeapObject.h | 1 + 2 files changed, 5 insertions(+) diff --git a/runtime/cpp/HeapObject.cpp b/runtime/cpp/HeapObject.cpp index 31eec620..1ae9e78c 100644 --- a/runtime/cpp/HeapObject.cpp +++ b/runtime/cpp/HeapObject.cpp @@ -103,6 +103,10 @@ void Egg::HeapObject::beNotSpecial() { this->unsetFlags(SmallHeader::Flags::IsSpecial); } +void Egg::HeapObject::beSpecial() { + this->setFlags(SmallHeader::Flags::IsSpecial); +} + void HeapObject::beStrong() { this->beNotSpecial(); } diff --git a/runtime/cpp/HeapObject.h b/runtime/cpp/HeapObject.h index e5d2a877..0620c12a 100644 --- a/runtime/cpp/HeapObject.h +++ b/runtime/cpp/HeapObject.h @@ -163,6 +163,7 @@ struct HeapObject void beLarge(); void beNotSpecial(); + void beSpecial(); void beStrong(); void beSeen(); From 2dacfa01aab2a3e314e1305fd16c6aaf6de714da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Mon, 28 Apr 2025 11:06:21 -0300 Subject: [PATCH 13/24] [vm-cpp] add primitive to set special bit in object headers --- runtime/cpp/Evaluator/Evaluator.cpp | 9 +++++++++ runtime/cpp/Evaluator/Evaluator.h | 1 + 2 files changed, 10 insertions(+) diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index a57443c1..7d66f3d4 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -112,6 +112,7 @@ void Evaluator::initializePrimitives() this->addPrimitive("Behavior", &Evaluator::primitiveBehavior); this->addPrimitive("SetBehavior", &Evaluator::primitiveSetBehavior); this->addPrimitive("Class", &Evaluator::primitiveClass); + this->addPrimitive("UnderBeSpecial", &Evaluator::primitiveUnderBeSpecial); this->addPrimitive("UnderHash", &Evaluator::primitiveUnderHash); this->addPrimitive("UnderIsBytes", &Evaluator::primitiveUnderIsBytes); this->addPrimitive("UnderPointersSize", &Evaluator::primitiveUnderPointersSize); @@ -877,6 +878,14 @@ Object* Evaluator::primitiveStringReplaceFromToWithStartingAt() { return receiver; } +Object* Evaluator::primitiveUnderBeSpecial() { + auto receiver = this->_context->self(); + if (!receiver->isSmallInteger()) + receiver->asHeapObject()->beSpecial(); + + return receiver; +} + Object* Evaluator::primitiveUnderHash() { return newIntObject(this->_context->self()->asHeapObject()->hash()); } diff --git a/runtime/cpp/Evaluator/Evaluator.h b/runtime/cpp/Evaluator/Evaluator.h index d3aa48bd..0f0d7d4b 100644 --- a/runtime/cpp/Evaluator/Evaluator.h +++ b/runtime/cpp/Evaluator/Evaluator.h @@ -233,6 +233,7 @@ class Evaluator : public SExpressionVisitor { Object* primitiveSetBehavior(); Object* primitiveSize(); Object* primitiveStringReplaceFromToWithStartingAt(); + Object* primitiveUnderBeSpecial(); Object* primitiveUnderHash(); Object* primitiveUnderIsBytes(); Object* primitiveUnderPointersSize(); From fa65aadf45665c09a29309b90689b57f908162c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Mon, 28 Apr 2025 11:11:41 -0300 Subject: [PATCH 14/24] [kernel] move references from Smalltalk to Kernel --- modules/FFI/ExternalMemory.st | 2 +- modules/Kernel/Float.st | 12 ++--- modules/Kernel/KernelModule.st | 40 +++++++++++++++- modules/Kernel/ProtoObject.st | 2 +- modules/Kernel/SmalltalkSession.st | 59 ++++++++++++++++++++++-- modules/Kernel/SmalltalkSystem.st | 73 ++---------------------------- modules/Kernel/Species.st | 10 +--- modules/Kernel/Warning.st | 2 +- 8 files changed, 107 insertions(+), 93 deletions(-) diff --git a/modules/FFI/ExternalMemory.st b/modules/FFI/ExternalMemory.st index 34d21624..e843ca44 100644 --- a/modules/FFI/ExternalMemory.st +++ b/modules/FFI/ExternalMemory.st @@ -189,7 +189,7 @@ ExternalMemory >> externalCopy [ { #category : #finalization } ExternalMemory >> finalizationRegistry [ - ^Smalltalk resourceRegistry + ^Kernel session resourceRegistry ] { #category : #finalization } diff --git a/modules/Kernel/Float.st b/modules/Kernel/Float.st index 12c7fc7d..abea14f6 100644 --- a/modules/Kernel/Float.st +++ b/modules/Kernel/Float.st @@ -513,7 +513,7 @@ Float >> abs [ { #category : #trigonometry } Float >> arcTan [ - ^Smalltalk os libc atan: self + ^Kernel host libc atan: self ] { #category : #converting } @@ -583,7 +583,7 @@ Float >> coerce: aNumber [ { #category : #trigonometry } Float >> cos [ - ^Smalltalk os libc cos: self + ^Kernel host libc cos: self ] { #category : #trigonometry } @@ -598,7 +598,7 @@ Float >> errorOn: aSymbol status: anInteger [ { #category : #logarithms } Float >> exp [ - ^Smalltalk os libc exp: self + ^Kernel host libc exp: self ] { #category : #accessing } @@ -707,7 +707,7 @@ Float >> isSpecialValue [ Float >> ln [ self > 0 ifFalse: [^self error: 'ln is not defined for ' , self printString]. - ^Smalltalk os libc log: self + ^Kernel host libc log: self ] { #category : #accessing } @@ -868,7 +868,7 @@ Float >> significand [ { #category : #trigonometry } Float >> sin [ - ^Smalltalk os libc sin: self + ^Kernel host libc sin: self ] { #category : #accessing } @@ -896,7 +896,7 @@ Float >> storeOn: aStream [ { #category : #trigonometry } Float >> tan [ - ^Smalltalk os libc tan: self + ^Kernel host libc tan: self ] { #category : #arithmetic } diff --git a/modules/Kernel/KernelModule.st b/modules/Kernel/KernelModule.st index 81f5f43e..59654c54 100644 --- a/modules/Kernel/KernelModule.st +++ b/modules/Kernel/KernelModule.st @@ -15,6 +15,8 @@ Class { 'host', 'CRITICAL', 'unhandledErrorHandler', + 'session', + 'properties', 'utf8', 'utf16', 'utf32' @@ -93,10 +95,27 @@ KernelModule >> critical: aBlock [ aBlock value ] +{ #category : #accessing } +KernelModule >> ensurePropertyTableFor: anObject [ + ^properties at: anObject ifAbsentPut: [IdentityDictionary new] +] + +{ #category : #'startup/shutdown' } +KernelModule >> ephemeronsDo: aBlock [ + session ephemeronsDo: aBlock. + properties ephemeronsDo: aBlock +] + +{ #category : #accessing } KernelModule >> exit [ host exit: 0 ] +{ #category : #accessing } +KernelModule >> finalizer [ + ^session finalizer +] + { #category : #services } KernelModule >> freezeOnUnhandledExceptions [ unhandledErrorHandler := [:exception | self _halt] @@ -122,7 +141,20 @@ KernelModule >> initialize [ keys do: [:symbol | | obj | obj := namespace at: symbol. obj isClass ifTrue: [classes add: obj]. - exports add: symbol] + exports add: symbol]. + session := SmalltalkSession new. + properties := WeakIdentityDictionary new. + +] + +{ #category : #accessing } +KernelModule >> properties [ + ^properties +] + +{ #category : #accessing } +KernelModule >> propertiesFor: anObject [ + ^properties at: anObject ifAbsent: nil ] { #category : #services } @@ -171,6 +203,12 @@ KernelModule >> processor [ ^Processor ] +{ #category : #initialization } +KernelModule >> rehashWeakRegistries [ + session rehashWeakRegistries. + properties rehash +] + { #category : #removing } KernelModule >> removeKey: aSymbol from: aMethodDictionary ifAbsent: aBlock [ | cm | diff --git a/modules/Kernel/ProtoObject.st b/modules/Kernel/ProtoObject.st index 0f10e83c..1e892bf1 100644 --- a/modules/Kernel/ProtoObject.st +++ b/modules/Kernel/ProtoObject.st @@ -249,7 +249,7 @@ ProtoObject >> errorVMSpecific [ { #category : #finalization } ProtoObject >> finalizationRegistry [ - ^Smalltalk finalizer + ^Kernel finalizer ] { #category : #finalization } diff --git a/modules/Kernel/SmalltalkSession.st b/modules/Kernel/SmalltalkSession.st index ce1abc35..7cbca4aa 100644 --- a/modules/Kernel/SmalltalkSession.st +++ b/modules/Kernel/SmalltalkSession.st @@ -4,25 +4,57 @@ Class { #instVars : [ 'name', 'username', - 'args' + 'args', + 'resources', + 'finalizer' ], #category : #Kernel } { #category : #accessing } -SmalltalkSession >> commandLine [ - ^CommandLine from: args +SmalltalkSession >> args [ + ^args +] + +{ #category : #accessing } +SmalltalkSession >> args: anArray [ + args := anArray +] + +{ #category : #'startup/shutdown' } +SmalltalkSession >> closeExternalResources [ + resources do: [:object | object sessionShutdown] +] + + +{ #category : #'startup/shutdown' } +SmalltalkSession >> ephemeronsDo: aBlock [ + resources ephemeronsDo: aBlock. + finalizer ephemeronsDo: aBlock. ] { #category : #shutdown } SmalltalkSession >> exit: code [ - [self shutdown] ensure: [Smalltalk os exit: code] + [self shutdown] ensure: [Kernel host exit: code] +] + +{ #category : #accessing } +SmalltalkSession >> finalizer [ + ^finalizer ] { #category : #initialization } SmalltalkSession >> initialize [ super initialize. - name := 'bee session' + name := 'egg session'. + finalizer := WeakIdentitySet new. + resources := WeakIdentitySet new +] + +{ #category : #initialization } +SmalltalkSession >> initializeFinalizationBlocks [ + finalizer finalizer: [:object | object finalize]. + resources finalizer: [:object | object finalize] ] { #category : #accessing } @@ -30,6 +62,23 @@ SmalltalkSession >> name [ ^name ] +{ #category : #initialization } +SmalltalkSession >> rehashWeakRegistries [ + resources rehash. + finalizer rehash +] + +{ #category : #accessing } +SmalltalkSession >> resourceRegistry [ + ^resources +] + +{ #category : #'startup/shutdown' } +SmalltalkSession >> startUp [ + self initializeFinalizationBlocks. + resources do: [:object | object sessionStartup] +] + { #category : #accessing } SmalltalkSession >> username [ ^username diff --git a/modules/Kernel/SmalltalkSystem.st b/modules/Kernel/SmalltalkSystem.st index 81cae498..be0ff7a1 100644 --- a/modules/Kernel/SmalltalkSystem.st +++ b/modules/Kernel/SmalltalkSystem.st @@ -8,16 +8,9 @@ Class { #superclass : #Object, #instVars : [ 'globals', - 'memory', - 'resources', - 'properties', - 'finalizer', 'eventHandlers', 'registeredEvents', - 'externals', - 'eventDispatcher', - 'nativizer', - 'session' + 'eventDispatcher' ], #classVars : [ 'Implementors', @@ -129,29 +122,11 @@ SmalltalkSystem >> classNamed: aString [ ^global isSpecies ifTrue: [meta ifTrue: [global class] ifFalse: [global]] ] -{ #category : #'startup/shutdown' } -SmalltalkSystem >> closeExternalResources [ - resources do: [:object | object sessionShutdown]. - externals do: [:object | object sessionShutdown] -] - { #category : #services } SmalltalkSystem >> collectGarbage [ memory forceCompact ] -{ #category : #accessing } -SmalltalkSystem >> ensurePropertyTableFor: anObject [ - ^properties at: anObject ifAbsentPut: [IdentityDictionary new] -] - -{ #category : #'startup/shutdown' } -SmalltalkSystem >> ephemeronsDo: aBlock [ - resources ephemeronsDo: aBlock. - finalizer ephemeronsDo: aBlock. - properties ephemeronsDo: aBlock -] - { #category : #accessing } SmalltalkSystem >> eventDispatcher [ ^eventDispatcher @@ -238,18 +213,8 @@ SmalltalkSystem >> includesKey: aSymbol [ { #category : #initialization } SmalltalkSystem >> initialize [ - finalizer := WeakIdentitySet new. - resources := WeakIdentitySet new. - properties := WeakIdentityDictionary new. eventHandlers := WeakIdentityDictionary new. - registeredEvents := WeakIdentityDictionary new. - externals := OrderedCollection new -] - -{ #category : #initialization } -SmalltalkSystem >> initializeFinalizationBlocks [ - finalizer finalizer: [:object | object finalize]. - resources finalizer: [:object | object finalize] + registeredEvents := WeakIdentityDictionary new ] { #category : #testing } @@ -304,21 +269,6 @@ SmalltalkSystem >> processAllMessages [ eventDispatcher processAllMessages ] -{ #category : #accessing } -SmalltalkSystem >> properties [ - ^properties -] - -{ #category : #accessing } -SmalltalkSystem >> propertiesFor: anObject [ - ^properties at: anObject ifAbsent: nil -] - -{ #category : #services } -SmalltalkSystem >> recursiveBacktrace: aString [ - Smalltalk exit -] - { #category : #accessing } SmalltalkSystem >> register: aSet for: aClass [ registeredEvents at: aClass put: aSet @@ -329,17 +279,10 @@ SmalltalkSystem >> registeredEventsFor: aClass [ ^registeredEvents at: aClass ifAbsent: nil ] -{ #category : #services } -SmalltalkSystem >> registerExternal: externalObject [ - externals add: externalObject -] { #category : #initialization } SmalltalkSystem >> rehashWeakRegistries [ eventHandlers rehash. - resources rehash. - finalizer rehash. - properties rehash. registeredEvents rehash ] @@ -394,11 +337,6 @@ SmalltalkSystem >> renameClass: aClass to: aSymbol [ aClass name: symbol ] -{ #category : #accessing } -SmalltalkSystem >> resourceRegistry [ - ^resources -] - { #category : #'binding libraries' } SmalltalkSystem >> segmentLoaded: anImageSegment [ @@ -433,14 +371,11 @@ SmalltalkSystem >> showBacktraceOf: aProcess label: aString [ { #category : #'startup/shutdown' } SmalltalkSystem >> startUp [ - self - initializeFinalizationBlocks; - ephemeronsDo: [:e | e activate]. - resources do: [:object | object sessionStartup]. + session startUp. + self ephemeronsDo: [:e | e activate]. Float startUp. memory startUp. "platform startUp." - session := SmalltalkSession new ] { #category : #accessing } diff --git a/modules/Kernel/Species.st b/modules/Kernel/Species.st index 76f907e6..7810929a 100644 --- a/modules/Kernel/Species.st +++ b/modules/Kernel/Species.st @@ -74,16 +74,9 @@ Species >> allClassVarNames [ ^(self withAllSuperclasses reversed gather: [:cls | cls classVarNames]) asArray ] -{ #category : #private } -Species >> allExistingInstances [ - ^Memory current allInstancesOf: self -] - { #category : #instances } Species >> allInstances [ - ^[ - Smalltalk collectGarbage. - self allExistingInstances] evaluateAtomically + ^Kernel memory allInstancesOf: self ] { #category : #queries } @@ -111,7 +104,6 @@ Species >> allSubinstances [ | subinstances | subinstances := OrderedCollection new. [ - Smalltalk collectGarbage. self withAllSubclassesDo: [:cls | subinstances addAll: cls allExistingInstances]] diff --git a/modules/Kernel/Warning.st b/modules/Kernel/Warning.st index 14318600..473be2d2 100644 --- a/modules/Kernel/Warning.st +++ b/modules/Kernel/Warning.st @@ -11,6 +11,6 @@ Class { { #category : #actions } Warning >> defaultAction [ - Smalltalk session warnAbout: self description + Kernel host logWarning: self description, String cr ] From 64b1db341da4ae524d659d5a5d5d09b42a5790e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Mon, 28 Apr 2025 11:21:40 -0300 Subject: [PATCH 15/24] [kernel] add _beSpecial to ProtoObject --- modules/Kernel/ProtoObject.st | 6 ++++++ modules/Kernel/VM/ProtoObject.st | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/modules/Kernel/ProtoObject.st b/modules/Kernel/ProtoObject.st index 1e892bf1..81c9282f 100644 --- a/modules/Kernel/ProtoObject.st +++ b/modules/Kernel/ProtoObject.st @@ -61,6 +61,12 @@ ProtoObject >> _basicAt: anInteger [ ^self errorVMSpecific ] +{ #category : #underprimitives } +ProtoObject >> _beSpecial [ + #UnderBeSpecial. "hack to avoid missing symbol error during bootstrap" + ^self errorVMSpecific +] + { #category : #'header access' } ProtoObject >> _copyBasicHeaderFrom: other [ self errorVMSpecific diff --git a/modules/Kernel/VM/ProtoObject.st b/modules/Kernel/VM/ProtoObject.st index 27646c5e..263c7d13 100644 --- a/modules/Kernel/VM/ProtoObject.st +++ b/modules/Kernel/VM/ProtoObject.st @@ -5,6 +5,13 @@ Extension { #name : #ProtoObject } +{ #category : '*Primitives' } +ProtoObject >> _beSpecial [ + + self primitiveFailed. + +] + { #category : '*Primitives' } ProtoObject >> _hash [ From bd2a72c1e92dda82bb1a28c7f787d5d97cf6a3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Mon, 28 Apr 2025 11:22:45 -0300 Subject: [PATCH 16/24] [ffi] remove unnecessary logging --- modules/FFI/Posix/PosixLibraryLoader.st | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/FFI/Posix/PosixLibraryLoader.st b/modules/FFI/Posix/PosixLibraryLoader.st index 7ac556be..0d635710 100644 --- a/modules/FFI/Posix/PosixLibraryLoader.st +++ b/modules/FFI/Posix/PosixLibraryLoader.st @@ -2,9 +2,9 @@ Copyright (c) 2024, Javier Pimás. See (MIT) license in root directory. - I'm an object that allows loading dynamic libraries in Linux. For that, - I call dlopen and dlsym, part of dl library. That library is initialized - when the linux process is launched. + I'm an object that allows loading dynamic libraries in Linux and Mac. For that, + I call dlopen and dlsym, part of dl library. To bootstrap, the dl library + object handle and dlsym addresses are initialized through a host VM primitive. " Class { @@ -31,12 +31,10 @@ PosixLibraryLoader >> bootstrapOpen: anExternalLibrary [ filename := self libraryFilename: anExternalLibrary class. path := anExternalLibrary class libpath, filename. parameter := Array with: path. - Kernel log: 'Loading ', filename, String cr. handle := filename = 'libc.dylib' ifTrue: [dl handle asInteger] ifFalse: [dl dlopen: parameter flags: 1. "RTLD_LAZY"]. handle = 0 ifTrue: [dl lastError]. - Kernel log: 'handle is', handle printString, String cr. anExternalLibrary address: handle. ] @@ -75,7 +73,6 @@ PosixLibraryLoader >> libraryFilename: externalLibrary [ PosixLibraryLoader >> open: anExternalLibrary [ | filename path handle | filename := self libraryFilename: anExternalLibrary class. - Kernel log: 'Loading ', filename, String cr. path := anExternalLibrary class libpath, filename. handle := dl dlopen: path externalCopy asParameter flags: 1. "RTLD_LAZY" handle = 0 ifTrue: [Error signal: dl lastError]. From 8bbedeccc22db0a69af7f21f087f62dcb70d6ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Mon, 28 Apr 2025 11:42:43 -0300 Subject: [PATCH 17/24] [cpp-httplib] make ssl and crypto linking also work on macos --- modules/HTTP/CPPHTTPServer/lib/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/HTTP/CPPHTTPServer/lib/CMakeLists.txt b/modules/HTTP/CPPHTTPServer/lib/CMakeLists.txt index ed65fc6f..e75274e2 100644 --- a/modules/HTTP/CPPHTTPServer/lib/CMakeLists.txt +++ b/modules/HTTP/CPPHTTPServer/lib/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.5.0) +cmake_minimum_required(VERSION 3.20) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -11,6 +11,5 @@ set(SOURCE_FILES server.cpp) find_package(OpenSSL REQUIRED) add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} PRIVATE ssl crypto) - +target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto) From 8bffd2e58884177fa5249fc16f614f9fddeaa5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 15:29:26 -0300 Subject: [PATCH 18/24] [http] remove renamed file --- .../HTTP/CPPHTTPServer/HTTPServerModule.st | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 modules/HTTP/CPPHTTPServer/HTTPServerModule.st diff --git a/modules/HTTP/CPPHTTPServer/HTTPServerModule.st b/modules/HTTP/CPPHTTPServer/HTTPServerModule.st deleted file mode 100644 index ab302931..00000000 --- a/modules/HTTP/CPPHTTPServer/HTTPServerModule.st +++ /dev/null @@ -1,20 +0,0 @@ -" - Copyright (c) 2024, Javier Pimás. - See (MIT) license in root directory. -" - -Class { - #name : #HTTPServerModule, - #superclass : #Module, - #instVars : [ - 'server' - ], - #category : #'CPPHTTPServer' -} - -{ #category : #spec } -HTTPServerModule >> imports [ - ^{ - #FFI -> #(ExternalLibrary ExternalObject). - } -] From f29afb47ccf9e97f4158304d4d2d68ae13074a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 18:41:32 -0300 Subject: [PATCH 19/24] [vm-cpp] disable doing GC in callbacks for now (we have to make that GC safe) --- modules/HTTP/CPPHTTPServer/HTTPResponse.st | 18 ++++++++++++ modules/HTTP/CPPHTTPServer/HTTPServer.st | 33 ++++++++-------------- runtime/cpp/Allocator/GCHeap.cpp | 5 +++- runtime/cpp/Evaluator/Evaluator.cpp | 9 ++++-- runtime/cpp/Evaluator/Evaluator.h | 4 +++ 5 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 modules/HTTP/CPPHTTPServer/HTTPResponse.st diff --git a/modules/HTTP/CPPHTTPServer/HTTPResponse.st b/modules/HTTP/CPPHTTPServer/HTTPResponse.st new file mode 100644 index 00000000..fdd92ab8 --- /dev/null +++ b/modules/HTTP/CPPHTTPServer/HTTPResponse.st @@ -0,0 +1,18 @@ +" + Copyright (c) 2024, Javier Pimás. + See (MIT) license in root directory. +" + +Class { + #name : #HTTPResponse, + #superclass : #ExternalObject, + #category : #'CPPHTTPServer' +} + +{ #category : #spec } +HTTPResponse >> setContents: aString type: anotherString [ + self class module library + response: handle asParameter + setContents: aString externalCopy asParameter + type: anotherString externalCopy asParameter +] diff --git a/modules/HTTP/CPPHTTPServer/HTTPServer.st b/modules/HTTP/CPPHTTPServer/HTTPServer.st index 6a1226e2..2dd85c42 100644 --- a/modules/HTTP/CPPHTTPServer/HTTPServer.st +++ b/modules/HTTP/CPPHTTPServer/HTTPServer.st @@ -6,42 +6,31 @@ Class { #name : #HTTPServer, #superclass : #ExternalObject, - #instVars : [ - 'library' - ], - #category : #'HTTPServer' + #category : #'CPPHTTPServer' } -{ #category : #accessing } -HTTPServer >> baseUri [ - ^baseUri -] - -{ #category : #accessing } -HTTPServer >> baseUri: aString [ - baseUri := aString -] - { #category : #spec } -HTTPServer >> handle: request with: handler into: response with: selector [ +HTTPServer >> handle: requestHandle with: handler into: responseHandle with: selector [ + | request response | + request := HTTPRequest new handle: requestHandle. + response := HTTPResponse new handle: responseHandle. handler handle: request into: response with: selector. - ^ response + ^responseHandle ] { #category : #spec } HTTPServer >> initialize [ - library := HTTPServerLibrary new open. - self handle: library newServer. + self handle: self library newServer. ] { #category : #spec } HTTPServer >> library [ - ^library + ^self class module library ] { #category : #spec } HTTPServer >> routeGET: uri to: selector with: handler [ - library + self library server: self asParameter GET: uri externalCopy asParameter callback: [ :request :response | self handle: request with: handler into: response with: selector ] asCallback @@ -49,10 +38,10 @@ HTTPServer >> routeGET: uri to: selector with: handler [ { #category : #spec } HTTPServer >> start [ - library startServer: self asParameter + self library startServer: self asParameter ] { #category : #initializing } HTTPServer >> stop [ - library stopServer: self asParameter + self library stopServer: self asParameter ] diff --git a/runtime/cpp/Allocator/GCHeap.cpp b/runtime/cpp/Allocator/GCHeap.cpp index d286e518..6a8ffe59 100644 --- a/runtime/cpp/Allocator/GCHeap.cpp +++ b/runtime/cpp/Allocator/GCHeap.cpp @@ -1,6 +1,9 @@ #include #include "GCHeap.h" + +#include "Evaluator/Evaluator.h" + #include "GCSpace.h" #include "KnownObjects.h" #include "AllocationZone.h" @@ -80,7 +83,7 @@ uintptr_t GCHeap::allocate_(uint32_t size) { if (size > LargeThreshold) return this->allocateLarge_(size); - if (this->isAtGCSafepoint()) + if (this->isAtGCSafepoint() && !_runtime->_evaluator->isInCallback()) this->collectIfTime(); else requestGC(); diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index 7d66f3d4..947886f3 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -40,7 +40,8 @@ Evaluator::Evaluator(Runtime *runtime, HeapObject *falseObj, HeapObject *trueObj _runtime(runtime), _nilObj(nilObj), _trueObj(trueObj), - _falseObj(falseObj) + _falseObj(falseObj), + _inCallback(false) { _linearizer = new SExpressionLinearizer(); _linearizer->runtime_(_runtime); @@ -426,7 +427,8 @@ void Evaluator::visitOpReturn(SOpReturn *anSOpReturn) { this->popFrameAndPrepare(); - _runtime->_heap->collectIfTime(); + if (!_inCallback) + _runtime->_heap->collectIfTime(); } void Evaluator::visitOpNonLocalReturn(SOpNonLocalReturn *anSOpNonLocalReturn) @@ -595,7 +597,10 @@ void Evaluator::evaluateCallback_(void *ret, HeapObject *closure, int argc, void this->_context->regPC_(_work->size()); _context->buildClosureFrameFor_code_environment_(receiver, block, closure); } + auto prev = _inCallback; + _inCallback = true; this->evaluate(); + _inCallback = prev; this->_context->regPC_(prevPC); for (size_t i = 0; i < argc; ++i) { this->_context->pop(); diff --git a/runtime/cpp/Evaluator/Evaluator.h b/runtime/cpp/Evaluator/Evaluator.h index 0f0d7d4b..28bdccf7 100644 --- a/runtime/cpp/Evaluator/Evaluator.h +++ b/runtime/cpp/Evaluator/Evaluator.h @@ -40,6 +40,8 @@ class Evaluator : public SExpressionVisitor { std::vector *_work; + bool _inCallback; + public: using PrimitivePointer = Object* (Evaluator::*)(); using UndermessagePointer = Object* (Evaluator::*)(Object *, std::vector &args); @@ -131,6 +133,8 @@ class Evaluator : public SExpressionVisitor { HeapObject* false_() { return this->_falseObj; } + + bool isInCallback() { return _inCallback; } HeapObject* lookup_startingAt_sendSite_(HeapObject* symbol, HeapObject *behavior, SAbstractMessage *message); Object* invoke_with_(HeapObject* method, Object *receiver); From eaf5f7b58cc829cdd8d5e7cef2059d86735a0a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 18:42:34 -0300 Subject: [PATCH 20/24] [vm-cpp] make replaceStringFromToWithStartingAt primitive check for errors --- runtime/cpp/Evaluator/Evaluator.cpp | 39 +++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/runtime/cpp/Evaluator/Evaluator.cpp b/runtime/cpp/Evaluator/Evaluator.cpp index 947886f3..f1ae28da 100644 --- a/runtime/cpp/Evaluator/Evaluator.cpp +++ b/runtime/cpp/Evaluator/Evaluator.cpp @@ -874,13 +874,38 @@ Object* Evaluator::primitiveSize() { } Object* Evaluator::primitiveStringReplaceFromToWithStartingAt() { - auto receiver = this->_context->self(); - receiver->asHeapObject()->replaceBytesFrom_to_with_startingAt_( - this->_context->firstArgument()->asSmallInteger()->asNative(), - this->_context->secondArgument()->asSmallInteger()->asNative(), - this->_context->thirdArgument()->asHeapObject(), - this->_context->fourthArgument()->asSmallInteger()->asNative()); - return receiver; + auto receiver = this->_context->self()->asHeapObject(); + auto from = this->_context->firstArgument(); + auto to = this->_context->secondArgument(); + auto source = this->_context->thirdArgument(); + auto starting = this->_context->fourthArgument(); + + if (!from->isSmallInteger() || !to->isSmallInteger() || !starting->isSmallInteger()) + return this->failPrimitive(); + + if (source->isSmallInteger()) + return this->failPrimitive(); + + if (_runtime->speciesOf_((Object*)receiver) != _runtime->speciesOf_(source)) + return this->failPrimitive(); + + auto fromint = from->asSmallInteger()->asNative(); + auto toint = to->asSmallInteger()->asNative(); + auto startingint = starting->asSmallInteger()->asNative(); + + if (toint > receiver->size()) + return this->failPrimitive(); + + auto len = to - from + 1; + auto last = startingint + len - 1; + auto hsource = source->asHeapObject(); + if (last > hsource->size()) + return this->failPrimitive(); + + receiver->replaceBytesFrom_to_with_startingAt_( + fromint, toint, hsource, startingint); + + return (Object*)receiver; } Object* Evaluator::primitiveUnderBeSpecial() { From cdbb08608f71e127699b351fcd61ab660a683335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 18:43:56 -0300 Subject: [PATCH 21/24] [kernel] implement String>>replaceFrom:to:with:startingAt: failure path --- modules/Kernel/VM/String.st | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/Kernel/VM/String.st b/modules/Kernel/VM/String.st index b31cb8f4..45aaec18 100644 --- a/modules/Kernel/VM/String.st +++ b/modules/Kernel/VM/String.st @@ -8,6 +8,17 @@ Extension { #name : #String } { #category : '*Primitives' } String >> replaceFrom: start to: end with: collection startingAt: index [ + collection hasBytes + ifTrue: [self + replaceBytesFrom: start + to: end + with: collection + startingAt: index] + ifFalse: [super + replaceFrom: start + to: end + with: collection + startingAt: index] ] From 7ab0343a274660f956947aa61e512efed79e015a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 18:45:51 -0300 Subject: [PATCH 22/24] [http] implement ffi glue for request path_params at --- modules/HTTP/CPPHTTPServer/lib/server.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/HTTP/CPPHTTPServer/lib/server.cpp b/modules/HTTP/CPPHTTPServer/lib/server.cpp index b82cddee..cc1eb01b 100644 --- a/modules/HTTP/CPPHTTPServer/lib/server.cpp +++ b/modules/HTTP/CPPHTTPServer/lib/server.cpp @@ -29,11 +29,17 @@ void Server_Delete(void *cserver) { delete server; } +char* Request_ParamAt(void *creq, char *key, char *type) +{ + httplib::Request *req = reinterpret_cast(creq); + + return (char*)req->path_params.at(key).c_str(); +} void Response_SetContent(void *cres, char *content, char *type) { - httplib::Response *res = reinterpret_cast(cres); - res->set_content(content, type); + httplib::Response *res = reinterpret_cast(cres); + res->set_content(content, type); } } From f61efaad3fd6dffdbfb2995111190a4c642b81c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 18:47:39 -0300 Subject: [PATCH 23/24] [http] implement st side of Request_ParamAt ffi binding --- modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st b/modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st index 6f8e232b..10546b3e 100644 --- a/modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st +++ b/modules/HTTP/CPPHTTPServer/HTTPServerLibrary.st @@ -19,32 +19,37 @@ HTTPServerLibrary class >> libpath [ ^'./' ] -{ #category : #spec } +{ #category : #server } HTTPServerLibrary >> deleteServer: aServer [ ] -{ #category : #spec } +{ #category : #server } HTTPServerLibrary >> newServer [ ] -{ #category : #spec } +{ #category : #server } HTTPServerLibrary >> server: aServer GET: url callback: aCallback [ ] -{ #category : #spec } +{ #category : #server } HTTPServerLibrary >> startServer: aServer [ ] -{ #category : #initializing } +{ #category : #server } HTTPServerLibrary >> stopServer: aServer [ ] -{ #category : #initializing } +{ #category : #request } +HTTPServerLibrary >> request: aRequest paramAt: aString [ + +] + +{ #category : #response } HTTPServerLibrary >> response: aResponse setContents: aString type: anotherString [ ] From da1633e912bfed6acae79b1ccde12ccc33948be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Pim=C3=A1s?= Date: Tue, 29 Apr 2025 18:50:02 -0300 Subject: [PATCH 24/24] [http] update example for improved http server api, make hello :name parametric --- modules/Examples/HTTPServer/ExampleAPI.st | 16 ++++--------- .../Examples/HTTPServer/HTTPServerModule.st | 24 ++++++++++++------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/modules/Examples/HTTPServer/ExampleAPI.st b/modules/Examples/HTTPServer/ExampleAPI.st index a3f85ef2..845a95c2 100644 --- a/modules/Examples/HTTPServer/ExampleAPI.st +++ b/modules/Examples/HTTPServer/ExampleAPI.st @@ -3,18 +3,17 @@ Class { #superclass : #Object, #instVars : [ 'request', - 'response', - 'server' + 'response' ], #category : #'Examples-HTTPServer' } { #category : #spec } ExampleAPI >> hello [ - server library - response: response asParameter - setContents: 'hello, world!' externalCopy asParameter - type: 'text/html' externalCopy asParameter + | name | + name := request paramAt: 'name'. + name isEmpty ifTrue: [name := 'world']. + response setContents: 'hello, ', name, '!' type: 'text/html' ] { #category : #spec } @@ -27,8 +26,3 @@ ExampleAPI >> response: aResponse [ response := aResponse ] -{ #category : #spec } -ExampleAPI >> server: aCPPHTTPServer [ - server := aCPPHTTPServer -] - diff --git a/modules/Examples/HTTPServer/HTTPServerModule.st b/modules/Examples/HTTPServer/HTTPServerModule.st index 15e0abee..68de8ba8 100644 --- a/modules/Examples/HTTPServer/HTTPServerModule.st +++ b/modules/Examples/HTTPServer/HTTPServerModule.st @@ -10,22 +10,30 @@ Class { { #category : #spec } HTTPServerModule >> imports [ ^{ - #'HTTP.CPPHTTPServer' -> #(CPPHTTPServer). + #'HTTP.CPPHTTPServer' -> #(HTTPServer). #FFI -> #(ExternalLibrary). - } ] +{ #category : #spec } +HTTPServerModule >> handle: request into: response with: selector [ + | api | + api := ExampleAPI new + request: request; + response: response. + api perform: selector. + "response headersAt: 'Access-Control-Allow-Origin' put: '*'." +] + { #category : #services } HTTPServerModule >> main: arguments [ - | server | - "Transcript show: 'starting server!'." + | server base | ExternalLibrary module initializeForCurrentPlatform. - - server := CPPHTTPServer new apiClass: ExampleAPI. + base := arguments at: 3 ifAbsent: ['/egg']. + server := HTTPServer new. server - baseUri: '/egg'; - routeGET: '/hello' to: #hello. + routeGET: base, '/hello/:name' to: #hello with: self. + Kernel log: 'server configured, starting!', String cr. server start. ^0 ]