Last active
November 25, 2025 23:03
-
-
Save acquitelol/fd8ce04e6a5896d72b965ba84dd13668 to your computer and use it in GitHub Desktop.
A Node V8 module in Elle without an `extern "C"` wrapper. Note: only works on aarch64.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This is Elle https://github.com/acquitelol/elle NOT Rust | |
| // I just need the syntax highlighting | |
| use std/prelude; | |
| namespace V8Local; | |
| external fn _ZN2v86Object3SetENS_5LocalINS_7ContextEEENS1_INS_5ValueEEES5_( | |
| void **self, | |
| void *context, | |
| void *key, | |
| void *value | |
| ) @alias(V8Local::Set) -> Option<bool>; | |
| namespace V8Isolate; | |
| external fn _ZN2v87Isolate10GetCurrentEv() @alias(V8Isolate::GetCurrent) -> V8Isolate *; | |
| external fn _ZN2v87Isolate17GetCurrentContextEv(V8Isolate *self) @alias(V8Isolate::GetCurrentContext) -> void *; | |
| struct V8FunctionTemplate @nofmt { u8 _ } | |
| external fn _ZN2v816FunctionTemplate3NewEPNS_7IsolateEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEENS_5LocalIS4_EENSA_INS_9SignatureEEEiNS_19ConstructorBehaviorENS_14SideEffectTypeEPKNS_9CFunctionEttt( | |
| V8Isolate *isolate, | |
| fn(void *) callback, | |
| void *data, | |
| void *signature, | |
| i32 length, | |
| i32 behavior, | |
| i32 side_effect_type, | |
| fn() c_function, | |
| u16 instance_type, | |
| u16 allowed_receiver_instance_type_range_start, | |
| u16 allowed_receiver_instance_type_range_end | |
| ) @alias(V8FunctionTemplate::new) -> void *; | |
| external fn _ZN2v816FunctionTemplate11GetFunctionENS_5LocalINS_7ContextEEE( | |
| V8FunctionTemplate *self, | |
| void *context | |
| ) @alias(V8FunctionTemplate::GetFunction) -> void *; | |
| struct V8HandleScope @nofmt { | |
| @unused void *i_isolate_, | |
| @unused void *prev_next_, | |
| @unused void *prev_limit_ | |
| } | |
| external fn _ZN2v811HandleScopeC1EPNS_7IsolateE( | |
| V8HandleScope *self, | |
| V8Isolate *isolate | |
| ) @alias(V8HandleScope::init) -> V8HandleScope; | |
| external fn _ZN2v811HandleScopeD1Ev(V8HandleScope *self) @alias(V8HandleScope::destroy); | |
| namespace V8String; | |
| external fn _ZN2v86String11NewFromUtf8EPNS_7IsolateEPKcNS_13NewStringTypeEi( | |
| V8Isolate *isolate, | |
| string value, | |
| i32 type, | |
| i32 length | |
| ) @alias(V8String::NewFromUtf8) -> void **; | |
| namespace V8Function; | |
| external fn _ZN2v88Function7SetNameENS_5LocalINS_6StringEEE(V8Function *self, void *name) @alias(V8Function::SetName); | |
| struct V8FunctionCallbackInfo { | |
| void **implicit_args_, | |
| void **values_, | |
| u64 length_ // padded to maintain size | |
| } | |
| fn V8FunctionCallbackInfo::GetIsolate(V8FunctionCallbackInfo *self) -> V8Isolate * { | |
| return self.implicit_args_[1]; | |
| } | |
| struct NodeModule @nofmt { | |
| i32 version, | |
| u32 flags, | |
| void *dso_handle, | |
| string filename, | |
| fn(void *, void *, void *) register_func, | |
| fn() context_register_func, | |
| string modname, | |
| void *priv, | |
| NodeModule *link | |
| } | |
| const NODE_MODULE_VERSION = 137; | |
| const get_current_file = fn(ElleMeta meta) meta.file; | |
| external fn node_module_register(NodeModule *module); | |
| fn hello(V8FunctionCallbackInfo *args) { | |
| isolate := args.GetIsolate(); | |
| context := isolate.GetCurrentContext(); | |
| arg := #cast(i32, args.values_[0] >> 32); | |
| args.implicit_args_[3] = *V8String::NewFromUtf8( | |
| isolate, | |
| "Hello from Elle! You passed {}".format(arg), | |
| 0, -1 | |
| ); | |
| } | |
| fn load_env() { | |
| ElleEnv *env = mem::malloc(#size(ElleEnv)); | |
| env.allocator = ArbitraryAllocator::new(); | |
| env.default_allocator = GCAllocator::new(); | |
| env.stack_top = &0; | |
| #env = env; | |
| #reset_allocator(); | |
| } | |
| fn set_method(void *recv, string name, fn(void *) callback) { | |
| isolate := V8Isolate::GetCurrent(); | |
| scope := V8HandleScope {}; | |
| defer scope.destroy(); | |
| scope.init(isolate); | |
| context := isolate.GetCurrentContext(); | |
| template := V8FunctionTemplate::new(isolate, callback, nil, nil, 0, 1, 0, nil, 0, 0, 0); | |
| func := V8FunctionTemplate::GetFunction(template, context); | |
| func_name := V8String::NewFromUtf8(isolate, name, 1, -1); | |
| V8Function::SetName(func, func_name); | |
| res := V8Local::Set(recv, context, func_name, func); | |
| } | |
| fn register_test() { | |
| load_env(); | |
| node_module_register(Box::new(NodeModule { | |
| version = NODE_MODULE_VERSION, | |
| flags = 0, | |
| dso_handle = nil, | |
| filename = get_current_file(), | |
| register_func = fn(recv) set_method(recv, "test", hello), | |
| context_register_func = nil, | |
| modname = "test", | |
| priv = nil, | |
| link = nil, | |
| }).to_ptr()); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| main.node: main.o | |
| cc -shared -fPIC main.o -L$(HOME)/.local/lib -lelle -Wl,-undefined,dynamic_lookup -o main.node | |
| main.o: main.s | |
| echo ".section __DATA,__mod_init_func,mod_init_funcs" >> main.s | |
| echo ".p2align 3" >> main.s | |
| echo ".quad _register_test" >> main.s | |
| cc main.s -c -o main.o | |
| main.s: | |
| ellec main.le --asm -c | |
| test.node: | |
| clang++ -std=c++20 -O3 -fPIC -shared test.cpp \ | |
| -I$(HOME)/.nvm/versions/node/v19.0.0/include/node \ | |
| -o test.node \ | |
| -Wl,-undefined,dynamic_lookup | |
| test.ll: | |
| clang++ -std=c++20 -S -emit-llvm -O3 test.cpp \ | |
| -I$(HOME)/.nvm/versions/node/v19.0.0/include/node \ | |
| -o test.ll |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment