@@ -458,15 +458,34 @@ object WasmBinaryWriter {
458
458
private final val SectionTag = 0x0D
459
459
460
460
private final class Buffer {
461
- private val buf = new java.io.ByteArrayOutputStream ()
461
+ private var buf : Array [Byte ] = new Array [Byte ](1024 * 1024 )
462
+ private var size : Int = 0
462
463
463
- def result (): Array [Byte ] = buf.toByteArray()
464
+ private def ensureCapacity (capacity : Int ): Unit = {
465
+ if (buf.length < capacity) {
466
+ val newCapacity = Integer .highestOneBit(capacity) << 1
467
+ buf = java.util.Arrays .copyOf(buf, newCapacity)
468
+ }
469
+ }
464
470
465
- def byte (b : Byte ): Unit =
466
- buf.write(b & 0xFF )
471
+ def currentGlobalOffset : Int = size
467
472
468
- def rawByteArray (array : Array [Byte ]): Unit =
469
- buf.write(array)
473
+ def result (): Array [Byte ] =
474
+ java.util.Arrays .copyOf(buf, size)
475
+
476
+ def byte (b : Byte ): Unit = {
477
+ val newSize = size + 1
478
+ ensureCapacity(newSize)
479
+ buf(size) = b
480
+ size = newSize
481
+ }
482
+
483
+ def rawByteArray (array : Array [Byte ]): Unit = {
484
+ val newSize = size + array.length
485
+ ensureCapacity(newSize)
486
+ System .arraycopy(array, 0 , buf, size, array.length)
487
+ size = newSize
488
+ }
470
489
471
490
def boolean (b : Boolean ): Unit =
472
491
byte(if (b) 1 else 0 )
@@ -526,21 +545,40 @@ object WasmBinaryWriter {
526
545
}
527
546
528
547
def byteLengthSubSection (f : Buffer => Unit ): Unit = {
529
- val subBuffer = new Buffer ()
530
- f(subBuffer)
531
- val subResult = subBuffer.result()
548
+ // Reserve 4 bytes at the current offset to store the byteLength later
549
+ val byteLengthOffset = size
550
+ val startOffset = byteLengthOffset + 4
551
+ ensureCapacity(startOffset)
552
+ size = startOffset // do not write the 4 bytes for now
553
+
554
+ f(this )
555
+
556
+ // Compute byteLength
557
+ val endOffset = size
558
+ val byteLength = endOffset - startOffset
559
+
560
+ assert(byteLength < (1 << 28 ), s " Cannot write a subsection that large: $byteLength" )
532
561
533
- this .u32(subResult.length)
534
- this .rawByteArray(subResult)
562
+ /* Write the byteLength in the reserved slot. Note that we *always* use
563
+ * 4 bytes to store the byteLength, even when less bytes are necessary in
564
+ * the unsigned LEB encoding. The WebAssembly spec specifically calls out
565
+ * this choice as valid. We leverage it to have predictable total offsets
566
+ * when write the code section, which is important to efficiently
567
+ * generate source maps.
568
+ */
569
+ buf(byteLengthOffset) = ((byteLength & 0x7F ) | 0x80 ).toByte
570
+ buf(byteLengthOffset + 1 ) = (((byteLength >>> 7 ) & 0x7F ) | 0x80 ).toByte
571
+ buf(byteLengthOffset + 2 ) = (((byteLength >>> 14 ) & 0x7F ) | 0x80 ).toByte
572
+ buf(byteLengthOffset + 3 ) = ((byteLength >>> 21 ) & 0x7F ).toByte
535
573
}
536
574
537
575
@ tailrec
538
576
private def unsignedLEB128 (value : Long ): Unit = {
539
577
val next = value >>> 7
540
578
if (next == 0 ) {
541
- buf.write (value.toInt )
579
+ byte (value.toByte )
542
580
} else {
543
- buf.write(( value.toInt & 0x7F ) | 0x80 )
581
+ byte((( value.toInt & 0x7F ) | 0x80 ).toByte )
544
582
unsignedLEB128(next)
545
583
}
546
584
}
@@ -550,9 +588,9 @@ object WasmBinaryWriter {
550
588
val chunk = value.toInt & 0x7F
551
589
val next = value >> 7
552
590
if (next == (if ((chunk & 0x40 ) != 0 ) - 1 else 0 )) {
553
- buf.write (chunk)
591
+ byte (chunk.toByte )
554
592
} else {
555
- buf.write( chunk | 0x80 )
593
+ byte(( chunk | 0x80 ).toByte )
556
594
signedLEB128(next)
557
595
}
558
596
}
0 commit comments