mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: bind/call/apply 异步目标 TailCall 改走异步调用入口
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_builtins"
|
name = "oxide_builtins"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_bytecode"
|
name = "oxide_bytecode"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cfg"
|
name = "oxide_cfg"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_emit",
|
"oxide_emit",
|
||||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cli"
|
name = "oxide_cli"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_code_cache"
|
name = "oxide_code_cache"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lru",
|
"lru",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_compiler"
|
name = "oxide_compiler"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_dce"
|
name = "oxide_dce"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_emit"
|
name = "oxide_emit"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_engine"
|
name = "oxide_engine"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_ir"
|
name = "oxide_ir"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_kernel"
|
name = "oxide_kernel"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_liveness"
|
name = "oxide_liveness"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_log"
|
name = "oxide_log"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_parser"
|
name = "oxide_parser"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_regalloc"
|
name = "oxide_regalloc"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_runtime_api"
|
name = "oxide_runtime_api"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_test262"
|
name = "oxide_test262"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_types"
|
name = "oxide_types"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.13.11"
|
version = "0.13.12"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ impl Vm {
|
|||||||
/// 2. `build_native_args` 打包实参下标表。
|
/// 2. `build_native_args` 打包实参下标表。
|
||||||
/// 3. 经 `native_fn_ptr_to_fn` 取得函数项并执行;执行前后快照/恢复 `regs[254]`。
|
/// 3. 经 `native_fn_ptr_to_fn` 取得函数项并执行;执行前后快照/恢复 `regs[254]`。
|
||||||
/// 4. 按 `NativeResult` 三态回写:`Ok` 写 `regs[0]`;`Err` 以原始值走 `unwind`;
|
/// 4. 按 `NativeResult` 三态回写:`Ok` 写 `regs[0]`;`Err` 以原始值走 `unwind`;
|
||||||
/// `TailCall` 目标为 native 时同步调用,否则压字节码帧。
|
/// `TailCall` 目标为 native 时同步调用,异步与生成器字节码目标走内联入口,
|
||||||
|
/// 其余压字节码帧。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 调用方须保证 `obj` 已是 native 函数:`native_fn()` 为空时此处 unwrap 失败。
|
/// - 调用方须保证 `obj` 已是 native 函数:`native_fn()` 为空时此处 unwrap 失败。
|
||||||
@@ -129,6 +130,18 @@ impl Vm {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 异步与生成器目标:走内联入口(内部创建异步 Promise 或生成器迭代器对象),
|
||||||
|
// 结果写结果槽,不压同步帧。
|
||||||
|
if obj.sub_module_index() > 0 {
|
||||||
|
let sub = self.callee_module(obj);
|
||||||
|
if matches!(sub, Some(m) if m.is_async || m.is_generator) {
|
||||||
|
self.constructing_native = false;
|
||||||
|
let result = self.call_bytecode_function_inline(callee, obj, this, &args)?;
|
||||||
|
self.regs[0] = result;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return self.raise_type_error("CALL target is not callable");
|
return self.raise_type_error("CALL target is not callable");
|
||||||
|
|||||||
@@ -386,3 +386,67 @@ fn bound_function_length_name_pins() {
|
|||||||
let result = eval(&mut vm, "function target() {} target.bind().bind().name").unwrap();
|
let result = eval(&mut vm, "function target() {} target.bind().bind().name").unwrap();
|
||||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "bound bound target");
|
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "bound bound target");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 执行源码并取顶层结果;Promise 结果 drain 到 settled 值(口径与 async_tests.rs 一致)。
|
||||||
|
fn eval_drain(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||||
|
vm.set_compiler_service(Arc::new(DefaultCompilerService));
|
||||||
|
let result = eval(vm, source)?;
|
||||||
|
if result.is_object() {
|
||||||
|
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||||
|
if obj.is_promise_obj() {
|
||||||
|
match oxide_vm::promise::promise_settled_value(obj) {
|
||||||
|
Some((true, v)) => return Ok(v),
|
||||||
|
Some((false, v)) => return Err(format!("rejected: {v}")),
|
||||||
|
None => return Err("promise pending".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_call_apply_bind_async_target_returns_promise() {
|
||||||
|
// call/apply/bind 作用于异步目标:结果是 Promise,drain 后的值与直接调用一致。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval_drain(&mut vm, "async function f(x){ return x; } f.call(null, 1)").unwrap();
|
||||||
|
assert_eq!(result, JsValue::int(1));
|
||||||
|
let result = eval_drain(&mut vm, "async function f(x){ return x; } f.apply(null, [2])").unwrap();
|
||||||
|
assert_eq!(result, JsValue::int(2));
|
||||||
|
let result = eval_drain(&mut vm, "async function f(x){ return x; } var b = f.bind(null); b(3)").unwrap();
|
||||||
|
assert_eq!(result, JsValue::int(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_call_async_target_rejection_keeps_value() {
|
||||||
|
// 异步目标抛错:Promise 以原值拒绝,.then 的拒绝臂收到原值。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval_drain(
|
||||||
|
&mut vm,
|
||||||
|
"async function f(){ throw 42; } f.call(null).then(v => 'ok:'+v, e => 'err:'+e)",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "err:42");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_call_bind_generator_target_returns_iterator() {
|
||||||
|
// call/bind 作用于同步生成器目标:返回迭代器对象(next() 结果对象,非函数体返回值)。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
// call 结果是迭代器对象,不是函数体返回值 99。
|
||||||
|
let result = eval(&mut vm, "function* g(){ return 99; } typeof g.call(null)").unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "object");
|
||||||
|
// 迭代器首个 next() 返回 done: true(生成器未 yield 即 return)。
|
||||||
|
let result = eval(&mut vm, "function* g(){ return 99; } g.call(null).next().done").unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
// bind 作用于生成器目标:包装器调用同样返回迭代器对象。
|
||||||
|
let result = eval(&mut vm, "function* g(){ return 99; } typeof g.bind(null)()").unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "object");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_bind_async_generator_target_returns_iterator() {
|
||||||
|
// bind 作用于异步生成器目标:返回异步生成器迭代器对象。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "async function* g(){ return 99; } typeof g.bind(null)()").unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "object");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user