mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 18:42:26 -05:00 
			
		
		
		
	[experiment] add alternative wasm sqlite3 implementation available via build-tag (#2863)
This allows for building GoToSocial with [SQLite transpiled to WASM](https://github.com/ncruces/go-sqlite3) and accessed through [Wazero](https://wazero.io/).
This commit is contained in:
		
					parent
					
						
							
								cce21c11cb
							
						
					
				
			
			
				commit
				
					
						1e7b32490d
					
				
			
		
					 398 changed files with 86174 additions and 684 deletions
				
			
		
							
								
								
									
										352
									
								
								vendor/github.com/tetratelabs/wazero/builder.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								vendor/github.com/tetratelabs/wazero/builder.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,352 @@ | |||
| package wazero | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 
 | ||||
| 	"github.com/tetratelabs/wazero/api" | ||||
| 	"github.com/tetratelabs/wazero/internal/wasm" | ||||
| ) | ||||
| 
 | ||||
| // HostFunctionBuilder defines a host function (in Go), so that a | ||||
| // WebAssembly binary (e.g. %.wasm file) can import and use it. | ||||
| // | ||||
| // Here's an example of an addition function: | ||||
| // | ||||
| //	hostModuleBuilder.NewFunctionBuilder(). | ||||
| //		WithFunc(func(cxt context.Context, x, y uint32) uint32 { | ||||
| //			return x + y | ||||
| //		}). | ||||
| //		Export("add") | ||||
| // | ||||
| // # Memory | ||||
| // | ||||
| // All host functions act on the importing api.Module, including any memory | ||||
| // exported in its binary (%.wasm file). If you are reading or writing memory, | ||||
| // it is sand-boxed Wasm memory defined by the guest. | ||||
| // | ||||
| // Below, `m` is the importing module, defined in Wasm. `fn` is a host function | ||||
| // added via Export. This means that `x` was read from memory defined in Wasm, | ||||
| // not arbitrary memory in the process. | ||||
| // | ||||
| //	fn := func(ctx context.Context, m api.Module, offset uint32) uint32 { | ||||
| //		x, _ := m.Memory().ReadUint32Le(ctx, offset) | ||||
| //		return x | ||||
| //	} | ||||
| // | ||||
| // # Notes | ||||
| // | ||||
| //   - This is an interface for decoupling, not third-party implementations. | ||||
| //     All implementations are in wazero. | ||||
| type HostFunctionBuilder interface { | ||||
| 	// WithGoFunction is an advanced feature for those who need higher | ||||
| 	// performance than WithFunc at the cost of more complexity. | ||||
| 	// | ||||
| 	// Here's an example addition function: | ||||
| 	// | ||||
| 	//	builder.WithGoFunction(api.GoFunc(func(ctx context.Context, stack []uint64) { | ||||
| 	//		x, y := api.DecodeI32(stack[0]), api.DecodeI32(stack[1]) | ||||
| 	//		sum := x + y | ||||
| 	//		stack[0] = api.EncodeI32(sum) | ||||
| 	//	}), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32}) | ||||
| 	// | ||||
| 	// As you can see above, defining in this way implies knowledge of which | ||||
| 	// WebAssembly api.ValueType is appropriate for each parameter and result. | ||||
| 	// | ||||
| 	// See WithGoModuleFunction if you also need to access the calling module. | ||||
| 	WithGoFunction(fn api.GoFunction, params, results []api.ValueType) HostFunctionBuilder | ||||
| 
 | ||||
| 	// WithGoModuleFunction is an advanced feature for those who need higher | ||||
| 	// performance than WithFunc at the cost of more complexity. | ||||
| 	// | ||||
| 	// Here's an example addition function that loads operands from memory: | ||||
| 	// | ||||
| 	//	builder.WithGoModuleFunction(api.GoModuleFunc(func(ctx context.Context, m api.Module, stack []uint64) { | ||||
| 	//		mem := m.Memory() | ||||
| 	//		offset := api.DecodeU32(stack[0]) | ||||
| 	// | ||||
| 	//		x, _ := mem.ReadUint32Le(ctx, offset) | ||||
| 	//		y, _ := mem.ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes! | ||||
| 	//		sum := x + y | ||||
| 	// | ||||
| 	//		stack[0] = api.EncodeU32(sum) | ||||
| 	//	}), []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32}) | ||||
| 	// | ||||
| 	// As you can see above, defining in this way implies knowledge of which | ||||
| 	// WebAssembly api.ValueType is appropriate for each parameter and result. | ||||
| 	// | ||||
| 	// See WithGoFunction if you don't need access to the calling module. | ||||
| 	WithGoModuleFunction(fn api.GoModuleFunction, params, results []api.ValueType) HostFunctionBuilder | ||||
| 
 | ||||
| 	// WithFunc uses reflect.Value to map a go `func` to a WebAssembly | ||||
| 	// compatible Signature. An input that isn't a `func` will fail to | ||||
| 	// instantiate. | ||||
| 	// | ||||
| 	// Here's an example of an addition function: | ||||
| 	// | ||||
| 	//	builder.WithFunc(func(cxt context.Context, x, y uint32) uint32 { | ||||
| 	//		return x + y | ||||
| 	//	}) | ||||
| 	// | ||||
| 	// # Defining a function | ||||
| 	// | ||||
| 	// Except for the context.Context and optional api.Module, all parameters | ||||
| 	// or result types must map to WebAssembly numeric value types. This means | ||||
| 	// uint32, int32, uint64, int64, float32 or float64. | ||||
| 	// | ||||
| 	// api.Module may be specified as the second parameter, usually to access | ||||
| 	// memory. This is important because there are only numeric types in Wasm. | ||||
| 	// The only way to share other data is via writing memory and sharing | ||||
| 	// offsets. | ||||
| 	// | ||||
| 	//	builder.WithFunc(func(ctx context.Context, m api.Module, offset uint32) uint32 { | ||||
| 	//		mem := m.Memory() | ||||
| 	//		x, _ := mem.ReadUint32Le(ctx, offset) | ||||
| 	//		y, _ := mem.ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes! | ||||
| 	//		return x + y | ||||
| 	//	}) | ||||
| 	// | ||||
| 	// This example propagates context properly when calling other functions | ||||
| 	// exported in the api.Module: | ||||
| 	// | ||||
| 	//	builder.WithFunc(func(ctx context.Context, m api.Module, offset, byteCount uint32) uint32 { | ||||
| 	//		fn = m.ExportedFunction("__read") | ||||
| 	//		results, err := fn(ctx, offset, byteCount) | ||||
| 	//	--snip-- | ||||
| 	WithFunc(interface{}) HostFunctionBuilder | ||||
| 
 | ||||
| 	// WithName defines the optional module-local name of this function, e.g. | ||||
| 	// "random_get" | ||||
| 	// | ||||
| 	// Note: This is not required to match the Export name. | ||||
| 	WithName(name string) HostFunctionBuilder | ||||
| 
 | ||||
| 	// WithParameterNames defines optional parameter names of the function | ||||
| 	// signature, e.x. "buf", "buf_len" | ||||
| 	// | ||||
| 	// Note: When defined, names must be provided for all parameters. | ||||
| 	WithParameterNames(names ...string) HostFunctionBuilder | ||||
| 
 | ||||
| 	// WithResultNames defines optional result names of the function | ||||
| 	// signature, e.x. "errno" | ||||
| 	// | ||||
| 	// Note: When defined, names must be provided for all results. | ||||
| 	WithResultNames(names ...string) HostFunctionBuilder | ||||
| 
 | ||||
| 	// Export exports this to the HostModuleBuilder as the given name, e.g. | ||||
| 	// "random_get" | ||||
| 	Export(name string) HostModuleBuilder | ||||
| } | ||||
| 
 | ||||
| // HostModuleBuilder is a way to define host functions (in Go), so that a | ||||
| // WebAssembly binary (e.g. %.wasm file) can import and use them. | ||||
| // | ||||
| // Specifically, this implements the host side of an Application Binary | ||||
| // Interface (ABI) like WASI or AssemblyScript. | ||||
| // | ||||
| // For example, this defines and instantiates a module named "env" with one | ||||
| // function: | ||||
| // | ||||
| //	ctx := context.Background() | ||||
| //	r := wazero.NewRuntime(ctx) | ||||
| //	defer r.Close(ctx) // This closes everything this Runtime created. | ||||
| // | ||||
| //	hello := func() { | ||||
| //		println("hello!") | ||||
| //	} | ||||
| //	env, _ := r.NewHostModuleBuilder("env"). | ||||
| //		NewFunctionBuilder().WithFunc(hello).Export("hello"). | ||||
| //		Instantiate(ctx) | ||||
| // | ||||
| // If the same module may be instantiated multiple times, it is more efficient | ||||
| // to separate steps. Here's an example: | ||||
| // | ||||
| //	compiled, _ := r.NewHostModuleBuilder("env"). | ||||
| //		NewFunctionBuilder().WithFunc(getRandomString).Export("get_random_string"). | ||||
| //		Compile(ctx) | ||||
| // | ||||
| //	env1, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.1")) | ||||
| //	env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2")) | ||||
| // | ||||
| // See HostFunctionBuilder for valid host function signatures and other details. | ||||
| // | ||||
| // # Notes | ||||
| // | ||||
| //   - This is an interface for decoupling, not third-party implementations. | ||||
| //     All implementations are in wazero. | ||||
| //   - HostModuleBuilder is mutable: each method returns the same instance for | ||||
| //     chaining. | ||||
| //   - methods do not return errors, to allow chaining. Any validation errors | ||||
| //     are deferred until Compile. | ||||
| //   - Functions are indexed in order of calls to NewFunctionBuilder as | ||||
| //     insertion ordering is needed by ABI such as Emscripten (invoke_*). | ||||
| type HostModuleBuilder interface { | ||||
| 	// Note: until golang/go#5860, we can't use example tests to embed code in interface godocs. | ||||
| 
 | ||||
| 	// NewFunctionBuilder begins the definition of a host function. | ||||
| 	NewFunctionBuilder() HostFunctionBuilder | ||||
| 
 | ||||
| 	// Compile returns a CompiledModule that can be instantiated by Runtime. | ||||
| 	Compile(context.Context) (CompiledModule, error) | ||||
| 
 | ||||
| 	// Instantiate is a convenience that calls Compile, then Runtime.InstantiateModule. | ||||
| 	// This can fail for reasons documented on Runtime.InstantiateModule. | ||||
| 	// | ||||
| 	// Here's an example: | ||||
| 	// | ||||
| 	//	ctx := context.Background() | ||||
| 	//	r := wazero.NewRuntime(ctx) | ||||
| 	//	defer r.Close(ctx) // This closes everything this Runtime created. | ||||
| 	// | ||||
| 	//	hello := func() { | ||||
| 	//		println("hello!") | ||||
| 	//	} | ||||
| 	//	env, _ := r.NewHostModuleBuilder("env"). | ||||
| 	//		NewFunctionBuilder().WithFunc(hello).Export("hello"). | ||||
| 	//		Instantiate(ctx) | ||||
| 	// | ||||
| 	// # Notes | ||||
| 	// | ||||
| 	//   - Closing the Runtime has the same effect as closing the result. | ||||
| 	//   - Fields in the builder are copied during instantiation: Later changes do not affect the instantiated result. | ||||
| 	//   - To avoid using configuration defaults, use Compile instead. | ||||
| 	Instantiate(context.Context) (api.Module, error) | ||||
| } | ||||
| 
 | ||||
| // hostModuleBuilder implements HostModuleBuilder | ||||
| type hostModuleBuilder struct { | ||||
| 	r              *runtime | ||||
| 	moduleName     string | ||||
| 	exportNames    []string | ||||
| 	nameToHostFunc map[string]*wasm.HostFunc | ||||
| } | ||||
| 
 | ||||
| // NewHostModuleBuilder implements Runtime.NewHostModuleBuilder | ||||
| func (r *runtime) NewHostModuleBuilder(moduleName string) HostModuleBuilder { | ||||
| 	return &hostModuleBuilder{ | ||||
| 		r:              r, | ||||
| 		moduleName:     moduleName, | ||||
| 		nameToHostFunc: map[string]*wasm.HostFunc{}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // hostFunctionBuilder implements HostFunctionBuilder | ||||
| type hostFunctionBuilder struct { | ||||
| 	b           *hostModuleBuilder | ||||
| 	fn          interface{} | ||||
| 	name        string | ||||
| 	paramNames  []string | ||||
| 	resultNames []string | ||||
| } | ||||
| 
 | ||||
| // WithGoFunction implements HostFunctionBuilder.WithGoFunction | ||||
| func (h *hostFunctionBuilder) WithGoFunction(fn api.GoFunction, params, results []api.ValueType) HostFunctionBuilder { | ||||
| 	h.fn = &wasm.HostFunc{ParamTypes: params, ResultTypes: results, Code: wasm.Code{GoFunc: fn}} | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| // WithGoModuleFunction implements HostFunctionBuilder.WithGoModuleFunction | ||||
| func (h *hostFunctionBuilder) WithGoModuleFunction(fn api.GoModuleFunction, params, results []api.ValueType) HostFunctionBuilder { | ||||
| 	h.fn = &wasm.HostFunc{ParamTypes: params, ResultTypes: results, Code: wasm.Code{GoFunc: fn}} | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| // WithFunc implements HostFunctionBuilder.WithFunc | ||||
| func (h *hostFunctionBuilder) WithFunc(fn interface{}) HostFunctionBuilder { | ||||
| 	h.fn = fn | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| // WithName implements HostFunctionBuilder.WithName | ||||
| func (h *hostFunctionBuilder) WithName(name string) HostFunctionBuilder { | ||||
| 	h.name = name | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| // WithParameterNames implements HostFunctionBuilder.WithParameterNames | ||||
| func (h *hostFunctionBuilder) WithParameterNames(names ...string) HostFunctionBuilder { | ||||
| 	h.paramNames = names | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| // WithResultNames implements HostFunctionBuilder.WithResultNames | ||||
| func (h *hostFunctionBuilder) WithResultNames(names ...string) HostFunctionBuilder { | ||||
| 	h.resultNames = names | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| // Export implements HostFunctionBuilder.Export | ||||
| func (h *hostFunctionBuilder) Export(exportName string) HostModuleBuilder { | ||||
| 	var hostFn *wasm.HostFunc | ||||
| 	if fn, ok := h.fn.(*wasm.HostFunc); ok { | ||||
| 		hostFn = fn | ||||
| 	} else { | ||||
| 		hostFn = &wasm.HostFunc{Code: wasm.Code{GoFunc: h.fn}} | ||||
| 	} | ||||
| 
 | ||||
| 	// Assign any names from the builder | ||||
| 	hostFn.ExportName = exportName | ||||
| 	if h.name != "" { | ||||
| 		hostFn.Name = h.name | ||||
| 	} | ||||
| 	if len(h.paramNames) != 0 { | ||||
| 		hostFn.ParamNames = h.paramNames | ||||
| 	} | ||||
| 	if len(h.resultNames) != 0 { | ||||
| 		hostFn.ResultNames = h.resultNames | ||||
| 	} | ||||
| 
 | ||||
| 	h.b.ExportHostFunc(hostFn) | ||||
| 	return h.b | ||||
| } | ||||
| 
 | ||||
| // ExportHostFunc implements wasm.HostFuncExporter | ||||
| func (b *hostModuleBuilder) ExportHostFunc(fn *wasm.HostFunc) { | ||||
| 	if _, ok := b.nameToHostFunc[fn.ExportName]; !ok { // add a new name | ||||
| 		b.exportNames = append(b.exportNames, fn.ExportName) | ||||
| 	} | ||||
| 	b.nameToHostFunc[fn.ExportName] = fn | ||||
| } | ||||
| 
 | ||||
| // NewFunctionBuilder implements HostModuleBuilder.NewFunctionBuilder | ||||
| func (b *hostModuleBuilder) NewFunctionBuilder() HostFunctionBuilder { | ||||
| 	return &hostFunctionBuilder{b: b} | ||||
| } | ||||
| 
 | ||||
| // Compile implements HostModuleBuilder.Compile | ||||
| func (b *hostModuleBuilder) Compile(ctx context.Context) (CompiledModule, error) { | ||||
| 	module, err := wasm.NewHostModule(b.moduleName, b.exportNames, b.nameToHostFunc, b.r.enabledFeatures) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} else if err = module.Validate(b.r.enabledFeatures); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	c := &compiledModule{module: module, compiledEngine: b.r.store.Engine} | ||||
| 	listeners, err := buildFunctionListeners(ctx, module) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if err = b.r.store.Engine.CompileModule(ctx, module, listeners, false); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// typeIDs are static and compile-time known. | ||||
| 	typeIDs, err := b.r.store.GetFunctionTypeIDs(module.TypeSection) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c.typeIDs = typeIDs | ||||
| 
 | ||||
| 	return c, nil | ||||
| } | ||||
| 
 | ||||
| // Instantiate implements HostModuleBuilder.Instantiate | ||||
| func (b *hostModuleBuilder) Instantiate(ctx context.Context) (api.Module, error) { | ||||
| 	if compiled, err := b.Compile(ctx); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		compiled.(*compiledModule).closeWithModule = true | ||||
| 		return b.r.InstantiateModule(ctx, compiled, NewModuleConfig()) | ||||
| 	} | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue