Skip to content

Commit d9aa0f6

Browse files
mi-acV8-internal LUCI CQ
authored andcommitted
Preserve leading comments when transpiling JS
JS files often contain meta data in leading comments. We require these comments to be able to execute JS code again after transpiling it with the FuzzILTool. This preserves such comments, whenever the `--outputPathJS` option is used. The comments are extracted using information from the Babel AST in the parser. Bug: 442444727 Change-Id: Ibc9fda5f99a69123672b75970f9b5801c2695074 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8839676 Reviewed-by: Matthias Liedtke <[email protected]> Commit-Queue: Michael Achenbach <[email protected]>
1 parent 62e4d2f commit d9aa0f6

File tree

4 files changed

+26
-7
lines changed

4 files changed

+26
-7
lines changed

Sources/FuzzILTool/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ else if args.has("--compile") {
188188
}
189189

190190
if let js_path = args["--outputPathJS"] {
191-
let content = jsLifter.lift(program)
191+
let content = ast.leadingComments + jsLifter.lift(program)
192192
do {
193193
try content.write(to: URL(fileURLWithPath: js_path), atomically: false, encoding: String.Encoding.utf8)
194194
} catch {

Sources/Fuzzilli/Compiler/Parser/parser.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ function tryReadFile(path) {
3636
function parse(script, proto) {
3737
let ast = Parser.parse(script, { plugins: ["explicitResourceManagement", "v8intrinsic"] });
3838

39+
// We assume leading comments (and whitespace) until the starting
40+
// character of the first node of the program. This way
41+
// is easier than rebuilding the comments from Babel's
42+
// `leadingComments` AST nodes, which don't include whitespace and
43+
// newlines.
44+
const firstNode = ast.program.body[0];
45+
let leadingComments = '';
46+
if (firstNode) {
47+
leadingComments = script.substring(0, firstNode.start);
48+
}
49+
3950
function assertNoError(err) {
4051
if (err) throw err;
4152
}
@@ -46,7 +57,7 @@ function parse(script, proto) {
4657

4758
function visitProgram(node) {
4859
const AST = proto.lookupType('compiler.protobuf.AST');
49-
let program = {statements: []};
60+
let program = {leadingComments: leadingComments, statements: []};
5061
for (let child of node.body) {
5162
program.statements.push(visitStatement(child));
5263
}
@@ -667,7 +678,7 @@ protobuf.load(astProtobufDefinitionPath, function(err, root) {
667678
if (err)
668679
throw err;
669680

670-
let ast = parse(script, root);
681+
const ast = parse(script, root);
671682

672683
// Uncomment this to print the AST to stdout (will be very verbose).
673684
//console.log(JSON.stringify(ast, null, 2));

Sources/Fuzzilli/Protobuf/ast.pb.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ public struct Compiler_Protobuf_AST: Sendable {
153153
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
154154
// methods supported on all messages.
155155

156+
public var leadingComments: String = String()
157+
156158
public var statements: [Compiler_Protobuf_Statement] = []
157159

158160
public var unknownFields = SwiftProtobuf.UnknownStorage()
@@ -2455,28 +2457,33 @@ extension Compiler_Protobuf_FunctionType: SwiftProtobuf._ProtoNameProviding {
24552457

24562458
extension Compiler_Protobuf_AST: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
24572459
public static let protoMessageName: String = _protobuf_package + ".AST"
2458-
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}statements\0")
2460+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}leadingComments\0\u{1}statements\0")
24592461

24602462
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
24612463
while let fieldNumber = try decoder.nextFieldNumber() {
24622464
// The use of inline closures is to circumvent an issue where the compiler
24632465
// allocates stack space for every case branch when no optimizations are
24642466
// enabled. https://github.com/apple/swift-protobuf/issues/1034
24652467
switch fieldNumber {
2466-
case 1: try { try decoder.decodeRepeatedMessageField(value: &self.statements) }()
2468+
case 1: try { try decoder.decodeSingularStringField(value: &self.leadingComments) }()
2469+
case 2: try { try decoder.decodeRepeatedMessageField(value: &self.statements) }()
24672470
default: break
24682471
}
24692472
}
24702473
}
24712474

24722475
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
2476+
if !self.leadingComments.isEmpty {
2477+
try visitor.visitSingularStringField(value: self.leadingComments, fieldNumber: 1)
2478+
}
24732479
if !self.statements.isEmpty {
2474-
try visitor.visitRepeatedMessageField(value: self.statements, fieldNumber: 1)
2480+
try visitor.visitRepeatedMessageField(value: self.statements, fieldNumber: 2)
24752481
}
24762482
try unknownFields.traverse(visitor: &visitor)
24772483
}
24782484

24792485
public static func ==(lhs: Compiler_Protobuf_AST, rhs: Compiler_Protobuf_AST) -> Bool {
2486+
if lhs.leadingComments != rhs.leadingComments {return false}
24802487
if lhs.statements != rhs.statements {return false}
24812488
if lhs.unknownFields != rhs.unknownFields {return false}
24822489
return true

Sources/Fuzzilli/Protobuf/ast.proto

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ syntax = "proto3";
1616
package compiler.protobuf;
1717

1818
message AST {
19-
repeated Statement statements = 1;
19+
string leadingComments = 1;
20+
repeated Statement statements = 2;
2021
}
2122

2223
// A parameter in a function declaration. Not an expression on its own.

0 commit comments

Comments
 (0)