Skip to content

Commit 718c480

Browse files
Reuse constant slots for the same bit pattern values
1 parent 0eef0b2 commit 718c480

File tree

2 files changed

+31
-12
lines changed

2 files changed

+31
-12
lines changed

Sources/WasmKit/Execution/UntypedValue.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// NOTE: This type assumes any non-null references can be represented as a
44
/// 63-bits unsigned integer. This assumption allows us to use the
55
/// same storage space for all value types.
6-
struct UntypedValue: Equatable {
6+
struct UntypedValue: Equatable, Hashable {
77
/// The internal storage of the value.
88
let storage: UInt64
99

Sources/WasmKit/Translator.swift

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,32 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
731731
}
732732
}
733733

734+
struct ConstSlots {
735+
private(set) var values: [UntypedValue]
736+
private var indexByValue: [UntypedValue: Int]
737+
let stackLayout: StackLayout
738+
739+
init(stackLayout: StackLayout) {
740+
self.values = []
741+
self.indexByValue = [:]
742+
self.stackLayout = stackLayout
743+
}
744+
745+
mutating func allocate(_ value: Value) -> Int? {
746+
let untyped = UntypedValue(value)
747+
if let allocated = indexByValue[untyped] {
748+
// NOTE: Share the same const slot for exactly the same bit pattern
749+
// values even having different types
750+
return allocated
751+
}
752+
guard values.count < stackLayout.constantSlotSize else { return nil }
753+
let constSlotIndex = values.count
754+
values.append(untyped)
755+
indexByValue[untyped] = constSlotIndex
756+
return constSlotIndex
757+
}
758+
}
759+
734760
let allocator: ISeqAllocator
735761
let funcTypeInterner: Interner<FunctionType>
736762
let module: Context
@@ -744,7 +770,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
744770
let functionIndex: FunctionIndex
745771
/// Whether a call to this function should be intercepted
746772
let intercepting: Bool
747-
var constantSlots: [UntypedValue]
773+
var constantSlots: ConstSlots
748774

749775
init(
750776
allocator: ISeqAllocator,
@@ -767,7 +793,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
767793
self.locals = Locals(types: type.parameters + locals)
768794
self.functionIndex = functionIndex
769795
self.intercepting = intercepting
770-
self.constantSlots = []
796+
self.constantSlots = ConstSlots(stackLayout: stackLayout)
771797

772798
do {
773799
let endLabel = self.iseqBuilder.allocLabel()
@@ -944,7 +970,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
944970
for (idx, instruction) in instructions.enumerated() {
945971
buffer[idx] = instruction
946972
}
947-
let constants = allocator.allocateConstants(self.constantSlots)
973+
let constants = allocator.allocateConstants(self.constantSlots.values)
948974
return InstructionSequence(
949975
instructions: buffer,
950976
maxStackHeight: Int(valueStack.stackRegBase) + valueStack.maxHeight,
@@ -1563,15 +1589,8 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
15631589
}
15641590
}
15651591

1566-
private mutating func allocateConstSlot(_ type: ValueType, _ value: Value) -> Int? {
1567-
guard constantSlots.count < stackLayout.constantSlotSize else { return nil }
1568-
let constSlotIndex = constantSlots.count
1569-
constantSlots.append(UntypedValue(value))
1570-
return constSlotIndex
1571-
}
1572-
15731592
private mutating func visitConst(_ type: ValueType, _ value: Value) {
1574-
if let constSlotIndex = allocateConstSlot(type, value) {
1593+
if let constSlotIndex = constantSlots.allocate(value) {
15751594
valueStack.pushConst(constSlotIndex, type: type)
15761595
return
15771596
}

0 commit comments

Comments
 (0)