diff --git a/.github/workflows/test-release.yaml b/.github/workflows/test-release.yaml index 906062c6..12beda75 100644 --- a/.github/workflows/test-release.yaml +++ b/.github/workflows/test-release.yaml @@ -249,6 +249,10 @@ jobs: setup: | sudo apt-get update sudo apt-get install -y gcc-powerpc64le-linux-gnu + - target: s390x-unknown-linux-gnu + setup: | + sudo apt-get update + sudo apt-get install -y gcc-s390x-linux-gnu steps: - uses: actions/checkout@v4 @@ -383,6 +387,12 @@ jobs: arch: 'ppc64' libc: 'gnu' without-lerna: true + - image: 'node:{:version}-slim' + target: s390x-unknown-linux-gnu + args: '--platform linux/s390x' + arch: 's390x' + libc: 'gnu' + without-lerna: true - image: 'node:{:version}-alpine' target: x86_64-unknown-linux-musl args: '' diff --git a/cli/src/api/templates/ci-template.ts b/cli/src/api/templates/ci-template.ts index 75fde639..f9750498 100644 --- a/cli/src/api/templates/ci-template.ts +++ b/cli/src/api/templates/ci-template.ts @@ -85,6 +85,12 @@ jobs: sudo apt-get update sudo apt-get install gcc-powerpc64le-linux-gnu -y build: ${packageManager} build --platform --target powerpc64le-unknown-linux-gnu + - host: ubuntu-latest + target: 's390x-unknown-linux-gnu' + setup: | + sudo apt-get update + sudo apt-get install gcc-s390x-linux-gnu -y + build: ${packageManager} build --platform --target s390x-unknown-linux-gnu - host: ubuntu-latest target: 'wasm32-wasi-preview1-threads' build: ${packageManager} build --platform --target wasm32-wasi-preview1-threads diff --git a/cli/src/utils/__tests__/__snapshots__/target.spec.ts.md b/cli/src/utils/__tests__/__snapshots__/target.spec.ts.md index 6403f629..03e88728 100644 --- a/cli/src/utils/__tests__/__snapshots__/target.spec.ts.md +++ b/cli/src/utils/__tests__/__snapshots__/target.spec.ts.md @@ -128,6 +128,13 @@ Generated by [AVA](https://avajs.dev). platformArchABI: 'linux-ppc64-gnu', triple: 'powerpc64le-unknown-linux-gnu', }, + { + abi: 'gnu', + arch: 's390x', + platform: 'linux', + platformArchABI: 'linux-s390x-gnu', + triple: 's390x-unknown-linux-gnu', + }, { abi: 'wasi', arch: 'wasm32', diff --git a/cli/src/utils/__tests__/__snapshots__/target.spec.ts.snap b/cli/src/utils/__tests__/__snapshots__/target.spec.ts.snap index 3c8261cf..fcec5bf4 100644 Binary files a/cli/src/utils/__tests__/__snapshots__/target.spec.ts.snap and b/cli/src/utils/__tests__/__snapshots__/target.spec.ts.snap differ diff --git a/cli/src/utils/target.ts b/cli/src/utils/target.ts index f120895c..fb58cba3 100644 --- a/cli/src/utils/target.ts +++ b/cli/src/utils/target.ts @@ -24,6 +24,7 @@ export const AVAILABLE_TARGETS = [ 'universal-apple-darwin', 'riscv64gc-unknown-linux-gnu', 'powerpc64le-unknown-linux-gnu', + 's390x-unknown-linux-gnu', 'wasm32-wasi-preview1-threads', ] as const @@ -40,6 +41,7 @@ export const TARGET_LINKER: Record = { 'aarch64-unknown-linux-musl': 'aarch64-linux-musl-gcc', 'riscv64gc-unknown-linux-gnu': 'riscv64-linux-gnu-gcc', 'powerpc64le-unknown-linux-gnu': 'powerpc64le-linux-gnu-gcc', + 's390x-unknown-linux-gnu': 's390x-linux-gnu-gcc', } // https://nodejs.org/api/process.html#process_process_arch diff --git a/crates/napi/src/bindgen_runtime/js_values/bigint.rs b/crates/napi/src/bindgen_runtime/js_values/bigint.rs index 5261e137..cd2da832 100644 --- a/crates/napi/src/bindgen_runtime/js_values/bigint.rs +++ b/crates/napi/src/bindgen_runtime/js_values/bigint.rs @@ -107,8 +107,7 @@ impl BigInt { if len == 1 { (self.words[0] as i128, false) } else { - let i128_words: [i64; 2] = [self.words[0] as _, self.words[1] as _]; - let mut val = unsafe { ptr::read(i128_words.as_ptr() as *const i128) }; + let mut val = self.words[0] as i128 + ((self.words[1] as i128) << 64); if self.sign_bit { val = -val; } @@ -125,8 +124,7 @@ impl BigInt { if len == 1 { (self.sign_bit, self.words[0] as u128, false) } else { - let u128_words: [u64; 2] = [self.words[0], self.words[1]]; - let val = unsafe { ptr::read(u128_words.as_ptr() as *const u128) }; + let val = self.words[0] as u128 + ((self.words[1] as u128) << 64); (self.sign_bit, val, len > 2) } } @@ -156,7 +154,16 @@ impl ToNapiValue for i128 { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result { let mut raw_value = ptr::null_mut(); let sign_bit = i32::from(val <= 0); - let words = &val as *const i128 as *const u64; + if cfg!(target_endian = "little") { + let words = &val as *const i128 as *const u64; + check_status!(unsafe { + sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) + })?; + return Ok(raw_value); + } + + let arr: [u64; 2] = [val as _, (val >> 64) as _]; + let words = &arr as *const u64; check_status!(unsafe { sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value) })?; @@ -167,7 +174,14 @@ impl ToNapiValue for i128 { impl ToNapiValue for u128 { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result { let mut raw_value = ptr::null_mut(); - let words = &val as *const u128 as *const u64; + if cfg!(target_endian = "little") { + let words = &val as *const u128 as *const u64; + check_status!(unsafe { sys::napi_create_bigint_words(env, 0, 2, words, &mut raw_value) })?; + return Ok(raw_value); + } + + let arr: [u64; 2] = [val as _, (val >> 64) as _]; + let words = &arr as *const u64; check_status!(unsafe { sys::napi_create_bigint_words(env, 0, 2, words, &mut raw_value) })?; Ok(raw_value) } @@ -226,20 +240,19 @@ impl From for BigInt { impl From for BigInt { fn from(val: i128) -> Self { let sign_bit = val < 0; - let words = (if sign_bit { -val } else { val }).to_ne_bytes(); + let val = if sign_bit { -val } else { val }; BigInt { sign_bit, - words: unsafe { std::slice::from_raw_parts(words.as_ptr() as *mut _, 2).to_vec() }, + words: vec![val as _, (val >> 64) as _], } } } impl From for BigInt { fn from(val: u128) -> Self { - let words = val.to_ne_bytes(); BigInt { sign_bit: false, - words: unsafe { std::slice::from_raw_parts(words.as_ptr() as *mut _, 2).to_vec() }, + words: vec![val as _, (val >> 64) as _], } } } diff --git a/crates/napi/src/env.rs b/crates/napi/src/env.rs index 25cf5db8..b27e30c4 100644 --- a/crates/napi/src/env.rs +++ b/crates/napi/src/env.rs @@ -119,7 +119,16 @@ impl Env { pub fn create_bigint_from_i128(&self, value: i128) -> Result { let mut raw_value = ptr::null_mut(); let sign_bit = i32::from(value <= 0); - let words = &value as *const i128 as *const u64; + if cfg!(target_endian = "little") { + let words = &value as *const i128 as *const u64; + check_status!(unsafe { + sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value) + })?; + return Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2)); + } + + let arr: [u64; 2] = [value as _, (value >> 64) as _]; + let words = &arr as *const u64; check_status!(unsafe { sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value) })?; @@ -129,7 +138,14 @@ impl Env { #[cfg(feature = "napi6")] pub fn create_bigint_from_u128(&self, value: u128) -> Result { let mut raw_value = ptr::null_mut(); - let words = &value as *const u128 as *const u64; + if cfg!(target_endian = "little") { + let words = &value as *const u128 as *const u64; + check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?; + return Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2)); + } + + let arr: [u64; 2] = [value as _, (value >> 64) as _]; + let words = &arr as *const u64; check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?; Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2)) } diff --git a/crates/napi/src/js_values/bigint.rs b/crates/napi/src/js_values/bigint.rs index a72b44b0..0e96dbf8 100644 --- a/crates/napi/src/js_values/bigint.rs +++ b/crates/napi/src/js_values/bigint.rs @@ -246,17 +246,22 @@ impl JsBigInt { pub fn get_i128(&mut self) -> Result<(i128, bool)> { let (signed, words) = self.get_words()?; - let high_part = words.first().copied().unwrap_or(0).to_le_bytes(); - let low_part = words.get(1).copied().unwrap_or(0).to_le_bytes(); + let low_part = words.first().copied().unwrap_or(0).to_ne_bytes(); + let high_part = words.get(1).copied().unwrap_or(0).to_ne_bytes(); let mut val = [0_u8; std::mem::size_of::()]; - - let (high_val, low_val) = val.split_at_mut(low_part.len()); + let high_val: &mut [u8]; + let low_val: &mut [u8]; + if cfg!(target_endian = "little") { + (low_val, high_val) = val.split_at_mut(low_part.len()); + } else { + (high_val, low_val) = val.split_at_mut(low_part.len()); + } high_val.copy_from_slice(&high_part); low_val.copy_from_slice(&low_part); - let mut val = i128::from_le_bytes(val); + let mut val = i128::from_ne_bytes(val); let mut loss = words.len() > 2; let mut overflow = false; @@ -275,17 +280,23 @@ impl JsBigInt { pub fn get_u128(&mut self) -> Result<(bool, u128, bool)> { let (signed, words) = self.get_words()?; - let high_part = words.first().copied().unwrap_or(0).to_le_bytes(); - let low_part = words.get(1).copied().unwrap_or(0).to_le_bytes(); + let low_part = words.first().copied().unwrap_or(0).to_ne_bytes(); + let high_part = words.get(1).copied().unwrap_or(0).to_ne_bytes(); - let mut val = [0_u8; std::mem::size_of::()]; - - let (high_val, low_val) = val.split_at_mut(low_part.len()); + let mut val = [0_u8; std::mem::size_of::()]; + let high_val: &mut [u8]; + let low_val: &mut [u8]; + if cfg!(target_endian = "little") { + (low_val, high_val) = val.split_at_mut(low_part.len()); + } else { + (high_val, low_val) = val.split_at_mut(low_part.len()); + } high_val.copy_from_slice(&high_part); low_val.copy_from_slice(&low_part); - let val = u128::from_le_bytes(val); + let val = u128::from_ne_bytes(val); + let len = words.len(); Ok((signed, val, len > 2)) diff --git a/crates/napi/src/js_values/ser.rs b/crates/napi/src/js_values/ser.rs index 9a53b2ba..42f4b3a1 100644 --- a/crates/napi/src/js_values/ser.rs +++ b/crates/napi/src/js_values/ser.rs @@ -1,6 +1,4 @@ use std::result::Result as StdResult; -#[cfg(feature = "napi6")] -use std::slice; use serde::{ser, Serialize, Serializer}; @@ -124,12 +122,7 @@ impl<'env> Serializer for Ser<'env> { #[cfg(feature = "napi6")] fn serialize_u128(self, v: u128) -> Result { - let words_ref = &v as *const _; - let words = unsafe { slice::from_raw_parts(words_ref as *const u64, 2) }; - self - .0 - .create_bigint_from_words(false, words.to_vec()) - .map(|v| v.raw) + self.0.create_bigint_from_u128(v).map(|v| v.raw) } #[cfg(all( @@ -147,12 +140,7 @@ impl<'env> Serializer for Ser<'env> { #[cfg(feature = "napi6")] fn serialize_i128(self, v: i128) -> Result { - let words_ref = &(v as u128) as *const _; - let words = unsafe { slice::from_raw_parts(words_ref as *const u64, 2) }; - self - .0 - .create_bigint_from_words(v < 0, words.to_vec()) - .map(|v| v.raw) + self.0.create_bigint_from_i128(v).map(|v| v.raw) } fn serialize_unit(self) -> Result {