Skip to content

Commit 337535d

Browse files
Feature/await expression (#469)
* Implements compilation of the await expression * Implements basic test to ensure that await is covered in CompilerTests
1 parent 98357eb commit 337535d

File tree

5 files changed

+142
-1
lines changed

5 files changed

+142
-1
lines changed

Sources/Fuzzilli/Compiler/Compiler.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,14 @@ public class JavaScriptCompiler {
10811081
case .v8IntrinsicIdentifier:
10821082
fatalError("V8IntrinsicIdentifiers must be handled as part of their surrounding CallExpression")
10831083

1084+
case .awaitExpression(let awaitExpression):
1085+
// TODO await is also allowed at the top level of a module
1086+
if !contextAnalyzer.context.contains(.asyncFunction) {
1087+
throw CompilerError.invalidNodeError("`await` is currently only supported in async functions")
1088+
}
1089+
let argument = try compileExpression(awaitExpression.argument)
1090+
return emit(Await(), withInputs: [argument]).output
1091+
10841092
}
10851093
}
10861094

Sources/Fuzzilli/Compiler/Parser/parser.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,10 @@ function parse(script, proto) {
580580
case 'V8IntrinsicIdentifier': {
581581
return makeExpression('V8IntrinsicIdentifier', { name: node.name });
582582
}
583+
case 'AwaitExpression': {
584+
let argument = visitExpression(node.argument);
585+
return makeExpression('AwaitExpression', { argument });
586+
}
583587
default: {
584588
throw "Unhandled node type " + node.type;
585589
}

Sources/Fuzzilli/Protobuf/ast.pb.swift

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,27 @@ public struct Compiler_Protobuf_TernaryExpression: @unchecked Sendable {
19311931
fileprivate var _storage = _StorageClass.defaultInstance
19321932
}
19331933

1934+
public struct Compiler_Protobuf_AwaitExpression: @unchecked Sendable {
1935+
// SwiftProtobuf.Message conformance is added in an extension below. See the
1936+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
1937+
// methods supported on all messages.
1938+
1939+
public var argument: Compiler_Protobuf_Expression {
1940+
get {return _storage._argument ?? Compiler_Protobuf_Expression()}
1941+
set {_uniqueStorage()._argument = newValue}
1942+
}
1943+
/// Returns true if `argument` has been explicitly set.
1944+
public var hasArgument: Bool {return _storage._argument != nil}
1945+
/// Clears the value of `argument`. Subsequent reads from it will return its default value.
1946+
public mutating func clearArgument() {_uniqueStorage()._argument = nil}
1947+
1948+
public var unknownFields = SwiftProtobuf.UnknownStorage()
1949+
1950+
public init() {}
1951+
1952+
fileprivate var _storage = _StorageClass.defaultInstance
1953+
}
1954+
19341955
public struct Compiler_Protobuf_Expression: @unchecked Sendable {
19351956
// SwiftProtobuf.Message conformance is added in an extension below. See the
19361957
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@@ -2141,6 +2162,14 @@ public struct Compiler_Protobuf_Expression: @unchecked Sendable {
21412162
set {_uniqueStorage()._expression = .ternaryExpression(newValue)}
21422163
}
21432164

2165+
public var awaitExpression: Compiler_Protobuf_AwaitExpression {
2166+
get {
2167+
if case .awaitExpression(let v)? = _storage._expression {return v}
2168+
return Compiler_Protobuf_AwaitExpression()
2169+
}
2170+
set {_uniqueStorage()._expression = .awaitExpression(newValue)}
2171+
}
2172+
21442173
public var unknownFields = SwiftProtobuf.UnknownStorage()
21452174

21462175
public enum OneOf_Expression: Equatable, Sendable {
@@ -2169,6 +2198,7 @@ public struct Compiler_Protobuf_Expression: @unchecked Sendable {
21692198
case sequenceExpression(Compiler_Protobuf_SequenceExpression)
21702199
case v8IntrinsicIdentifier(Compiler_Protobuf_V8IntrinsicIdentifier)
21712200
case ternaryExpression(Compiler_Protobuf_TernaryExpression)
2201+
case awaitExpression(Compiler_Protobuf_AwaitExpression)
21722202

21732203
}
21742204

@@ -6513,6 +6543,82 @@ extension Compiler_Protobuf_TernaryExpression: SwiftProtobuf.Message, SwiftProto
65136543
}
65146544
}
65156545

6546+
extension Compiler_Protobuf_AwaitExpression: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
6547+
public static let protoMessageName: String = _protobuf_package + ".AwaitExpression"
6548+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
6549+
1: .same(proto: "argument"),
6550+
]
6551+
6552+
fileprivate class _StorageClass {
6553+
var _argument: Compiler_Protobuf_Expression? = nil
6554+
6555+
#if swift(>=5.10)
6556+
// This property is used as the initial default value for new instances of the type.
6557+
// The type itself is protecting the reference to its storage via CoW semantics.
6558+
// This will force a copy to be made of this reference when the first mutation occurs;
6559+
// hence, it is safe to mark this as `nonisolated(unsafe)`.
6560+
static nonisolated(unsafe) let defaultInstance = _StorageClass()
6561+
#else
6562+
static let defaultInstance = _StorageClass()
6563+
#endif
6564+
6565+
private init() {}
6566+
6567+
init(copying source: _StorageClass) {
6568+
_argument = source._argument
6569+
}
6570+
}
6571+
6572+
fileprivate mutating func _uniqueStorage() -> _StorageClass {
6573+
if !isKnownUniquelyReferenced(&_storage) {
6574+
_storage = _StorageClass(copying: _storage)
6575+
}
6576+
return _storage
6577+
}
6578+
6579+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
6580+
_ = _uniqueStorage()
6581+
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
6582+
while let fieldNumber = try decoder.nextFieldNumber() {
6583+
// The use of inline closures is to circumvent an issue where the compiler
6584+
// allocates stack space for every case branch when no optimizations are
6585+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
6586+
switch fieldNumber {
6587+
case 1: try { try decoder.decodeSingularMessageField(value: &_storage._argument) }()
6588+
default: break
6589+
}
6590+
}
6591+
}
6592+
}
6593+
6594+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
6595+
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
6596+
// The use of inline closures is to circumvent an issue where the compiler
6597+
// allocates stack space for every if/case branch local when no optimizations
6598+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
6599+
// https://github.com/apple/swift-protobuf/issues/1182
6600+
try { if let v = _storage._argument {
6601+
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
6602+
} }()
6603+
}
6604+
try unknownFields.traverse(visitor: &visitor)
6605+
}
6606+
6607+
public static func ==(lhs: Compiler_Protobuf_AwaitExpression, rhs: Compiler_Protobuf_AwaitExpression) -> Bool {
6608+
if lhs._storage !== rhs._storage {
6609+
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
6610+
let _storage = _args.0
6611+
let rhs_storage = _args.1
6612+
if _storage._argument != rhs_storage._argument {return false}
6613+
return true
6614+
}
6615+
if !storagesAreEqual {return false}
6616+
}
6617+
if lhs.unknownFields != rhs.unknownFields {return false}
6618+
return true
6619+
}
6620+
}
6621+
65166622
extension Compiler_Protobuf_Expression: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
65176623
public static let protoMessageName: String = _protobuf_package + ".Expression"
65186624
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
@@ -6541,6 +6647,7 @@ extension Compiler_Protobuf_Expression: SwiftProtobuf.Message, SwiftProtobuf._Me
65416647
23: .same(proto: "sequenceExpression"),
65426648
24: .same(proto: "v8IntrinsicIdentifier"),
65436649
25: .same(proto: "ternaryExpression"),
6650+
26: .same(proto: "awaitExpression"),
65446651
]
65456652

