Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Support bytecode functions in JS_WriteObject #977

Open
bnoordhuis opened this issue Mar 15, 2025 · 1 comment
Open

Support bytecode functions in JS_WriteObject #977

bnoordhuis opened this issue Mar 15, 2025 · 1 comment
Labels
bug Something isn't working

Comments

@bnoordhuis
Copy link
Contributor

#975 adds Array.fromAsync as a lazy-loaded bytecode function.

It's actually implemented as a bytecode module with a single exported function that returns the actual Array.fromAsync function.

I did it in this roundabout fashion because JS_WriteObject does not seem capable of directly serializing a bytecode function1, only when it's embedded in something else, like a script or module.

Things to improve:

  1. Support bytecode functions in JS_WriteObject

  2. Add a flag to qjsc to compile the input as a function instead of as a script or module.

1 It's possible ES classes don't work either but I didn't test that

@bnoordhuis bnoordhuis added the bug Something isn't working label Mar 15, 2025
@bnoordhuis
Copy link
Contributor Author

My notes:

  1. it almost works in the sense that JS_WriteObject(JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, p->u.func)) where p->class_id == JS_CLASS_BYTECODE_FUNCTION1 writes a BC_TAG_FUNCTION_BYTECODE object
  2. reading that back produces a JS_TAG_FUNCTION_BYTECODE value
  3. you can't JS_Call that value directly, you first need to JS_EvalFunction it
  4. the return value from that function you can JS_Call; it's a JS_TAG_OBJECT with p->class_id == JS_CLASS_BYTECODE_FUNCTION...
  5. ...which is really just a function object wrapper around the JS_TAG_FUNCTION_BYTECODE value from (2)

1 Note the inconsistent spelling: function bytecode vs. bytecode function

Getting JS_WriteObject to write the bytecode is easy (see diff) but it also needs to store the class id, otherwise JS_ReadObject doesn't know whether to deserialize it as a regular function, async function, generator, etc.

diff --git a/quickjs.c b/quickjs.c
index ba4cf1a..a5ca972 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -34421,6 +34421,10 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
             default:
                 if (is_typed_array(p->class_id)) {
                     ret = JS_WriteTypedArray(s, obj);
+                } else if (js_class_has_bytecode(p->class_id)) {
+                    JSValue fun = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE,
+                                           p->u.func.function_bytecode);
+                    ret = JS_WriteFunctionTag(s, fun);
                 } else {
                     JS_ThrowTypeError(s->ctx, "unsupported object class");
                     ret = -1;

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant