Skip to content

Commit ea68e64

Browse files
o-V8-internal LUCI CQ
authored andcommitted
Implement support for a number of recent JS language features
* JSON.parse source text access & RawJSON * Iterator helpers * upsert Change-Id: I1dad9b38c1a42ba8cfdb055651db06e0947dd184 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8814317 Reviewed-by: Matthias Liedtke <mliedtke@google.com> Commit-Queue: Olivier Flückiger <olivf@google.com> Auto-Submit: Olivier Flückiger <olivf@google.com>
1 parent 3b241b0 commit ea68e64

1 file changed

Lines changed: 116 additions & 56 deletions

File tree

Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift

Lines changed: 116 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ public class JavaScriptEnvironment: ComponentBase {
322322
registerObjectGroup(.jsStrings)
323323
registerObjectGroup(.jsArrays)
324324
registerObjectGroup(.jsArguments)
325+
registerObjectGroup(.jsIterator)
326+
registerObjectGroup(.jsIteratorPrototype)
327+
registerObjectGroup(.jsIteratorConstructor)
325328
registerObjectGroup(.jsGenerators)
326329
registerObjectGroup(.jsPromises)
327330
registerObjectGroup(.jsRegExps)
@@ -552,6 +555,7 @@ public class JavaScriptEnvironment: ComponentBase {
552555
registerBuiltin("Boolean", ofType: .jsBooleanConstructor)
553556
registerBuiltin("Number", ofType: .jsNumberConstructor)
554557
registerBuiltin("Symbol", ofType: .jsSymbolConstructor)
558+
registerBuiltin("Iterator", ofType: .jsIteratorConstructor)
555559
registerBuiltin("BigInt", ofType: .jsBigIntConstructor)
556560
registerBuiltin("RegExp", ofType: .jsRegExpConstructor)
557561
for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError"] {
@@ -1009,20 +1013,26 @@ public extension ILType {
10091013
/// Type of a JavaScript array.
10101014
static let jsArray = ILType.iterable + ILType.object(ofGroup: "Array", withProperties: ["length"], withMethods: ["at", "concat", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "some", "reduce", "reduceRight", "toString", "toLocaleString", "toReversed", "toSorted", "toSpliced", "with", "join", "lastIndexOf", "values", "flat", "flatMap"])
10111015

1012-
/// Type of a function's arguments object.
1016+
/// Type of a JavaScript function's arguments object.
10131017
static let jsArguments = ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"])
10141018

1019+
/// Type of a JavaScript Iterator object.
1020+
static let jsIterator = ILType.iterable + ILType.object(ofGroup: "Iterator", withProperties: ["value", "done"], withMethods: ["next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", "toArray", "forEach", "some", "every", "find"])
1021+
1022+
/// Type of the JavaScript Iterator constructor builtin.
1023+
static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from"])
1024+
10151025
/// Type of a JavaScript generator object.
10161026
static let jsGenerator = ILType.iterable + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"])
10171027

10181028
/// Type of a JavaScript Promise object.
10191029
static let jsPromise = ILType.object(ofGroup: "Promise", withMethods: ["catch", "finally", "then"])
10201030

10211031
/// Type of a JavaScript Map object.
1022-
static let jsMap = ILType.iterable + ILType.object(ofGroup: "Map", withProperties: ["size"], withMethods: ["clear", "delete", "entries", "forEach", "get", "has", "keys", "set", "values"])
1032+
static let jsMap = ILType.iterable + ILType.object(ofGroup: "Map", withProperties: ["size"], withMethods: ["clear", "delete", "entries", "forEach", "get", "has", "keys", "set", "values", "getOrInsert", "getOrInsertComputed"])
10231033

10241034
/// Type of a JavaScript WeakMap object.
1025-
static let jsWeakMap = ILType.object(ofGroup: "WeakMap", withMethods: ["delete", "get", "has", "set"])
1035+
static let jsWeakMap = ILType.object(ofGroup: "WeakMap", withMethods: ["delete", "get", "has", "set", "getOrInsert", "getOrInsertComputed"])
10261036

10271037
/// Type of a JavaScript Set object.
10281038
static let jsSet = ILType.iterable + ILType.object(ofGroup: "Set", withProperties: ["size"], withMethods: ["add", "clear", "delete", "entries", "forEach", "has", "keys", "values"])
@@ -1149,7 +1159,7 @@ public extension ILType {
11491159
static let jsDateConstructor = ILType.functionAndConstructor([.opt(.string | .number)] => .jsDate) + .object(ofGroup: "DateConstructor", withProperties: ["prototype"], withMethods: ["UTC", "now", "parse"])
11501160

11511161
/// Type of the JavaScript JSON object builtin.
1152-
static let jsJSONObject = ILType.object(ofGroup: "JSON", withMethods: ["parse", "stringify"])
1162+
static let jsJSONObject = ILType.object(ofGroup: "JSON", withMethods: ["parse", "stringify", "rawJSON", "isRawJSON"])
11531163

11541164
/// Type of the JavaScript Reflect object builtin.
11551165
static let jsReflectObject = ILType.object(ofGroup: "Reflect", withMethods: ["apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"])
@@ -1306,10 +1316,16 @@ public extension ObjectGroup {
13061316
// on the prototype. We hide them from the prototype object to avoid
13071317
// generating `let v0 = Intl.DateTimeFormat.prototype.format`.
13081318
// https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.format
1319+
// TODO(mliedtke): Find a nicer interface than manually excluding some
1320+
// magic combinations here.
13091321
if receiver.name == "Intl.DateTimeFormat" || receiver.name == "Intl.NumberFormat" {
13101322
properties.removeValue(forKey: "format")
13111323
} else if receiver.name == "Intl.Collator" {
13121324
properties.removeValue(forKey: "compare")
1325+
} else if receiver.name == "Iterator" {
1326+
properties.removeValue(forKey: "next")
1327+
properties.removeValue(forKey: "return")
1328+
properties.removeValue(forKey: "throw")
13131329
}
13141330
return ObjectGroup(
13151331
name: name,
@@ -1342,7 +1358,7 @@ public extension ObjectGroup {
13421358
"indexOf" : [.jsAnything, .opt(.integer)] => .integer,
13431359
"lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer,
13441360
"match" : [.regexp] => .jsString,
1345-
"matchAll" : [.regexp] => .jsString,
1361+
"matchAll" : [.regexp] => .jsIterator,
13461362
"normalize" : [] => .jsString, // the first parameter must be a specific string value, so we have a CodeGenerator for that instead
13471363
"padEnd" : [.integer, .opt(.string)] => .jsString,
13481364
"padStart" : [.integer, .opt(.string)] => .jsString,
@@ -1399,7 +1415,7 @@ public extension ObjectGroup {
13991415
methods: [
14001416
"at" : [.integer] => .jsAnything,
14011417
"copyWithin" : [.integer, .integer, .opt(.integer)] => .jsArray,
1402-
"entries" : [] => .jsArray,
1418+
"entries" : [] => .jsIterator,
14031419
"every" : [.function(), .opt(.object())] => .boolean,
14041420
"fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined,
14051421
"find" : [.function(), .opt(.object())] => .jsAnything,
@@ -1410,14 +1426,14 @@ public extension ObjectGroup {
14101426
"includes" : [.jsAnything, .opt(.integer)] => .boolean,
14111427
"indexOf" : [.jsAnything, .opt(.integer)] => .integer,
14121428
"join" : [.string] => .jsString,
1413-
"keys" : [] => .object(), // returns an array iterator
1429+
"keys" : [] => .jsIterator,
14141430
"lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer,
14151431
"reduce" : [.function(), .opt(.jsAnything)] => .jsAnything,
14161432
"reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything,
14171433
"reverse" : [] => .undefined,
14181434
"some" : [.function(), .opt(.jsAnything)] => .boolean,
14191435
"sort" : [.function()] => .undefined,
1420-
"values" : [] => .object(),
1436+
"values" : [] => .jsIterator,
14211437
"pop" : [] => .jsAnything,
14221438
"push" : [.jsAnything...] => .integer,
14231439
"shift" : [] => .jsAnything,
@@ -1477,14 +1493,52 @@ public extension ObjectGroup {
14771493
methods: [:]
14781494
)
14791495

1496+
static let jsIterator = ObjectGroup(
1497+
name: "Iterator",
1498+
instanceType: .jsIterator,
1499+
properties: [
1500+
"done": .boolean,
1501+
"value": .jsAnything
1502+
],
1503+
methods: [
1504+
"next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]),
1505+
"return" : [.jsAnything] => .object(withProperties: ["done", "value"]),
1506+
"throw" : [.jsAnything] => .object(withProperties: ["done", "value"]),
1507+
"map" : [.function()] => .jsIterator,
1508+
"filter" : [.function()] => .jsIterator,
1509+
"take" : [.integer] => .jsIterator,
1510+
"drop" : [.integer] => .jsIterator,
1511+
"flatMap" : [.function()] => .jsIterator,
1512+
"reduce" : [.function(), .opt(.jsAnything)] => .jsAnything,
1513+
"toArray" : [] => .jsArray,
1514+
"forEach" : [.function()] => .undefined,
1515+
"some" : [.function()] => .boolean,
1516+
"every" : [.function()] => .boolean,
1517+
"find" : [.function()] => .jsAnything,
1518+
]
1519+
)
1520+
1521+
static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator)
1522+
1523+
static let jsIteratorConstructor = ObjectGroup(
1524+
name: "IteratorConstructor",
1525+
instanceType: .jsIteratorConstructor,
1526+
properties: [
1527+
"prototype" : jsIteratorPrototype.instanceType
1528+
],
1529+
methods: [
1530+
"from" : [.jsAnything] => .jsIterator,
1531+
]
1532+
)
1533+
14801534
static let jsGenerators = ObjectGroup(
14811535
name: "Generator",
14821536
instanceType: .jsGenerator,
14831537
properties: [:],
14841538
methods: [
1485-
"next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]),
1486-
"return" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]),
1487-
"throw" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"])
1539+
"next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]),
1540+
"return" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]),
1541+
"throw" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]),
14881542
]
14891543
)
14901544

@@ -1508,15 +1562,17 @@ public extension ObjectGroup {
15081562
"size" : .integer
15091563
],
15101564
methods: [
1511-
"clear" : [] => .undefined,
1512-
"delete" : [.jsAnything] => .boolean,
1513-
"entries" : [] => .object(),
1514-
"forEach" : [.function(), .opt(.object())] => .undefined,
1515-
"get" : [.jsAnything] => .jsAnything,
1516-
"has" : [.jsAnything] => .boolean,
1517-
"keys" : [] => .object(),
1518-
"set" : [.jsAnything, .jsAnything] => .jsMap,
1519-
"values" : [] => .object(),
1565+
"clear" : [] => .undefined,
1566+
"delete" : [.jsAnything] => .boolean,
1567+
"entries" : [] => .jsIterator,
1568+
"forEach" : [.function(), .opt(.object())] => .undefined,
1569+
"get" : [.jsAnything] => .jsAnything,
1570+
"has" : [.jsAnything] => .boolean,
1571+
"keys" : [] => .jsIterator,
1572+
"set" : [.jsAnything, .jsAnything] => .jsMap,
1573+
"values" : [] => .jsIterator,
1574+
"getOrInsert" : [.jsAnything, .jsAnything] => .jsAnything,
1575+
"getOrInsertComputed": [.jsAnything, .function()] => .jsAnything,
15201576
]
15211577
)
15221578

@@ -1526,10 +1582,12 @@ public extension ObjectGroup {
15261582
instanceType: .jsWeakMap,
15271583
properties: [:],
15281584
methods: [
1529-
"delete" : [.jsAnything] => .boolean,
1530-
"get" : [.jsAnything] => .jsAnything,
1531-
"has" : [.jsAnything] => .boolean,
1532-
"set" : [.jsAnything, .jsAnything] => .jsWeakMap,
1585+
"delete" : [.jsAnything] => .boolean,
1586+
"get" : [.jsAnything] => .jsAnything,
1587+
"has" : [.jsAnything] => .boolean,
1588+
"set" : [.jsAnything, .jsAnything] => .jsWeakMap,
1589+
"getOrInsert" : [.jsAnything, .jsAnything] => .jsAnything,
1590+
"getOrInsertComputed": [.jsAnything, .function()] => .jsAnything,
15331591
]
15341592
)
15351593

@@ -1544,11 +1602,11 @@ public extension ObjectGroup {
15441602
"add" : [.jsAnything] => .jsSet,
15451603
"clear" : [] => .undefined,
15461604
"delete" : [.jsAnything] => .boolean,
1547-
"entries" : [] => .object(),
1605+
"entries" : [] => .jsIterator,
15481606
"forEach" : [.function(), .opt(.object())] => .undefined,
15491607
"has" : [.jsAnything] => .boolean,
1550-
"keys" : [] => .object(),
1551-
"values" : [] => .object(),
1608+
"keys" : [] => .jsIterator,
1609+
"values" : [] => .jsIterator,
15521610
]
15531611
)
15541612

@@ -1592,12 +1650,12 @@ public extension ObjectGroup {
15921650
properties: [
15931651
"byteLength" : .integer,
15941652
"maxByteLength" : .integer,
1595-
"resizable" : .boolean
1653+
"resizable" : .boolean,
15961654
],
15971655
methods: [
1598-
"resize" : [.integer] => .undefined,
1599-
"slice" : [.integer, .opt(.integer)] => .jsArrayBuffer,
1600-
"transfer" : [] => .jsArrayBuffer,
1656+
"resize" : [.integer] => .undefined,
1657+
"slice" : [.integer, .opt(.integer)] => .jsArrayBuffer,
1658+
"transfer" : [.opt(.integer)] => .jsArrayBuffer,
16011659
]
16021660
)
16031661

@@ -1636,32 +1694,32 @@ public extension ObjectGroup {
16361694
"length" : .integer
16371695
],
16381696
methods: [
1639-
"at" : [.integer] => .jsAnything,
1640-
"copyWithin" : [.integer, .integer, .opt(.integer)] => .undefined,
1641-
"entries" : [] => .jsArray,
1642-
"every" : [.function(), .opt(.object())] => .boolean,
1643-
"fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined,
1644-
"find" : [.function(), .opt(.object())] => .jsAnything,
1645-
"findIndex" : [.function(), .opt(.object())] => .integer,
1646-
"findLast" : [.function(), .opt(.object())] => .jsAnything,
1697+
"at" : [.integer] => .jsAnything,
1698+
"copyWithin" : [.integer, .integer, .opt(.integer)] => .undefined,
1699+
"entries" : [] => .jsIterator,
1700+
"every" : [.function(), .opt(.object())] => .boolean,
1701+
"fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined,
1702+
"find" : [.function(), .opt(.object())] => .jsAnything,
1703+
"findIndex" : [.function(), .opt(.object())] => .integer,
1704+
"findLast" : [.function(), .opt(.object())] => .jsAnything,
16471705
"findLastIndex" : [.function(), .opt(.object())] => .integer,
1648-
"forEach" : [.function(), .opt(.object())] => .undefined,
1649-
"includes" : [.jsAnything, .opt(.integer)] => .boolean,
1650-
"indexOf" : [.jsAnything, .opt(.integer)] => .integer,
1651-
"join" : [.string] => .jsString,
1652-
"keys" : [] => .object(), // returns an array iterator
1653-
"lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer,
1654-
"reduce" : [.function(), .opt(.jsAnything)] => .jsAnything,
1655-
"reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything,
1656-
"reverse" : [] => .undefined,
1657-
"set" : [.object(), .opt(.integer)] => .undefined,
1658-
"some" : [.function(), .opt(.jsAnything)] => .boolean,
1659-
"sort" : [.function()] => .undefined,
1660-
"values" : [] => .object(),
1661-
"filter" : [.function(), .opt(.object())] => .jsTypedArray(variant),
1662-
"map" : [.function(), .opt(.object())] => .jsTypedArray(variant),
1663-
"slice" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant),
1664-
"subarray" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant),
1706+
"forEach" : [.function(), .opt(.object())] => .undefined,
1707+
"includes" : [.jsAnything, .opt(.integer)] => .boolean,
1708+
"indexOf" : [.jsAnything, .opt(.integer)] => .integer,
1709+
"join" : [.string] => .jsString,
1710+
"keys" : [] => .jsIterator,
1711+
"lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer,
1712+
"reduce" : [.function(), .opt(.jsAnything)] => .jsAnything,
1713+
"reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything,
1714+
"reverse" : [] => .undefined,
1715+
"set" : [.object(), .opt(.integer)] => .undefined,
1716+
"some" : [.function(), .opt(.jsAnything)] => .boolean,
1717+
"sort" : [.function()] => .undefined,
1718+
"values" : [] => .jsIterator,
1719+
"filter" : [.function(), .opt(.object())] => .jsTypedArray(variant),
1720+
"map" : [.function(), .opt(.object())] => .jsTypedArray(variant),
1721+
"slice" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant),
1722+
"subarray" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant),
16651723
"toString" : [] => .jsString,
16661724
"toLocaleString" : [.opt(.string), .opt(.object())] => .jsString,
16671725
"toReversed" : [] => .jsTypedArray(variant),
@@ -2032,6 +2090,8 @@ public extension ObjectGroup {
20322090
methods: [
20332091
"parse" : [.string, .opt(.function())] => .jsAnything,
20342092
"stringify" : [.jsAnything, .opt(.function()), .opt(.number | .string)] => .jsString,
2093+
"rawJSON" : [.plain(.string | .number | .boolean)] => .jsAnything,
2094+
"isRawJSON" : [.jsAnything] => .boolean,
20352095
]
20362096
)
20372097

0 commit comments

Comments
 (0)