fix: preserve plain reference rebinding during read-only calls
This commit is contained in:
@@ -28,6 +28,9 @@ impl EndorStringObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorStringObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@@ -87,6 +90,9 @@ impl EndorDictObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorDictObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@@ -126,6 +132,9 @@ impl EndorCellObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorCellObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@@ -199,6 +208,9 @@ impl EndorFunctionObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorFunctionObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@@ -302,6 +314,9 @@ impl EndorBaseExceptionObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorBaseExceptionObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -174,6 +174,9 @@ impl EndorCodeObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorCodeObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -203,6 +203,9 @@ impl ContextNativeFunction {
|
||||
}
|
||||
|
||||
impl ObjectPayload for ContextNativeFunction {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -276,6 +276,9 @@ impl EndorNumberObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorNumberObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -120,6 +120,13 @@ pub trait ObjectPayload: Any + fmt::Debug + Send + Sync {
|
||||
/// object identity after replacing its host-owned target. Ordinary payloads
|
||||
/// return false and retain normal value assignment. Implementations must
|
||||
/// validate before mutation and must not add untraced managed-object edges.
|
||||
/// True only when legacy assign_from always returns false. Read-only
|
||||
/// callers can then rebind a local reference without attempting mutation.
|
||||
/// assignment_cell is checked first and remains a protected write protocol.
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn assign_from(&self, _source: &dyn ObjectPayload) -> Result<bool, VmError> {
|
||||
Ok(false)
|
||||
}
|
||||
@@ -141,6 +148,9 @@ pub trait ObjectPayload: Any + fmt::Debug + Send + Sync {
|
||||
pub struct Record;
|
||||
|
||||
impl ObjectPayload for Record {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@@ -180,6 +190,9 @@ impl EndorNativeFunctionObject {
|
||||
pub type NativeFunction = EndorNativeFunctionObject;
|
||||
|
||||
impl ObjectPayload for EndorNativeFunctionObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -72,13 +72,14 @@ impl ObjectStore {
|
||||
}
|
||||
|
||||
pub fn assign_from(&mut self, target: ObjectRef, source: ObjectRef) -> Result<bool, VmError> {
|
||||
self.heap.prepare_change(target)?;
|
||||
self.object(target)?;
|
||||
self.object(source)?;
|
||||
if let Some(cell) = self
|
||||
.object(target)?
|
||||
.payload()
|
||||
.assignment_cell(source, self)?
|
||||
{
|
||||
self.heap.prepare_change(target)?;
|
||||
// Replacing the Cell edge may otherwise reclaim a target which is
|
||||
// reachable only through the edge being removed.
|
||||
self.retain(target)?;
|
||||
@@ -89,6 +90,10 @@ impl ObjectStore {
|
||||
self.release(target)?;
|
||||
return result.map(|()| true);
|
||||
}
|
||||
if self.is_read_only() && self.object(target)?.payload().reference_assignment_only() {
|
||||
return Ok(false);
|
||||
}
|
||||
self.heap.prepare_change(target)?;
|
||||
let changed = self
|
||||
.object(target)?
|
||||
.payload()
|
||||
|
||||
@@ -50,6 +50,9 @@ impl EndorTypeObject {
|
||||
}
|
||||
|
||||
impl ObjectPayload for EndorTypeObject {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
@@ -462,6 +465,9 @@ struct BoundMethod {
|
||||
function: ObjectRef,
|
||||
}
|
||||
impl ObjectPayload for BoundMethod {
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ fn read_only_scopes_block_existing_container_and_type_writes_but_allow_fresh_res
|
||||
);
|
||||
let fresh = store.new_object().unwrap();
|
||||
store.set_attr(fresh, "value", objects::Value::Nil).unwrap();
|
||||
assert!(!store.assign_from(record, fresh).unwrap());
|
||||
let nested = store.begin_read_only();
|
||||
assert!(
|
||||
store
|
||||
|
||||
@@ -27,7 +27,7 @@ function 和每个对象参数在移交前取得根;VM 完成调用准备后
|
||||
|
||||
## 只读调用与读取依赖
|
||||
|
||||
Vm::call_read_only_with_limits 沿用显式帧与预算,返回拥有式结果及借用式读取对象身份列表。进入时现存对象的属性、载荷、容器、Cell、类型边与共享赋值写入均在 prepare_change 屏障前拒绝;调用内新分配的结果图可以正常构造。作用域正常返回或报错后恢复;这不提供 panic 恢复或外部 I/O 沙箱。
|
||||
Vm::call_read_only_with_limits 沿用显式帧与预算,返回拥有式结果及借用式读取对象身份列表。进入时现存对象的属性、载荷、容器、Cell、类型边与共享赋值写入均在 prepare_change 屏障前拒绝;调用内新分配的结果图可以正常构造。局部变量对普通引用的重新绑定仍可进行:已知无可变 legacy assign_from 的载荷声明 reference_assignment_only=true,共享 assignment_cell 写入仍先检查屏障;未知宿主载荷默认保守拒绝。作用域正常返回或报错后恢复;这不提供 panic 恢复或外部 I/O 沙箱。
|
||||
|
||||
ObjectStore 的 begin_read_only/end_read_only 提供同样的 LIFO 嵌套机制,is_read_only 供宿主协议检查。保护集合与读取集合不持有 GC 根,代际句柄避免槽位复用误判。读取是对象粒度;宿主须把借用身份转为版本依赖并验证存活,不能据此保活整个对象图。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user