@@ -213,7 +213,9 @@ public class ProgramBuilder {
213213 /// Returns a random string value.
214214 public func randString( ) -> String {
215215 return withEqualProbability ( {
216- self . randPropertyForReading ( )
216+ self . randPropertyName ( )
217+ } , {
218+ self . randMethodName ( )
217219 } , {
218220 chooseUniform ( from: self . fuzzer. environment. interestingStrings)
219221 } , {
@@ -268,39 +270,56 @@ public class ProgramBuilder {
268270 return chooseUniform ( from: fuzzer. environment. builtins)
269271 }
270272
271- /// Returns the name of a random property suitable for read access.
272- public func randPropertyForReading( ) -> String {
273- return chooseUniform ( from: fuzzer. environment. readableProperties)
273+ /// Returns a random builtin property name.
274+ ///
275+ /// This will return a random name from the environment's list of builtin property names,
276+ /// i.e. a property that exists on (at least) one builtin object type.
277+ func randBuiltinPropertyName( ) -> String {
278+ return chooseUniform ( from: fuzzer. environment. builtinProperties)
274279 }
275280
276- /// Returns the name of a random property suitable for write access.
277- public func randPropertyForWriting( ) -> String {
278- return chooseUniform ( from: fuzzer. environment. writableProperties)
281+ /// Returns a random custom property name.
282+ ///
283+ /// This will select a random property from a (usually relatively small) set of custom property names defined by the environment.
284+ ///
285+ /// This should generally be used in one of two situations:
286+ /// 1. If a new property is added to an object.
287+ /// In that case, we prefer to add properties with custom names (e.g. ".a", ".b") instead of properties
288+ /// with names that exist in the environment (e.g. ".length", ".prototype"). This way, in the resulting code
289+ /// it will be fairly clear when a builtin property is accessed vs. a custom one. It also increases the chances
290+ /// of selecting an existing property when choosing a random property to access, see the next point.
291+ /// 2. If we have no static type information about the object we're accessing.
292+ /// In that case there is a higher chance of success when using the small set of custom property names
293+ /// instead of the much larger set of all property names that exist in the environment (or something else).
294+ public func randCustomPropertyName( ) -> String {
295+ return chooseUniform ( from: fuzzer. environment. customProperties)
279296 }
280297
281- /// Returns the name of a random property suitable for defining on new objects.
282- public func randPropertyForDefining( ) -> String {
283- if probability ( 0.5 ) {
284- return randPropertyForWriting ( )
285- } else {
286- return chooseUniform ( from: fuzzer. environment. customProperties)
287- }
298+ /// Returns either a builtin or a custom property name, with equal probability.
299+ public func randPropertyName( ) -> String {
300+ return probability ( 0.5 ) ? randBuiltinPropertyName ( ) : randCustomPropertyName ( )
288301 }
289302
290- /// Returns the name of a random method.
291- public func randMethod( ) -> String {
292- return chooseUniform ( from: fuzzer. environment. methods)
303+ /// Returns a random builtin method name.
304+ ///
305+ /// This will return a random name from the environment's list of builtin method names,
306+ /// i.e. a method that exists on (at least) one builtin object type.
307+ public func randBuiltinMethodName( ) -> String {
308+ return chooseUniform ( from: fuzzer. environment. builtinMethods)
293309 }
294310
295- /// Returns the name of a random method suitable for defining on new objects.
296- public func randMethodForDefining( ) -> String {
297- if probability ( 0.10 ) {
298- // TODO should there be a environment.writableMethods that includes the custom method
299- // names and things like valueOf, etc. Maybe it's ok since they are in writableProperties...
300- return randMethod ( )
301- } else {
302- return chooseUniform ( from: fuzzer. environment. customMethods)
303- }
311+ /// Returns a random custom method name.
312+ ///
313+ /// This will select a random method from a (usually relatively small) set of custom method names defined by the environment.
314+ ///
315+ /// See the comment for randCustomPropertyName() for when this should be used.
316+ public func randCustomMethodName( ) -> String {
317+ return chooseUniform ( from: fuzzer. environment. customMethods)
318+ }
319+
320+ /// Returns either a builtin or a custom method name, with equal probability.
321+ public func randMethodName( ) -> String {
322+ return probability ( 0.5 ) ? randBuiltinMethodName ( ) : randCustomMethodName ( )
304323 }
305324
306325
@@ -1357,6 +1376,8 @@ public class ProgramBuilder {
13571376 fileprivate var existingGetters : [ String ] = [ ]
13581377 fileprivate var existingSetters : [ String ] = [ ]
13591378
1379+ public fileprivate( set) var hasPrototype = false
1380+
13601381 fileprivate init ( in b: ProgramBuilder ) {
13611382 assert ( b. context. contains ( . objectLiteral) )
13621383 self . b = b
@@ -1389,26 +1410,36 @@ public class ProgramBuilder {
13891410 public func addProperty( _ name: String , as value: Variable ) {
13901411 b. emit ( ObjectLiteralAddProperty ( propertyName: name) , withInputs: [ value] )
13911412 }
1413+
13921414 public func addElement( _ index: Int64 , as value: Variable ) {
13931415 b. emit ( ObjectLiteralAddElement ( index: index) , withInputs: [ value] )
13941416 }
1417+
13951418 public func addComputedProperty( _ name: Variable , as value: Variable ) {
13961419 b. emit ( ObjectLiteralAddComputedProperty ( ) , withInputs: [ name, value] )
13971420 }
1421+
13981422 public func copyProperties( from obj: Variable ) {
13991423 b. emit ( ObjectLiteralCopyProperties ( ) , withInputs: [ obj] )
14001424 }
1425+
1426+ public func setPrototype( to proto: Variable ) {
1427+ b. emit ( ObjectLiteralSetPrototype ( ) , withInputs: [ proto] )
1428+ }
1429+
14011430 public func addMethod( _ name: String , with descriptor: SubroutineDescriptor , _ body: ( [ Variable ] ) -> ( ) ) {
14021431 b. setSignatureForNextFunction ( descriptor. signature)
14031432 let instr = b. emit ( BeginObjectLiteralMethod ( methodName: name, parameters: descriptor. parameters) )
14041433 body ( Array ( instr. innerOutputs) )
14051434 b. emit ( EndObjectLiteralMethod ( ) )
14061435 }
1436+
14071437 public func addGetter( for name: String , _ body: ( _ this: Variable ) -> ( ) ) {
14081438 let instr = b. emit ( BeginObjectLiteralGetter ( propertyName: name) )
14091439 body ( instr. innerOutput)
14101440 b. emit ( EndObjectLiteralGetter ( ) )
14111441 }
1442+
14121443 public func addSetter( for name: String , _ body: ( _ this: Variable , _ val: Variable ) -> ( ) ) {
14131444 let instr = b. emit ( BeginObjectLiteralSetter ( propertyName: name) )
14141445 body ( instr. innerOutput ( 0 ) , instr. innerOutput ( 1 ) )
@@ -2294,6 +2325,8 @@ public class ProgramBuilder {
22942325 case . objectLiteralCopyProperties:
22952326 // Cannot generally determine what fields this installs.
22962327 break
2328+ case . objectLiteralSetPrototype:
2329+ currentObjectLiteral. hasPrototype = true
22972330 case . beginObjectLiteralMethod( let op) :
22982331 currentObjectLiteral. existingMethods. append ( op. methodName)
22992332 case . beginObjectLiteralGetter( let op) :
0 commit comments