feat: 支持位运算字节码与 ToInt32/ToUint32

This commit is contained in:
爱特每羊队
2026-06-09 14:42:58 +08:00
parent f54383ef63
commit ad8e870997
9 changed files with 347 additions and 1 deletions
+17
View File
@@ -34,6 +34,23 @@ pub fn to_number(val: JsValue, string_forge: &StringForge) -> f64 {
f64::NAN
}
pub fn to_uint32(val: JsValue, string_forge: &StringForge) -> u32 {
let n = to_number(val, string_forge);
if n == 0.0 || !n.is_finite() {
return 0;
}
n.trunc().rem_euclid(4_294_967_296.0) as u32
}
pub fn to_int32(val: JsValue, string_forge: &StringForge) -> i32 {
let int = to_uint32(val, string_forge);
if int > i32::MAX as u32 {
(int as i64 - 4_294_967_296i64) as i32
} else {
int as i32
}
}
pub fn to_string(string_forge: &StringForge, val: JsValue) -> String {
if val.is_int() {
return val.as_int().to_string();
+104
View File
@@ -0,0 +1,104 @@
use crate::coercion;
use crate::vm::Vm;
use oxide_types::value::JsValue;
impl Vm {
#[inline(always)]
fn write_ushr_result(&mut self, rd: usize, result: u32) {
if result <= i32::MAX as u32 {
self.regs[rd] = JsValue::int(result as i32);
} else {
self.regs[rd] = JsValue::float(result as f64);
}
}
#[inline(always)]
pub(crate) fn dispatch_bit_and(&mut self, rd: usize, a: usize, b: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(coercion::to_int32(self.regs[a], sf) & coercion::to_int32(self.regs[b], sf));
}
#[inline(always)]
pub(crate) fn dispatch_bit_or(&mut self, rd: usize, a: usize, b: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(coercion::to_int32(self.regs[a], sf) | coercion::to_int32(self.regs[b], sf));
}
#[inline(always)]
pub(crate) fn dispatch_bit_xor(&mut self, rd: usize, a: usize, b: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(coercion::to_int32(self.regs[a], sf) ^ coercion::to_int32(self.regs[b], sf));
}
#[inline(always)]
pub(crate) fn dispatch_shl(&mut self, rd: usize, a: usize, b: usize) {
let sf = self.kernel.string_forge().as_ref();
let lhs = coercion::to_int32(self.regs[a], sf);
let shift = coercion::to_uint32(self.regs[b], sf) & 0x1F;
self.regs[rd] = JsValue::int(lhs.wrapping_shl(shift));
}
#[inline(always)]
pub(crate) fn dispatch_shr(&mut self, rd: usize, a: usize, b: usize) {
let sf = self.kernel.string_forge().as_ref();
let lhs = coercion::to_int32(self.regs[a], sf);
let shift = coercion::to_uint32(self.regs[b], sf) & 0x1F;
self.regs[rd] = JsValue::int(lhs >> shift);
}
#[inline(always)]
pub(crate) fn dispatch_ushr(&mut self, rd: usize, a: usize, b: usize) {
let sf = self.kernel.string_forge().as_ref();
let lhs = coercion::to_uint32(self.regs[a], sf);
let shift = coercion::to_uint32(self.regs[b], sf) & 0x1F;
self.write_ushr_result(rd, lhs >> shift);
}
#[inline(always)]
pub(crate) fn dispatch_bit_not(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(!coercion::to_int32(self.regs[a], sf));
}
#[inline(always)]
pub(crate) fn dispatch_compound_bit_and(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(coercion::to_int32(self.regs[rd], sf) & coercion::to_int32(self.regs[a], sf));
}
#[inline(always)]
pub(crate) fn dispatch_compound_bit_or(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(coercion::to_int32(self.regs[rd], sf) | coercion::to_int32(self.regs[a], sf));
}
#[inline(always)]
pub(crate) fn dispatch_compound_bit_xor(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
self.regs[rd] = JsValue::int(coercion::to_int32(self.regs[rd], sf) ^ coercion::to_int32(self.regs[a], sf));
}
#[inline(always)]
pub(crate) fn dispatch_compound_shl(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
let lhs = coercion::to_int32(self.regs[rd], sf);
let shift = coercion::to_uint32(self.regs[a], sf) & 0x1F;
self.regs[rd] = JsValue::int(lhs.wrapping_shl(shift));
}
#[inline(always)]
pub(crate) fn dispatch_compound_shr(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
let lhs = coercion::to_int32(self.regs[rd], sf);
let shift = coercion::to_uint32(self.regs[a], sf) & 0x1F;
self.regs[rd] = JsValue::int(lhs >> shift);
}
#[inline(always)]
pub(crate) fn dispatch_compound_ushr(&mut self, rd: usize, a: usize) {
let sf = self.kernel.string_forge().as_ref();
let lhs = coercion::to_uint32(self.regs[rd], sf);
let shift = coercion::to_uint32(self.regs[a], sf) & 0x1F;
self.write_ushr_result(rd, lhs >> shift);
}
}
+1
View File
@@ -1,4 +1,5 @@
pub(crate) mod arithmetic;
pub(crate) mod bitwise;
pub(crate) mod call;
pub(crate) mod comparison;
pub(crate) mod control_flow;
+52
View File
@@ -657,6 +657,34 @@ impl Vm {
self.regs[rd] = JsValue::float(-v);
}
OpCode::BIT_AND => {
self.dispatch_bit_and(rd, a, b);
}
OpCode::BIT_OR => {
self.dispatch_bit_or(rd, a, b);
}
OpCode::BIT_XOR => {
self.dispatch_bit_xor(rd, a, b);
}
OpCode::SHL => {
self.dispatch_shl(rd, a, b);
}
OpCode::SHR => {
self.dispatch_shr(rd, a, b);
}
OpCode::USHR => {
self.dispatch_ushr(rd, a, b);
}
OpCode::BIT_NOT => {
self.dispatch_bit_not(rd, a);
}
OpCode::EQ => {
self.dispatch_eq(rd, a, b);
}
@@ -1277,6 +1305,30 @@ impl Vm {
self.regs[rd] = JsValue::float(l.powf(r));
}
OpCode::COMPOUND_AND => {
self.dispatch_compound_bit_and(rd, a);
}
OpCode::COMPOUND_OR => {
self.dispatch_compound_bit_or(rd, a);
}
OpCode::COMPOUND_XOR => {
self.dispatch_compound_bit_xor(rd, a);
}
OpCode::COMPOUND_SHL => {
self.dispatch_compound_shl(rd, a);
}
OpCode::COMPOUND_SHR => {
self.dispatch_compound_shr(rd, a);
}
OpCode::COMPOUND_USHR => {
self.dispatch_compound_ushr(rd, a);
}
OpCode::TYPEOF => {
self.dispatch_typeof(rd, a);
}
+50
View File
@@ -103,3 +103,53 @@ fn eval_compound_add_expr_value() {
fn eval_compound_undefined() {
assert_eq!(eval("var x; x+=1; x"), "NaN");
}
#[test]
fn eval_bitwise_direct_ops() {
assert_eq!(eval("5 & 3"), "1");
assert_eq!(eval("5 | 2"), "7");
assert_eq!(eval("5 ^ 1"), "4");
assert_eq!(eval("1 << 3"), "8");
assert_eq!(eval("-8 >> 1"), "-4");
assert_eq!(eval("-1 >>> 0"), "4294967295");
assert_eq!(eval("~0"), "-1");
}
#[test]
fn eval_bitwise_coercion() {
assert_eq!(eval("'3' | 0"), "3");
assert_eq!(eval("'x' | 0"), "0");
assert_eq!(eval("undefined | 0"), "0");
assert_eq!(eval("NaN | 0"), "0");
assert_eq!(eval("1.9 | 0"), "1");
assert_eq!(eval("-1.9 | 0"), "-1");
}
#[test]
fn eval_shift_masking() {
assert_eq!(eval("1 << 32"), "1");
assert_eq!(eval("1 << 33"), "2");
assert_eq!(eval("8 >> 33"), "4");
}
#[test]
fn eval_ushr_boundaries() {
assert_eq!(eval("2147483647 >>> 0"), "2147483647");
assert_eq!(eval("2147483648 >>> 0"), "2147483648");
assert_eq!(eval("-1 >>> 1"), "2147483647");
}
#[test]
fn eval_compound_bitwise_ops() {
assert_eq!(eval("var x=5; x &= 3; x"), "1");
assert_eq!(eval("var x=5; x |= 2; x"), "7");
assert_eq!(eval("var x=5; x ^= 1; x"), "4");
assert_eq!(eval("var x=1; x <<= 5; x"), "32");
assert_eq!(eval("var x=-8; x >>= 1; x"), "-4");
assert_eq!(eval("var x=-1; x >>>= 0; x"), "4294967295");
}
#[test]
fn eval_bitwise_in_control_flow() {
assert_eq!(eval("var x=3; if ((x & 1) == 1) { 7 } else { 9 }"), "7");
}
+23
View File
@@ -82,3 +82,26 @@ fn test_strict_equality_int_float_equal() {
fn test_strict_equality_null_undefined() {
assert!(!coercion::strict_equality(JsValue::null(), JsValue::undefined()));
}
#[test]
fn test_to_int32_and_to_uint32() {
let vm = Vm::new();
let sf = vm.kernel().string_forge().as_ref();
let string_three = {
let (idx, hash) = vm.kernel().string_forge().intern("3");
JsValue::string(idx, hash)
};
let string_bad = {
let (idx, hash) = vm.kernel().string_forge().intern("x");
JsValue::string(idx, hash)
};
assert_eq!(coercion::to_int32(string_three, sf), 3);
assert_eq!(coercion::to_int32(string_bad, sf), 0);
assert_eq!(coercion::to_int32(JsValue::undefined(), sf), 0);
assert_eq!(coercion::to_int32(JsValue::float(1.9), sf), 1);
assert_eq!(coercion::to_int32(JsValue::float(-1.9), sf), -1);
assert_eq!(coercion::to_int32(JsValue::float(f64::NAN), sf), 0);
assert_eq!(coercion::to_int32(JsValue::float(f64::INFINITY), sf), 0);
assert_eq!(coercion::to_uint32(JsValue::int(-1), sf), 4_294_967_295);
}