Skip to content

Implement node:vm #2785

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 18, 2023
Merged

Implement node:vm #2785

merged 10 commits into from
May 18, 2023

Conversation

silversquirl
Copy link
Contributor

Resolves #401

@silversquirl silversquirl marked this pull request as ready for review May 2, 2023 01:14
@silversquirl silversquirl marked this pull request as draft May 2, 2023 01:16
{ "cachedDataRejected"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, scriptGetCachedDataRejected, nullptr } },
{ "createCachedData"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, scriptCreateCachedData, 0 } },
{ "runInContext"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, scriptRunInContext, 0 } },
{ "sourceMapURL"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly|PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, scriptGetSourceMapURL, nullptr } },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, to implement this, have a look at JSC::FunctionExecutable. I vaguely remember something in there to extract the sourceMapURL

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question I had here was whether I should be using a custom property here or just set the field on the object during init.
I feel like the latter might be simpler, but I'm not sure exactly how to do it - if you have any examples of code that sets object fields you could link that'd be great :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo we should keep it as a custom getter/setter (present state)

as an optional optimization, if we think people will frequently call it, then we could add a mutable WriteBarrier<JSC::JSString> cachedSourceMapURL; on the Script to cache it

The sourceMapURL may be lazily loaded in JSC (i haven't checked), in which case making it a property on the object would be less efficient

@Jarred-Sumner
Copy link
Collaborator

a weird thing we should consider

do we want the transpiler to run in these VM global objects? if we use Zig::GlobalObject it will

@silversquirl
Copy link
Contributor Author

Interesting question. Can you think of any downsides to having it run? I guess it could have a small performance impact?

@Jarred-Sumner
Copy link
Collaborator

yes to performance impact, but also the transpiler only outputs ESM modules which means eval, and any sloppy mode features would not work

however, does require work in node:vm? i don't know

@silversquirl
Copy link
Contributor Author

does require work in node:vm?

no

$ cat vm.js
const vm = require("node:vm");
vm.runInThisContext(`require("node:fs");`);
$  node vm.js
evalmachine.<anonymous>:1
require("node:fs");
^

ReferenceError: require is not defined
    at evalmachine.<anonymous>:1:1
    at Script.runInThisContext (node:vm:129:12)
    at Object.runInThisContext (node:vm:313:38)
    at Object.<anonymous> (/home/silver/code/play-js/vm.js:2:4)
    at Module._compile (node:internal/modules/cjs/loader:1165:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1219:10)
    at Module.load (node:internal/modules/cjs/loader:1043:32)
    at Function.Module._load (node:internal/modules/cjs/loader:878:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:22:47

}

ArgList args(callFrame);
return runInContext(globalObject, script, globalObject->globalThis(), globalObject->globalScope(), args.at(0));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
JSObject* context = asObject(contextArg);

JSScope* contextScope = JSWithScope::create(vm, globalObject, globalObject->globalScope(), context);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have to use a new JSGlobalObject since if you assign to a global in a context it shouldn't impact the calling context
image

I think we can use JSProxy here:

https://github.com/oven-sh/WebKit/blob/6bd997e38e30f50b3114b178f4d5e2fc5da6da25/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp#L699-L707

WebCore has to do some similar strange things due to the combo of:

  • Web Extensions
  • iframes accessing parent window
  • regular userland code

@jimmywarting
Copy link

how about screwing the cjs syntax and only supporting the ESM system as nodes experimental vm?

@Jarred-Sumner
Copy link
Collaborator

how about screwing the cjs syntax and only supporting the ESM system as nodes experimental vm?

The goal for node:vm in bun is to improve node compatibility, so no

@silversquirl
Copy link
Contributor Author

Not complete but the rest is beyond my JSC knowledge right now so this can be merged as a first step :)

Hopefully it should get a decent chunk of the stuff that depends on node:vm working - the slight differences and missing features in this implementation are probably relatively niche.

@Jarred-Sumner Jarred-Sumner merged commit ac64eb4 into oven-sh:main May 18, 2023
@Jarred-Sumner
Copy link
Collaborator

great

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support vm module
3 participants