From 125b91ddae7024b7e986701786d18b2175b4440c Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 8 Jun 2026 07:47:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E8=BF=9B=E4=B8=80=E6=AD=A5?= =?UTF-8?q?=E6=8B=86=E5=88=86=E5=87=BD=E6=95=B0=E6=89=A7=E8=A1=8C=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BB=A5=E7=AE=80=E5=8C=96=E4=B8=BB=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/dispatch/arithmetic.rs | 22 +- crates/oxide_vm/src/dispatch/comparison.rs | 78 ++++- crates/oxide_vm/src/dispatch/control_flow.rs | 32 +- crates/oxide_vm/src/dispatch/misc.rs | 41 ++- crates/oxide_vm/src/vm.rs | 343 ++----------------- 5 files changed, 189 insertions(+), 327 deletions(-) diff --git a/crates/oxide_vm/src/dispatch/arithmetic.rs b/crates/oxide_vm/src/dispatch/arithmetic.rs index 0e9d58a1..d8e449bc 100644 --- a/crates/oxide_vm/src/dispatch/arithmetic.rs +++ b/crates/oxide_vm/src/dispatch/arithmetic.rs @@ -1 +1,21 @@ -// dispatch helper functions extracted from vm.rs +use crate::coercion; +use crate::vm::Vm; +use oxide_types::value::JsValue; + +impl Vm { + #[inline(always)] + pub(crate) fn dispatch_add(&mut self, rd: usize, a: usize, b: usize) { + let lhs = self.regs[a]; + let rhs = self.regs[b]; + if lhs.is_string() || rhs.is_string() { + let ls = coercion::to_string(self.kernel.string_forge().as_ref(), lhs); + let rs = coercion::to_string(self.kernel.string_forge().as_ref(), rhs); + let concat = format!("{ls}{rs}"); + self.regs[rd] = self.intern(&concat); + } else { + let ln = coercion::to_number(lhs, self.kernel.string_forge().as_ref()); + let rn = coercion::to_number(rhs, self.kernel.string_forge().as_ref()); + self.regs[rd] = JsValue::float(ln + rn); + } + } +} diff --git a/crates/oxide_vm/src/dispatch/comparison.rs b/crates/oxide_vm/src/dispatch/comparison.rs index 0e9d58a1..b2c40699 100644 --- a/crates/oxide_vm/src/dispatch/comparison.rs +++ b/crates/oxide_vm/src/dispatch/comparison.rs @@ -1 +1,77 @@ -// dispatch helper functions extracted from vm.rs +use crate::coercion; +use crate::vm::Vm; +use oxide_types::value::JsValue; + +impl Vm { + #[inline(always)] + pub(crate) fn dispatch_eq(&mut self, rd: usize, a: usize, b: usize) { + let eq = coercion::abstract_eq( + self.regs[a], + self.regs[b], + self.kernel.string_forge().as_ref(), + ); + self.regs[rd] = JsValue::bool(eq); + } + + #[inline(always)] + pub(crate) fn dispatch_neq(&mut self, rd: usize, a: usize, b: usize) { + let ne = !coercion::abstract_eq( + self.regs[a], + self.regs[b], + self.kernel.string_forge().as_ref(), + ); + self.regs[rd] = JsValue::bool(ne); + } + + #[inline(always)] + pub(crate) fn dispatch_lt(&mut self, rd: usize, a: usize, b: usize) { + let rel = coercion::relational_compare( + self.kernel.string_forge().as_ref(), + self.regs[a], + self.regs[b], + ); + self.regs[rd] = JsValue::bool(rel.unwrap_or(false)); + } + + #[inline(always)] + pub(crate) fn dispatch_gt(&mut self, rd: usize, a: usize, b: usize) { + let rel = coercion::relational_compare( + self.kernel.string_forge().as_ref(), + self.regs[b], + self.regs[a], + ); + self.regs[rd] = JsValue::bool(rel.unwrap_or(false)); + } + + #[inline(always)] + pub(crate) fn dispatch_lte(&mut self, rd: usize, a: usize, b: usize) { + let rel = coercion::relational_compare( + self.kernel.string_forge().as_ref(), + self.regs[b], + self.regs[a], + ); + self.regs[rd] = JsValue::bool(!rel.unwrap_or(true)); + } + + #[inline(always)] + pub(crate) fn dispatch_gte(&mut self, rd: usize, a: usize, b: usize) { + let rel = coercion::relational_compare( + self.kernel.string_forge().as_ref(), + self.regs[a], + self.regs[b], + ); + self.regs[rd] = JsValue::bool(!rel.unwrap_or(true)); + } + + #[inline(always)] + pub(crate) fn dispatch_strict_eq(&mut self, rd: usize, a: usize, b: usize) { + let eq = coercion::strict_equality(self.regs[a], self.regs[b]); + self.regs[rd] = JsValue::bool(eq); + } + + #[inline(always)] + pub(crate) fn dispatch_strict_neq(&mut self, rd: usize, a: usize, b: usize) { + let ne = !coercion::strict_equality(self.regs[a], self.regs[b]); + self.regs[rd] = JsValue::bool(ne); + } +} diff --git a/crates/oxide_vm/src/dispatch/control_flow.rs b/crates/oxide_vm/src/dispatch/control_flow.rs index 0e9d58a1..66103847 100644 --- a/crates/oxide_vm/src/dispatch/control_flow.rs +++ b/crates/oxide_vm/src/dispatch/control_flow.rs @@ -1 +1,31 @@ -// dispatch helper functions extracted from vm.rs +use crate::coercion; +use crate::vm::Vm; +use oxide_types::value::JsValue; + +impl Vm { + #[inline(always)] + pub(crate) fn dispatch_and(&mut self, rd: usize, a: usize, b: usize) { + let val = self.regs[a]; + if coercion::to_boolean(val, self.kernel.string_forge().as_ref()) { + self.regs[rd] = self.regs[b]; + } else { + self.regs[rd] = val; + } + } + + #[inline(always)] + pub(crate) fn dispatch_or(&mut self, rd: usize, a: usize, b: usize) { + let val = self.regs[a]; + if coercion::to_boolean(val, self.kernel.string_forge().as_ref()) { + self.regs[rd] = val; + } else { + self.regs[rd] = self.regs[b]; + } + } + + #[inline(always)] + pub(crate) fn dispatch_not(&mut self, rd: usize, a: usize) { + let b = !coercion::to_boolean(self.regs[a], self.kernel.string_forge().as_ref()); + self.regs[rd] = JsValue::bool(b); + } +} diff --git a/crates/oxide_vm/src/dispatch/misc.rs b/crates/oxide_vm/src/dispatch/misc.rs index 0e9d58a1..43a86207 100644 --- a/crates/oxide_vm/src/dispatch/misc.rs +++ b/crates/oxide_vm/src/dispatch/misc.rs @@ -1 +1,40 @@ -// dispatch helper functions extracted from vm.rs +use crate::vm::Vm; + +impl Vm { + #[inline(always)] + pub(crate) fn dispatch_load_const(&mut self, rd: usize, instr: u32) -> Result<(), String> { + let idx = (instr >> 16) as usize; + if idx < self.constants.len() { + self.regs[rd] = self.constants[idx]; + Ok(()) + } else { + Err(format!("constant index {idx} out of bounds")) + } + } + + #[inline(always)] + pub(crate) fn dispatch_typeof(&mut self, rd: usize, a: usize) { + let val = self.regs[a]; + let result = if val.is_undefined() { + "undefined" + } else if val.is_null() { + "object" + } else if val.is_bool() { + "boolean" + } else if val.is_int() || val.is_double() { + "number" + } else if val.is_string() { + "string" + } else if val.is_object() { + let obj = unsafe { &*val.as_js_object_ptr() }; + if obj.is_function() { + "function" + } else { + "object" + } + } else { + "undefined" + }; + self.regs[rd] = self.intern(result); + } +} diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index af3fb52f..39c20bd7 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -521,27 +521,11 @@ impl Vm { OpCode::HALT => return Ok(self.regs[0]), OpCode::LOAD_CONST => { - let idx = opcode::imm16(instr) as usize; - if idx < self.constants.len() { - self.regs[rd] = self.constants[idx]; - } else { - return Err(format!("constant index {idx} out of bounds")); - } + self.dispatch_load_const(rd, instr)?; } OpCode::ADD => { - let lhs = self.regs[a]; - let rhs = self.regs[b]; - if lhs.is_string() || rhs.is_string() { - let ls = coercion::to_string(self.kernel.string_forge().as_ref(), lhs); - let rs = coercion::to_string(self.kernel.string_forge().as_ref(), rhs); - let concat = format!("{ls}{rs}"); - self.regs[rd] = self.intern(&concat); - } else { - let ln = coercion::to_number(lhs, self.kernel.string_forge().as_ref()); - let rn = coercion::to_number(rhs, self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::float(ln + rn); - } + self.dispatch_add(rd, a, b); } OpCode::SUB => { @@ -566,67 +550,35 @@ impl Vm { } OpCode::EQ => { - let eq = coercion::abstract_eq( - self.regs[a], - self.regs[b], - self.kernel.string_forge().as_ref(), - ); - self.regs[rd] = JsValue::bool(eq); + self.dispatch_eq(rd, a, b); } OpCode::NEQ => { - let ne = !coercion::abstract_eq( - self.regs[a], - self.regs[b], - self.kernel.string_forge().as_ref(), - ); - self.regs[rd] = JsValue::bool(ne); + self.dispatch_neq(rd, a, b); } OpCode::LT => { - let rel = coercion::relational_compare( - self.kernel.string_forge().as_ref(), - self.regs[a], - self.regs[b], - ); - self.regs[rd] = JsValue::bool(rel.unwrap_or(false)); + self.dispatch_lt(rd, a, b); } OpCode::GT => { - let rel = coercion::relational_compare( - self.kernel.string_forge().as_ref(), - self.regs[b], - self.regs[a], - ); - self.regs[rd] = JsValue::bool(rel.unwrap_or(false)); + self.dispatch_gt(rd, a, b); } OpCode::LTE => { - let rel = coercion::relational_compare( - self.kernel.string_forge().as_ref(), - self.regs[b], - self.regs[a], - ); - self.regs[rd] = JsValue::bool(!rel.unwrap_or(true)); + self.dispatch_lte(rd, a, b); } OpCode::GTE => { - let rel = coercion::relational_compare( - self.kernel.string_forge().as_ref(), - self.regs[a], - self.regs[b], - ); - self.regs[rd] = JsValue::bool(!rel.unwrap_or(true)); + self.dispatch_gte(rd, a, b); } OpCode::STRICT_EQ => { - let eq = coercion::strict_equality(self.regs[a], self.regs[b]); - self.regs[rd] = JsValue::bool(eq); + self.dispatch_strict_eq(rd, a, b); } OpCode::STRICT_NEQ => { - let ne = !coercion::strict_equality(self.regs[a], self.regs[b]); - self.regs[rd] = JsValue::bool(ne); + self.dispatch_strict_neq(rd, a, b); } OpCode::UNARY_PLUS => { @@ -1195,28 +1147,7 @@ impl Vm { } OpCode::TYPEOF => { - let val = self.regs[a]; - let result = if val.is_undefined() { - "undefined" - } else if val.is_null() { - "object" - } else if val.is_bool() { - "boolean" - } else if val.is_int() || val.is_double() { - "number" - } else if val.is_string() { - "string" - } else if val.is_object() { - let obj = unsafe { &*val.as_js_object_ptr() }; - if obj.is_function() { - "function" - } else { - "object" - } - } else { - "undefined" - }; - self.regs[rd] = self.intern(result); + self.dispatch_typeof(rd, a); } OpCode::VOID => { @@ -1240,21 +1171,15 @@ impl Vm { } OpCode::NOT => { - let cond = - coercion::to_boolean(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = JsValue::bool(!cond); + self.dispatch_not(rd, a); } OpCode::AND => { - let cond = - coercion::to_boolean(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = if cond { self.regs[b] } else { self.regs[a] }; + self.dispatch_and(rd, a, b); } OpCode::OR => { - let cond = - coercion::to_boolean(self.regs[a], self.kernel.string_forge().as_ref()); - self.regs[rd] = if cond { self.regs[a] } else { self.regs[b] }; + self.dispatch_or(rd, a, b); } OpCode::INC_PRE => { @@ -1430,45 +1355,7 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let rhs = self.regs[a]; let new_val = if prop_val.is_string() || rhs.is_string() { @@ -1493,45 +1380,7 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let rn = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); @@ -1547,45 +1396,7 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let rn = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); @@ -1601,45 +1412,7 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let rn = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); @@ -1655,45 +1428,7 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let rn = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref()); @@ -1709,45 +1444,7 @@ impl Vm { } let obj = unsafe { &mut *obj_ptr }; let prop_name_si = self.regs[b].as_string_index(); - let ext0 = self.bytecode[self.pc]; - let ext1 = self.bytecode[self.pc + 1]; - let ext2 = self.bytecode[self.pc + 2]; - self.pc += 3; - let cached_shape_id = ext0 & 0x00FF_FFFF; - let cached_ptr = ((ext2 as u64) << 32) | (ext1 as u64); - - let prop_val = if cached_shape_id != 0 - && cached_shape_id == obj.shape_id() - && cached_ptr != 0 - { - unsafe { *(cached_ptr as *const JsValue) } - } else if let Some(template) = - self.kernel.prop_forge().get_template(obj.shape_id()) - { - if let Some(ptr) = self.template_prop_ptr(obj, &template) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - unsafe { *ptr } - } else { - self.resolve_property(obj, prop_name_si) - .unwrap_or(JsValue::undefined()) - } - } else if let Some(val) = self.resolve_property(obj, prop_name_si) { - let pos = self - .kernel - .shape_forge() - .lookup_position(obj.shape_id(), prop_name_si) - .unwrap_or(0); - if let Some(ptr) = obj.prop_ptr_at(pos) { - self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; - self.bytecode[self.pc - 2] = ptr as u32; - self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; - } - val - } else { - JsValue::undefined() - }; + let prop_val = member_read_prop!(self, obj, prop_name_si); let ln = coercion::to_number(prop_val, self.kernel.string_forge().as_ref()); let rn = coercion::to_number(self.regs[a], self.kernel.string_forge().as_ref());