compiler: avoid alloc with stack pointer ceil and reuse bytes reader (#1344)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -184,11 +184,9 @@ func TestCompiler_compileMaybeGrowStack(t *testing.T) {
|
|||||||
err := compiler.compilePreamble()
|
err := compiler.compilePreamble()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.NotNil(t, compiler.getOnStackPointerCeilDeterminedCallBack())
|
|
||||||
|
|
||||||
stackLen := uint64(len(env.stack()))
|
stackLen := uint64(len(env.stack()))
|
||||||
stackBasePointer := stackLen - baseOffset // Ceil <= stackLen - stackBasePointer = no need to grow!
|
stackBasePointer := stackLen - baseOffset // Ceil <= stackLen - stackBasePointer = no need to grow!
|
||||||
compiler.getOnStackPointerCeilDeterminedCallBack()(stackPointerCeil)
|
compiler.assignStackPointerCeil(stackPointerCeil)
|
||||||
env.setStackBasePointer(stackBasePointer)
|
env.setStackBasePointer(stackBasePointer)
|
||||||
|
|
||||||
compiler.compileExitFromNativeCode(nativeCallStatusCodeReturned)
|
compiler.compileExitFromNativeCode(nativeCallStatusCodeReturned)
|
||||||
|
|||||||
@@ -237,14 +237,14 @@ func (j *compilerEnv) requireNewCompiler(t *testing.T, functionType *wasm.Functi
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompilerImpl is the interface used for architecture-independent unit tests in this pkg.
|
// compilerImpl is the interface used for architecture-independent unit tests in this pkg.
|
||||||
// This is currently implemented by amd64 and arm64.
|
// This is currently implemented by amd64 and arm64.
|
||||||
type compilerImpl interface {
|
type compilerImpl interface {
|
||||||
compiler
|
compiler
|
||||||
compileExitFromNativeCode(nativeCallStatusCode)
|
compileExitFromNativeCode(nativeCallStatusCode)
|
||||||
compileMaybeGrowStack() error
|
compileMaybeGrowStack() error
|
||||||
compileReturnFunction() error
|
compileReturnFunction() error
|
||||||
getOnStackPointerCeilDeterminedCallBack() func(uint64)
|
assignStackPointerCeil(uint64)
|
||||||
setStackPointerCeil(uint64)
|
setStackPointerCeil(uint64)
|
||||||
compileReleaseRegisterToStack(loc *runtimeValueLocation)
|
compileReleaseRegisterToStack(loc *runtimeValueLocation)
|
||||||
setRuntimeValueLocationStack(runtimeValueLocationStack)
|
setRuntimeValueLocationStack(runtimeValueLocationStack)
|
||||||
|
|||||||
@@ -92,10 +92,11 @@ type amd64Compiler struct {
|
|||||||
labels [wazeroir.LabelKindNum][]amd64LabelInfo
|
labels [wazeroir.LabelKindNum][]amd64LabelInfo
|
||||||
// stackPointerCeil is the greatest stack pointer value (from runtimeValueLocationStack) seen during compilation.
|
// stackPointerCeil is the greatest stack pointer value (from runtimeValueLocationStack) seen during compilation.
|
||||||
stackPointerCeil uint64
|
stackPointerCeil uint64
|
||||||
// onStackPointerCeilDeterminedCallBack hold a callback which are called when the max stack pointer is determined BEFORE generating native code.
|
// assignStackPointerCeilNeeded holds an asm.Node whose AssignDestinationConstant must be called with the determined stack pointer ceiling.
|
||||||
onStackPointerCeilDeterminedCallBack func(stackPointerCeil uint64)
|
assignStackPointerCeilNeeded asm.Node
|
||||||
withListener bool
|
withListener bool
|
||||||
typ *wasm.FunctionType
|
typ *wasm.FunctionType
|
||||||
|
br *bytes.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAmd64Compiler() compiler {
|
func newAmd64Compiler() compiler {
|
||||||
@@ -103,6 +104,7 @@ func newAmd64Compiler() compiler {
|
|||||||
assembler: amd64.NewAssembler(),
|
assembler: amd64.NewAssembler(),
|
||||||
locationStack: newRuntimeValueLocationStack(),
|
locationStack: newRuntimeValueLocationStack(),
|
||||||
cpuFeatures: platform.CpuFeatures,
|
cpuFeatures: platform.CpuFeatures,
|
||||||
|
br: bytes.NewReader(nil),
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@@ -123,6 +125,7 @@ func (c *amd64Compiler) Init(typ *wasm.FunctionType, ir *wazeroir.CompilationRes
|
|||||||
withListener: withListener,
|
withListener: withListener,
|
||||||
labels: c.labels,
|
labels: c.labels,
|
||||||
typ: typ,
|
typ: typ,
|
||||||
|
br: c.br,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,17 +251,15 @@ func (c *amd64Compiler) compile() (code []byte, stackPointerCeil uint64, err err
|
|||||||
|
|
||||||
// Now that the max stack pointer is determined, we are invoking the callback.
|
// Now that the max stack pointer is determined, we are invoking the callback.
|
||||||
// Note this MUST be called before Assemble() below.
|
// Note this MUST be called before Assemble() below.
|
||||||
if c.onStackPointerCeilDeterminedCallBack != nil {
|
c.assignStackPointerCeil(stackPointerCeil)
|
||||||
c.onStackPointerCeilDeterminedCallBack(stackPointerCeil)
|
|
||||||
c.onStackPointerCeilDeterminedCallBack = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err = c.assembler.Assemble()
|
code, err = c.assembler.Assemble()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
code, err = platform.MmapCodeSegment(bytes.NewReader(code), len(code))
|
c.br.Reset(code)
|
||||||
|
code, err = platform.MmapCodeSegment(c.br, len(code))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +269,13 @@ func (c *amd64Compiler) compileUnreachable() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assignStackPointerCeil implements compilerImpl.assignStackPointerCeil for the amd64 architecture.
|
||||||
|
func (c *amd64Compiler) assignStackPointerCeil(ceil uint64) {
|
||||||
|
if c.assignStackPointerCeilNeeded != nil {
|
||||||
|
c.assignStackPointerCeilNeeded.AssignDestinationConstant(int64(ceil) << 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// compileSet implements compiler.compileSet for the amd64 architecture.
|
// compileSet implements compiler.compileSet for the amd64 architecture.
|
||||||
func (c *amd64Compiler) compileSet(o *wazeroir.UnionOperation) error {
|
func (c *amd64Compiler) compileSet(o *wazeroir.UnionOperation) error {
|
||||||
depth := int(o.U1)
|
depth := int(o.U1)
|
||||||
@@ -4949,9 +4957,7 @@ func (c *amd64Compiler) compileMaybeGrowStack() error {
|
|||||||
|
|
||||||
// If stack base pointer + max stack pointer > stackLen, we need to grow the stack.
|
// If stack base pointer + max stack pointer > stackLen, we need to grow the stack.
|
||||||
cmpWithStackPointerCeil := c.assembler.CompileRegisterToConst(amd64.CMPQ, tmpRegister, 0)
|
cmpWithStackPointerCeil := c.assembler.CompileRegisterToConst(amd64.CMPQ, tmpRegister, 0)
|
||||||
c.onStackPointerCeilDeterminedCallBack = func(stackPointerCeil uint64) {
|
c.assignStackPointerCeilNeeded = cmpWithStackPointerCeil
|
||||||
cmpWithStackPointerCeil.AssignDestinationConstant(int64(stackPointerCeil) << 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump if we have no need to grow.
|
// Jump if we have no need to grow.
|
||||||
jmpIfNoNeedToGrowStack := c.assembler.CompileJump(amd64.JCC)
|
jmpIfNoNeedToGrowStack := c.assembler.CompileJump(amd64.JCC)
|
||||||
|
|||||||
@@ -577,11 +577,6 @@ func collectRegistersFromRuntimeValues(locs []*runtimeValueLocation) []asm.Regis
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile implements compilerImpl.getOnStackPointerCeilDeterminedCallBack for the amd64 architecture.
|
|
||||||
func (c *amd64Compiler) getOnStackPointerCeilDeterminedCallBack() func(uint64) {
|
|
||||||
return c.onStackPointerCeilDeterminedCallBack
|
|
||||||
}
|
|
||||||
|
|
||||||
// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
|
// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
|
||||||
func (c *amd64Compiler) setStackPointerCeil(v uint64) {
|
func (c *amd64Compiler) setStackPointerCeil(v uint64) {
|
||||||
c.stackPointerCeil = v
|
c.stackPointerCeil = v
|
||||||
|
|||||||
@@ -26,16 +26,18 @@ type arm64Compiler struct {
|
|||||||
labels [wazeroir.LabelKindNum][]arm64LabelInfo
|
labels [wazeroir.LabelKindNum][]arm64LabelInfo
|
||||||
// stackPointerCeil is the greatest stack pointer value (from runtimeValueLocationStack) seen during compilation.
|
// stackPointerCeil is the greatest stack pointer value (from runtimeValueLocationStack) seen during compilation.
|
||||||
stackPointerCeil uint64
|
stackPointerCeil uint64
|
||||||
// onStackPointerCeilDeterminedCallBack hold a callback which are called when the ceil of stack pointer is determined before generating native code.
|
// assignStackPointerCeilNeeded holds an asm.Node whose AssignDestinationConstant must be called with the determined stack pointer ceiling.
|
||||||
onStackPointerCeilDeterminedCallBack func(stackPointerCeil uint64)
|
assignStackPointerCeilNeeded asm.Node
|
||||||
withListener bool
|
withListener bool
|
||||||
typ *wasm.FunctionType
|
typ *wasm.FunctionType
|
||||||
|
br *bytes.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArm64Compiler() compiler {
|
func newArm64Compiler() compiler {
|
||||||
return &arm64Compiler{
|
return &arm64Compiler{
|
||||||
assembler: arm64.NewAssembler(arm64ReservedRegisterForTemporary),
|
assembler: arm64.NewAssembler(arm64ReservedRegisterForTemporary),
|
||||||
locationStack: newRuntimeValueLocationStack(),
|
locationStack: newRuntimeValueLocationStack(),
|
||||||
|
br: bytes.NewReader(nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +53,7 @@ func (c *arm64Compiler) Init(typ *wasm.FunctionType, ir *wazeroir.CompilationRes
|
|||||||
assembler: assembler, locationStack: locationStack,
|
assembler: assembler, locationStack: locationStack,
|
||||||
ir: ir, withListener: withListener, labels: c.labels,
|
ir: ir, withListener: withListener, labels: c.labels,
|
||||||
typ: typ,
|
typ: typ,
|
||||||
|
br: c.br,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,9 +124,7 @@ func (c *arm64Compiler) compile() (code []byte, stackPointerCeil uint64, err err
|
|||||||
|
|
||||||
// Now that the ceil of stack pointer is determined, we are invoking the callback.
|
// Now that the ceil of stack pointer is determined, we are invoking the callback.
|
||||||
// Note: this must be called before Assemble() below.
|
// Note: this must be called before Assemble() below.
|
||||||
if c.onStackPointerCeilDeterminedCallBack != nil {
|
c.assignStackPointerCeil(stackPointerCeil)
|
||||||
c.onStackPointerCeilDeterminedCallBack(stackPointerCeil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var original []byte
|
var original []byte
|
||||||
original, err = c.assembler.Assemble()
|
original, err = c.assembler.Assemble()
|
||||||
@@ -131,7 +132,8 @@ func (c *arm64Compiler) compile() (code []byte, stackPointerCeil uint64, err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
code, err = platform.MmapCodeSegment(bytes.NewReader(original), len(original))
|
c.br.Reset(original)
|
||||||
|
code, err = platform.MmapCodeSegment(c.br, len(original))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +145,13 @@ type arm64LabelInfo struct {
|
|||||||
initialStack runtimeValueLocationStack
|
initialStack runtimeValueLocationStack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assignStackPointerCeil implements compilerImpl.assignStackPointerCeil for the arm64 architecture.
|
||||||
|
func (c *arm64Compiler) assignStackPointerCeil(ceil uint64) {
|
||||||
|
if c.assignStackPointerCeilNeeded != nil {
|
||||||
|
c.assignStackPointerCeilNeeded.AssignSourceConstant(int64(ceil) << 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *arm64Compiler) label(label wazeroir.Label) *arm64LabelInfo {
|
func (c *arm64Compiler) label(label wazeroir.Label) *arm64LabelInfo {
|
||||||
kind := label.Kind()
|
kind := label.Kind()
|
||||||
frames := c.labels[kind]
|
frames := c.labels[kind]
|
||||||
@@ -268,9 +277,7 @@ func (c *arm64Compiler) compileMaybeGrowStack() error {
|
|||||||
)
|
)
|
||||||
// At this point of compilation, we don't know the value of stack point ceil,
|
// At this point of compilation, we don't know the value of stack point ceil,
|
||||||
// so we lazily resolve the value later.
|
// so we lazily resolve the value later.
|
||||||
c.onStackPointerCeilDeterminedCallBack = func(stackPointerCeil uint64) {
|
c.assignStackPointerCeilNeeded = loadStackPointerCeil
|
||||||
loadStackPointerCeil.AssignSourceConstant(int64(stackPointerCeil) << 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare tmpX (len(ce.stack) - ce.stackBasePointer) and tmpY (ce.stackPointerCeil)
|
// Compare tmpX (len(ce.stack) - ce.stackBasePointer) and tmpY (ce.stackPointerCeil)
|
||||||
c.assembler.CompileTwoRegistersToNone(arm64.CMP, tmpX, tmpY)
|
c.assembler.CompileTwoRegistersToNone(arm64.CMP, tmpX, tmpY)
|
||||||
|
|||||||
@@ -100,11 +100,6 @@ func TestArm64Compiler_readInstructionAddress(t *testing.T) {
|
|||||||
require.Equal(t, nativeCallStatusCodeReturned, env.compilerStatus())
|
require.Equal(t, nativeCallStatusCodeReturned, env.compilerStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile implements compilerImpl.getOnStackPointerCeilDeterminedCallBack for the amd64 architecture.
|
|
||||||
func (c *arm64Compiler) getOnStackPointerCeilDeterminedCallBack() func(uint64) {
|
|
||||||
return c.onStackPointerCeilDeterminedCallBack
|
|
||||||
}
|
|
||||||
|
|
||||||
// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
|
// compile implements compilerImpl.setStackPointerCeil for the amd64 architecture.
|
||||||
func (c *arm64Compiler) setStackPointerCeil(v uint64) {
|
func (c *arm64Compiler) setStackPointerCeil(v uint64) {
|
||||||
c.stackPointerCeil = v
|
c.stackPointerCeil = v
|
||||||
|
|||||||
Reference in New Issue
Block a user