util.import
コメントによれば__parent__をたどってcallerのグローバルオブジェクトにインポートされるって書いてあります。
まだfx3に移行できてなくて触ってないので検証してないですけど。
なんか一回ぜんぜんべつのなにもない環境で読み込んだやつのシンボルテーブルをwalkしてぜんぶコピーしてる雰囲気。GlobalForLocationの中で実際にファイルを読み込んでコンパイルしてます。
js/src/xpconnect/loader/mozJSComponentLoader.cpp
/* [JSObject] import (in AUTF8String registryLocation, [optional] in JSObject targetObj ); */ NS_IMETHODIMP mozJSComponentLoader::Import(const nsACString & registryLocation) { ... snip ... PRUint32 argc = 0; rv = cc->GetArgc(&argc); NS_ENSURE_SUCCESS(rv, rv); if (argc > 1) { // The caller passed in the optional second argument. Get it. jsval *argv = nsnull; rv = cc->GetArgvPtr(&argv); NS_ENSURE_SUCCESS(rv, rv); if (!JSVAL_IS_OBJECT(argv[1])) { return ReportOnCaller(cc, ERROR_SCOPE_OBJ, PromiseFlatCString(registryLocation).get()); } targetObject = JSVAL_TO_OBJECT(argv[1]); } else { // Our targetObject is the caller's global object. Find it by // walking the calling object's parent chain. nsCOMPtr<nsIXPConnectWrappedNative> wn; rv = cc->GetCalleeWrapper(getter_AddRefs(wn)); NS_ENSURE_SUCCESS(rv, rv); wn->GetJSObject(&targetObject); if (!targetObject) { NS_ERROR("null calling object"); return NS_ERROR_FAILURE; } JSObject *parent; while ((parent = JS_GetParent(cx, targetObject))) targetObject = parent; } JSObject *globalObj = nsnull; rv = ImportInto(registryLocation, targetObject, cc, &globalObj); /* [noscript] JSObjectPtr importInto(in AUTF8String registryLocation, in JSObjectPtr targetObj); */ NS_IMETHODIMP mozJSComponentLoader::ImportInto(const nsACString & aLocation, JSObject * targetObj, nsIXPCNativeCallContext * cc, JSObject * *_retval) { ... snip ... nsCAutoString scheme; rv = ioService->ExtractScheme(aLocation, scheme); if (NS_FAILED(rv) || !scheme.EqualsLiteral("resource")) { *_retval = nsnull; return NS_ERROR_INVALID_ARG; } // Get the resource:// URI. nsCOMPtr<nsIURI> resURI; rv = ioService->NewURI(aLocation, nsnull, nsnull, getter_AddRefs(resURI)); nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(resURI, &rv); NS_ENSURE_SUCCESS(rv, rv); // Get the file belonging to it. nsCOMPtr<nsIFile> file; rv = fileURL->GetFile(getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsILocalFile> componentFile = do_QueryInterface(file, &rv); ... snip ... ModuleEntry* mod; nsAutoPtr<ModuleEntry> newEntry; if (!mImports.Get(lfhash, &mod) && !mInProgressImports.Get(lfhash, &mod)) { newEntry = new ModuleEntry; if (!newEntry || !mInProgressImports.Put(lfhash, newEntry)) return NS_ERROR_OUT_OF_MEMORY; rv = GlobalForLocation(componentFile, &newEntry->global, &newEntry->location); mInProgressImports.Remove(lfhash); if (NS_FAILED(rv)) { *_retval = nsnull; return NS_ERROR_FILE_NOT_FOUND; } mod = newEntry; } NS_ASSERTION(mod->global, "Import table contains entry with no global"); *_retval = mod->global; for (jsuint i = 0; i < symbolCount; ++i) { jsval val; JSString *symbolName; if (!JS_GetElement(mContext, symbolsObj, i, &val) || !JSVAL_IS_STRING(val)) { return ReportOnCaller(cc, ERROR_ARRAY_ELEMENT, PromiseFlatCString(aLocation).get(), i); } symbolName = JSVAL_TO_STRING(val); if (!JS_GetProperty(mContext, mod->global, JS_GetStringBytes(symbolName), &val)) { return ReportOnCaller(cc, ERROR_GETTING_SYMBOL, PromiseFlatCString(aLocation).get(), JS_GetStringBytes(symbolName)); } if (!JS_SetProperty(mContext, targetObj, JS_GetStringBytes(symbolName), &val)) { return ReportOnCaller(cc, ERROR_SETTING_SYMBOL, PromiseFlatCString(aLocation).get(), JS_GetStringBytes(symbolName)); } ... snip ... } }