├── .gitignore ├── README.md ├── configure ├── .travis.yml ├── Cargo.toml ├── makefile.cargo ├── Makefile.in ├── gen.py ├── examples └── callback.rs ├── src ├── trace.rs ├── lib.rs ├── glue.rs ├── jsval.rs ├── rust.rs └── jsglue.cpp └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | libmozjs.so 2 | *~ 3 | js 4 | /doc 5 | /target 6 | /Cargo.lock 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-mozjs 2 | 3 | Rust bindings to SpiderMonkey 4 | 5 | [Documentation](http://doc.servo.org/js/) 6 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SRCDIR="$(cd $(dirname $0) && pwd)" 4 | sed "s#%VPATH%#${SRCDIR}#" ${SRCDIR}/Makefile.in > Makefile 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: 9000 3 | rust: 4 | - nightly 5 | 6 | script: 7 | - cargo build --verbose 8 | - cargo test --verbose 9 | branches: 10 | except: 11 | - master 12 | notifications: 13 | webhooks: http://build.servo.org:54856/travis 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "js" 4 | version = "0.1.0" 5 | authors = ["The Servo Project Developers"] 6 | 7 | build = "build.rs" 8 | 9 | [features] 10 | debugmozjs = ['mozjs_sys/debugmozjs'] 11 | 12 | [dependencies.mozjs_sys] 13 | git = "https://github.com/servo/mozjs" 14 | 15 | [dependencies] 16 | libc = "*" 17 | rustc-serialize = "*" 18 | log = "*" 19 | heapsize = "0.1.1" 20 | -------------------------------------------------------------------------------- /makefile.cargo: -------------------------------------------------------------------------------- 1 | ifneq ($(HOST),$(TARGET)) 2 | 3 | CXX ?= $(TARGET)-g++ 4 | AR ?= $(TARGET)-ar 5 | 6 | else 7 | 8 | CXX ?= g++ 9 | AR ?= ar 10 | 11 | endif 12 | 13 | CFLAGS += -fPIC -std=c++11 -DJS_NO_JSVAL_JSID_STRUCT_TYPES 14 | 15 | ifeq ($(shell $(CXX) -v 2>&1 | grep -c 'clang version\|Apple.*clang'),1) 16 | CFLAGS += -Wno-c++0x-extensions -Wno-return-type-c-linkage -Wno-invalid-offsetof 17 | endif 18 | 19 | ifneq (,$(CARGO_FEATURE_DEBUGMOZJS)) 20 | CFLAGS += -g -O0 -DDEBUG -D_DEBUG 21 | endif 22 | 23 | CFLAGS += -I$(DEP_MOZJS_OUTDIR)/dist/include 24 | 25 | .PHONY: all 26 | all: $(OUT_DIR)/libjsglue.a 27 | 28 | $(OUT_DIR)/libjsglue.a: $(OUT_DIR)/jsglue.o 29 | $(AR) rcs $@ $^ 30 | 31 | $(OUT_DIR)/jsglue.o: src/jsglue.cpp 32 | $(CXX) $(CFLAGS) -fno-rtti $< -o $@ -c 33 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | VPATH=%VPATH% 2 | 3 | CXX ?= g++ 4 | RUSTC ?= rustc 5 | AR ?= ar 6 | RUSTFLAGS ?= 7 | EXT_DEPS ?= 8 | CFLAGS += -fPIC 9 | RUSTDOC ?= rustdoc 10 | RUSTDOC_FLAGS ?= 11 | RUSTDOC_TARGET ?= doc 12 | 13 | ifeq ($(shell $(CXX) -v 2>&1 | grep -c 'clang version\|Apple.*clang'),1) 14 | CFLAGS += -Wno-c++0x-extensions -Wno-return-type-c-linkage -Wno-invalid-offsetof 15 | endif 16 | 17 | RUST_SRC = $(shell find $(VPATH)/src -type f -name '*.rs') 18 | 19 | .PHONY: all 20 | all: libjs.dummy 21 | 22 | libjs.dummy: src/lib.rs $(RUST_SRC) libjsglue.a $(EXT_DEPS) 23 | $(RUSTC) $(RUSTFLAGS) $< --out-dir . 24 | touch $@ 25 | 26 | js-test: src/lib.rs $(RUST_SRC) libjsglue.a 27 | $(RUSTC) $(RUSTFLAGS) $< -o $@ --test 28 | 29 | libjsglue.a: jsglue.o 30 | $(AR) rcs libjsglue.a jsglue.o 31 | 32 | jsglue.o: src/jsglue.cpp 33 | $(CXX) $(CFLAGS) -fno-rtti $< -o $@ -c 34 | 35 | .PHONY: doc 36 | doc: $(RUSTDOC_TARGET)/js/index.html 37 | 38 | $(RUSTDOC_TARGET)/js/index.html: src/lib.rs $(RUST_SRC) libjsglue.a $(EXT_DEPS) 39 | $(RUSTDOC) $(RUSTDOC_FLAGS) $< -o $(RUSTDOC_TARGET) 40 | 41 | check: js-test 42 | ./js-test 43 | 44 | .PHONY: clean 45 | clean: 46 | rm -f js-test *.o *.a *.so *.dylib *.rlib *.dll *.dummy 47 | -------------------------------------------------------------------------------- /gen.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | # You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | import argparse, subprocess; 6 | 7 | bindgen = "bindgen"; 8 | 9 | jsapi = "../mozjs/js/src/jsapi.h" 10 | includes = [ 11 | "-I", "../mozjs/js/src/dist/include", 12 | ] 13 | sysincludes = [ 14 | "-isystem", "/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5/include", 15 | "-isystem", "/usr/lib/gcc/x86_64-redhat-linux/4.7.0/include", 16 | ] 17 | 18 | args = [ 19 | bindgen, 20 | "-l", "mozjs", 21 | "-o", "jsapi.rs", 22 | "-match" ,"js", 23 | jsapi] 24 | args += includes + sysincludes 25 | 26 | subprocess.call(args) 27 | 28 | # To generate jsglue: 29 | # DYLD_LIBRARY_PATH=~/versioned/rust-mozilla/build/llvm/x86_64-apple-darwin/Release+Asserts/lib/ ~/versioned/rust-bindgen/bindgen ./jsglue.c -I ../../build/src/mozjs/dist/include/ -match glue > glue.rs 30 | 31 | # jdm used 32 | # LD_LIBRARY_PATH=~/sdb/rust/build/llvm/x86_64-unknown-linux-gnu/Release+Asserts/lib/ ~/sdb/rust-bindgen/bindgen ./jsglue.c -I ../../build/src/mozjs/dist/include/ -isystem /usr/lib/gcc/x86_64-redhat-linux/4.7.0/include/ -match glue >glue.rs 33 | # on Fedora 17 34 | # 35 | # and remember to mark all generated functions as #[rust_stack] 36 | -------------------------------------------------------------------------------- /examples/callback.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | extern crate js; 6 | extern crate libc; 7 | 8 | use std::ffi::CStr; 9 | use std::ptr; 10 | use std::str; 11 | 12 | use js::{JSCLASS_RESERVED_SLOTS_MASK,JSCLASS_RESERVED_SLOTS_SHIFT,JSCLASS_GLOBAL_SLOT_COUNT,JSCLASS_IS_GLOBAL}; 13 | use js::jsapi::JS_GlobalObjectTraceHook; 14 | use js::jsapi::{CallArgs,CompartmentOptions,OnNewGlobalHookOption,Rooted,Value}; 15 | use js::jsapi::{JS_DefineFunction,JS_Init,JS_NewGlobalObject,JS_EncodeStringToUTF8,JS_ReportError}; 16 | use js::jsapi::{JSAutoCompartment,JSAutoRequest,JSContext,JSClass}; 17 | use js::jsval::UndefinedValue; 18 | use js::rust::Runtime; 19 | 20 | static CLASS: &'static JSClass = &JSClass { 21 | name: b"test\0" as *const u8 as *const libc::c_char, 22 | flags: JSCLASS_IS_GLOBAL | ((JSCLASS_GLOBAL_SLOT_COUNT & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), 23 | addProperty: None, 24 | delProperty: None, 25 | getProperty: None, 26 | setProperty: None, 27 | enumerate: None, 28 | resolve: None, 29 | convert: None, 30 | finalize: None, 31 | call: None, 32 | hasInstance: None, 33 | construct: None, 34 | trace: Some(JS_GlobalObjectTraceHook), 35 | reserved: [0 as *mut _; 25] 36 | }; 37 | 38 | fn main() { 39 | unsafe { 40 | JS_Init(); 41 | } 42 | let runtime = Runtime::new(); 43 | let context = runtime.cx(); 44 | 45 | unsafe { 46 | let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook; 47 | let c_option = CompartmentOptions::default(); 48 | let _ar = JSAutoRequest::new(context); 49 | let global = JS_NewGlobalObject(context, CLASS, ptr::null_mut(), h_option, &c_option); 50 | let global_root = Rooted::new(context, global); 51 | let global = global_root.handle(); 52 | let _ac = JSAutoCompartment::new(context, global.get()); 53 | let function = JS_DefineFunction(context, global, b"puts\0".as_ptr() as *const libc::c_char, 54 | Some(puts), 1, 0); 55 | assert!(!function.is_null()); 56 | let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');".to_string(); 57 | let _ = runtime.evaluate_script(global, javascript, "test.js".to_string(), 0); 58 | } 59 | } 60 | 61 | unsafe extern "C" fn puts(context: *mut JSContext, argc: u32, vp: *mut Value) -> bool { 62 | let args = CallArgs::from_vp(vp, argc); 63 | 64 | if args._base.argc_ != 1 { 65 | JS_ReportError(context, b"puts() requires exactly 1 argument\0".as_ptr() as *const libc::c_char); 66 | return false; 67 | } 68 | 69 | let arg = args.get(0); 70 | let js = js::rust::ToString(context, arg); 71 | let message_root = Rooted::new(context, js); 72 | let message = JS_EncodeStringToUTF8(context, message_root.handle()); 73 | let message = CStr::from_ptr(message); 74 | println!("{}", str::from_utf8(message.to_bytes()).unwrap()); 75 | 76 | args.rval().set(UndefinedValue()); 77 | return true; 78 | } 79 | -------------------------------------------------------------------------------- /src/trace.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use jsapi::JSTracer; 6 | 7 | use serialize::Encoder; 8 | 9 | impl Encoder<()> for JSTracer { 10 | fn emit_nil(&mut self) -> Result<(), ()> { Ok(()) } 11 | fn emit_uint(&mut self, _v: uint) -> Result<(), ()> { Ok(()) } 12 | fn emit_u64(&mut self, _v: u64) -> Result<(), ()> { Ok(()) } 13 | fn emit_u32(&mut self, __v: u32) -> Result<(), ()> { Ok(()) } 14 | fn emit_u16(&mut self, _v: u16) -> Result<(), ()> { Ok(()) } 15 | fn emit_u8(&mut self, _v: u8) -> Result<(), ()> { Ok(()) } 16 | fn emit_int(&mut self, _v: int) -> Result<(), ()> { Ok(()) } 17 | fn emit_i64(&mut self, _v: i64) -> Result<(), ()> { Ok(()) } 18 | fn emit_i32(&mut self, _v: i32) -> Result<(), ()> { Ok(()) } 19 | fn emit_i16(&mut self, _v: i16) -> Result<(), ()> { Ok(()) } 20 | fn emit_i8(&mut self, _v: i8) -> Result<(), ()> { Ok(()) } 21 | fn emit_bool(&mut self, _v: bool) -> Result<(), ()> { Ok(()) } 22 | fn emit_f64(&mut self, _v: f64) -> Result<(), ()> { Ok(()) } 23 | fn emit_f32(&mut self, _v: f32) -> Result<(), ()> { Ok(()) } 24 | fn emit_char(&mut self, _v: char) -> Result<(), ()> { Ok(()) } 25 | fn emit_str(&mut self, _v: &str) -> Result<(), ()> { Ok(()) } 26 | fn emit_enum(&mut self, _name: &str, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 27 | f(self) 28 | } 29 | fn emit_enum_variant(&mut self, _v_name: &str, _v_id: uint, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 30 | f(self) 31 | } 32 | fn emit_enum_variant_arg(&mut self, _a_idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 33 | f(self) 34 | } 35 | fn emit_enum_struct_variant(&mut self, _v_name: &str, _v_id: uint, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 36 | f(self) 37 | } 38 | fn emit_enum_struct_variant_field(&mut self, _f_name: &str, _f_idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 39 | f(self) 40 | } 41 | fn emit_struct(&mut self, _name: &str, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 42 | f(self) 43 | } 44 | fn emit_struct_field(&mut self, _f_name: &str, _f_idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 45 | f(self) 46 | } 47 | fn emit_tuple(&mut self, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 48 | f(self) 49 | } 50 | fn emit_tuple_arg(&mut self, _idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 51 | f(self) 52 | } 53 | fn emit_tuple_struct(&mut self, _name: &str, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 54 | f(self) 55 | } 56 | fn emit_tuple_struct_arg(&mut self, _f_idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 57 | f(self) 58 | } 59 | fn emit_option(&mut self, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 60 | f(self) 61 | } 62 | fn emit_option_none(&mut self) -> Result<(), ()> { Ok(()) } 63 | fn emit_option_some(&mut self, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 64 | f(self) 65 | } 66 | fn emit_seq(&mut self, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 67 | f(self) 68 | } 69 | fn emit_seq_elt(&mut self, _idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 70 | f(self) 71 | } 72 | fn emit_map(&mut self, _len: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 73 | f(self) 74 | } 75 | fn emit_map_elt_key(&mut self, _idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 76 | f(self) 77 | } 78 | fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut JSTracer| -> Result<(), ()>) -> Result<(), ()> { 79 | f(self) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #![crate_name = "js"] 6 | #![crate_type = "rlib"] 7 | 8 | #![feature(core_intrinsics)] 9 | #![feature(link_args)] 10 | #![feature(str_utf16)] 11 | #![feature(unsafe_no_drop_flag)] 12 | #![feature(const_fn)] 13 | 14 | #![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)] 15 | 16 | extern crate libc; 17 | #[macro_use] 18 | extern crate log; 19 | #[macro_use] 20 | extern crate heapsize; 21 | extern crate rustc_serialize as serialize; 22 | extern crate mozjs_sys; 23 | 24 | #[cfg(target_os = "linux")] 25 | #[cfg(target_pointer_width = "64")] 26 | mod jsapi_linux_64; 27 | 28 | #[cfg(target_os = "macos")] 29 | #[cfg(target_pointer_width = "64")] 30 | mod jsapi_macos_64; 31 | 32 | #[cfg(target_os = "windows")] 33 | #[cfg(target_pointer_width = "64")] 34 | mod jsapi_windows_gcc_64; 35 | 36 | #[cfg(not(target_os = "windows"))] 37 | #[cfg(target_pointer_width = "32")] 38 | mod jsapi_linux_32; 39 | 40 | pub mod jsapi { 41 | #[cfg(target_os = "linux")] 42 | #[cfg(target_pointer_width = "64")] 43 | pub use jsapi_linux_64::*; 44 | 45 | #[cfg(target_os = "macos")] 46 | #[cfg(target_pointer_width = "64")] 47 | pub use jsapi_macos_64::*; 48 | 49 | #[cfg(target_os = "windows")] 50 | #[cfg(target_pointer_width = "64")] 51 | pub use jsapi_windows_gcc_64::*; 52 | 53 | #[cfg(not(target_os = "windows"))] 54 | #[cfg(target_pointer_width = "32")] 55 | pub use jsapi_linux_32::*; 56 | } 57 | 58 | pub mod rust; 59 | pub mod glue; 60 | pub mod jsval; 61 | 62 | use jsapi::{JSContext, JSProtoKey, Heap}; 63 | use jsval::JSVal; 64 | use rust::GCMethods; 65 | 66 | use libc::c_uint; 67 | 68 | use heapsize::HeapSizeOf; 69 | 70 | pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32; 71 | pub const default_stacksize: usize = 8192; 72 | 73 | pub const JSID_TYPE_STRING: i64 = 0; 74 | pub const JSID_TYPE_INT: i64 = 1; 75 | pub const JSID_TYPE_VOID: i64 = 2; 76 | pub const JSID_TYPE_OBJECT: i64 = 4; 77 | pub const JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6; 78 | pub const JSID_TYPE_MASK: i64 = 7; 79 | 80 | pub const JSFUN_CONSTRUCTOR: u32 = 0x400; /* native that can be called as a ctor */ 81 | 82 | pub const JSPROP_ENUMERATE: c_uint = 0x01; 83 | pub const JSPROP_READONLY: c_uint = 0x02; 84 | pub const JSPROP_PERMANENT: c_uint = 0x04; 85 | pub const JSPROP_GETTER: c_uint = 0x10; 86 | pub const JSPROP_SETTER: c_uint = 0x20; 87 | pub const JSPROP_SHARED: c_uint = 0x40; 88 | pub const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08; 89 | 90 | pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8; 91 | pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8; 92 | pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint; 93 | 94 | pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint = 95 | JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH; 96 | pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1); 97 | pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4; 98 | pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31; 99 | 100 | pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4; 101 | pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5; 102 | pub const JSCLASS_USERBIT1: u32 = 1 << 7; 103 | 104 | pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4); 105 | 106 | pub const JSSLOT_PROXY_PRIVATE: u32 = 1; 107 | 108 | pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100; 109 | 110 | pub const JSITER_ENUMERATE: c_uint = 0x1; 111 | pub const JSITER_FOREACH: c_uint = 0x2; 112 | pub const JSITER_KEYVALUE: c_uint = 0x4; 113 | pub const JSITER_OWNONLY: c_uint = 0x8; 114 | pub const JSITER_HIDDEN: c_uint = 0x10; 115 | pub const JSITER_SYMBOLS: c_uint = 0x20; 116 | pub const JSITER_SYMBOLSONLY: c_uint = 0x40; 117 | 118 | #[link(name = "jsglue")] 119 | extern { } 120 | 121 | #[cfg(target_os = "android")] 122 | #[link(name = "stdc++")] 123 | extern { } 124 | 125 | #[cfg(target_os = "android")] 126 | #[link(name = "gcc")] 127 | extern { } 128 | 129 | #[inline(always)] 130 | pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal { 131 | vp.offset(2) 132 | } 133 | 134 | #[inline(always)] 135 | pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal { 136 | *vp 137 | } 138 | 139 | // This is measured properly by the heap measurement implemented in SpiderMonkey. 140 | impl> HeapSizeOf for Heap { 141 | fn heap_size_of_children(&self) -> usize { 142 | 0 143 | } 144 | } 145 | known_heap_size!(0, JSVal); 146 | 147 | -------------------------------------------------------------------------------- /src/glue.rs: -------------------------------------------------------------------------------- 1 | use jsapi::*; 2 | 3 | pub const JS_STRUCTURED_CLONE_VERSION: u32 = 5; 4 | 5 | pub enum Action { } 6 | unsafe impl Sync for ProxyTraps { } 7 | /* automatically generated by rust-bindgen */ 8 | 9 | #[repr(C)] 10 | #[derive(Copy, Clone)] 11 | pub struct ProxyTraps { 12 | pub enter: ::std::option::Option bool>, 16 | pub getOwnPropertyDescriptor: ::std::option::Option) 24 | -> bool>, 25 | pub defineProperty: ::std::option::Option, 31 | result: 32 | *mut ObjectOpResult) 33 | -> bool>, 34 | pub ownPropertyKeys: ::std::option::Option bool>, 39 | pub delete_: ::std::option::Option bool>, 44 | pub enumerate: ::std::option::Option bool>, 49 | pub preventExtensions: ::std::option::Option bool>, 55 | pub isExtensible: ::std::option::Option bool>, 59 | pub has: ::std::option::Option bool>, 63 | pub get: ::std::option::Option bool>, 68 | pub set: ::std::option::Option bool>, 74 | pub call: ::std::option::Option bool>, 78 | pub construct: ::std::option::Option bool>, 82 | pub getPropertyDescriptor: ::std::option::Option) 88 | -> bool>, 89 | pub hasOwn: ::std::option::Option bool>, 93 | pub getOwnEnumerablePropertyKeys: ::std::option::Option bool>, 101 | pub nativeCall: ::std::option::Option bool>, 106 | pub hasInstance: ::std::option::Option bool>, 111 | pub objectClassIs: ::std::option::Option bool>, 115 | pub className: ::std::option::Option *const i8>, 119 | pub fun_toString: ::std::option::Option *mut JSString>, 124 | pub boxedValue_unbox: ::std::option::Option bool>, 129 | pub defaultValue: ::std::option::Option bool>, 135 | pub trace: ::std::option::Option, 138 | pub finalize: ::std::option::Option, 141 | pub objectMoved: ::std::option::Option, 144 | pub isCallable: ::std::option::Option bool>, 146 | pub isConstructor: ::std::option::Option bool>, 148 | } 149 | impl ::std::default::Default for ProxyTraps { 150 | fn default() -> ProxyTraps { unsafe { ::std::mem::zeroed() } } 151 | } 152 | #[repr(C)] 153 | #[derive(Copy, Clone)] 154 | pub struct WrapperProxyHandler { 155 | pub mTraps: ProxyTraps, 156 | } 157 | impl ::std::default::Default for WrapperProxyHandler { 158 | fn default() -> WrapperProxyHandler { unsafe { ::std::mem::zeroed() } } 159 | } 160 | #[repr(C)] 161 | #[derive(Copy, Clone)] 162 | pub struct ForwardingProxyHandler { 163 | pub mTraps: ProxyTraps, 164 | pub mExtra: *const ::libc::c_void, 165 | } 166 | impl ::std::default::Default for ForwardingProxyHandler { 167 | fn default() -> ForwardingProxyHandler { unsafe { ::std::mem::zeroed() } } 168 | } 169 | extern "C" { 170 | pub fn InvokeGetOwnPropertyDescriptor(handler: *const ::libc::c_void, 171 | cx: *mut JSContext, 172 | proxy: HandleObject, id: HandleId, 173 | desc: 174 | MutableHandle) 175 | -> bool; 176 | pub fn RUST_JS_NumberValue(d: f64) -> Value; 177 | pub fn RUST_FUNCTION_VALUE_TO_JITINFO(v: Value) -> *const JSJitInfo; 178 | pub fn CallJitGetterOp(info: *const JSJitInfo, cx: *mut JSContext, 179 | thisObj: HandleObject, 180 | specializedThis: *mut ::libc::c_void, argc: u32, 181 | vp: *mut Value) -> bool; 182 | pub fn CallJitSetterOp(info: *const JSJitInfo, cx: *mut JSContext, 183 | thisObj: HandleObject, 184 | specializedThis: *mut ::libc::c_void, argc: u32, 185 | vp: *mut Value) -> bool; 186 | pub fn CallJitMethodOp(info: *const JSJitInfo, cx: *mut JSContext, 187 | thisObj: HandleObject, 188 | specializedThis: *mut ::libc::c_void, argc: u32, 189 | vp: *mut Value) -> bool; 190 | pub fn CreateProxyHandler(aTraps: *const ProxyTraps, 191 | aExtra: *const ::libc::c_void) 192 | -> *const ::libc::c_void; 193 | pub fn CreateWrapperProxyHandler(aTraps: *const ProxyTraps) 194 | -> *const ::libc::c_void; 195 | pub fn GetCrossCompartmentWrapper() -> *const ::libc::c_void; 196 | pub fn NewCompileOptions(aCx: *mut JSContext, aFile: *const ::libc::c_char, 197 | aLine: u32) -> *mut ReadOnlyCompileOptions; 198 | pub fn DeleteCompileOptions(aOpts: *mut ReadOnlyCompileOptions); 199 | pub fn NewProxyObject(aCx: *mut JSContext, 200 | aHandler: *const ::libc::c_void, aPriv: HandleValue, 201 | proto: *mut JSObject, parent: *mut JSObject, 202 | call: *mut JSObject, construct: *mut JSObject) 203 | -> *mut JSObject; 204 | pub fn WrapperNew(aCx: *mut JSContext, aObj: HandleObject, 205 | aHandler: *const ::libc::c_void, aClass: *const JSClass, 206 | aSingleton: bool) 207 | -> *mut JSObject; 208 | pub fn GetProxyExtra(obj: *mut JSObject, slot: u32) -> Value; 209 | pub fn GetProxyPrivate(obj: *mut JSObject) -> Value; 210 | pub fn SetProxyExtra(obj: *mut JSObject, slot: u32, val: Value); 211 | pub fn RUST_JSID_IS_INT(id: HandleId) -> bool; 212 | pub fn RUST_JSID_TO_INT(id: HandleId) -> i32; 213 | pub fn int_to_jsid(i: i32) -> jsid; 214 | pub fn RUST_JSID_IS_STRING(id: HandleId) -> bool; 215 | pub fn RUST_JSID_TO_STRING(id: HandleId) -> *mut JSString; 216 | pub fn RUST_SET_JITINFO(func: *mut JSFunction, info: *const JSJitInfo); 217 | pub fn RUST_INTERNED_STRING_TO_JSID(cx: *mut JSContext, 218 | str: *mut JSString) -> jsid; 219 | pub fn RUST_js_GetErrorMessage(userRef: *mut ::libc::c_void, 220 | errorNumber: u32) 221 | -> *const JSErrorFormatString; 222 | pub fn IsProxyHandlerFamily(obj: *mut JSObject) -> u8; 223 | pub fn GetProxyHandlerExtra(obj: *mut JSObject) -> *const ::libc::c_void; 224 | pub fn GetProxyHandler(obj: *mut JSObject) -> *const ::libc::c_void; 225 | pub fn ReportError(aCx: *mut JSContext, aError: *const i8); 226 | pub fn IsWrapper(obj: *mut JSObject) -> bool; 227 | pub fn UnwrapObject(obj: *mut JSObject, stopAtOuter: u8) -> *mut JSObject; 228 | pub fn AppendToAutoIdVector(v: *mut AutoIdVector, id: jsid) -> bool; 229 | pub fn CreateAutoObjectVector(aCx: *mut JSContext) 230 | -> *mut AutoObjectVector; 231 | pub fn AppendToAutoObjectVector(v: *mut AutoObjectVector, 232 | obj: *mut JSObject) -> bool; 233 | pub fn DeleteAutoObjectVector(v: *mut AutoObjectVector); 234 | pub fn CollectServoSizes(rt: *mut JSRuntime, sizes: *mut ServoSizes) -> bool; 235 | } 236 | -------------------------------------------------------------------------------- /src/jsval.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | use jsapi::{JSObject, JSString, JSGCTraceKind}; 6 | use jsapi::JSGCTraceKind::{JSTRACE_OBJECT, JSTRACE_STRING}; 7 | use jsapi::Value; 8 | use jsapi::jsval_layout; 9 | use jsapi::JSValueType; 10 | 11 | use libc::c_void; 12 | use std::mem; 13 | 14 | pub type JSVal = Value; 15 | 16 | #[cfg(target_pointer_width = "64")] 17 | const JSVAL_TAG_SHIFT: usize = 47; 18 | 19 | #[cfg(target_pointer_width = "64")] 20 | const JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0u32; 21 | 22 | #[cfg(target_pointer_width = "32")] 23 | const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80; 24 | 25 | #[cfg(target_pointer_width = "64")] 26 | #[repr(u32)] 27 | #[allow(dead_code)] 28 | enum ValueTag { 29 | INT32 = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_INT32 as u32), 30 | UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), 31 | STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32), 32 | SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32), 33 | BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), 34 | MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32), 35 | NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32), 36 | OBJECT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_OBJECT as u32), 37 | } 38 | 39 | #[cfg(target_pointer_width = "32")] 40 | #[repr(u32)] 41 | #[allow(dead_code)] 42 | enum ValueTag { 43 | PRIVATE = 0, 44 | INT32 = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_INT32 as u32), 45 | UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), 46 | STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32), 47 | SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32), 48 | BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), 49 | MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32), 50 | NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32), 51 | OBJECT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_OBJECT as u32), 52 | } 53 | 54 | #[cfg(target_pointer_width = "64")] 55 | #[repr(u64)] 56 | #[allow(dead_code)] 57 | enum ValueShiftedTag { 58 | MAX_DOUBLE = (((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64), 59 | INT32 = ((ValueTag::INT32 as u64) << JSVAL_TAG_SHIFT), 60 | UNDEFINED = ((ValueTag::UNDEFINED as u64) << JSVAL_TAG_SHIFT), 61 | STRING = ((ValueTag::STRING as u64) << JSVAL_TAG_SHIFT), 62 | SYMBOL = ((ValueTag::SYMBOL as u64) << JSVAL_TAG_SHIFT), 63 | BOOLEAN = ((ValueTag::BOOLEAN as u64) << JSVAL_TAG_SHIFT), 64 | MAGIC = ((ValueTag::MAGIC as u64) << JSVAL_TAG_SHIFT), 65 | NULL = ((ValueTag::NULL as u64) << JSVAL_TAG_SHIFT), 66 | OBJECT = ((ValueTag::OBJECT as u64) << JSVAL_TAG_SHIFT), 67 | } 68 | 69 | 70 | #[cfg(target_pointer_width = "64")] 71 | const JSVAL_PAYLOAD_MASK: u64 = 0x00007FFFFFFFFFFF; 72 | 73 | fn AsJSVal(val: u64) -> JSVal { 74 | JSVal { 75 | data: jsval_layout { 76 | _bindgen_data_: val 77 | } 78 | } 79 | } 80 | 81 | #[cfg(target_pointer_width = "64")] 82 | #[inline(always)] 83 | fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal { 84 | AsJSVal(((tag as u32 as u64) << JSVAL_TAG_SHIFT) | payload) 85 | } 86 | 87 | #[cfg(target_pointer_width = "32")] 88 | #[inline(always)] 89 | fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal { 90 | AsJSVal(((tag as u32 as u64) << 32) | payload) 91 | } 92 | 93 | #[inline(always)] 94 | pub fn NullValue() -> JSVal { 95 | BuildJSVal(ValueTag::NULL, 0) 96 | } 97 | 98 | #[inline(always)] 99 | pub fn UndefinedValue() -> JSVal { 100 | BuildJSVal(ValueTag::UNDEFINED, 0) 101 | } 102 | 103 | #[inline(always)] 104 | pub fn Int32Value(i: i32) -> JSVal { 105 | BuildJSVal(ValueTag::INT32, i as u32 as u64) 106 | } 107 | 108 | #[cfg(target_pointer_width = "64")] 109 | #[inline(always)] 110 | pub fn DoubleValue(f: f64) -> JSVal { 111 | let bits: u64 = unsafe { mem::transmute(f) }; 112 | assert!(bits <= ValueShiftedTag::MAX_DOUBLE as u64); 113 | AsJSVal(bits) 114 | } 115 | 116 | #[cfg(target_pointer_width = "32")] 117 | #[inline(always)] 118 | pub fn DoubleValue(f: f64) -> JSVal { 119 | let bits: u64 = unsafe { mem::transmute(f) }; 120 | let val = AsJSVal(bits); 121 | assert!(val.is_double()); 122 | val 123 | } 124 | 125 | #[inline(always)] 126 | pub fn UInt32Value(ui: u32) -> JSVal { 127 | if ui > 0x7fffffff { 128 | DoubleValue(ui as f64) 129 | } else { 130 | Int32Value(ui as i32) 131 | } 132 | } 133 | 134 | #[cfg(target_pointer_width = "64")] 135 | #[inline(always)] 136 | pub fn StringValue(s: &JSString) -> JSVal { 137 | let bits = s as *const JSString as usize as u64; 138 | assert!((bits >> JSVAL_TAG_SHIFT) == 0); 139 | BuildJSVal(ValueTag::STRING, bits) 140 | } 141 | 142 | #[cfg(target_pointer_width = "32")] 143 | #[inline(always)] 144 | pub fn StringValue(s: &JSString) -> JSVal { 145 | let bits = s as *const JSString as usize as u64; 146 | BuildJSVal(ValueTag::STRING, bits) 147 | } 148 | 149 | #[inline(always)] 150 | pub fn BooleanValue(b: bool) -> JSVal { 151 | BuildJSVal(ValueTag::BOOLEAN, b as u64) 152 | } 153 | 154 | #[cfg(target_pointer_width = "64")] 155 | #[inline(always)] 156 | pub fn ObjectValue(o: &JSObject) -> JSVal { 157 | let bits = o as *const JSObject as usize as u64; 158 | assert!((bits >> JSVAL_TAG_SHIFT) == 0); 159 | BuildJSVal(ValueTag::OBJECT, bits) 160 | } 161 | 162 | #[cfg(target_pointer_width = "32")] 163 | #[inline(always)] 164 | pub fn ObjectValue(o: &JSObject) -> JSVal { 165 | let bits = o as *const JSObject as usize as u64; 166 | BuildJSVal(ValueTag::OBJECT, bits) 167 | } 168 | 169 | #[inline(always)] 170 | pub fn ObjectOrNullValue(o: *mut JSObject) -> JSVal { 171 | if o.is_null() { 172 | NullValue() 173 | } else { 174 | ObjectValue(unsafe { &*o }) 175 | } 176 | } 177 | 178 | #[cfg(target_pointer_width = "64")] 179 | #[inline(always)] 180 | pub fn PrivateValue(o: *const c_void) -> JSVal { 181 | let ptrBits = o as usize as u64; 182 | assert!((ptrBits & 1) == 0); 183 | AsJSVal(ptrBits >> 1) 184 | } 185 | 186 | #[cfg(target_pointer_width = "32")] 187 | #[inline(always)] 188 | pub fn PrivateValue(o: *const c_void) -> JSVal { 189 | let ptrBits = o as usize as u64; 190 | assert!((ptrBits & 1) == 0); 191 | BuildJSVal(ValueTag::PRIVATE, ptrBits) 192 | } 193 | 194 | impl JSVal { 195 | fn asBits(&self) -> u64 { 196 | self.data._bindgen_data_ 197 | } 198 | 199 | #[cfg(target_pointer_width = "64")] 200 | pub fn is_undefined(&self) -> bool { 201 | self.asBits() == ValueShiftedTag::UNDEFINED as u64 202 | } 203 | 204 | #[cfg(target_pointer_width = "32")] 205 | pub fn is_undefined(&self) -> bool { 206 | (self.asBits() >> 32) == ValueTag::UNDEFINED as u64 207 | } 208 | 209 | #[cfg(target_pointer_width = "64")] 210 | pub fn is_null(&self) -> bool { 211 | self.asBits() == ValueShiftedTag::NULL as u64 212 | } 213 | 214 | #[cfg(target_pointer_width = "32")] 215 | pub fn is_null(&self) -> bool { 216 | (self.asBits() >> 32) == ValueTag::NULL as u64 217 | } 218 | 219 | pub fn is_null_or_undefined(&self) -> bool { 220 | self.is_null() || self.is_undefined() 221 | } 222 | 223 | #[cfg(target_pointer_width = "64")] 224 | pub fn is_boolean(&self) -> bool { 225 | (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BOOLEAN as u64 226 | } 227 | 228 | #[cfg(target_pointer_width = "32")] 229 | pub fn is_boolean(&self) -> bool { 230 | (self.asBits() >> 32) == ValueTag::BOOLEAN as u64 231 | } 232 | 233 | #[cfg(target_pointer_width = "64")] 234 | pub fn is_int32(&self) -> bool { 235 | (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::INT32 as u64 236 | } 237 | 238 | #[cfg(target_pointer_width = "32")] 239 | pub fn is_int32(&self) -> bool { 240 | (self.asBits() >> 32) == ValueTag::INT32 as u64 241 | } 242 | 243 | #[cfg(target_pointer_width = "64")] 244 | pub fn is_double(&self) -> bool { 245 | self.asBits() <= ValueShiftedTag::MAX_DOUBLE as u64 246 | } 247 | 248 | #[cfg(target_pointer_width = "32")] 249 | pub fn is_double(&self) -> bool { 250 | (self.asBits() >> 32) <= JSVAL_TAG_CLEAR as u64 251 | } 252 | 253 | #[cfg(target_pointer_width = "64")] 254 | pub fn is_number(&self) -> bool { 255 | const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET: u64 = ValueShiftedTag::UNDEFINED as u64; 256 | self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET 257 | } 258 | 259 | #[cfg(target_pointer_width = "32")] 260 | pub fn is_number(&self) -> bool { 261 | const JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET: u64 = ValueTag::INT32 as u64; 262 | (self.asBits() >> 32) <= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET 263 | } 264 | 265 | #[cfg(target_pointer_width = "64")] 266 | pub fn is_primitive(&self) -> bool { 267 | const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = ValueShiftedTag::OBJECT as u64; 268 | self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET 269 | } 270 | 271 | #[cfg(target_pointer_width = "32")] 272 | pub fn is_primitive(&self) -> bool { 273 | const JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET: u64 = ValueTag::OBJECT as u64; 274 | (self.asBits() >> 32) < JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET 275 | } 276 | 277 | #[cfg(target_pointer_width = "64")] 278 | pub fn is_string(&self) -> bool { 279 | (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::STRING as u64 280 | } 281 | 282 | #[cfg(target_pointer_width = "32")] 283 | pub fn is_string(&self) -> bool { 284 | (self.asBits() >> 32) == ValueTag::STRING as u64 285 | } 286 | 287 | #[cfg(target_pointer_width = "64")] 288 | pub fn is_object(&self) -> bool { 289 | assert!((self.asBits() >> JSVAL_TAG_SHIFT) <= ValueTag::OBJECT as u64); 290 | self.asBits() >= ValueShiftedTag::OBJECT as u64 291 | } 292 | 293 | #[cfg(target_pointer_width = "32")] 294 | pub fn is_object(&self) -> bool { 295 | (self.asBits() >> 32) == ValueTag::OBJECT as u64 296 | } 297 | 298 | #[cfg(target_pointer_width = "64")] 299 | pub fn is_symbol(&self) -> bool { 300 | self.asBits() == ValueShiftedTag::SYMBOL as u64 301 | } 302 | 303 | #[cfg(target_pointer_width = "32")] 304 | pub fn is_symbol(&self) -> bool { 305 | (self.asBits() >> 32) == ValueTag::SYMBOL as u64 306 | } 307 | 308 | #[cfg(target_pointer_width = "64")] 309 | pub fn to_boolean(&self) -> bool { 310 | assert!(self.is_boolean()); 311 | (self.asBits() & JSVAL_PAYLOAD_MASK) != 0 312 | } 313 | 314 | #[cfg(target_pointer_width = "32")] 315 | pub fn to_boolean(&self) -> bool { 316 | (self.asBits() & 0x00000000FFFFFFFF) != 0 317 | } 318 | 319 | pub fn to_int32(&self) -> i32 { 320 | assert!(self.is_int32()); 321 | (self.asBits() & 0x00000000FFFFFFFF) as i32 322 | } 323 | 324 | pub fn to_double(&self) -> f64 { 325 | assert!(self.is_double()); 326 | unsafe { mem::transmute(self.asBits()) } 327 | } 328 | 329 | pub fn to_number(&self) -> f64 { 330 | assert!(self.is_number()); 331 | if self.is_double() { 332 | self.to_double() 333 | } else { 334 | self.to_int32() as f64 335 | } 336 | } 337 | 338 | pub fn to_object(&self) -> *mut JSObject { 339 | assert!(self.is_object()); 340 | self.to_object_or_null() 341 | } 342 | 343 | #[cfg(target_pointer_width = "64")] 344 | pub fn to_string(&self) -> *mut JSString { 345 | assert!(self.is_string()); 346 | let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; 347 | ptrBits as usize as *mut JSString 348 | } 349 | 350 | #[cfg(target_pointer_width = "32")] 351 | pub fn to_string(&self) -> *mut JSString { 352 | assert!(self.is_string()); 353 | let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32; 354 | ptrBits as *mut JSString 355 | } 356 | 357 | #[cfg(target_pointer_width = "64")] 358 | pub fn is_object_or_null(&self) -> bool { 359 | const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET: u64 = ValueShiftedTag::NULL as u64; 360 | assert!((self.asBits() >> JSVAL_TAG_SHIFT) <= ValueTag::OBJECT as u64); 361 | self.asBits() >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET 362 | } 363 | 364 | #[cfg(target_pointer_width = "32")] 365 | pub fn is_object_or_null(&self) -> bool { 366 | const JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET: u64 = ValueTag::NULL as u64; 367 | assert!((self.asBits() >> 32) <= ValueTag::OBJECT as u64); 368 | (self.asBits() >> 32) >= JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET 369 | } 370 | 371 | #[cfg(target_pointer_width = "64")] 372 | pub fn to_object_or_null(&self) -> *mut JSObject { 373 | assert!(self.is_object_or_null()); 374 | let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; 375 | assert!((ptrBits & 0x7) == 0); 376 | ptrBits as usize as *mut JSObject 377 | } 378 | 379 | #[cfg(target_pointer_width = "32")] 380 | pub fn to_object_or_null(&self) -> *mut JSObject { 381 | assert!(self.is_object_or_null()); 382 | let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32; 383 | ptrBits as *mut JSObject 384 | } 385 | 386 | #[cfg(target_pointer_width = "64")] 387 | pub fn to_private(&self) -> *const c_void { 388 | assert!(self.is_double()); 389 | assert!((self.asBits() & 0x8000000000000000u64) == 0); 390 | (self.asBits() << 1) as usize as *const c_void 391 | } 392 | 393 | #[cfg(target_pointer_width = "32")] 394 | pub fn to_private(&self) -> *const c_void { 395 | let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32; 396 | ptrBits as *const c_void 397 | } 398 | 399 | #[cfg(target_pointer_width = "64")] 400 | pub fn is_gcthing(&self) -> bool { 401 | const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET: u64 = ValueShiftedTag::STRING as u64; 402 | self.asBits() >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET 403 | } 404 | 405 | #[cfg(target_pointer_width = "32")] 406 | pub fn is_gcthing(&self) -> bool { 407 | const JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET: u64 = ValueTag::STRING as u64; 408 | (self.asBits() >> 32) >= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET 409 | } 410 | 411 | #[cfg(target_pointer_width = "64")] 412 | pub fn to_gcthing(&self) -> *mut c_void { 413 | assert!(self.is_gcthing()); 414 | let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; 415 | assert!((ptrBits & 0x7) == 0); 416 | ptrBits as *mut c_void 417 | } 418 | 419 | #[cfg(target_pointer_width = "32")] 420 | pub fn to_gcthing(&self) -> *mut c_void { 421 | assert!(self.is_gcthing()); 422 | let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32; 423 | ptrBits as *mut c_void 424 | } 425 | 426 | pub fn is_markable(&self) -> bool { 427 | self.is_gcthing() && !self.is_null() 428 | } 429 | 430 | pub fn trace_kind(&self) -> JSGCTraceKind { 431 | assert!(self.is_markable()); 432 | if self.is_object() { 433 | JSTRACE_OBJECT 434 | } else { 435 | JSTRACE_STRING 436 | } 437 | 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | 375 | -------------------------------------------------------------------------------- /src/rust.rs: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | //! Rust wrappers around the raw JS apis 6 | 7 | use libc::types::os::arch::c95::{size_t, c_uint}; 8 | use libc::c_char; 9 | use std::ffi; 10 | use std::str; 11 | use std::ptr; 12 | use std::mem; 13 | use std::u32; 14 | use std::default::Default; 15 | use std::intrinsics::return_address; 16 | use std::ops::{Deref, DerefMut}; 17 | use std::cell::UnsafeCell; 18 | use std::marker::PhantomData; 19 | use jsapi::{JS_NewContext, JS_DestroyContext, JS_NewRuntime, JS_DestroyRuntime}; 20 | use jsapi::{JSContext, JSRuntime, JSObject, JSFlatString, JSFunction, JSString, Symbol, JSScript, jsid, Value}; 21 | use jsapi::{RuntimeOptionsRef, ContextOptionsRef, ReadOnlyCompileOptions}; 22 | use jsapi::{JS_SetErrorReporter, Evaluate3, JSErrorReport}; 23 | use jsapi::{JS_SetGCParameter, JSGCParamKey}; 24 | use jsapi::{Heap, Cell, HeapCellPostBarrier, HeapCellRelocate, HeapValuePostBarrier, HeapValueRelocate}; 25 | use jsapi::{ThingRootKind, ContextFriendFields}; 26 | use jsapi::{Rooted, RootedValue, Handle, MutableHandle, MutableHandleBase, RootedBase}; 27 | use jsapi::{MutableHandleValue, HandleValue, HandleObject, HandleBase}; 28 | use jsapi::AutoObjectVector; 29 | use jsapi::{ToBooleanSlow, ToNumberSlow, ToStringSlow}; 30 | use jsapi::{ToInt32Slow, ToUint32Slow, ToUint16Slow, ToInt64Slow, ToUint64Slow}; 31 | use jsapi::{JSAutoRequest, JS_BeginRequest, JS_EndRequest}; 32 | use jsapi::{JSAutoCompartment, JS_EnterCompartment, JS_LeaveCompartment}; 33 | use jsapi::{JSJitMethodCallArgs, JSJitGetterCallArgs, JSJitSetterCallArgs, CallArgs}; 34 | use jsapi::{NullHandleValue, UndefinedHandleValue, JSID_VOID}; 35 | use jsapi::{CallArgsBase, CallReceiverBase, IncludeUsedRval, UsedRvalBase}; 36 | use jsapi::CompartmentOptions; 37 | use jsval::UndefinedValue; 38 | use glue::{CreateAutoObjectVector, AppendToAutoObjectVector, DeleteAutoObjectVector}; 39 | use glue::{NewCompileOptions, DeleteCompileOptions}; 40 | use default_stacksize; 41 | use default_heapsize; 42 | 43 | // ___________________________________________________________________________ 44 | // friendly Rustic API to runtimes 45 | 46 | /// A wrapper for the `JSRuntime` and `JSContext` structures in SpiderMonkey. 47 | pub struct Runtime { 48 | rt: *mut JSRuntime, 49 | cx: *mut JSContext, 50 | } 51 | 52 | impl Runtime { 53 | /// Creates a new `JSRuntime` and `JSContext`. 54 | pub fn new() -> Runtime { 55 | let js_runtime = unsafe { 56 | JS_NewRuntime(default_heapsize, ChunkSize as u32, ptr::null_mut()) 57 | }; 58 | assert!(!js_runtime.is_null()); 59 | 60 | // Unconstrain the runtime's threshold on nominal heap size, to avoid 61 | // triggering GC too often if operating continuously near an arbitrary 62 | // finite threshold. This leaves the maximum-JS_malloc-bytes threshold 63 | // still in effect to cause periodical, and we hope hygienic, 64 | // last-ditch GCs from within the GC's allocator. 65 | unsafe { 66 | JS_SetGCParameter(js_runtime, JSGCParamKey::JSGC_MAX_BYTES, u32::MAX); 67 | } 68 | 69 | let js_context = unsafe { 70 | JS_NewContext(js_runtime, default_stacksize as size_t) 71 | }; 72 | assert!(!js_context.is_null()); 73 | 74 | unsafe { 75 | let runtimeopts = RuntimeOptionsRef(js_runtime); 76 | let contextopts = ContextOptionsRef(js_context); 77 | 78 | (*runtimeopts).set_varObjFix_(true); 79 | (*runtimeopts).set_baseline_(true); 80 | (*runtimeopts).set_ion_(true); 81 | 82 | (*contextopts).set_dontReportUncaught_(true); 83 | (*contextopts).set_autoJSAPIOwnsErrorReporting_(true); 84 | JS_SetErrorReporter(js_runtime, Some(reportError)); 85 | } 86 | 87 | Runtime { 88 | rt: js_runtime, 89 | cx: js_context, 90 | } 91 | } 92 | 93 | /// Returns the `JSRuntime` object. 94 | pub fn rt(&self) -> *mut JSRuntime { 95 | self.rt 96 | } 97 | 98 | /// Returns the `JSContext` object. 99 | pub fn cx(&self) -> *mut JSContext { 100 | self.cx 101 | } 102 | 103 | pub fn evaluate_script(&self, glob: HandleObject, script: String, filename: String, line_num: u32) 104 | -> Result<(),()> { 105 | let script_utf16: Vec = script.utf16_units().collect(); 106 | let filename_cstr = ffi::CString::new(filename.as_bytes()).unwrap(); 107 | debug!("Evaluating script from {} with content {}", filename, script); 108 | // SpiderMonkey does not approve of null pointers. 109 | let (ptr, len) = if script_utf16.len() == 0 { 110 | static empty: &'static [u16] = &[]; 111 | (empty.as_ptr(), 0) 112 | } else { 113 | (script_utf16.as_ptr(), script_utf16.len() as c_uint) 114 | }; 115 | assert!(!ptr.is_null()); 116 | let _ar = JSAutoRequest::new(self.cx()); 117 | let _ac = JSAutoCompartment::new(self.cx(), glob.get()); 118 | let options = CompileOptionsWrapper::new(self.cx(), filename_cstr.as_ptr(), line_num); 119 | 120 | let scopechain = AutoObjectVectorWrapper::new(self.cx()); 121 | 122 | let mut rval = RootedValue::new(self.cx(), UndefinedValue()); 123 | 124 | unsafe { 125 | if !Evaluate3(self.cx(), scopechain.ptr, options.ptr, 126 | ptr as *const u16, len as size_t, 127 | rval.handle_mut()) { 128 | debug!("...err!"); 129 | Err(()) 130 | } else { 131 | // we could return the script result but then we'd have 132 | // to root it and so forth and, really, who cares? 133 | debug!("...ok!"); 134 | Ok(()) 135 | } 136 | } 137 | } 138 | } 139 | 140 | impl Drop for Runtime { 141 | fn drop(&mut self) { 142 | unsafe { 143 | JS_DestroyContext(self.cx); 144 | JS_DestroyRuntime(self.rt); 145 | } 146 | } 147 | } 148 | 149 | // ___________________________________________________________________________ 150 | // Rooting API for standard JS things 151 | 152 | trait RootKind { 153 | fn rootKind() -> ThingRootKind; 154 | } 155 | 156 | impl RootKind for *mut JSObject { 157 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_OBJECT } 158 | } 159 | 160 | impl RootKind for *mut JSFlatString { 161 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_STRING } 162 | } 163 | 164 | impl RootKind for *mut JSFunction { 165 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_OBJECT } 166 | } 167 | 168 | impl RootKind for *mut JSString { 169 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_STRING } 170 | } 171 | 172 | impl RootKind for *mut Symbol { 173 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_OBJECT } 174 | } 175 | 176 | impl RootKind for *mut JSScript { 177 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_SCRIPT } 178 | } 179 | 180 | impl RootKind for jsid { 181 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_ID } 182 | } 183 | 184 | impl RootKind for Value { 185 | fn rootKind() -> ThingRootKind { ThingRootKind::THING_ROOT_VALUE } 186 | } 187 | 188 | impl Rooted { 189 | pub fn new_with_addr(cx: *mut JSContext, initial: T, addr: *const u8) -> Rooted { 190 | let ctxfriend: &mut ContextFriendFields = unsafe { 191 | mem::transmute(cx) 192 | }; 193 | 194 | let kind = T::rootKind() as usize; 195 | let root = Rooted:: { 196 | _base: RootedBase { _phantom0: PhantomData }, 197 | stack: &mut ctxfriend.thingGCRooters[kind], 198 | prev: ctxfriend.thingGCRooters[kind], 199 | ptr: initial, 200 | }; 201 | 202 | ctxfriend.thingGCRooters[kind] = unsafe { mem::transmute(addr) }; 203 | root 204 | } 205 | 206 | pub fn new(cx: *mut JSContext, initial: T) -> Rooted { 207 | Rooted::new_with_addr(cx, initial, unsafe { return_address() }) 208 | } 209 | 210 | pub fn handle(&self) -> Handle { 211 | unsafe { 212 | Handle::from_marked_location(&self.ptr) 213 | } 214 | } 215 | 216 | pub fn handle_mut(&mut self) -> MutableHandle { 217 | unsafe { 218 | MutableHandle::from_marked_location(&mut self.ptr) 219 | } 220 | } 221 | } 222 | 223 | impl Handle { 224 | pub fn get(&self) -> T { 225 | unsafe { *self.ptr } 226 | } 227 | 228 | pub unsafe fn from_marked_location(ptr: *const T) -> Handle { 229 | Handle { 230 | _base: HandleBase { _phantom0: PhantomData }, 231 | ptr: ptr, 232 | } 233 | } 234 | } 235 | 236 | impl Deref for Handle { 237 | type Target = T; 238 | 239 | fn deref<'a>(&'a self) -> &'a T { 240 | unsafe { &*self.ptr } 241 | } 242 | } 243 | 244 | impl MutableHandle { 245 | pub unsafe fn from_marked_location(ptr: *mut T) -> MutableHandle { 246 | MutableHandle { 247 | _base: MutableHandleBase { _phantom0: PhantomData }, 248 | ptr: ptr, 249 | } 250 | } 251 | 252 | pub fn to_handle(&self) -> Handle { 253 | unsafe { 254 | Handle::from_marked_location(self.ptr as *const _) 255 | } 256 | } 257 | } 258 | 259 | impl Deref for MutableHandle { 260 | type Target = T; 261 | 262 | fn deref<'a>(&'a self) -> &'a T { 263 | unsafe { &*self.ptr } 264 | } 265 | } 266 | 267 | impl DerefMut for MutableHandle { 268 | fn deref_mut<'a>(&'a mut self) -> &'a mut T { 269 | unsafe { &mut *self.ptr } 270 | } 271 | } 272 | 273 | impl HandleValue { 274 | pub fn null() -> HandleValue { 275 | NullHandleValue 276 | } 277 | 278 | pub fn undefined() -> HandleValue { 279 | UndefinedHandleValue 280 | } 281 | } 282 | 283 | const ConstNullValue: *mut JSObject = 0 as *mut JSObject; 284 | 285 | impl HandleObject { 286 | pub fn null() -> HandleObject { 287 | unsafe { 288 | HandleObject::from_marked_location(&ConstNullValue) 289 | } 290 | } 291 | } 292 | 293 | impl MutableHandle { 294 | pub fn get(&self) -> T { 295 | unsafe { *self.ptr } 296 | } 297 | 298 | pub fn set(&self, v: T) { 299 | unsafe { *self.ptr = v } 300 | } 301 | 302 | pub fn handle(&self) -> Handle { 303 | unsafe { 304 | Handle::from_marked_location(&*self.ptr) 305 | } 306 | } 307 | } 308 | 309 | impl Drop for Rooted { 310 | fn drop(&mut self) { 311 | unsafe { 312 | assert!(*self.stack == mem::transmute(&*self)); 313 | *self.stack = self.prev; 314 | } 315 | } 316 | } 317 | 318 | impl Default for jsid { 319 | fn default() -> jsid { JSID_VOID } 320 | } 321 | 322 | impl Default for Value { 323 | fn default() -> Value { UndefinedValue() } 324 | } 325 | 326 | impl Default for CompartmentOptions { 327 | fn default() -> Self { unsafe { ::std::mem::zeroed() } } 328 | } 329 | 330 | const ChunkShift: usize = 20; 331 | const ChunkSize: usize = 1 << ChunkShift; 332 | const ChunkMask: usize = ChunkSize - 1; 333 | 334 | #[cfg(target_pointer_width = "32")] 335 | const ChunkLocationOffset: usize = ChunkSize - 2 * 4 - 8; 336 | 337 | #[cfg(target_pointer_width = "64")] 338 | const ChunkLocationOffset: usize = ChunkSize - 2 * 8 - 8; 339 | 340 | const ChunkLocationBitNursery: usize = 1; 341 | 342 | fn IsInsideNursery(p: *mut Cell) -> bool { 343 | if p.is_null() { 344 | return false; 345 | } 346 | 347 | let mut addr: usize = unsafe { mem::transmute(p) }; 348 | addr = (addr & !ChunkMask) | ChunkLocationOffset; 349 | 350 | let location: *const u32 = unsafe { mem::transmute(addr) }; 351 | let location = unsafe { *location }; 352 | assert!(location != 0); 353 | (location & ChunkLocationBitNursery as u32) != 0 354 | } 355 | 356 | pub trait GCMethods { 357 | fn needs_post_barrier(v: T) -> bool; 358 | unsafe fn post_barrier(v: *mut T); 359 | unsafe fn relocate(v: *mut T); 360 | } 361 | 362 | impl GCMethods for jsid { 363 | fn needs_post_barrier(_: jsid) -> bool { return false; } 364 | unsafe fn post_barrier(_: *mut jsid) { unreachable!() } 365 | unsafe fn relocate(_: *mut jsid) { unreachable!() } 366 | } 367 | 368 | impl GCMethods<*mut JSObject> for *mut JSObject { 369 | fn needs_post_barrier(v: *mut JSObject) -> bool { 370 | return unsafe { IsInsideNursery(mem::transmute(v)) }; 371 | } 372 | unsafe fn post_barrier(v: *mut *mut JSObject) { 373 | HeapCellPostBarrier(mem::transmute(v)); 374 | } 375 | unsafe fn relocate(v: *mut *mut JSObject) { 376 | HeapCellRelocate(mem::transmute(v)); 377 | } 378 | } 379 | 380 | impl GCMethods<*mut JSString> for *mut JSString { 381 | fn needs_post_barrier(v: *mut JSString) -> bool { 382 | return unsafe { IsInsideNursery(mem::transmute(v)) }; 383 | } 384 | unsafe fn post_barrier(v: *mut *mut JSString) { 385 | HeapCellPostBarrier(mem::transmute(v)); 386 | } 387 | unsafe fn relocate(v: *mut *mut JSString) { 388 | HeapCellRelocate(mem::transmute(v)); 389 | } 390 | } 391 | 392 | impl GCMethods<*mut JSScript> for *mut JSScript { 393 | fn needs_post_barrier(v: *mut JSScript) -> bool { 394 | return unsafe { IsInsideNursery(mem::transmute(v)) }; 395 | } 396 | unsafe fn post_barrier(v: *mut *mut JSScript) { 397 | HeapCellPostBarrier(mem::transmute(v)); 398 | } 399 | unsafe fn relocate(v: *mut *mut JSScript) { 400 | HeapCellRelocate(mem::transmute(v)); 401 | } 402 | } 403 | 404 | impl GCMethods<*mut JSFunction> for *mut JSFunction { 405 | fn needs_post_barrier(v: *mut JSFunction) -> bool { 406 | return unsafe { IsInsideNursery(mem::transmute(v)) }; 407 | } 408 | unsafe fn post_barrier(v: *mut *mut JSFunction) { 409 | HeapCellPostBarrier(mem::transmute(v)); 410 | } 411 | unsafe fn relocate(v: *mut *mut JSFunction) { 412 | HeapCellRelocate(mem::transmute(v)); 413 | } 414 | } 415 | 416 | impl GCMethods for Value { 417 | fn needs_post_barrier(v: Value) -> bool { 418 | return v.is_object() && 419 | unsafe { IsInsideNursery(mem::transmute(v.to_object())) }; 420 | } 421 | unsafe fn post_barrier(v: *mut Value) { 422 | HeapValuePostBarrier(v); 423 | } 424 | unsafe fn relocate(v: *mut Value) { 425 | HeapValueRelocate(v); 426 | } 427 | } 428 | 429 | impl + Copy> Heap { 430 | pub fn set(&mut self, v: T) { 431 | unsafe { 432 | if T::needs_post_barrier(v) { 433 | *self.ptr.get() = v; 434 | T::post_barrier(self.ptr.get()); 435 | } else if T::needs_post_barrier(self.get()) { 436 | T::relocate(self.ptr.get()); 437 | *self.ptr.get() = v; 438 | } else { 439 | *self.ptr.get() = v; 440 | } 441 | } 442 | } 443 | 444 | pub fn get(&self) -> T { 445 | unsafe { *self.ptr.get() } 446 | } 447 | 448 | pub fn get_unsafe(&self) -> *mut T { 449 | self.ptr.get() 450 | } 451 | 452 | pub fn handle(&self) -> Handle { 453 | unsafe { 454 | Handle::from_marked_location(self.ptr.get() as *const _) 455 | } 456 | } 457 | } 458 | 459 | impl Default for Heap<*mut JSObject> { 460 | fn default() -> Heap<*mut JSObject> { 461 | Heap { 462 | ptr: UnsafeCell::new(ptr::null_mut()) 463 | } 464 | } 465 | } 466 | 467 | impl Default for Heap { 468 | fn default() -> Heap { 469 | Heap { 470 | ptr: UnsafeCell::new(Value::default()) 471 | } 472 | } 473 | } 474 | 475 | impl + Copy> Drop for Heap { 476 | fn drop(&mut self) { 477 | if T::needs_post_barrier(self.get()) { 478 | unsafe { T::relocate(self.get_unsafe()) }; 479 | } 480 | } 481 | } 482 | 483 | 484 | // ___________________________________________________________________________ 485 | // Implementations for various things in jsapi.rs 486 | 487 | impl JSAutoRequest { 488 | pub fn new(cx: *mut JSContext) -> JSAutoRequest { 489 | unsafe { JS_BeginRequest(cx); } 490 | JSAutoRequest { 491 | mContext: cx 492 | } 493 | } 494 | } 495 | 496 | impl Drop for JSAutoRequest { 497 | fn drop(&mut self) { 498 | unsafe { JS_EndRequest(self.mContext); } 499 | } 500 | } 501 | 502 | impl JSAutoCompartment { 503 | pub fn new(cx: *mut JSContext, target: *mut JSObject) -> JSAutoCompartment { 504 | JSAutoCompartment { 505 | cx_: cx, 506 | oldCompartment_: unsafe { JS_EnterCompartment(cx, target) } 507 | } 508 | } 509 | } 510 | 511 | impl Drop for JSAutoCompartment { 512 | fn drop(&mut self) { 513 | unsafe { JS_LeaveCompartment(self.cx_, self.oldCompartment_); } 514 | } 515 | } 516 | 517 | impl JSJitMethodCallArgs { 518 | pub fn get(&self, i: u32) -> HandleValue { 519 | assert!(i < self._base.argc_); 520 | unsafe { 521 | HandleValue::from_marked_location(self._base._base.argv_.offset(i as isize)) 522 | } 523 | } 524 | 525 | pub fn get_mut(&self, i: u32) -> MutableHandleValue { 526 | assert!(i < self._base.argc_); 527 | unsafe { 528 | MutableHandleValue::from_marked_location(self._base._base.argv_.offset(i as isize)) 529 | } 530 | } 531 | 532 | pub fn rval(&self) -> MutableHandleValue { 533 | unsafe { 534 | MutableHandleValue::from_marked_location(self._base._base.argv_.offset(-2)) 535 | } 536 | } 537 | } 538 | 539 | // XXX need to hack up bindgen to convert this better so we don't have 540 | // to duplicate so much code here 541 | impl CallArgs { 542 | pub fn from_vp(vp: *mut Value, argc: u32) -> CallArgs { 543 | CallArgs { 544 | _base: CallArgsBase { 545 | _base: CallReceiverBase { 546 | _base: IncludeUsedRval { _base: UsedRvalBase }, 547 | argv_: unsafe { vp.offset(2) }, 548 | }, 549 | argc_: argc, 550 | } 551 | } 552 | } 553 | 554 | pub fn get(&self, i: u32) -> HandleValue { 555 | assert!(i < self._base.argc_); 556 | unsafe { 557 | HandleValue::from_marked_location(self._base._base.argv_.offset(i as isize)) 558 | } 559 | } 560 | 561 | pub fn get_mut(&self, i: u32) -> MutableHandleValue { 562 | assert!(i < self._base.argc_); 563 | unsafe { 564 | MutableHandleValue::from_marked_location(self._base._base.argv_.offset(i as isize)) 565 | } 566 | } 567 | 568 | pub fn rval(&self) -> MutableHandleValue { 569 | unsafe { 570 | MutableHandleValue::from_marked_location(self._base._base.argv_.offset(-2)) 571 | } 572 | } 573 | 574 | pub fn thisv(&self) -> HandleValue { 575 | unsafe { 576 | HandleValue::from_marked_location(self._base._base.argv_.offset(-1)) 577 | } 578 | } 579 | } 580 | 581 | impl JSJitGetterCallArgs { 582 | pub fn rval(&self) -> MutableHandleValue { 583 | self._base 584 | } 585 | } 586 | 587 | impl JSJitSetterCallArgs { 588 | pub fn get(&self, i: u32) -> HandleValue { 589 | assert!(i == 0); 590 | self._base.to_handle() 591 | } 592 | } 593 | 594 | // ___________________________________________________________________________ 595 | // Wrappers around things in jsglue.cpp 596 | 597 | pub struct AutoObjectVectorWrapper { 598 | pub ptr: *mut AutoObjectVector 599 | } 600 | 601 | impl AutoObjectVectorWrapper { 602 | pub fn new(cx: *mut JSContext) -> AutoObjectVectorWrapper { 603 | AutoObjectVectorWrapper { 604 | ptr: unsafe { 605 | CreateAutoObjectVector(cx) 606 | } 607 | } 608 | } 609 | 610 | pub fn append(&self, obj: *mut JSObject) -> bool { 611 | unsafe { 612 | AppendToAutoObjectVector(self.ptr, obj) 613 | } 614 | } 615 | } 616 | 617 | impl Drop for AutoObjectVectorWrapper { 618 | fn drop(&mut self) { 619 | unsafe { DeleteAutoObjectVector(self.ptr) } 620 | } 621 | } 622 | 623 | pub struct CompileOptionsWrapper { 624 | pub ptr: *mut ReadOnlyCompileOptions 625 | } 626 | 627 | impl CompileOptionsWrapper { 628 | pub fn new(cx: *mut JSContext, file: *const ::libc::c_char, line: c_uint) -> CompileOptionsWrapper { 629 | CompileOptionsWrapper { 630 | ptr: unsafe { NewCompileOptions(cx, file, line) } 631 | } 632 | } 633 | } 634 | 635 | impl Drop for CompileOptionsWrapper { 636 | fn drop(&mut self) { 637 | unsafe { DeleteCompileOptions(self.ptr) } 638 | } 639 | } 640 | 641 | // ___________________________________________________________________________ 642 | // Fast inline converters 643 | 644 | #[inline] 645 | pub fn ToBoolean(v: HandleValue) -> bool { 646 | let val = unsafe { *v.ptr }; 647 | 648 | if val.is_boolean() { 649 | return val.to_boolean(); 650 | } 651 | 652 | if val.is_int32() { 653 | return val.to_int32() != 0; 654 | } 655 | 656 | if val.is_null_or_undefined() { 657 | return false; 658 | } 659 | 660 | if val.is_double() { 661 | let d = val.to_double(); 662 | return !d.is_nan() && d != 0f64; 663 | } 664 | 665 | if val.is_symbol() { 666 | return true; 667 | } 668 | 669 | unsafe { ToBooleanSlow(v) } 670 | } 671 | 672 | #[inline] 673 | pub fn ToNumber(cx: *mut JSContext, v: HandleValue) -> Result { 674 | let val = unsafe { *v.ptr }; 675 | if val.is_number() { 676 | return Ok(val.to_number()); 677 | } 678 | 679 | let mut out = Default::default(); 680 | unsafe { 681 | if ToNumberSlow(cx, val, &mut out) { 682 | Ok(out) 683 | } else { 684 | Err(()) 685 | } 686 | } 687 | } 688 | 689 | #[inline] 690 | fn convert_from_int32( 691 | cx: *mut JSContext, 692 | v: HandleValue, 693 | conv_fn: unsafe extern "C" fn(*mut JSContext, HandleValue, *mut T) -> bool) 694 | -> Result { 695 | 696 | let val = unsafe { *v.ptr }; 697 | if val.is_int32() { 698 | let intval: i64 = val.to_int32() as i64; 699 | // TODO: do something better here that works on big endian 700 | let intval = unsafe { *(&intval as *const i64 as *const T) }; 701 | return Ok(intval); 702 | } 703 | 704 | let mut out = Default::default(); 705 | unsafe { 706 | if conv_fn(cx, v, &mut out) { 707 | Ok(out) 708 | } else { 709 | Err(()) 710 | } 711 | } 712 | } 713 | 714 | #[inline] 715 | pub fn ToInt32(cx: *mut JSContext, v: HandleValue) -> Result { 716 | convert_from_int32::(cx, v, ToInt32Slow) 717 | } 718 | 719 | #[inline] 720 | pub fn ToUint32(cx: *mut JSContext, v: HandleValue) -> Result { 721 | convert_from_int32::(cx, v, ToUint32Slow) 722 | } 723 | 724 | #[inline] 725 | pub fn ToUint16(cx: *mut JSContext, v: HandleValue) -> Result { 726 | convert_from_int32::(cx, v, ToUint16Slow) 727 | } 728 | 729 | #[inline] 730 | pub fn ToInt64(cx: *mut JSContext, v: HandleValue) -> Result { 731 | convert_from_int32::(cx, v, ToInt64Slow) 732 | } 733 | 734 | #[inline] 735 | pub fn ToUint64(cx: *mut JSContext, v: HandleValue) -> Result { 736 | convert_from_int32::(cx, v, ToUint64Slow) 737 | } 738 | 739 | #[inline] 740 | pub fn ToString(cx: *mut JSContext, v: HandleValue) -> *mut JSString { 741 | let val = unsafe { *v.ptr }; 742 | if val.is_string() { 743 | return val.to_string(); 744 | } 745 | 746 | unsafe { 747 | ToStringSlow(cx, v) 748 | } 749 | } 750 | 751 | pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) { 752 | let fnptr = (*report).filename; 753 | let fname = if !fnptr.is_null() { 754 | let c_str = ffi::CStr::from_ptr(fnptr); 755 | str::from_utf8(c_str.to_bytes()).ok().unwrap().to_string() 756 | } else { 757 | "none".to_string() 758 | }; 759 | let lineno = (*report).lineno; 760 | let column = (*report).column; 761 | let c_str = ffi::CStr::from_ptr(msg); 762 | let msg = str::from_utf8(c_str.to_bytes()).ok().unwrap().to_string(); 763 | error!("Error at {}:{}:{}: {}\n", fname, lineno, column, msg); 764 | } 765 | 766 | #[cfg(test)] 767 | pub mod test { 768 | use {JSCLASS_IS_GLOBAL, JSCLASS_GLOBAL_SLOT_COUNT}; 769 | use {JSCLASS_RESERVED_SLOTS_MASK, JSCLASS_RESERVED_SLOTS_SHIFT}; 770 | use super::Runtime; 771 | use jsapi::JS_Init; 772 | use jsapi::JSClass; 773 | use jsapi::{JS_NewGlobalObject, JS_PropertyStub, JS_StrictPropertyStub}; 774 | use jsapi::{RootedObject, CompartmentOptions, OnNewGlobalHookOption}; 775 | use jsapi::JS_GlobalObjectTraceHook; 776 | 777 | use libc; 778 | 779 | use std::ptr; 780 | 781 | #[test] 782 | pub fn dummy() { 783 | static CLASS: JSClass = JSClass { 784 | name: b"Global\0" as *const u8 as *const libc::c_char, 785 | flags: JSCLASS_IS_GLOBAL | 786 | ((JSCLASS_GLOBAL_SLOT_COUNT & JSCLASS_RESERVED_SLOTS_MASK) << 787 | JSCLASS_RESERVED_SLOTS_SHIFT), 788 | // JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT), 789 | addProperty: None, 790 | delProperty: None, 791 | getProperty: None, 792 | setProperty: None, 793 | enumerate: None, 794 | resolve: None, 795 | convert: None, 796 | finalize: None, 797 | call: None, 798 | hasInstance: None, 799 | construct: None, 800 | trace: Some(JS_GlobalObjectTraceHook), 801 | 802 | reserved: [0 as *mut libc::c_void; 25] 803 | }; 804 | 805 | unsafe { assert!(JS_Init()); } 806 | let rt = Runtime::new(); 807 | let global = RootedObject::new(rt.cx(), unsafe { 808 | JS_NewGlobalObject(rt.cx(), &CLASS, ptr::null_mut(), 809 | OnNewGlobalHookOption::FireOnNewGlobalHook, 810 | &CompartmentOptions::default()) 811 | }); 812 | assert!(rt.evaluate_script(global.handle(), "1 + 1".to_owned(), 813 | "test".to_owned(), 1).is_ok()); 814 | } 815 | 816 | } 817 | -------------------------------------------------------------------------------- /src/jsglue.cpp: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | #define __STDC_LIMIT_MACROS 6 | #include 7 | 8 | #include "js-config.h" 9 | 10 | #ifdef JS_DEBUG 11 | // A hack for MFBT. Guard objects need this to work. 12 | #define DEBUG 1 13 | #endif 14 | 15 | #include "jsapi.h" 16 | #include "jsfriendapi.h" 17 | #include "js/Proxy.h" 18 | #include "js/Class.h" 19 | #include "jswrapper.h" 20 | #include "js/MemoryMetrics.h" 21 | 22 | #include "assert.h" 23 | 24 | struct ProxyTraps { 25 | bool (*enter)(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, 26 | js::BaseProxyHandler::Action action, bool *bp); 27 | 28 | bool (*getOwnPropertyDescriptor)(JSContext *cx, JS::HandleObject proxy, 29 | JS::HandleId id, 30 | JS::MutableHandle desc); 31 | bool (*defineProperty)(JSContext *cx, JS::HandleObject proxy, 32 | JS::HandleId id, 33 | JS::Handle desc, 34 | JS::ObjectOpResult &result); 35 | bool (*ownPropertyKeys)(JSContext *cx, JS::HandleObject proxy, 36 | JS::AutoIdVector &props); 37 | bool (*delete_)(JSContext *cx, JS::HandleObject proxy, 38 | JS::HandleId id, JS::ObjectOpResult &result); 39 | 40 | bool (*enumerate)(JSContext *cx, JS::HandleObject proxy, 41 | JS::MutableHandleObject objp); 42 | 43 | // getPrototype 44 | // setPrototype 45 | // setImmutablePrototype 46 | 47 | bool (*preventExtensions)(JSContext *cx, JS::HandleObject proxy, 48 | JS::ObjectOpResult &result); 49 | 50 | bool (*isExtensible)(JSContext *cx, JS::HandleObject proxy, bool *succeeded); 51 | 52 | bool (*has)(JSContext *cx, JS::HandleObject proxy, 53 | JS::HandleId id, bool *bp); 54 | bool (*get)(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver, 55 | JS::HandleId id, JS::MutableHandleValue vp); 56 | bool (*set)(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver, 57 | JS::HandleId id, JS::MutableHandleValue vp, 58 | JS::ObjectOpResult &result); 59 | 60 | bool (*call)(JSContext *cx, JS::HandleObject proxy, 61 | const JS::CallArgs &args); 62 | bool (*construct)(JSContext *cx, JS::HandleObject proxy, 63 | const JS::CallArgs &args); 64 | 65 | bool (*getPropertyDescriptor)(JSContext *cx, JS::HandleObject proxy, 66 | JS::HandleId id, 67 | JS::MutableHandle desc); 68 | bool (*hasOwn)(JSContext *cx, JS::HandleObject proxy, 69 | JS::HandleId id, bool *bp); 70 | bool (*getOwnEnumerablePropertyKeys)(JSContext *cx, JS::HandleObject proxy, 71 | JS::AutoIdVector &props); 72 | bool (*nativeCall)(JSContext *cx, JS::IsAcceptableThis test, 73 | JS::NativeImpl impl, JS::CallArgs args); 74 | bool (*hasInstance)(JSContext *cx, JS::HandleObject proxy, 75 | JS::MutableHandleValue v, bool *bp); 76 | bool (*objectClassIs)(JS::HandleObject obj, js::ESClassValue classValue, 77 | JSContext *cx); 78 | const char *(*className)(JSContext *cx, JS::HandleObject proxy); 79 | JSString *(*fun_toString)(JSContext *cx, JS::HandleObject proxy, 80 | unsigned indent); 81 | //bool (*regexp_toShared)(JSContext *cx, JS::HandleObject proxy, RegExpGuard *g); 82 | bool (*boxedValue_unbox)(JSContext *cx, JS::HandleObject proxy, 83 | JS::MutableHandleValue vp); 84 | bool (*defaultValue)(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); 85 | void (*trace)(JSTracer *trc, JSObject *proxy); 86 | void (*finalize)(JSFreeOp *fop, JSObject *proxy); 87 | void (*objectMoved)(JSObject *proxy, const JSObject *old); 88 | 89 | bool (*isCallable)(JSObject *obj); 90 | bool (*isConstructor)(JSObject *obj); 91 | 92 | // watch 93 | // unwatch 94 | // getElements 95 | 96 | // weakmapKeyDelegate 97 | // isScripted 98 | }; 99 | 100 | static int HandlerFamily; 101 | 102 | #define DEFER_TO_TRAP_OR_BASE_CLASS(_base) \ 103 | \ 104 | virtual bool enter(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, \ 105 | _base::Action action, bool *bp) const override \ 106 | { \ 107 | return mTraps.enter \ 108 | ? mTraps.enter(cx, proxy, id, action, bp) \ 109 | : _base::enter(cx, proxy, id, action, bp); \ 110 | } \ 111 | \ 112 | /* Standard internal methods. */ \ 113 | virtual bool enumerate(JSContext *cx, JS::HandleObject proxy, \ 114 | JS::MutableHandleObject objp) const override \ 115 | { \ 116 | return mTraps.enumerate \ 117 | ? mTraps.enumerate(cx, proxy, objp) \ 118 | : _base::enumerate(cx, proxy, objp); \ 119 | } \ 120 | \ 121 | virtual bool has(JSContext* cx, JS::HandleObject proxy, \ 122 | JS::HandleId id, bool *bp) const override \ 123 | { \ 124 | return mTraps.has \ 125 | ? mTraps.has(cx, proxy, id, bp) \ 126 | : _base::has(cx, proxy, id, bp); \ 127 | } \ 128 | \ 129 | virtual bool get(JSContext* cx, JS::HandleObject proxy, \ 130 | JS::HandleObject receiver, \ 131 | JS::HandleId id, JS::MutableHandleValue vp) const override \ 132 | { \ 133 | return mTraps.get \ 134 | ? mTraps.get(cx, proxy, receiver, id, vp) \ 135 | : _base::get(cx, proxy, receiver, id, vp); \ 136 | } \ 137 | \ 138 | virtual bool set(JSContext* cx, JS::HandleObject proxy, \ 139 | JS::HandleObject receiver, \ 140 | JS::HandleId id, JS::MutableHandleValue vp, \ 141 | JS::ObjectOpResult &result) const override \ 142 | { \ 143 | return mTraps.set \ 144 | ? mTraps.set(cx, proxy, receiver, id, vp, result) \ 145 | : _base::set(cx, proxy, receiver, id, vp, result); \ 146 | } \ 147 | \ 148 | virtual bool call(JSContext* cx, JS::HandleObject proxy, \ 149 | const JS::CallArgs &args) const override \ 150 | { \ 151 | return mTraps.call \ 152 | ? mTraps.call(cx, proxy, args) \ 153 | : _base::call(cx, proxy, args); \ 154 | } \ 155 | \ 156 | virtual bool construct(JSContext* cx, JS::HandleObject proxy, \ 157 | const JS::CallArgs &args) const override \ 158 | { \ 159 | return mTraps.construct \ 160 | ? mTraps.construct(cx, proxy, args) \ 161 | : _base::construct(cx, proxy, args); \ 162 | } \ 163 | \ 164 | /* Spidermonkey extensions. */ \ 165 | virtual bool hasOwn(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, \ 166 | bool* bp) const override \ 167 | { \ 168 | return mTraps.hasOwn \ 169 | ? mTraps.hasOwn(cx, proxy, id, bp) \ 170 | : _base::hasOwn(cx, proxy, id, bp); \ 171 | } \ 172 | \ 173 | virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, \ 174 | JS::HandleObject proxy, \ 175 | JS::AutoIdVector &props) const override \ 176 | { \ 177 | return mTraps.getOwnEnumerablePropertyKeys \ 178 | ? mTraps.getOwnEnumerablePropertyKeys(cx, proxy, props) \ 179 | : _base::getOwnEnumerablePropertyKeys(cx, proxy, props); \ 180 | } \ 181 | \ 182 | virtual bool nativeCall(JSContext* cx, JS::IsAcceptableThis test, \ 183 | JS::NativeImpl impl, \ 184 | JS::CallArgs args) const override \ 185 | { \ 186 | return mTraps.nativeCall \ 187 | ? mTraps.nativeCall(cx, test, impl, args) \ 188 | : _base::nativeCall(cx, test, impl, args); \ 189 | } \ 190 | \ 191 | virtual bool hasInstance(JSContext* cx, JS::HandleObject proxy, \ 192 | JS::MutableHandleValue v, bool* bp) const override \ 193 | { \ 194 | return mTraps.hasInstance \ 195 | ? mTraps.hasInstance(cx, proxy, v, bp) \ 196 | : _base::hasInstance(cx, proxy, v, bp); \ 197 | } \ 198 | \ 199 | virtual bool objectClassIs(JS::HandleObject obj, \ 200 | js::ESClassValue classValue, \ 201 | JSContext* cx) const override \ 202 | { \ 203 | return mTraps.objectClassIs \ 204 | ? mTraps.objectClassIs(obj, classValue, cx) \ 205 | : _base::objectClassIs(obj, classValue, cx); \ 206 | } \ 207 | \ 208 | virtual const char *className(JSContext *cx, JS::HandleObject proxy) const override\ 209 | { \ 210 | return mTraps.className \ 211 | ? mTraps.className(cx, proxy) \ 212 | : _base::className(cx, proxy); \ 213 | } \ 214 | \ 215 | virtual JSString* fun_toString(JSContext* cx, JS::HandleObject proxy, \ 216 | unsigned indent) const override \ 217 | { \ 218 | return mTraps.fun_toString \ 219 | ? mTraps.fun_toString(cx, proxy, indent) \ 220 | : _base::fun_toString(cx, proxy, indent); \ 221 | } \ 222 | \ 223 | virtual bool boxedValue_unbox(JSContext* cx, JS::HandleObject proxy, \ 224 | JS::MutableHandleValue vp) const override \ 225 | { \ 226 | return mTraps.boxedValue_unbox \ 227 | ? mTraps.boxedValue_unbox(cx, proxy, vp) \ 228 | : _base::boxedValue_unbox(cx, proxy, vp); \ 229 | } \ 230 | \ 231 | virtual bool defaultValue(JSContext* cx, JS::HandleObject obj, JSType hint, \ 232 | JS::MutableHandleValue vp) const override \ 233 | { \ 234 | return mTraps.defaultValue \ 235 | ? mTraps.defaultValue(cx, obj, hint, vp) \ 236 | : _base::defaultValue(cx, obj, hint, vp); \ 237 | } \ 238 | \ 239 | virtual void trace(JSTracer* trc, JSObject* proxy) const override \ 240 | { \ 241 | mTraps.trace \ 242 | ? mTraps.trace(trc, proxy) \ 243 | : _base::trace(trc, proxy); \ 244 | } \ 245 | \ 246 | virtual void finalize(JSFreeOp* fop, JSObject* proxy) const override \ 247 | { \ 248 | mTraps.finalize \ 249 | ? mTraps.finalize(fop, proxy) \ 250 | : _base::finalize(fop, proxy); \ 251 | } \ 252 | \ 253 | virtual void objectMoved(JSObject* proxy, \ 254 | const JSObject *old) const override \ 255 | { \ 256 | mTraps.objectMoved \ 257 | ? mTraps.objectMoved(proxy, old) \ 258 | : _base::objectMoved(proxy, old); \ 259 | } \ 260 | \ 261 | virtual bool isCallable(JSObject* obj) const override \ 262 | { \ 263 | return mTraps.isCallable \ 264 | ? mTraps.isCallable(obj) \ 265 | : _base::isCallable(obj); \ 266 | } \ 267 | \ 268 | virtual bool isConstructor(JSObject* obj) const override \ 269 | { \ 270 | return mTraps.isConstructor \ 271 | ? mTraps.isConstructor(obj) \ 272 | : _base::isConstructor(obj); \ 273 | } 274 | 275 | class WrapperProxyHandler : public js::Wrapper 276 | { 277 | ProxyTraps mTraps; 278 | public: 279 | WrapperProxyHandler(const ProxyTraps& aTraps) 280 | : js::Wrapper(0), mTraps(aTraps) {} 281 | 282 | virtual bool finalizeInBackground(JS::Value priv) const override 283 | { 284 | return false; 285 | } 286 | 287 | DEFER_TO_TRAP_OR_BASE_CLASS(js::Wrapper) 288 | 289 | virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, 290 | JS::HandleId id, 291 | JS::MutableHandle desc) const override 292 | { 293 | return mTraps.getOwnPropertyDescriptor 294 | ? mTraps.getOwnPropertyDescriptor(cx, proxy, id, desc) 295 | : js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc); 296 | } 297 | 298 | virtual bool defineProperty(JSContext *cx, 299 | JS::HandleObject proxy, JS::HandleId id, 300 | JS::MutableHandle desc, 301 | JS::ObjectOpResult &result) const override 302 | { 303 | return mTraps.defineProperty 304 | ? mTraps.defineProperty(cx, proxy, id, desc, result) 305 | : js::Wrapper::defineProperty(cx, proxy, id, desc, result); 306 | } 307 | 308 | virtual bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, 309 | JS::AutoIdVector &props) const override 310 | { 311 | return mTraps.ownPropertyKeys 312 | ? mTraps.ownPropertyKeys(cx, proxy, props) 313 | : js::Wrapper::ownPropertyKeys(cx, proxy, props); 314 | } 315 | 316 | virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, 317 | JS::ObjectOpResult &result) const override 318 | { 319 | return mTraps.delete_ 320 | ? mTraps.delete_(cx, proxy, id, result) 321 | : js::Wrapper::delete_(cx, proxy, id, result); 322 | } 323 | 324 | virtual bool preventExtensions(JSContext *cx, JS::HandleObject proxy, 325 | JS::ObjectOpResult &result) const override 326 | { 327 | return mTraps.preventExtensions 328 | ? mTraps.preventExtensions(cx, proxy, result) 329 | : js::Wrapper::preventExtensions(cx, proxy, result); 330 | } 331 | 332 | virtual bool isExtensible(JSContext *cx, JS::HandleObject proxy, 333 | bool *succeeded) const override 334 | { 335 | return mTraps.isExtensible 336 | ? mTraps.isExtensible(cx, proxy, succeeded) 337 | : js::Wrapper::isExtensible(cx, proxy, succeeded); 338 | } 339 | 340 | virtual bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, 341 | JS::HandleId id, 342 | JS::MutableHandle desc) const override 343 | { 344 | return mTraps.getPropertyDescriptor 345 | ? mTraps.getPropertyDescriptor(cx, proxy, id, desc) 346 | : js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc); 347 | } 348 | }; 349 | 350 | class ForwardingProxyHandler : public js::BaseProxyHandler 351 | { 352 | ProxyTraps mTraps; 353 | const void* mExtra; 354 | public: 355 | ForwardingProxyHandler(const ProxyTraps& aTraps, const void* aExtra) 356 | : js::BaseProxyHandler(&HandlerFamily), mTraps(aTraps), mExtra(aExtra) {} 357 | 358 | const void* getExtra() const { 359 | return mExtra; 360 | } 361 | 362 | virtual bool finalizeInBackground(JS::Value priv) const override 363 | { 364 | return false; 365 | } 366 | 367 | DEFER_TO_TRAP_OR_BASE_CLASS(BaseProxyHandler) 368 | 369 | virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, 370 | JS::HandleId id, 371 | JS::MutableHandle desc) const override 372 | { 373 | return mTraps.getOwnPropertyDescriptor(cx, proxy, id, desc); 374 | } 375 | 376 | virtual bool defineProperty(JSContext *cx, 377 | JS::HandleObject proxy, JS::HandleId id, 378 | JS::MutableHandle desc, 379 | JS::ObjectOpResult &result) const override 380 | { 381 | return mTraps.defineProperty(cx, proxy, id, desc, result); 382 | } 383 | 384 | virtual bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, 385 | JS::AutoIdVector &props) const override 386 | { 387 | return mTraps.ownPropertyKeys(cx, proxy, props); 388 | } 389 | 390 | virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, 391 | JS::ObjectOpResult &result) const override 392 | { 393 | return mTraps.delete_(cx, proxy, id, result); 394 | } 395 | 396 | virtual bool preventExtensions(JSContext *cx, JS::HandleObject proxy, 397 | JS::ObjectOpResult &result) const override 398 | { 399 | return mTraps.preventExtensions(cx, proxy, result); 400 | } 401 | 402 | virtual bool isExtensible(JSContext *cx, JS::HandleObject proxy, 403 | bool *succeeded) const override 404 | { 405 | return mTraps.isExtensible(cx, proxy, succeeded); 406 | } 407 | 408 | virtual bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, 409 | JS::HandleId id, 410 | JS::MutableHandle desc) const override 411 | { 412 | return mTraps.getPropertyDescriptor(cx, proxy, id, desc); 413 | } 414 | }; 415 | 416 | extern "C" { 417 | 418 | bool 419 | InvokeGetOwnPropertyDescriptor( 420 | const void *handler, 421 | JSContext *cx, JS::HandleObject proxy, JS::HandleId id, 422 | JS::MutableHandle desc) 423 | { 424 | return static_cast(handler)-> 425 | getOwnPropertyDescriptor(cx, proxy, id, desc); 426 | } 427 | 428 | jsval 429 | RUST_JS_NumberValue(double d) 430 | { 431 | return JS_NumberValue(d); 432 | } 433 | 434 | const JSJitInfo* 435 | RUST_FUNCTION_VALUE_TO_JITINFO(jsval v) 436 | { 437 | return FUNCTION_VALUE_TO_JITINFO(v); 438 | } 439 | 440 | bool 441 | CallJitGetterOp(const JSJitInfo* info, JSContext* cx, 442 | JS::HandleObject thisObj, void* specializedThis, 443 | unsigned argc, JS::Value* vp) 444 | { 445 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 446 | return info->getter(cx, thisObj, specializedThis, JSJitGetterCallArgs(args)); 447 | } 448 | 449 | bool 450 | CallJitSetterOp(const JSJitInfo* info, JSContext* cx, 451 | JS::HandleObject thisObj, void* specializedThis, 452 | unsigned argc, JS::Value* vp) 453 | { 454 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 455 | return info->setter(cx, thisObj, specializedThis, JSJitSetterCallArgs(args)); 456 | } 457 | 458 | bool 459 | CallJitMethodOp(const JSJitInfo* info, JSContext* cx, 460 | JS::HandleObject thisObj, void* specializedThis, 461 | uint32_t argc, JS::Value* vp) 462 | { 463 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 464 | return info->method(cx, thisObj, specializedThis, JSJitMethodCallArgs(args)); 465 | } 466 | 467 | const void* 468 | CreateProxyHandler(const ProxyTraps* aTraps, const void* aExtra) 469 | { 470 | return new ForwardingProxyHandler(*aTraps, aExtra); 471 | } 472 | 473 | const void* 474 | CreateWrapperProxyHandler(const ProxyTraps* aTraps) 475 | { 476 | return new WrapperProxyHandler(*aTraps); 477 | } 478 | 479 | const void* 480 | GetCrossCompartmentWrapper() 481 | { 482 | return &js::CrossCompartmentWrapper::singleton; 483 | } 484 | 485 | JS::ReadOnlyCompileOptions* 486 | NewCompileOptions(JSContext* aCx, const char* aFile, unsigned aLine) 487 | { 488 | JS::OwningCompileOptions *opts = new JS::OwningCompileOptions(aCx); 489 | opts->setFileAndLine(aCx, aFile, aLine); 490 | opts->setVersion(JSVERSION_DEFAULT); 491 | return opts; 492 | } 493 | 494 | void 495 | DeleteCompileOptions(JS::ReadOnlyCompileOptions *aOpts) 496 | { 497 | delete static_cast(aOpts); 498 | } 499 | 500 | JSObject* 501 | NewProxyObject(JSContext* aCx, const void* aHandler, JS::HandleValue aPriv, 502 | JSObject* proto, JSObject* parent, JSObject* call, 503 | JSObject* construct) 504 | { 505 | js::ProxyOptions options; 506 | return js::NewProxyObject(aCx, (js::BaseProxyHandler*)aHandler, aPriv, proto, 507 | options); 508 | } 509 | 510 | JSObject* 511 | WrapperNew(JSContext* aCx, JS::HandleObject aObj, const void* aHandler, 512 | const JSClass* aClass, bool aSingleton) 513 | { 514 | js::WrapperOptions options; 515 | if (aClass) { 516 | options.setClass(js::Valueify(aClass)); 517 | } 518 | options.setSingleton(aSingleton); 519 | return js::Wrapper::New(aCx, aObj, (const js::Wrapper*)aHandler, options); 520 | } 521 | 522 | jsval 523 | GetProxyExtra(JSObject* obj, uint32_t slot) 524 | { 525 | return js::GetProxyExtra(obj, slot); 526 | } 527 | 528 | jsval 529 | GetProxyPrivate(JSObject* obj) 530 | { 531 | return js::GetProxyPrivate(obj); 532 | } 533 | 534 | void 535 | SetProxyExtra(JSObject* obj, uint32_t slot, jsval val) 536 | { 537 | return js::SetProxyExtra(obj, slot, val); 538 | } 539 | 540 | bool 541 | RUST_JSID_IS_INT(JS::HandleId id) 542 | { 543 | return JSID_IS_INT(id); 544 | } 545 | 546 | jsid 547 | int_to_jsid(int32_t i) 548 | { 549 | return INT_TO_JSID(i); 550 | } 551 | 552 | int32_t 553 | RUST_JSID_TO_INT(JS::HandleId id) 554 | { 555 | return JSID_TO_INT(id); 556 | } 557 | 558 | bool 559 | RUST_JSID_IS_STRING(JS::HandleId id) 560 | { 561 | return JSID_IS_STRING(id); 562 | } 563 | 564 | JSString* 565 | RUST_JSID_TO_STRING(JS::HandleId id) 566 | { 567 | return JSID_TO_STRING(id); 568 | } 569 | 570 | void 571 | RUST_SET_JITINFO(JSFunction* func, const JSJitInfo* info) { 572 | SET_JITINFO(func, info); 573 | } 574 | 575 | jsid 576 | RUST_INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str) { 577 | return INTERNED_STRING_TO_JSID(cx, str); 578 | } 579 | 580 | const JSErrorFormatString* 581 | RUST_js_GetErrorMessage(void* userRef, uint32_t errorNumber) 582 | { 583 | return js::GetErrorMessage(userRef, errorNumber); 584 | } 585 | 586 | bool 587 | IsProxyHandlerFamily(JSObject* obj) 588 | { 589 | return js::GetProxyHandler(obj)->family() == &HandlerFamily; 590 | } 591 | 592 | const void* 593 | GetProxyHandlerExtra(JSObject* obj) 594 | { 595 | const js::BaseProxyHandler* handler = js::GetProxyHandler(obj); 596 | assert(handler->family() == &HandlerFamily); 597 | return static_cast(handler)->getExtra(); 598 | } 599 | 600 | const void* 601 | GetProxyHandler(JSObject* obj) 602 | { 603 | const js::BaseProxyHandler* handler = js::GetProxyHandler(obj); 604 | assert(handler->family() == &HandlerFamily); 605 | return handler; 606 | } 607 | 608 | void 609 | ReportError(JSContext* aCx, const char* aError) 610 | { 611 | #ifdef DEBUG 612 | for (const char* p = aError; *p; ++p) { 613 | assert(*p != '%'); 614 | } 615 | #endif 616 | JS_ReportError(aCx, aError); 617 | } 618 | 619 | bool 620 | IsWrapper(JSObject* obj) 621 | { 622 | return js::IsWrapper(obj); 623 | } 624 | 625 | JSObject* 626 | UnwrapObject(JSObject* obj, bool stopAtOuter) 627 | { 628 | return js::CheckedUnwrap(obj, stopAtOuter); 629 | } 630 | 631 | bool 632 | AppendToAutoIdVector(JS::AutoIdVector* v, jsid id) 633 | { 634 | return v->append(id); 635 | } 636 | 637 | JS::AutoObjectVector* 638 | CreateAutoObjectVector(JSContext* aCx) 639 | { 640 | JS::AutoObjectVector* vec = new JS::AutoObjectVector(aCx); 641 | return vec; 642 | } 643 | 644 | bool 645 | AppendToAutoObjectVector(JS::AutoObjectVector* v, JSObject* obj) 646 | { 647 | return v->append(obj); 648 | } 649 | 650 | void 651 | DeleteAutoObjectVector(JS::AutoObjectVector* v) 652 | { 653 | delete v; 654 | } 655 | 656 | #if defined(__linux__) 657 | #include 658 | #elif defined(__APPLE__) 659 | #include 660 | #else 661 | #error "unsupported platform" 662 | #endif 663 | 664 | // SpiderMonkey-in-Rust currently uses system malloc, not jemalloc. 665 | static size_t MallocSizeOf(const void* aPtr) 666 | { 667 | #if defined(__linux__) 668 | return malloc_usable_size((void*)aPtr); 669 | #elif defined(__APPLE__) 670 | return malloc_size((void*)aPtr); 671 | #else 672 | #error "unsupported platform" 673 | #endif 674 | } 675 | 676 | bool 677 | CollectServoSizes(JSRuntime *rt, JS::ServoSizes *sizes) 678 | { 679 | mozilla::PodZero(sizes); 680 | return JS::AddServoSizeOf(rt, MallocSizeOf, 681 | /* ObjectPrivateVisitor = */ nullptr, sizes); 682 | } 683 | 684 | } // extern "C" 685 | --------------------------------------------------------------------------------