@@ -247,7 +247,8 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
247
247
/// Get a dynamic property on this Object by name. This is like
248
248
/// `get_property_local`, but it skips dynamic-dispatch TObject logic
249
249
/// and always gets a dynamic property on the base ScriptObject. If the
250
- /// property does not exist on the ScriptObject, this returns `None`.
250
+ /// object is sealed, or the dynamic property does not exist on the
251
+ /// ScriptObject, this returns `None`.
251
252
#[ no_dynamic]
252
253
fn get_dynamic_property ( self , local_name : AvmString < ' gc > ) -> Option < Value < ' gc > > {
253
254
use crate :: avm2:: object:: script_object:: maybe_int_property;
@@ -285,6 +286,14 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
285
286
/// Set a dynamic property on this Object by name. This is like
286
287
/// `set_property_local`, but it skips dynamic-dispatch TObject logic
287
288
/// and always sets a dynamic property on the base ScriptObject.
289
+ ///
290
+ /// Note that calling this method on a non-dynamic (sealed) object will
291
+ /// panic, as sealed objects cannot have dynamic properties set on them.
292
+ ///
293
+ /// Additionally, if the vtable of the object has the property `local_name`
294
+ /// in it, this method will still declare a dynamic property on the object
295
+ /// with the same name, so take care to only call this method on objects
296
+ /// that are known to not have the property `local_name` in their vtable.
288
297
#[ no_dynamic]
289
298
fn set_dynamic_property (
290
299
self ,
@@ -294,10 +303,13 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
294
303
) {
295
304
use crate :: avm2:: object:: script_object:: maybe_int_property;
296
305
306
+ let base = self . base ( ) ;
307
+ assert ! ( !base. is_sealed( ) ) ;
308
+
297
309
// See the comment in ScriptObjectWrapper::set_property_local
298
310
let key = maybe_int_property ( local_name) ;
299
311
300
- self . base ( ) . values_mut ( mc) . insert ( key, value) ;
312
+ base. values_mut ( mc) . insert ( key, value) ;
301
313
}
302
314
303
315
/// Purely an optimization for "array-like" access. This should return
@@ -368,12 +380,18 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
368
380
/// Delete a dynamic property on this Object by name. This is like
369
381
/// `delete_property_local`, but it skips dynamic-dispatch TObject logic
370
382
/// and always tries to delete a dynamic property on the base ScriptObject.
383
+ ///
384
+ /// This method will panic when called on a non-dynamic (sealed) object, as
385
+ /// sealed objects don't have dynamic properties to delete anyway.
371
386
#[ no_dynamic]
372
387
fn delete_dynamic_property ( self , name : AvmString < ' gc > , mc : & Mutation < ' gc > ) {
373
388
use crate :: avm2:: object:: script_object:: maybe_int_property;
374
389
390
+ let base = self . base ( ) ;
391
+ assert ! ( !base. is_sealed( ) ) ;
392
+
375
393
let key = maybe_int_property ( name) ;
376
- self . base ( ) . values_mut ( mc) . remove ( & key) ;
394
+ base. values_mut ( mc) . remove ( & key) ;
377
395
}
378
396
379
397
/// Retrieve a slot by its index.
0 commit comments