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  }