@@ -178,11 +178,6 @@ pub(crate) struct BuiltInConstructorWithPrototype<'ctx> {
178178 __proto__ : JsPrototype ,
179179 inherits : Option < JsObject > ,
180180 attributes : Attribute ,
181- /// If `Some`, the `constructor` property on the prototype will be installed
182- /// as a get/set accessor pair instead of as a writable data property.
183- /// This is needed by `Iterator.prototype.constructor` per the spec
184- /// (web-compat requirement).
185- constructor_accessor : Option < ( JsFunction , JsFunction ) > ,
186181}
187182
188183#[ allow( dead_code) ]
@@ -199,13 +194,6 @@ impl BuiltInConstructorWithPrototype<'_> {
199194 /// See [`BuiltInConstructorWithPrototype::build`].
200195 const OWN_PROTOTYPE_STORAGE_SLOTS : usize = 1 ;
201196
202- /// The number of storage slots properties that are always present in a
203- /// standard constructor's prototype object when `constructor` is installed
204- /// as a get/set **accessor** property (two slots: getter + setter).
205- ///
206- /// See [`BuiltInConstructorWithPrototype::constructor_accessor`].
207- const OWN_PROTOTYPE_STORAGE_SLOTS_ACCESSOR : usize = 2 ;
208-
209197 /// Specify how many arguments the constructor function takes.
210198 ///
211199 /// Default is `0`.
@@ -390,25 +378,6 @@ impl BuiltInConstructorWithPrototype<'_> {
390378 self
391379 }
392380
393- /// Installs `Iterator.prototype.constructor` (or any analogous property) as a
394- /// configurable, non-enumerable **accessor** descriptor instead of the default
395- /// writable data property.
396- ///
397- /// Per the [ECMAScript spec][spec], `Iterator.prototype.constructor` must be an
398- /// accessor for web-compatibility reasons: previously the property did not exist, so
399- /// making it a setter that ignores writes to the prototype avoids breaking existing code
400- /// that assigns `Iterator.prototype.constructor = ...`.
401- ///
402- /// When this method is called the `PROTOTYPE_STORAGE_SLOTS` constant on the
403- /// implementing built-in **must** account for two extra slots (getter + setter)
404- /// instead of the usual one slot for a data property.
405- ///
406- /// [spec]: https://tc39.es/ecma262/#sec-iterator.prototype.constructor
407- pub ( crate ) fn constructor_accessor ( mut self , get : JsFunction , set : JsFunction ) -> Self {
408- self . constructor_accessor = Some ( ( get, set) ) ;
409- self
410- }
411-
412381 #[ track_caller]
413382 pub ( crate ) fn build ( mut self ) {
414383 let length = self . length ;
@@ -418,52 +387,19 @@ impl BuiltInConstructorWithPrototype<'_> {
418387 self = self . static_property ( js_string ! ( "name" ) , name, Attribute :: CONFIGURABLE ) ;
419388 self = self . static_property ( PROTOTYPE , prototype, Attribute :: empty ( ) ) ;
420389
421- // Install the `constructor` property on the prototype — either as a writable
422- // data property (the common case) or as a get/set accessor (needed by
423- // `Iterator.prototype.constructor` for web-compat, see `constructor_accessor`).
424- if let Some ( ( get, set) ) = self . constructor_accessor . take ( ) {
425- // Accessor path: two storage slots (getter + setter). The `CONSTRUCTOR` key
426- // must NOT already be present (no duplicate insertion).
427- let mut attributes = SlotAttributes :: CONFIGURABLE ;
428- attributes. set ( SlotAttributes :: GET , true ) ;
429- attributes. set ( SlotAttributes :: SET , true ) ;
430- debug_assert ! (
431- !self
432- . prototype_property_table
433- . map
434- . contains_key( & CONSTRUCTOR . into( ) )
435- ) ;
436- self . prototype_property_table
437- . insert ( CONSTRUCTOR . into ( ) , attributes) ;
438- self . prototype_storage
439- . extend ( [ JsValue :: new ( get) , JsValue :: new ( set) ] ) ;
440- #[ cfg( debug_assertions) ]
441- assert ! (
442- self . prototype_storage. len( )
443- <= self . prototype_storage_slots_expected
444- + Self :: OWN_PROTOTYPE_STORAGE_SLOTS_ACCESSOR ,
445- "expected to allocate at most {} prototype storage slots, got {}. \
446- constant {}::PROTOTYPE_STORAGE_SLOTS may need to be adjusted",
447- self . prototype_storage_slots_expected,
448- self . prototype_storage. len( ) - Self :: OWN_PROTOTYPE_STORAGE_SLOTS_ACCESSOR ,
449- self . name. display_escaped( ) ,
450- ) ;
451- } else {
452- // Data property path (the default).
453- let attributes = self . attributes ;
454- let object = self . constructor . clone ( ) ;
455- self = self . property ( CONSTRUCTOR , object, attributes) ;
456- #[ cfg( debug_assertions) ]
457- assert ! (
458- self . prototype_storage. len( )
459- <= self . prototype_storage_slots_expected + Self :: OWN_PROTOTYPE_STORAGE_SLOTS ,
460- "expected to allocate at most {} prototype storage slots, got {}. \
390+ let attributes = self . attributes ;
391+ let object = self . constructor . clone ( ) ;
392+ self = self . property ( CONSTRUCTOR , object, attributes) ;
393+ #[ cfg( debug_assertions) ]
394+ assert ! (
395+ self . prototype_storage. len( )
396+ <= self . prototype_storage_slots_expected + Self :: OWN_PROTOTYPE_STORAGE_SLOTS ,
397+ "expected to allocate at most {} prototype storage slots, got {}. \
461398 constant {}::PROTOTYPE_STORAGE_SLOTS may need to be adjusted",
462- self . prototype_storage_slots_expected,
463- self . prototype_storage. len( ) - Self :: OWN_PROTOTYPE_STORAGE_SLOTS ,
464- self . name. display_escaped( ) ,
465- ) ;
466- }
399+ self . prototype_storage_slots_expected,
400+ self . prototype_storage. len( ) - Self :: OWN_PROTOTYPE_STORAGE_SLOTS ,
401+ self . name. display_escaped( ) ,
402+ ) ;
467403
468404 #[ cfg( debug_assertions) ]
469405 assert ! (
@@ -682,7 +618,6 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {
682618 __proto__ : Some ( realm. intrinsics ( ) . constructors ( ) . function ( ) . prototype ( ) ) ,
683619 inherits : Some ( realm. intrinsics ( ) . constructors ( ) . object ( ) . prototype ( ) ) ,
684620 attributes : Attribute :: WRITABLE | Attribute :: CONFIGURABLE | Attribute :: NON_ENUMERABLE ,
685- constructor_accessor : None ,
686621 }
687622 }
688623}
@@ -730,6 +665,36 @@ impl<T> BuiltInBuilder<'_, T> {
730665 self
731666 }
732667
668+ /// Adds a new accessor property to the builtin object.
669+ pub ( crate ) fn static_accessor < K > (
670+ self ,
671+ key : K ,
672+ get : Option < JsFunction > ,
673+ set : Option < JsFunction > ,
674+ attribute : Attribute ,
675+ ) -> Self
676+ where
677+ K : Into < PropertyKey > ,
678+ {
679+ let mut property = PropertyDescriptor :: builder ( )
680+ . enumerable ( attribute. enumerable ( ) )
681+ . configurable ( attribute. configurable ( ) ) ;
682+
683+ if let Some ( get) = get {
684+ property = property. get ( get) ;
685+ }
686+
687+ if let Some ( set) = set {
688+ property = property. set ( set) ;
689+ }
690+
691+ let key = key. into ( ) ;
692+
693+ self . object . insert ( key, property) ;
694+
695+ self
696+ }
697+
733698 /// Specify the `[[Prototype]]` internal field of the builtin object.
734699 ///
735700 /// Default is `Function.prototype` for constructors and `Object.prototype` for statics.
0 commit comments