@@ -297,7 +297,7 @@ public class JavaScriptEnvironment: ComponentBase {
297297 private var groups : [ String : ObjectGroup ] = [ : ]
298298
299299 // Producing generators, keyed on `type.group`
300- private var producingGenerators : [ String : EnvironmentValueGenerator ] = [ : ]
300+ private var producingGenerators : [ String : ( generator : EnvironmentValueGenerator , probability : Double ) ] = [ : ]
301301 private var producingMethods : [ ILType : [ ( group: String , method: String ) ] ] = [ : ]
302302 private var producingProperties : [ ILType : [ ( group: String , property: String ) ] ] = [ : ]
303303 private var subtypes : [ ILType : [ ILType ] ] = [ : ]
@@ -430,9 +430,23 @@ public class JavaScriptEnvironment: ComponentBase {
430430 registerTemporalFieldsObject ( . jsTemporalZonedDateTimeLikeObject, forWith: false , dateFields: true , timeFields: true , zonedFields: true )
431431 registerTemporalFieldsObject ( . jsTemporalZonedDateTimeLikeObjectForWith, forWith: true , dateFields: true , timeFields: true , zonedFields: true )
432432
433+ // This isn't a normal "temporal fields object" but is similar, and needs a similar producing generator
433434 registerObjectGroup ( . jsTemporalDurationLikeObject)
434435 addProducingGenerator ( forType: ObjectGroup . jsTemporalDurationLikeObject. instanceType, with: { b in b. createTemporalDurationFieldsObject ( ) } )
435436
437+ // Temporal types are produced by a large number of methods; which means findOrGenerateType(), when asked to produce
438+ // a Temporal type, will tend towards trying to call a method on another Temporal type, which needs more Temporal types,
439+ // leading to a large amount of code generated. We do wish to test these codepaths as well, but by and large we
440+ // just want a freshly generated type.
441+ addProducingGenerator ( forType: . jsTemporalInstant, with: { $0. constructTemporalInstant ( ) } , probability: 0.9 )
442+ addProducingGenerator ( forType: . jsTemporalDuration, with: { $0. constructTemporalDuration ( ) } , probability: 0.9 )
443+ addProducingGenerator ( forType: . jsTemporalPlainTime, with: { $0. constructTemporalTime ( ) } , probability: 0.9 )
444+ addProducingGenerator ( forType: . jsTemporalPlainYearMonth, with: { $0. constructTemporalYearMonth ( ) } , probability: 0.9 )
445+ addProducingGenerator ( forType: . jsTemporalPlainMonthDay, with: { $0. constructTemporalMonthDay ( ) } , probability: 0.9 )
446+ addProducingGenerator ( forType: . jsTemporalPlainDate, with: { $0. constructTemporalDate ( ) } , probability: 0.9 )
447+ addProducingGenerator ( forType: . jsTemporalPlainDateTime, with: { $0. constructTemporalDateTime ( ) } , probability: 0.9 )
448+ addProducingGenerator ( forType: . jsTemporalZonedDateTime, with: { $0. constructTemporalZonedDateTime ( ) } , probability: 0.9 )
449+
436450 // Register builtins that should be available for fuzzing.
437451 // Here it is easy to selectively disable/enable some APIs for fuzzing by
438452 // just commenting out the corresponding lines.
@@ -550,10 +564,18 @@ public class JavaScriptEnvironment: ComponentBase {
550564
551565 // Add a generator that produces an object of the provided `type`.
552566 //
553- // This is for groups that are never generated as return types of other objects; so we register
554- // a generator that can be called.
555- public func addProducingGenerator( forType type: ILType , with generator: @escaping EnvironmentValueGenerator ) {
556- producingGenerators [ type. group!] = generator
567+ // The probability is how often this generator should be called when this type is required.
568+ //
569+ // The default probability (1) is for groups that are never generated as return types of other objects.
570+ // Use a lower probability if there are other ways to generate the object.
571+ //
572+ // Note that Fuzzilli is able to discover ways to construct types on its own. There are two use cases for this:
573+ // - "Options bag" type objects where no JS API produces them, so we *must* run a producing generator
574+ // - Temporal objects: These can be obtained from the result of other API calls, however a
575+ // a lot of these API calls need more Temporal objects, leading to runaway recursion attempting
576+ // to generate a large number of Temporal objects. Instead, we bias heavily towards the producing generator.
577+ public func addProducingGenerator( forType type: ILType , with generator: @escaping EnvironmentValueGenerator , probability: Double = 1.0 ) {
578+ producingGenerators [ type. group!] = ( generator, probability)
557579 }
558580
559581 private func addProducingMethod( forType type: ILType , by method: String , on group: String ) {
@@ -724,7 +746,7 @@ public class JavaScriptEnvironment: ComponentBase {
724746
725747 // For ObjectGroups, get a generator that is registered as being able to produce this
726748 // ObjectGroup.
727- public func getProducingGenerator( ofType type: ILType ) -> EnvironmentValueGenerator ? {
749+ public func getProducingGenerator( ofType type: ILType ) -> ( generator : EnvironmentValueGenerator , probability : Double ) ? {
728750 type. group. flatMap { producingGenerators [ $0] }
729751 }
730752
0 commit comments