github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/asm/impl.go (about) 1 package asm 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 ) 7 8 // BaseAssemblerImpl includes code common to all architectures. 9 // 10 // Note: When possible, add code here instead of in architecture-specific files to reduce drift: 11 // As this is internal, exporting symbols only to reduce duplication is ok. 12 type BaseAssemblerImpl struct { 13 // SetBranchTargetOnNextNodes holds branch kind instructions (BR, conditional BR, etc.) 14 // where we want to set the next coming instruction as the destination of these BR instructions. 15 SetBranchTargetOnNextNodes []Node 16 17 // JumpTableEntries holds the information to build jump tables. 18 JumpTableEntries []JumpTableEntry 19 } 20 21 // JumpTableEntry is the necessary data to build a jump table. 22 // This is exported for testing purpose. 23 type JumpTableEntry struct { 24 t *StaticConst 25 labelInitialInstructions []Node 26 } 27 28 // SetJumpTargetOnNext implements AssemblerBase.SetJumpTargetOnNext 29 func (a *BaseAssemblerImpl) SetJumpTargetOnNext(node Node) { 30 a.SetBranchTargetOnNextNodes = append(a.SetBranchTargetOnNextNodes, node) 31 } 32 33 // BuildJumpTable implements AssemblerBase.BuildJumpTable 34 func (a *BaseAssemblerImpl) BuildJumpTable(table *StaticConst, labelInitialInstructions []Node) { 35 a.JumpTableEntries = append(a.JumpTableEntries, JumpTableEntry{ 36 t: table, 37 labelInitialInstructions: labelInitialInstructions, 38 }) 39 } 40 41 // FinalizeJumpTableEntry finalizes the build tables inside the given code. 42 func (a *BaseAssemblerImpl) FinalizeJumpTableEntry(code []byte) (err error) { 43 for i := range a.JumpTableEntries { 44 ent := &a.JumpTableEntries[i] 45 labelInitialInstructions := ent.labelInitialInstructions 46 table := ent.t 47 // Compile the offset table for each target. 48 base := labelInitialInstructions[0].OffsetInBinary() 49 for i, nop := range labelInitialInstructions { 50 if nop.OffsetInBinary()-base >= JumpTableMaximumOffset { 51 return fmt.Errorf("too large br_table") 52 } 53 // We store the offset from the beginning of the L0's initial instruction. 54 binary.LittleEndian.PutUint32(code[table.OffsetInBinary+uint64(i*4):table.OffsetInBinary+uint64((i+1)*4)], 55 uint32(nop.OffsetInBinary())-uint32(base)) 56 } 57 } 58 return 59 }