65466653
fileprivate class _StorageClass {
@@ -6903,6 +7010,19 @@ extension Compiler_Protobuf_Expression: SwiftProtobuf.Message, SwiftProtobuf._Me
69037010
_storage._expression = .ternaryExpression(v)
69047011
}
69057012
}()
7013+
case 26: try {
7014+
var v: Compiler_Protobuf_AwaitExpression?
7015+
var hadOneofValue = false
7016+
if let current = _storage._expression {
7017+
hadOneofValue = true
7018+
if case .awaitExpression(let m) = current {v = m}
7019+
}
7020+
try decoder.decodeSingularMessageField(value: &v)
7021+
if let v = v {
7022+
if hadOneofValue {try decoder.handleConflictingOneOf()}
7023+
_storage._expression = .awaitExpression(v)
7024+
}
7025+
}()
69067026
default: break
69077027
}
69087028
}
@@ -7016,6 +7136,10 @@ extension Compiler_Protobuf_Expression: SwiftProtobuf.Message, SwiftProtobuf._Me
70167136
guard case .ternaryExpression(let v)? = _storage._expression else { preconditionFailure() }
70177137
try visitor.visitSingularMessageField(value: v, fieldNumber: 25)
70187138
}()
7139+
case .awaitExpression?: try {
7140+
guard case .awaitExpression(let v)? = _storage._expression else { preconditionFailure() }
7141+
try visitor.visitSingularMessageField(value: v, fieldNumber: 26)
7142+
}()
70197143
case nil: break
70207144
}
70217145
}

Sources/Fuzzilli/Protobuf/ast.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,10 @@ message TernaryExpression {
421421
Expression alternate = 3;
422422
}
423423

424+
message AwaitExpression {
425+
Expression argument = 1;
426+
}
427+
424428
message Expression {
425429
oneof expression {
426430
Identifier identifier = 1;
@@ -448,5 +452,6 @@ message Expression {
448452
SequenceExpression sequenceExpression = 23;
449453
V8IntrinsicIdentifier v8IntrinsicIdentifier = 24;
450454
TernaryExpression ternaryExpression = 25;
455+
AwaitExpression awaitExpression = 26;
451456
}
452457
}

Tests/FuzzilliTests/CompilerTests/basic_functions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function* f5(n) {
2424
output(Array.from(f5(3)).length);
2525

2626
async function f6() {
27-
return 42;
27+
return await 42;
2828
}
2929
output(f6().constructor.name);
3030

0 commit comments

Comments
 (0)