Builtin functions for memory.grow and memory.size

This commit is contained in:
MrLetsplay 2024-10-27 00:07:14 +02:00
parent 6890c78743
commit 0c23c326ac
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
4 changed files with 102 additions and 23 deletions

View File

@ -385,7 +385,45 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) {
} }
} }
switch fc.Function {
case BUILTIN_MEMORY_GROW:
if !c.Wasm64 {
cast, err := castPrimitiveWAT(Primitive_U64, Primitive_U32)
if err != nil {
return "", err
}
wat += cast
}
wat += "memory.grow\n"
if !c.Wasm64 {
cast, err := castPrimitiveWAT(Primitive_I32, Primitive_I64)
if err != nil {
return "", err
}
wat += cast
}
return wat, nil
case BUILTIN_MEMORY_SIZE:
wat += "memory.size\n"
if !c.Wasm64 {
cast, err := castPrimitiveWAT(Primitive_U32, Primitive_U64)
if err != nil {
return "", err
}
wat += cast
}
return wat, nil
default:
return wat + "call $" + fc.Function + "\n", nil return wat + "call $" + fc.Function + "\n", nil
}
case Expression_Unary: case Expression_Unary:
unary := expr.Value.(UnaryExpression) unary := expr.Value.(UnaryExpression)
exprType := expr.ValueType.Value.(PrimitiveType) exprType := expr.ValueType.Value.(PrimitiveType)

View File

@ -113,6 +113,10 @@ type Lexer struct {
Position uint64 Position uint64
} }
func unknownPosition() TokenPosition {
return TokenPosition{SourceFile: "", Position: 0}
}
func (l *Lexer) error(message string) error { func (l *Lexer) error(message string) error {
return CompilerError{Position: TokenPosition{SourceFile: l.SourceFile, Position: l.LastTokenPosition}, Message: message} return CompilerError{Position: TokenPosition{SourceFile: l.SourceFile, Position: l.LastTokenPosition}, Message: message}
} }

View File

@ -9,5 +9,14 @@ void free(u64 address) {
} }
u64 growMemory(u64 numPages) { u64 growMemory(u64 numPages) {
i64 value = __builtin_memory_grow(numPages);
if(value == -1) {
return 0u64; return 0u64;
} }
return __builtin_memory_size();
}
u64 memorySize() {
return __builtin_memory_size();
}

View File

@ -14,6 +14,26 @@ type Validator struct {
CurrentFunction *ParsedFunction CurrentFunction *ParsedFunction
} }
const (
BUILTIN_MEMORY_GROW = "__builtin_memory_grow"
BUILTIN_MEMORY_SIZE = "__builtin_memory_size"
)
var builtinFunctions map[string]*ParsedFunction = map[string]*ParsedFunction{
BUILTIN_MEMORY_GROW: {
Name: BUILTIN_MEMORY_GROW,
FullName: "builtin." + BUILTIN_MEMORY_GROW,
Parameters: []ParsedParameter{{Name: "memory", Type: Type{Type: Type_Primitive, Value: Primitive_U64, Position: unknownPosition()}}},
ReturnType: &Type{Type: Type_Primitive, Value: Primitive_I64, Position: unknownPosition()},
},
BUILTIN_MEMORY_SIZE: {
Name: BUILTIN_MEMORY_SIZE,
FullName: "builtin." + BUILTIN_MEMORY_SIZE,
Parameters: []ParsedParameter{},
ReturnType: &Type{Type: Type_Primitive, Value: Primitive_U64, Position: unknownPosition()},
},
}
func isSameType(a Type, b Type) bool { func isSameType(a Type, b Type) bool {
if a.Type != b.Type { if a.Type != b.Type {
return false return false
@ -294,11 +314,14 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression) []error
case Expression_FunctionCall: case Expression_FunctionCall:
fc := expr.Value.(FunctionCallExpression) fc := expr.Value.(FunctionCallExpression)
calledFunc, ok := v.AllFunctions[fc.Function] calledFunc, ok := builtinFunctions[fc.Function]
if !ok {
calledFunc, ok = v.AllFunctions[fc.Function]
if !ok { if !ok {
errors = append(errors, v.createError("call to undefined function '"+fc.Function+"'", expr.Position)) errors = append(errors, v.createError("call to undefined function '"+fc.Function+"'", expr.Position))
return errors return errors
} }
}
if fc.Parameters != nil { if fc.Parameters != nil {
paramsErrors := v.validateExpression(fc.Parameters) paramsErrors := v.validateExpression(fc.Parameters)
@ -306,12 +329,18 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression) []error
errors = append(errors, paramsErrors...) errors = append(errors, paramsErrors...)
return errors return errors
} }
}
params := []*Expression{fc.Parameters} var params []*Expression
if fc.Parameters.Type == Expression_Tuple { if fc.Parameters == nil {
params = []*Expression{}
} else if fc.Parameters.Type == Expression_Tuple {
params = make([]*Expression, len(fc.Parameters.Value.(TupleExpression).Members))
for i := 0; i < len(fc.Parameters.Value.(TupleExpression).Members); i++ { for i := 0; i < len(fc.Parameters.Value.(TupleExpression).Members); i++ {
params[i] = &fc.Parameters.Value.(TupleExpression).Members[i] params[i] = &fc.Parameters.Value.(TupleExpression).Members[i]
} }
} else {
params = []*Expression{fc.Parameters}
} }
if len(params) != len(calledFunc.Parameters) { if len(params) != len(calledFunc.Parameters) {
@ -322,12 +351,11 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression) []error
typeGiven := params[i] typeGiven := params[i]
typeExpected := calledFunc.Parameters[i] typeExpected := calledFunc.Parameters[i]
if !isTypeExpandableTo(*typeGiven.ValueType, typeExpected.Type) { if !isTypeExpandableTo(*typeGiven.ValueType, typeExpected.Type) {
errors = append(errors, v.createError("invalid type for parameter "+strconv.Itoa(i), expr.Position)) errors = append(errors, v.createError("invalid type for parameter "+strconv.Itoa(i)+": expected "+typeExpected.Type.String()+", got "+typeGiven.ValueType.String(), expr.Position))
} }
expandExpressionToType(typeGiven, typeExpected.Type) expandExpressionToType(typeGiven, typeExpected.Type)
} }
}
expr.ValueType = calledFunc.ReturnType expr.ValueType = calledFunc.ReturnType
expr.Value = fc expr.Value = fc