Skip to content

Commit 046852e

Browse files
WasmParser: Turn init(LEB:) into top-level functions
1 parent b098410 commit 046852e

File tree

5 files changed

+69
-92
lines changed

5 files changed

+69
-92
lines changed

Sources/WasmParser/LEB.swift

Lines changed: 58 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,82 +4,78 @@ enum LEBError: Swift.Error, Equatable {
44
case insufficientBytes
55
}
66

7-
extension FixedWidthInteger where Self: UnsignedInteger {
8-
@inline(__always)
9-
init<Stream: ByteStream>(LEB stream: Stream) throws {
10-
let firstByte = try stream.consumeAny()
11-
var result: Self = Self(firstByte & 0b0111_1111)
12-
if _fastPath(firstByte & 0b1000_0000 == 0) {
13-
self = result
14-
return
15-
}
7+
@inline(__always)
8+
func decodeLEB128<IntType, Stream>(
9+
stream: Stream
10+
) throws -> IntType where IntType: FixedWidthInteger, IntType: UnsignedInteger, Stream: ByteStream {
11+
let firstByte = try stream.consumeAny()
12+
var result: IntType = IntType(firstByte & 0b0111_1111)
13+
if _fastPath(firstByte & 0b1000_0000 == 0) {
14+
return result
15+
}
1616

17-
var shift: UInt = 7
17+
var shift: UInt = 7
1818

19-
while true {
20-
let byte = try stream.consumeAny()
21-
let slice = Self(byte & 0b0111_1111)
22-
let nextShift = shift + 7
23-
if nextShift >= Self.bitWidth, (byte >> (UInt(Self.bitWidth) - shift)) != 0 {
24-
throw LEBError.integerRepresentationTooLong
25-
}
26-
result |= slice << shift
27-
shift = nextShift
28-
29-
guard byte & 0b1000_0000 != 0 else { break }
19+
while true {
20+
let byte = try stream.consumeAny()
21+
let slice = IntType(byte & 0b0111_1111)
22+
let nextShift = shift + 7
23+
if nextShift >= IntType.bitWidth, (byte >> (UInt(IntType.bitWidth) - shift)) != 0 {
24+
throw LEBError.integerRepresentationTooLong
3025
}
26+
result |= slice << shift
27+
shift = nextShift
3128

32-
self = result
29+
guard byte & 0b1000_0000 != 0 else { break }
3330
}
34-
}
3531

36-
extension FixedWidthInteger where Self: SignedInteger {
37-
@inline(__always)
38-
init<Stream: ByteStream>(LEB stream: Stream) throws {
39-
let firstByte = try stream.consumeAny()
40-
var result: Self = Self(firstByte & 0b0111_1111)
41-
if _fastPath(firstByte & 0b1000_0000 == 0) {
42-
// Interpret Int${Self.bitWidth-1} as Int${Self.bitWidth}
43-
self = (result << (Self.bitWidth - 7)) >> (Self.bitWidth - 7)
44-
return
45-
}
32+
return result
33+
}
4634

47-
var shift: Self = 7
35+
func decodeLEB128<IntType, Stream>(
36+
stream: Stream
37+
) throws -> IntType where IntType: FixedWidthInteger, IntType: RawSignedInteger, Stream: ByteStream {
38+
let firstByte = try stream.consumeAny()
39+
var result = IntType.Unsigned(firstByte & 0b0111_1111)
40+
if _fastPath(firstByte & 0b1000_0000 == 0) {
41+
// Interpret Int${Self.bitWidth-1} as Int${Self.bitWidth}
42+
return (IntType(bitPattern: result) << (IntType.bitWidth - 7)) >> (IntType.bitWidth - 7)
43+
}
4844

49-
var byte: UInt8
50-
repeat {
51-
byte = try stream.consumeAny()
45+
var shift: IntType = 7
5246

53-
let slice = Self(byte & 0b0111_1111)
54-
result |= slice << shift
47+
var byte: UInt8
48+
repeat {
49+
byte = try stream.consumeAny()
5550

56-
// When we don't have enough bit width
57-
if shift > (Self.bitWidth - 7) {
58-
let remainingBitWidth = Self.bitWidth - Int(shift)
59-
let continuationBit = (byte & 0b1000_0000) != 0
60-
// When a next byte is expected
61-
if continuationBit {
62-
throw LEBError.integerRepresentationTooLong
63-
}
51+
let slice = IntType.Unsigned(byte & 0b0111_1111)
52+
result |= slice << shift
6453

65-
let signAndDiscardingBits = Int8(bitPattern: byte << 1) >> remainingBitWidth
66-
// When meaningful bits are discarded
67-
if signAndDiscardingBits != 0 && signAndDiscardingBits != -1 {
68-
throw LEBError.overflow
69-
}
70-
self = result
71-
return
54+
// When we don't have enough bit width
55+
if shift > (IntType.bitWidth - 7) {
56+
let remainingBitWidth = IntType.bitWidth - Int(shift)
57+
let continuationBit = (byte & 0b1000_0000) != 0
58+
// When a next byte is expected
59+
if continuationBit {
60+
throw LEBError.integerRepresentationTooLong
7261
}
7362

74-
shift += 7
75-
} while byte & 0b1000_0000 != 0
76-
77-
// Sign flag is second high-order bit
78-
if byte & 0b0100_0000 != 0 {
79-
// Sign extend
80-
result |= Self(~0) << shift
63+
let signAndDiscardingBits = Int8(bitPattern: byte << 1) >> remainingBitWidth
64+
// When meaningful bits are discarded
65+
if signAndDiscardingBits != 0 && signAndDiscardingBits != -1 {
66+
throw LEBError.overflow
67+
}
68+
return IntType(bitPattern: result)
8169
}
8270

83-
self = result
71+
shift += 7
72+
} while byte & 0b1000_0000 != 0
73+
74+
// Sign flag is second high-order bit
75+
if byte & 0b0100_0000 != 0 {
76+
// Sign extend
77+
result |= IntType.Unsigned(bitPattern: ~0) << shift
8478
}
79+
80+
return IntType(bitPattern: result)
8581
}

Sources/WasmParser/Stream/FileHandleStream.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import SystemPackage
1+
import struct SystemPackage.FileDescriptor
22

33
public final class FileHandleStream: ByteStream {
44
private(set) public var currentIndex: Int = 0

Sources/WasmParser/WasmParser.swift

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import SystemPackage
1+
import struct SystemPackage.FilePath
2+
import struct SystemPackage.FileDescriptor
23
import WasmTypes
34

45
#if os(Windows)
@@ -352,20 +353,12 @@ extension ByteStream {
352353
@inline(__always)
353354
@usableFromInline
354355
func parseUnsigned<T: RawUnsignedInteger>(_: T.Type = T.self) throws -> T {
355-
return try T(LEB: self)
356+
try decodeLEB128(stream: self)
356357
}
357358

358-
@inline(__always)
359-
@usableFromInline
360-
func parseSigned<T: FixedWidthInteger & SignedInteger>() throws -> T {
361-
return try T(LEB: self)
362-
}
363-
364-
@inline(__always)
365359
@usableFromInline
366-
func parseInteger<T: RawUnsignedInteger>() throws -> T {
367-
let signed: T.Signed = try parseSigned()
368-
return signed.unsigned
360+
func parseSigned<T: FixedWidthInteger & RawSignedInteger>() throws -> T {
361+
try decodeLEB128(stream: self)
369362
}
370363
}
371364

@@ -406,16 +399,10 @@ extension Parser {
406399
try stream.parseUnsigned(T.self)
407400
}
408401

409-
@inline(__always)
410-
@inlinable
411-
func parseSigned<T: FixedWidthInteger & SignedInteger>() throws -> T {
412-
try stream.parseSigned()
413-
}
414-
415-
@inline(__always)
416402
@inlinable
417403
func parseInteger<T: RawUnsignedInteger>() throws -> T {
418-
try stream.parseInteger()
404+
let signed: T.Signed = try stream.parseSigned()
405+
return T(bitPattern: signed)
419406
}
420407

421408
func parseName() throws -> String {

Sources/WasmParser/WasmTypes.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,6 @@ extension RawUnsignedInteger {
324324
}
325325
}
326326

327-
extension RawSignedInteger {
328-
var unsigned: Unsigned {
329-
.init(bitPattern: self)
330-
}
331-
}
332-
333327
extension Instruction.Load {
334328
/// The alignment to the storage size of the memory access
335329
/// in log2 form.

Tests/WasmParserTests/LEBTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ final class LEBTest: XCTestCase {
6464
extension FixedWidthInteger where Self: UnsignedInteger {
6565
fileprivate init(LEB bytes: [UInt8]) throws {
6666
let stream = StaticByteStream(bytes: bytes)
67-
try self.init(LEB: stream)
67+
self = try decodeLEB128(stream: stream)
6868
}
6969
}
7070

71-
extension FixedWidthInteger where Self: SignedInteger {
71+
extension FixedWidthInteger where Self: RawSignedInteger {
7272
fileprivate init(LEB bytes: [UInt8]) throws {
7373
let stream = StaticByteStream(bytes: bytes)
74-
try self.init(LEB: stream)
74+
self = try decodeLEB128(stream: stream)
7575
}
7676
}

0 commit comments

Comments
 (0)