diff options
author | 2022-11-03 00:18:26 -0700 | |
---|---|---|
committer | 2022-11-03 00:18:26 -0700 | |
commit | 6142715c06d5eb3dbaa07901a6281ae1394483a9 (patch) | |
tree | c549d8597ba4f89b1e3a19efdcd2351297d5b5cb | |
parent | 34e130a3e0cb251cb163071b75228c6d521edf95 (diff) | |
download | bun-6142715c06d5eb3dbaa07901a6281ae1394483a9.tar.gz bun-6142715c06d5eb3dbaa07901a6281ae1394483a9.tar.zst bun-6142715c06d5eb3dbaa07901a6281ae1394483a9.zip |
Introduce `import.meta.primordials` for builtin JS
the `import.meta` object in Bun now has a `primordials` object which makes a handful of globals safe for access. Inside of bun: or node: modules, it is a special object (ownKeys is not implemented, so Object.keys() wont work on it)
- Array
- String
- `isPromise`
- `isCallable`
- `isConstructable`
- `tryGetById(foo, "bar')` which is like foo?.bar
- `arrayPush` which is like `Array.prototype.push`
- `Bun`
- `isAbortSignal`
cc @ThatOneBro @lawrencecchen
-rw-r--r-- | src/bun.js/bindings/ImportMetaObject.cpp | 1 | ||||
-rw-r--r-- | src/bun.js/bindings/ImportMetaObject.h | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 87 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 3 | ||||
-rw-r--r-- | test/bun.js/import-meta.test.js | 4 |
5 files changed, 95 insertions, 3 deletions
diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp index 17338da5c..cdd00ced2 100644 --- a/src/bun.js/bindings/ImportMetaObject.cpp +++ b/src/bun.js/bindings/ImportMetaObject.cpp @@ -319,6 +319,7 @@ void ImportMetaObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObj this->putDirect(vm, builtinNames.pathPublicName(), jsEmptyString(vm), 0); this->putDirect(vm, builtinNames.urlPublicName(), jsEmptyString(vm), 0); this->putDirect(vm, builtinNames.mainPublicName(), jsBoolean(false), 0); + this->putDirect(vm, Identifier::fromString(vm, "primordials"_s), jsUndefined(), JSC::PropertyAttribute::DontEnum | 0); String requireString = "[[require]]"_s; this->putDirect(vm, builtinNames.requirePublicName(), Zig::ImportMetaObject::createRequireFunction(vm, globalObject, requireString), PropertyAttribute::Builtin | PropertyAttribute::Function | 0); diff --git a/src/bun.js/bindings/ImportMetaObject.h b/src/bun.js/bindings/ImportMetaObject.h index ac50df12d..920d4f74f 100644 --- a/src/bun.js/bindings/ImportMetaObject.h +++ b/src/bun.js/bindings/ImportMetaObject.h @@ -67,6 +67,9 @@ public: if (view.startsWith('/')) { metaProperties->putDirect(vm, builtinNames.urlPublicName(), JSC::JSValue(JSC::jsString(vm, WTF::URL::fileURLWithFileSystemPath(view).string()))); } else { + if (view.startsWith("node:"_s) || view.startsWith("bun:"_s)) { + metaProperties->putDirect(globalObject->vm(), JSC::Identifier::fromString(globalObject->vm(), "primordials"_s), reinterpret_cast<Zig::GlobalObject*>(globalObject)->primordialsObject()); + } metaProperties->putDirect(vm, builtinNames.urlPublicName(), keyString); } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 637a06ed8..481fe8aeb 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -89,7 +89,6 @@ #include "JSStringDecoder.h" #include "JSReadableState.h" #include "JSReadableHelper.h" - #include "Process.h" #include "WebCoreJSBuiltinInternals.h" @@ -1940,6 +1939,81 @@ JSC_DEFINE_HOST_FUNCTION(functionReadableStreamToArrayBuffer, (JSGlobalObject * return ZigGlobalObject__readableStreamToArrayBufferBody(reinterpret_cast<Zig::GlobalObject*>(globalObject), JSValue::encode(readableStreamValue)); } +class BunPrimordialsObject final : public JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | GetOwnPropertySlotMayBeWrongAboutDontEnum; + static BunPrimordialsObject* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) + { + BunPrimordialsObject* ptr = new (NotNull, JSC::allocateCell<BunPrimordialsObject>(vm)) BunPrimordialsObject(vm, globalObject, structure); + ptr->finishCreation(vm); + return ptr; + } + + template<typename CellType, JSC::SubspaceAccess> + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(BunPrimordialsObject, Base); + return &vm.plainObjectSpace(); + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static bool getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) + { + JSC::VM& vm = globalObject->vm(); + + auto str = String(propertyName.publicName()); + SymbolImpl* symbol = vm.propertyNames->builtinNames().lookUpPrivateName(str); + if (!symbol) { + return false; + } + + auto identifier = JSC::Identifier::fromUid(vm, symbol); + if (auto value = globalObject->getIfPropertyExists(globalObject, identifier)) { + slot.setValue(globalObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly, value); + return true; + } else if (auto value = vm.bytecodeIntrinsicRegistry().lookup(identifier)) { + auto name = identifier.string(); + String functionText; + bool isFunction = false; + // this is...terrible code + if (name.characters8()[0] >= 'A' && name.characters8()[0] <= 'Z') { + functionText = makeString("(function () { return @"_s, name, ";\n})\n"_s); + } else if (name.characters8()[0] == 'p' || name.characters8()[0] == 't' || name.characters8()[0] == 'g') { + isFunction = true; + functionText = makeString("(function (arg1, arg2) { return @"_s, name, "(arg1, arg2);\n})\n"_s); + } else { + isFunction = true; + functionText = makeString("(function (arg1) { return @"_s, name, "(arg1);\n})\n"_s); + } + + SourceCode source = makeSource(WTFMove(functionText), {}); + JSFunction* func = JSFunction::create(vm, createBuiltinExecutable(vm, source, Identifier::fromString(vm, name), ImplementationVisibility::Public, ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, nullptr, source), globalObject); + + slot.setValue( + globalObject, + PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | 0, + isFunction ? JSValue(func) : JSC::call(globalObject, func, JSC::getCallData(func), globalObject, JSC::MarkedArgumentBuffer())); + + return true; + } + return false; + } + + DECLARE_INFO + + BunPrimordialsObject(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) + : JSC::JSNonFinalObject(vm, structure) + { + } +}; + +const ClassInfo BunPrimordialsObject::s_info = { "Primordials"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(BunPrimordialsObject) }; + void GlobalObject::finishCreation(VM& vm) { Base::finishCreation(vm); @@ -1992,6 +2066,14 @@ void GlobalObject::finishCreation(VM& vm) toJSNewlyCreated<IDLInterface<SubtleCrypto>>(*init.owner, global, WTFMove(crypto)).getObject()); }); + m_primordialsObject.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { + auto& global = *reinterpret_cast<Zig::GlobalObject*>(init.owner); + BunPrimordialsObject* object = BunPrimordialsObject::create(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.owner), + BunPrimordialsObject::createStructure(init.vm, init.owner, init.owner->objectPrototype())); + init.set(object); + }); + m_NapiClassStructure.initLater( [](LazyClassStructure::Initializer& init) { init.setStructure(Zig::NapiClass::createStructure(init.vm, init.global, init.global->functionPrototype())); @@ -2563,8 +2645,6 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "SubtleCrypto"_s), JSC::CustomGetterSetter::create(vm, getterSubtleCryptoConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CryptoKey"_s), JSC::CustomGetterSetter::create(vm, getterCryptoKeyConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - // putDirect(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().nativeReadableStreamPrototypePrivateName(), jsUndefined(), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum | 0); } // We set it in here since it's a global @@ -2824,6 +2904,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_performanceObject.visit(visitor); thisObject->m_navigatorObject.visit(visitor); thisObject->m_subtleCryptoObject.visit(visitor); + thisObject->m_primordialsObject.visit(visitor); thisObject->m_JSHTTPResponseSinkClassStructure.visit(visitor); thisObject->m_JSHTTPSResponseSinkClassStructure.visit(visitor); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index e91cf86bf..6863f72af 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -219,6 +219,7 @@ public: JSC::JSObject* encodeIntoObjectPrototype() { return m_encodeIntoObjectPrototype.getInitializedOnMainThread(this); } JSC::JSObject* performanceObject() { return m_performanceObject.getInitializedOnMainThread(this); } + JSC::JSObject* primordialsObject() { return m_primordialsObject.getInitializedOnMainThread(this); } JSC::JSObject* processObject() { @@ -417,6 +418,8 @@ private: LazyClassStructure m_JSReadableStateClassStructure; LazyClassStructure m_OnigurumaRegExpClassStructure; + LazyProperty<JSGlobalObject, JSObject> m_primordialsObject; + LazyProperty<JSGlobalObject, JSObject> m_navigatorObject; LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype; diff --git a/test/bun.js/import-meta.test.js b/test/bun.js/import-meta.test.js index f099797e5..a1ead978e 100644 --- a/test/bun.js/import-meta.test.js +++ b/test/bun.js/import-meta.test.js @@ -4,6 +4,10 @@ import sync from "./require-json.json"; const { path, dir } = import.meta; +it("primordials are not here!", () => { + expect(import.meta.primordials === undefined).toBe(true); +}); + it("import.meta.resolveSync", () => { expect( import.meta.resolveSync("./" + import.meta.file, import.meta.path) |