gecko-dev/js/rust/build.rs
Jon Coppeard 4c9a0dab80 Bug 1634459 - Simplify the wrapper used for rooting non-GC thing types r=jandem
Previously this stored a function pointer to do the tracing along with the rooted thing. The patch changes this to use a virtual method for the tracing. Calling the method on the base class means we don't need to do address arithmetic to find wher the trace function is stored and we don't need the alignment restrictions, because the virtual trace method knows the layout of its class.

I had to add a traits class, mainly to get the address of the rooted thing inside the wrapper since we need to be able to get the address of the wrapper itself now for tracing.

The wrapper class is renamed from DispatchWrapper to RootedTraceable.

Differential Revision: https://phabricator.services.mozilla.com/D73421
2020-05-04 16:53:56 +00:00

496 lines
14 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate bindgen;
extern crate cmake;
extern crate env_logger;
extern crate glob;
use std::env;
use std::path;
fn main() {
env_logger::init();
build_jsapi_bindings();
build_jsglue_cpp();
}
/// Build the ./src/jsglue.cpp file containing C++ glue methods built on top of
/// JSAPI.
fn build_jsglue_cpp() {
let dst = cmake::Config::new(".").build();
println!("cargo:rustc-link-search=native={}/lib", dst.display());
println!("cargo:rustc-link-lib=static=jsglue");
println!("cargo:rerun-if-changed=src/jsglue.cpp");
}
/// Find the public include directory within our mozjs-sys crate dependency.
fn get_mozjs_include_dir() -> path::PathBuf {
let out_dir = env::var("OUT_DIR").expect("cargo should invoke us with the OUT_DIR env var set");
let mut target_build_dir = path::PathBuf::from(out_dir);
target_build_dir.push("../../");
let mut include_dir_glob = target_build_dir.display().to_string();
include_dir_glob.push_str("mozjs_sys-*/out/dist/include");
let entries =
glob::glob(&include_dir_glob).expect("Should find entries for mozjs-sys include dir");
for entry in entries {
if let Ok(path) = entry {
return path
.canonicalize()
.expect("Should canonicalize include path");
}
}
panic!("Should have found either a mozjs_sys in target/debug or in target/release");
}
/// Invoke bindgen on the JSAPI headers to produce raw FFI bindings for use from
/// Rust.
///
/// To add or remove which functions, types, and variables get bindings
/// generated, see the `const` configuration variables below.
fn build_jsapi_bindings() {
let mut builder = bindgen::builder()
.rust_target(bindgen::RustTarget::Stable_1_19)
.size_t_is_usize(true)
.header("./etc/wrapper.hpp")
.raw_line("pub use self::root::*;")
// Translate every enum with the "rustified enum" strategy. We should
// investigate switching to the "constified module" strategy, which has
// similar ergonomics but avoids some potential Rust UB footguns.
.rustified_enum(".*")
.enable_cxx_namespaces();
if cfg!(feature = "debugmozjs") {
builder = builder
.clang_arg("-DJS_GC_ZEAL")
.clang_arg("-DDEBUG")
.clang_arg("-DJS_DEBUG");
}
if cfg!(feature = "bigint") {
builder = builder.clang_arg("-DENABLE_BIGINT");
}
let include_dir = get_mozjs_include_dir();
let include_dir = include_dir
.to_str()
.expect("Path to mozjs include dir should be utf-8");
builder = builder.clang_arg("-I");
builder = builder.clang_arg(include_dir);
for ty in UNSAFE_IMPL_SYNC_TYPES {
builder = builder.raw_line(format!("unsafe impl Sync for {} {{}}", ty));
}
for extra in EXTRA_CLANG_FLAGS {
builder = builder.clang_arg(*extra);
}
for ty in WHITELIST_TYPES {
builder = builder.whitelist_type(ty);
}
for var in WHITELIST_VARS {
builder = builder.whitelist_var(var);
}
for func in WHITELIST_FUNCTIONS {
builder = builder.whitelist_function(func);
}
if cfg!(feature = "bigint") {
builder = builder.whitelist_type("JS::BigInt");
}
for ty in OPAQUE_TYPES {
builder = builder.opaque_type(ty);
}
for ty in BLACKLIST_TYPES {
builder = builder.blacklist_type(ty);
}
let bindings = builder
.generate()
.expect("Should generate JSAPI bindings OK");
let out = path::PathBuf::from(env::var("OUT_DIR").unwrap());
if cfg!(feature = "debugmozjs") {
bindings
.write_to_file(out.join("jsapi_debug.rs"))
.expect("Should write bindings to file OK");
} else {
bindings
.write_to_file(out.join("jsapi.rs"))
.expect("Should write bindings to file OK");
}
println!("cargo:rerun-if-changed=etc/wrapper.hpp");
}
/// JSAPI types for which we should implement `Sync`.
const UNSAFE_IMPL_SYNC_TYPES: &'static [&'static str] = &[
"JSClass",
"JSFunctionSpec",
"JSNativeWrapper",
"JSPropertySpec",
"JSTypedMethodJitInfo",
];
/// Flags passed through bindgen directly to Clang.
const EXTRA_CLANG_FLAGS: &'static [&'static str] = &[
"-x",
"c++",
"-std=gnu++17",
"-fno-sized-deallocation",
"-fno-aligned-new",
"-DRUST_BINDGEN",
];
/// Types which we want to generate bindings for (and every other type they
/// transitively use).
const WHITELIST_TYPES: &'static [&'static str] = &[
"JS::AutoCheckCannotGC",
"JS::CallArgs",
"JS::RealmOptions",
"JS::ContextOptions",
"js::DOMCallbacks",
"js::DOMProxyShadowsResult",
"js::ESClass",
"JS::ForOfIterator",
"JS::Handle",
"JS::HandleFunction",
"JS::HandleId",
"JS::HandleObject",
"JS::HandleString",
"JS::HandleValue",
"JS::HandleValueArray",
"JS::IsAcceptableThis",
"JSAutoRealm",
"JSAutoStructuredCloneBuffer",
"JSClass",
"JSClassOps",
"JSContext",
"JSErrNum",
"JSErrorCallback",
"JSErrorFormatString",
"JSErrorReport",
"JSExnType",
"JSLinearString",
"JSFunction",
"JSFunctionSpec",
"JS::GCDescription",
"JSGCInvocationKind",
"JSGCMode",
"JSGCParamKey",
"JS::GCProgress",
"JSGCStatus",
"JSJitCompilerOption",
"JSJitGetterCallArgs",
"JSJitMethodCallArgs",
"JSJitSetterCallArgs",
"JSNativeWrapper",
"JSPropertySpec",
"JSProtoKey",
"JSObject",
"JSString",
"JSStructuredCloneReader",
"JSStructuredCloneWriter",
"JSScript",
"JSType",
"JSTypedMethodJitInfo",
"JSValueTag",
"JSValueType",
"JSVersion",
"JSWrapObjectCallbacks",
"jsid",
"JS::Compartment",
"JS::Latin1Char",
"JS::detail::RootedPtr",
"JS::MutableHandle",
"JS::MutableHandleObject",
"JS::MutableHandleValue",
"JS::NativeImpl",
"js::ObjectOps",
"JS::ObjectOpResult",
"JS::PersistentRootedIdVector",
"JS::PersistentRootedObjectVector",
"JS::PromiseState",
"JS::PropertyDescriptor",
"JS::Rooted",
"JS::RootedObject",
"JS::RootedValue",
"JS::RootingContext",
"JS::RootKind",
"js::Scalar::Type",
"JS::ServoSizes",
"js::shadow::Object",
"js::shadow::ObjectGroup",
"JS::SourceText",
"js::StackFormat",
"JSStructuredCloneCallbacks",
"JS::Symbol",
"JS::SymbolCode",
"JS::TraceKind",
"JS::TransferableOwnership",
"JS::Value",
"JS::WarningReporter",
"JS::shadow::Realm",
"JS::shadow::Zone",
"JS::Zone",
];
/// Global variables we want to generate bindings to.
const WHITELIST_VARS: &'static [&'static str] = &[
"JS_STRUCTURED_CLONE_VERSION",
"JSCLASS_.*",
"JSFUN_.*",
"JSID_TYPE_VOID",
"JSITER_.*",
"JSPROP_.*",
"JS::FalseHandleValue",
"JS::NullHandleValue",
"JS::TrueHandleValue",
"JS::UndefinedHandleValue",
];
/// Functions we want to generate bindings to.
const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS::ExceptionStackOrNull",
"JS_AddExtraGCRootsTracer",
"JS_AddInterruptCallback",
"JS::AddPromiseReactions",
"js::AddRawValueRoot",
"JS_AlreadyHasOwnPropertyById",
"JS_AtomizeAndPinString",
"js::AssertSameCompartment",
"JS::BuildStackString",
"JS::Call",
"JS_CallFunctionName",
"JS_CallFunctionValue",
"JS::CallOriginalPromiseThen",
"JS::CallOriginalPromiseResolve",
"JS::CallOriginalPromiseReject",
"JS::CompileFunctionUtf8",
"JS::Construct",
"JS::ContextOptionsRef",
"JS_CopyPropertiesFrom",
"JS::CurrentGlobalOrNull",
"JS_DeletePropertyById",
"js::detail::IsWindowSlow",
"JS::Evaluate",
"JS_ForwardGetPropertyTo",
"JS_ForwardSetPropertyTo",
"JS::GCTraceKindToAscii",
"JS::GetArrayBufferLengthAndData",
"js::GetArrayBufferViewLengthAndData",
"js::GetFunctionNativeReserved",
"JS::GetNonCCWObjectGlobal",
"js::GetObjectProto",
"JS_GetObjectRuntime",
"JS_GetOwnPropertyDescriptorById",
"JS::GetPromiseResult",
"JS::GetPromiseState",
"JS_GetPropertyDescriptorById",
"js::GetPropertyKeys",
"JS_GetPrototype",
"JS_GetRuntime",
"js::GetStaticPrototype",
"JS_HasOwnPropertyById",
"JS_HasProperty",
"JS_HasPropertyById",
"JS::HeapBigIntWriteBarriers",
"JS::HeapObjectWriteBarriers",
"JS::HeapScriptWriteBarriers",
"JS::HeapStringWriteBarriers",
"JS::HeapValueWriteBarriers",
"JS_InitializePropertiesFromCompatibleNativeObject",
"JS::InitSelfHostedCode",
"JS::IsConstructor",
"JS::IsPromiseObject",
"JS_ClearPendingException",
"JS_DefineElement",
"JS_DefineFunction",
"JS_DefineFunctions",
"JS_DefineProperties",
"JS_DefineProperty",
"JS_DefinePropertyById",
"JS_DefineUCProperty",
"JS::detail::InitWithFailureDiagnostic",
"JS_DestroyContext",
"JS::DisableIncrementalGC",
"js::Dump.*",
"JS::EnterRealm",
"JS_EnumerateStandardClasses",
"JS_ErrorFromException",
"JS_FireOnNewGlobalObject",
"JS_free",
"JS_GC",
"JS::GetArrayBufferData",
"JS_GetArrayBufferViewType",
"JS_GetFloat32ArrayData",
"JS_GetFloat64ArrayData",
"JS_GetFunctionObject",
"JS_GetGCParameter",
"JS_GetInt16ArrayData",
"JS_GetInt32ArrayData",
"JS_GetInt8ArrayData",
"JS_GetLatin1StringCharsAndLength",
"JS_GetParentRuntime",
"JS_GetPendingException",
"JS_GetProperty",
"JS_GetPropertyById",
"js::GetPropertyKeys",
"JS_GetPrototype",
"JS_GetReservedSlot",
"JS::GetRealmErrorPrototype",
"JS::GetRealmFunctionPrototype",
"JS::GetRealmIteratorPrototype",
"JS::GetRealmObjectPrototype",
"JS::GetScriptedCallerGlobal",
"JS_GetTwoByteStringCharsAndLength",
"JS_GetUint16ArrayData",
"JS_GetUint32ArrayData",
"JS_GetUint8ArrayData",
"JS_GetUint8ClampedArrayData",
"JS::GetWellKnownSymbol",
"JS_GlobalObjectTraceHook",
"JS::HideScriptedCaller",
"JS::InitRealmStandardClasses",
"JS::IsArrayObject",
"JS_IsExceptionPending",
"JS_IsGlobalObject",
"JS::IsCallable",
"JS::LeaveRealm",
"JS_LinkConstructorAndPrototype",
"JS_MayResolveStandardClass",
"JS::NewArrayBuffer",
"JS::NewArrayObject",
"JS_NewContext",
"JS_NewFloat32Array",
"JS_NewFloat64Array",
"JS_NewFunction",
"js::NewFunctionWithReserved",
"JS_NewGlobalObject",
"JS_NewInt16Array",
"JS_NewInt32Array",
"JS_NewInt8Array",
"JS_NewObject",
"JS_NewObjectWithGivenProto",
"JS_NewObjectWithoutMetadata",
"JS_NewObjectWithUniqueType",
"JS_NewPlainObject",
"JS::NewPromiseObject",
"JS_NewStringCopyN",
"JS_NewUCStringCopyN",
"JS_NewUint16Array",
"JS_NewUint32Array",
"JS_NewUint8Array",
"JS_NewUint8ClampedArray",
"js::ObjectClassName",
"JS::ObjectIsDate",
"JS_ParseJSON",
"JS_ReadBytes",
"JS_ReadStructuredClone",
"JS_ReadUint32Pair",
"JS_RemoveExtraGCRootsTracer",
"js::RemoveRawValueRoot",
"JS_ReportErrorASCII",
"JS_ReportErrorNumberUTF8",
"JS_RequestInterruptCallback",
"JS_ResolveStandardClass",
"js::RunJobs",
"JS::SameValue",
"js::SetDOMCallbacks",
"js::SetDOMProxyInformation",
"JS::SetEnqueuePromiseJobCallback",
"js::SetFunctionNativeReserved",
"JS_SetGCCallback",
"JS::SetGCSliceCallback",
"JS_SetGCParameter",
"JS_SetGCZeal",
"JS::SetGetIncumbentGlobalCallback",
"JS_SetGlobalJitCompilerOption",
"JS_SetImmutablePrototype",
"JS_SetNativeStackQuota",
"JS_SetOffthreadIonCompilationEnabled",
"JS_SetParallelParsingEnabled",
"JS_SetPendingException",
"js::SetPreserveWrapperCallback",
"JS::SetPromiseRejectionTrackerCallback",
"JS_SetPrototype",
"js::SetWindowProxy",
"js::SetWindowProxyClass",
"JS_SetProperty",
"JS_SetReservedSlot",
"JS_SetWrapObjectCallbacks",
"JS_ShutDown",
"JS_SplicePrototype",
"js::StopDrainingJobQueue",
"JS_StrictPropertyStub",
"JS_StringEqualsAscii",
"JS_StringHasLatin1Chars",
"JS_WrapObject",
"JS_WrapValue",
"JS_WriteBytes",
"JS_WriteStructuredClone",
"JS_WriteUint32Pair",
"JS::ResolvePromise",
"JS::RejectPromise",
"JS::SetWarningReporter",
"js::ToBooleanSlow",
"js::ToInt32Slow",
"js::ToInt64Slow",
"js::ToNumberSlow",
"js::ToStringSlow",
"js::ToUint16Slow",
"js::ToUint32Slow",
"js::ToUint64Slow",
"JS_TransplantObject",
"js::detail::ToWindowProxyIfWindowSlow",
"JS::UnhideScriptedCaller",
"JS::UnwrapArrayBuffer",
"js::UnwrapArrayBufferView",
"js::UnwrapFloat32Array",
"js::UnwrapFloat64Array",
"js::UnwrapInt16Array",
"js::UnwrapInt32Array",
"js::UnwrapInt8Array",
"js::UnwrapUint16Array",
"js::UnwrapUint32Array",
"js::UnwrapUint8Array",
"js::UnwrapUint8ClampedArray",
"js::UseInternalJobQueues",
"JS_ValueToFunction",
];
/// Types that should be treated as an opaque blob of bytes whenever they show
/// up within a whitelisted type.
///
/// These are types which are too tricky for bindgen to handle, and/or use C++
/// features that don't have an equivalent in rust, such as partial template
/// specialization.
const OPAQUE_TYPES: &'static [&'static str] = &[
"JS::ReadOnlyCompileOptions",
"mozilla::BufferList",
"mozilla::UniquePtr.*",
"JS::PersistentRooted",
"JS::StackGCVector",
];
/// Types for which we should NEVER generate bindings, even if it is used within
/// a type or function signature that we are generating bindings for.
const BLACKLIST_TYPES: &'static [&'static str] = &[
// We provide our own definition because we need to express trait bounds in
// the definition of the struct to make our Drop implementation correct.
"JS::Heap",
];