mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: 三处手写压帧收敛单一入口并免实参堆 Vec 物化
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use crate::native::NativeFn;
|
use crate::native::NativeFn;
|
||||||
use crate::vm::{native_fn_ptr_to_fn, CallFrame, FrameContinuation, Vm};
|
use crate::vm::{native_fn_ptr_to_fn, FrameArgs, FrameContinuation, Vm};
|
||||||
use crate::{vm_debug, vm_trace};
|
use crate::{vm_debug, vm_trace};
|
||||||
use oxide_builtins::iterator::make_iterator_for_value;
|
use oxide_builtins::iterator::make_iterator_for_value;
|
||||||
use oxide_builtins::{builtins_debug, builtins_trace};
|
use oxide_builtins::{builtins_debug, builtins_trace};
|
||||||
@@ -7,7 +7,6 @@ use oxide_bytecode::opcode;
|
|||||||
use oxide_runtime_api::{to_boolean, NativeResult};
|
use oxide_runtime_api::{to_boolean, NativeResult};
|
||||||
use oxide_types::object::{Cell, JsObject, PropAttributes};
|
use oxide_types::object::{Cell, JsObject, PropAttributes};
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -90,7 +89,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
callee,
|
callee,
|
||||||
this,
|
this,
|
||||||
&args,
|
FrameArgs::Slice(&args),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
JsValue::undefined(),
|
JsValue::undefined(),
|
||||||
@@ -486,77 +485,21 @@ impl Vm {
|
|||||||
self.sub_modules.len()
|
self.sub_modules.len()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if self.frames.len() >= self.kernel_core.config.max_call_depth {
|
// 收敛到统一压帧入口:this = derived_this(super() 把实例交予父构造器),
|
||||||
return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded"));
|
// new.target 保持外层类;构造结果写回 regs[254]。
|
||||||
}
|
self.push_bytecode_frame(
|
||||||
|
super_ctor,
|
||||||
let sub_bytecode = Arc::clone(&self.sub_modules[sub_idx].bytecode);
|
derived_this,
|
||||||
let sub_n_args = self.sub_modules[sub_idx].n_args as usize;
|
FrameArgs::RegRange {
|
||||||
let sub_n_registers = self.sub_modules[sub_idx].n_registers;
|
first: first_arg_reg,
|
||||||
let sub_param_base = self.sub_modules[sub_idx].param_base as usize;
|
count: arg_count,
|
||||||
let caller_active_reg_limit = self.active_reg_limit.max(1);
|
},
|
||||||
let caller_reg_limit = self.call_window_limit(caller_active_reg_limit, call_window);
|
Some(254),
|
||||||
let saved_reg_offset = self.save_stack.len() as u32;
|
Some(derived_this),
|
||||||
self.save_stack.extend_from_slice(&self.regs[..caller_reg_limit as usize]);
|
new_target,
|
||||||
let saved_this = self.regs[254];
|
FrameContinuation::None,
|
||||||
let saved_new_target = self.regs[255];
|
call_window,
|
||||||
|
)?;
|
||||||
// 完整实参写入 spill 栈实参区(在帧的 spill 区之前),供 CREATE_ARGUMENTS 使用。
|
|
||||||
let args_base = self.spill_stack.len() as u32;
|
|
||||||
for i in 0..arg_count {
|
|
||||||
let src_reg = first_arg_reg.wrapping_add(i as u8) as usize;
|
|
||||||
self.spill_stack.push(self.regs[src_reg]);
|
|
||||||
}
|
|
||||||
let args_count = arg_count.min(u16::MAX as usize) as u16;
|
|
||||||
|
|
||||||
for i in 0..sub_n_args {
|
|
||||||
let src_reg = first_arg_reg.wrapping_add(i as u8) as usize;
|
|
||||||
self.regs[sub_param_base + i] = self.regs[src_reg];
|
|
||||||
}
|
|
||||||
self.regs[254] = derived_this;
|
|
||||||
self.regs[255] = new_target;
|
|
||||||
|
|
||||||
self.saved_bytecode_stack.push(std::mem::take(&mut self.bytecode));
|
|
||||||
self.saved_immutables_stack.push(self.active_immutables);
|
|
||||||
|
|
||||||
let function_name = self.sub_modules[sub_idx]
|
|
||||||
.function_name
|
|
||||||
.as_deref()
|
|
||||||
.map(|name| self.kernel_core.perm_interner().intern(name).0)
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
self.frames.push(CallFrame {
|
|
||||||
return_addr: self.pc,
|
|
||||||
function_name,
|
|
||||||
caller_reg_limit,
|
|
||||||
caller_active_reg_limit,
|
|
||||||
saved_reg_offset,
|
|
||||||
spill_offset: self.spill_stack.len() as u32,
|
|
||||||
arguments_base: args_base,
|
|
||||||
arguments_count: args_count,
|
|
||||||
saved_this,
|
|
||||||
saved_new_target,
|
|
||||||
callee: super_ctor,
|
|
||||||
construct_result_reg: Some(254),
|
|
||||||
constructed_this: Some(derived_this),
|
|
||||||
is_derived_constructor: super_obj.is_derived_constructor(),
|
|
||||||
continuation: FrameContinuation::None,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.bytecode = sub_bytecode;
|
|
||||||
let subs = Arc::clone(&self.sub_modules);
|
|
||||||
self.activate_immutables(sub_idx, &subs[sub_idx].constants);
|
|
||||||
self.cell_stack.push(Vec::with_capacity(subs[sub_idx].cells_needed as usize));
|
|
||||||
for (name, reg) in &self.sub_modules[sub_idx].builtin_reg_map.clone() {
|
|
||||||
let si = self.kernel_core.perm_interner().intern(name.as_str()).0;
|
|
||||||
let global = self.session.global_object();
|
|
||||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
|
|
||||||
self.regs[*reg as usize] = global.get_prop_at(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.active_reg_limit = sub_n_registers.max(1);
|
|
||||||
self.pc = 0;
|
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else {
|
} else {
|
||||||
self.raise_error_kind("TypeError", "super constructor is not callable")?;
|
self.raise_error_kind("TypeError", "super constructor is not callable")?;
|
||||||
@@ -794,7 +737,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
callee,
|
callee,
|
||||||
this_value,
|
this_value,
|
||||||
&args,
|
FrameArgs::Slice(&args),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
JsValue::undefined(),
|
JsValue::undefined(),
|
||||||
@@ -901,7 +844,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
constructor,
|
constructor,
|
||||||
this_value,
|
this_value,
|
||||||
&args,
|
FrameArgs::Slice(&args),
|
||||||
Some(rd as u8),
|
Some(rd as u8),
|
||||||
Some(new_obj_val),
|
Some(new_obj_val),
|
||||||
constructor,
|
constructor,
|
||||||
@@ -989,7 +932,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
super_ctor,
|
super_ctor,
|
||||||
derived_this,
|
derived_this,
|
||||||
&args,
|
FrameArgs::Slice(&args),
|
||||||
Some(254),
|
Some(254),
|
||||||
Some(derived_this),
|
Some(derived_this),
|
||||||
new_target,
|
new_target,
|
||||||
|
|||||||
@@ -194,8 +194,8 @@ impl Vm {
|
|||||||
/// 附 length / callee 属性。第一版为 unmapped(非严格)语义,索引与形参不同步。
|
/// 附 length / callee 属性。第一版为 unmapped(非严格)语义,索引与形参不同步。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 实参区由 `push_bytecode_frame` / `dispatch_super_call` / `dispatch_new_expression`
|
/// - 实参区由统一压帧入口 `push_bytecode_frame` 在推帧时写入 spill 栈;
|
||||||
/// 在推帧时写入 spill 栈;frames 为空(inline 同步调用)时读 `inline_args_*`。
|
/// frames 为空(inline 同步调用)时读 `inline_args_*`。
|
||||||
/// - 索引属性用 shape 槽存储(普通对象),length/callee 为不可枚举数据属性。
|
/// - 索引属性用 shape 槽存储(普通对象),length/callee 为不可枚举数据属性。
|
||||||
pub(crate) fn dispatch_create_arguments(&mut self, rd: usize) -> Result<(), String> {
|
pub(crate) fn dispatch_create_arguments(&mut self, rd: usize) -> Result<(), String> {
|
||||||
let (base, count) = match self.frames.last() {
|
let (base, count) = match self.frames.last() {
|
||||||
@@ -244,7 +244,7 @@ impl Vm {
|
|||||||
/// 2. 实参个数超出固定形参数的部分作为数组元素写入。
|
/// 2. 实参个数超出固定形参数的部分作为数组元素写入。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 实参来源与 CREATE_ARGUMENTS 相同(push_bytecode_frame / inline 路径写入 spill 栈)。
|
/// - 实参来源与 CREATE_ARGUMENTS 相同(统一压帧入口 `push_bytecode_frame` 写入 spill 栈)。
|
||||||
/// - 实参不足 `fixed_count` 时数组为空。
|
/// - 实参不足 `fixed_count` 时数组为空。
|
||||||
pub(crate) fn dispatch_create_rest_array(&mut self, rd: usize, fixed_count: usize) -> Result<(), String> {
|
pub(crate) fn dispatch_create_rest_array(&mut self, rd: usize, fixed_count: usize) -> Result<(), String> {
|
||||||
let (base, count) = match self.frames.last() {
|
let (base, count) = match self.frames.last() {
|
||||||
|
|||||||
@@ -163,6 +163,42 @@ pub enum FrameContinuation {
|
|||||||
AccessorSet,
|
AccessorSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 压帧实参来源:已物化切片或寄存器连续区间。
|
||||||
|
///
|
||||||
|
/// `RegRange` 直接引用调用方寄存器文件(CALL/NEW/SUPER_CALL 的实参在寄存器中
|
||||||
|
/// 天然连续排列),免去临时堆 `Vec<JsValue>` 物化,每次调用省 1 次分配/释放。
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) enum FrameArgs<'a> {
|
||||||
|
/// 已物化实参:spread 展开、TailCall、accessor 与初始执行路径。
|
||||||
|
Slice(&'a [JsValue]),
|
||||||
|
/// 寄存器连续区间 `regs[first .. first+count)`。
|
||||||
|
RegRange { first: u8, count: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameArgs<'_> {
|
||||||
|
/// 实参总数。
|
||||||
|
pub(crate) fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
FrameArgs::Slice(s) => s.len(),
|
||||||
|
FrameArgs::RegRange { count, .. } => *count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 取第 `i` 个实参;超出实参范围返回 undefined(与切片 `get(i)` 语义一致)。
|
||||||
|
pub(crate) fn get(&self, vm: &Vm, i: usize) -> JsValue {
|
||||||
|
match self {
|
||||||
|
FrameArgs::Slice(s) => s.get(i).copied().unwrap_or(JsValue::undefined()),
|
||||||
|
FrameArgs::RegRange { first, count } => {
|
||||||
|
if i < *count {
|
||||||
|
vm.regs[first.wrapping_add(i as u8) as usize]
|
||||||
|
} else {
|
||||||
|
JsValue::undefined()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 一次函数调用的调用帧:记录返回地址、调用方寄存器窗口与 `this`/`new.target`。
|
/// 一次函数调用的调用帧:记录返回地址、调用方寄存器窗口与 `this`/`new.target`。
|
||||||
///
|
///
|
||||||
/// 调用方寄存器窗口在 `save_stack` 中按 `saved_reg_offset` 保存,返回时由
|
/// 调用方寄存器窗口在 `save_stack` 中按 `saved_reg_offset` 保存,返回时由
|
||||||
@@ -1161,7 +1197,7 @@ impl Vm {
|
|||||||
|
|
||||||
#[expect(clippy::too_many_arguments)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub(crate) fn push_bytecode_frame(
|
pub(crate) fn push_bytecode_frame(
|
||||||
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], construct_result_reg: Option<u8>,
|
&mut self, callee: JsValue, this_value: JsValue, args: FrameArgs, construct_result_reg: Option<u8>,
|
||||||
constructed_this: Option<JsValue>, new_target: JsValue, continuation: FrameContinuation, call_window: u8,
|
constructed_this: Option<JsValue>, new_target: JsValue, continuation: FrameContinuation, call_window: u8,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
vm_trace!(
|
vm_trace!(
|
||||||
@@ -1205,7 +1241,7 @@ impl Vm {
|
|||||||
let saved_new_target = self.regs[255];
|
let saved_new_target = self.regs[255];
|
||||||
|
|
||||||
for i in 0..sub_n_args {
|
for i in 0..sub_n_args {
|
||||||
self.regs[sub_param_base + i] = args.get(i).copied().unwrap_or(JsValue::undefined());
|
self.regs[sub_param_base + i] = args.get(self, i);
|
||||||
}
|
}
|
||||||
self.regs[254] = if sub_is_arrow { obj.captured_this() } else { this_value };
|
self.regs[254] = if sub_is_arrow { obj.captured_this() } else { this_value };
|
||||||
self.regs[255] = new_target;
|
self.regs[255] = new_target;
|
||||||
@@ -1222,7 +1258,14 @@ impl Vm {
|
|||||||
// 完整实参写入 spill 栈实参区(在帧的 spill 区之前):CREATE_ARGUMENTS 据此
|
// 完整实参写入 spill 栈实参区(在帧的 spill 区之前):CREATE_ARGUMENTS 据此
|
||||||
// 构建 arguments 对象,帧恢复时随 spill 区截断一起丢弃。
|
// 构建 arguments 对象,帧恢复时随 spill 区截断一起丢弃。
|
||||||
let args_base = self.spill_stack.len() as u32;
|
let args_base = self.spill_stack.len() as u32;
|
||||||
self.spill_stack.extend_from_slice(args);
|
match args {
|
||||||
|
FrameArgs::Slice(s) => self.spill_stack.extend_from_slice(s),
|
||||||
|
FrameArgs::RegRange { first, count } => {
|
||||||
|
for i in 0..count {
|
||||||
|
self.spill_stack.push(self.regs[first.wrapping_add(i as u8) as usize]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let args_count = args.len().min(u16::MAX as usize) as u16;
|
let args_count = args.len().min(u16::MAX as usize) as u16;
|
||||||
|
|
||||||
self.frames.push(CallFrame {
|
self.frames.push(CallFrame {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::vm::{Completion, FrameContinuation, TryHandler, Vm};
|
use crate::vm::{Completion, FrameArgs, FrameContinuation, TryHandler, Vm};
|
||||||
use crate::vm_trace;
|
use crate::vm_trace;
|
||||||
use oxide_bytecode::opcode;
|
use oxide_bytecode::opcode;
|
||||||
use oxide_types::object::PropAttributes;
|
use oxide_types::object::PropAttributes;
|
||||||
@@ -34,35 +34,39 @@ impl Vm {
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else if obj.sub_module_index() > 0 {
|
} else if obj.sub_module_index() > 0 {
|
||||||
let sub_idx = obj.sub_module_index() as usize;
|
let sub_idx = obj.sub_module_index() as usize;
|
||||||
let args: Vec<JsValue> = (0..arg_count)
|
let this_value = self.regs[this_reg as usize];
|
||||||
.map(|i| self.regs[first_arg_reg.wrapping_add(i as u8) as usize])
|
let is_generator = sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_generator;
|
||||||
.collect();
|
let is_async = sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_async;
|
||||||
// 异步生成器函数调用返回异步生成器迭代器对象。
|
// 生成器/异步路径需把实参物化存进状态盒;普通字节码调用直接
|
||||||
if sub_idx < self.sub_modules.len()
|
// 引用寄存器连续区间,免临时堆 Vec(每次调用省 1 次分配)。
|
||||||
&& self.sub_modules[sub_idx].is_generator
|
if is_generator || is_async {
|
||||||
&& self.sub_modules[sub_idx].is_async
|
let args: Vec<JsValue> = (0..arg_count)
|
||||||
{
|
.map(|i| self.regs[first_arg_reg.wrapping_add(i as u8) as usize])
|
||||||
let gen =
|
.collect();
|
||||||
self.create_async_generator_object(callee, self.regs[this_reg as usize], &args)?;
|
// 异步生成器函数调用返回异步生成器迭代器对象。
|
||||||
self.regs[0] = gen;
|
if is_generator && is_async {
|
||||||
return Ok(false);
|
let gen = self.create_async_generator_object(callee, this_value, &args)?;
|
||||||
}
|
self.regs[0] = gen;
|
||||||
// 生成器函数调用返回迭代器对象,不执行函数体。
|
return Ok(false);
|
||||||
if sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_generator {
|
}
|
||||||
let gen = self.create_generator_object(callee, self.regs[this_reg as usize], &args)?;
|
// 生成器函数调用返回迭代器对象,不执行函数体。
|
||||||
self.regs[0] = gen;
|
if is_generator {
|
||||||
return Ok(false);
|
let gen = self.create_generator_object(callee, this_value, &args)?;
|
||||||
}
|
self.regs[0] = gen;
|
||||||
// 异步函数调用返回 capability promise,立即同步执行 body 到首个 await。
|
return Ok(false);
|
||||||
if sub_idx < self.sub_modules.len() && self.sub_modules[sub_idx].is_async {
|
}
|
||||||
let promise = self.create_async_object(callee, self.regs[this_reg as usize], &args)?;
|
// 异步函数调用返回 capability promise,立即同步执行 body 到首个 await。
|
||||||
|
let promise = self.create_async_object(callee, this_value, &args)?;
|
||||||
self.regs[0] = promise;
|
self.regs[0] = promise;
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
callee,
|
callee,
|
||||||
self.regs[this_reg as usize],
|
this_value,
|
||||||
&args,
|
FrameArgs::RegRange {
|
||||||
|
first: first_arg_reg,
|
||||||
|
count: arg_count,
|
||||||
|
},
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
JsValue::undefined(),
|
JsValue::undefined(),
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::native::NativeFn;
|
use crate::native::NativeFn;
|
||||||
use crate::vm::{native_fn_ptr_to_fn, CallFrame, ForInIter, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH};
|
use crate::vm::{native_fn_ptr_to_fn, ForInIter, FrameArgs, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH};
|
||||||
use crate::vm_trace;
|
use crate::vm_trace;
|
||||||
use oxide_runtime_api::{to_boolean, to_string_full, NativeResult, VmHost};
|
use oxide_runtime_api::{to_boolean, to_string_full, NativeResult, VmHost};
|
||||||
use oxide_types::object::{JsObject, PropAttributes};
|
use oxide_types::object::{JsObject, PropAttributes};
|
||||||
@@ -106,81 +104,27 @@ impl Vm {
|
|||||||
return self.raise_type_error("g is not a constructor").map(|_| true);
|
return self.raise_type_error("g is not a constructor").map(|_| true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.frames.len() >= self.kernel_core.config.max_call_depth {
|
|
||||||
return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_obj_val = JsValue::object(new_obj as *mut u8);
|
let new_obj_val = JsValue::object(new_obj as *mut u8);
|
||||||
let sub_bytecode = Arc::clone(&self.sub_modules[sub_idx].bytecode);
|
// 收敛到统一压帧入口:derived 构造器在 super() 前 this 为 undefined,
|
||||||
let sub_n_args = self.sub_modules[sub_idx].n_args as usize;
|
// 基类构造器 this = 新对象;new.target = 构造器本身。
|
||||||
let sub_n_registers = self.sub_modules[sub_idx].n_registers;
|
let this_value = if ctor_obj.is_derived_constructor() {
|
||||||
let sub_param_base = self.sub_modules[sub_idx].param_base as usize;
|
|
||||||
let caller_active_reg_limit = self.active_reg_limit.max(1);
|
|
||||||
let caller_reg_limit = self.call_window_limit(caller_active_reg_limit, call_window);
|
|
||||||
let saved_reg_offset = self.save_stack.len() as u32;
|
|
||||||
self.save_stack.extend_from_slice(&self.regs[..caller_reg_limit as usize]);
|
|
||||||
let saved_this = self.regs[254];
|
|
||||||
let saved_new_target = self.regs[255];
|
|
||||||
|
|
||||||
// 完整实参写入 spill 栈实参区(在帧的 spill 区之前),供 CREATE_ARGUMENTS 使用。
|
|
||||||
let args_base = self.spill_stack.len() as u32;
|
|
||||||
for i in 0..arg_count {
|
|
||||||
let src_reg = first_arg_reg.wrapping_add(i as u8) as usize;
|
|
||||||
self.spill_stack.push(self.regs[src_reg]);
|
|
||||||
}
|
|
||||||
let args_count = arg_count.min(u16::MAX as usize) as u16;
|
|
||||||
|
|
||||||
for i in 0..sub_n_args {
|
|
||||||
let src_reg = first_arg_reg.wrapping_add(i as u8) as usize;
|
|
||||||
self.regs[sub_param_base + i] = self.regs[src_reg];
|
|
||||||
}
|
|
||||||
self.regs[254] = if ctor_obj.is_derived_constructor() {
|
|
||||||
JsValue::undefined()
|
JsValue::undefined()
|
||||||
} else {
|
} else {
|
||||||
new_obj_val
|
new_obj_val
|
||||||
};
|
};
|
||||||
self.regs[255] = constructor;
|
self.push_bytecode_frame(
|
||||||
|
constructor,
|
||||||
self.saved_bytecode_stack.push(std::mem::take(&mut self.bytecode));
|
this_value,
|
||||||
self.saved_immutables_stack.push(self.active_immutables);
|
FrameArgs::RegRange {
|
||||||
|
first: first_arg_reg,
|
||||||
self.frames.push(CallFrame {
|
count: arg_count,
|
||||||
return_addr: self.pc,
|
},
|
||||||
function_name: self.sub_modules[sub_idx]
|
Some(rd as u8),
|
||||||
.function_name
|
Some(new_obj_val),
|
||||||
.as_deref()
|
constructor,
|
||||||
.map(|name| self.kernel_core.perm_interner().intern(name).0)
|
FrameContinuation::None,
|
||||||
.unwrap_or(0),
|
call_window,
|
||||||
caller_reg_limit,
|
)?;
|
||||||
caller_active_reg_limit,
|
|
||||||
saved_reg_offset,
|
|
||||||
spill_offset: self.spill_stack.len() as u32,
|
|
||||||
arguments_base: args_base,
|
|
||||||
arguments_count: args_count,
|
|
||||||
saved_this,
|
|
||||||
saved_new_target,
|
|
||||||
callee: constructor,
|
|
||||||
construct_result_reg: Some(rd as u8),
|
|
||||||
constructed_this: Some(new_obj_val),
|
|
||||||
is_derived_constructor: ctor_obj.is_derived_constructor(),
|
|
||||||
continuation: FrameContinuation::None,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.bytecode = sub_bytecode;
|
|
||||||
let subs = Arc::clone(&self.sub_modules);
|
|
||||||
self.activate_immutables(sub_idx, &subs[sub_idx].constants);
|
|
||||||
self.cell_stack.push(Vec::with_capacity(subs[sub_idx].cells_needed as usize));
|
|
||||||
|
|
||||||
for (name, reg) in &self.sub_modules[sub_idx].builtin_reg_map {
|
|
||||||
let si = self.kernel_core.perm_interner().intern(name.as_str()).0;
|
|
||||||
let global = self.session.global_object();
|
|
||||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
|
|
||||||
self.regs[*reg as usize] = global.get_prop_at(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.active_reg_limit = sub_n_registers.max(1);
|
|
||||||
self.pc = 0;
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
let error =
|
let error =
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::vm::{FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH};
|
use crate::vm::{FrameArgs, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH};
|
||||||
use crate::{ic_trace, vm_trace};
|
use crate::{ic_trace, vm_trace};
|
||||||
use oxide_kernel::prop_forge::PropTemplate;
|
use oxide_kernel::prop_forge::PropTemplate;
|
||||||
use oxide_runtime_api as coercion;
|
use oxide_runtime_api as coercion;
|
||||||
@@ -126,7 +126,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
getter,
|
getter,
|
||||||
receiver,
|
receiver,
|
||||||
&[],
|
FrameArgs::Slice(&[]),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
JsValue::undefined(),
|
JsValue::undefined(),
|
||||||
@@ -326,7 +326,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
setter,
|
setter,
|
||||||
receiver,
|
receiver,
|
||||||
&[val],
|
FrameArgs::Slice(&[val]),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
JsValue::undefined(),
|
JsValue::undefined(),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::sync::{Arc, OnceLock};
|
|||||||
|
|
||||||
use oxide_bytecode::module::CompiledModule;
|
use oxide_bytecode::module::CompiledModule;
|
||||||
|
|
||||||
use crate::vm::{CallFrame, FrameContinuation, InlineSyncState, Vm};
|
use crate::vm::{CallFrame, FrameArgs, FrameContinuation, InlineSyncState, Vm};
|
||||||
use crate::{vm_debug, vm_info, vm_trace, vm_warn};
|
use crate::{vm_debug, vm_info, vm_trace, vm_warn};
|
||||||
use oxide_types::object::JsObject;
|
use oxide_types::object::JsObject;
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
@@ -205,7 +205,7 @@ impl Vm {
|
|||||||
self.push_bytecode_frame(
|
self.push_bytecode_frame(
|
||||||
callee,
|
callee,
|
||||||
this_value,
|
this_value,
|
||||||
args,
|
FrameArgs::Slice(args),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
JsValue::undefined(),
|
JsValue::undefined(),
|
||||||
|
|||||||
Reference in New Issue
Block a user