Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ If you have an interest in working on any of these please reach out in Zulip!
* [x] Compiler out of experimental
* [x] Exception Handling
* [x] Threads Support
* [x] Extended Constant Expressions
* [ ] GC Support
* in progress

Expand Down
6 changes: 6 additions & 0 deletions runtime-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@
<wast>proposals/exception-handling/throw.wast</wast>
<wast>proposals/exception-handling/throw_ref.wast</wast>
<wast>proposals/exception-handling/try_table.wast</wast>
<wast>proposals/extended-const/data.wast</wast>
<wast>proposals/extended-const/elem.wast</wast>
<wast>proposals/extended-const/global.wast</wast>
<wast>proposals/function-references/binary.wast</wast>
<wast>proposals/function-references/br_on_non_null.wast</wast>
<wast>proposals/function-references/br_on_null.wast</wast>
Expand Down Expand Up @@ -375,6 +378,9 @@
<wast>proposals/exception-handling/throw.wast</wast>
<wast>proposals/exception-handling/throw_ref.wast</wast>
<wast>proposals/exception-handling/try_table.wast</wast>
<wast>proposals/extended-const/data.wast</wast>
<wast>proposals/extended-const/elem.wast</wast>
<wast>proposals/extended-const/global.wast</wast>
<wast>proposals/function-references/binary.wast</wast>
<wast>proposals/function-references/br_on_non_null.wast</wast>
<wast>proposals/function-references/br_on_null.wast</wast>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import static com.dylibso.chicory.wasm.types.OpCode.GLOBAL_GET;

import com.dylibso.chicory.wasm.MalformedException;
import com.dylibso.chicory.wasm.types.Instruction;
import com.dylibso.chicory.wasm.types.ValType;
import com.dylibso.chicory.wasm.types.Value;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.List;

Expand All @@ -16,44 +18,96 @@ public static long[] computeConstantValue(Instance instance, Instruction[] expr)
}

public static long[] computeConstantValue(Instance instance, List<Instruction> expr) {
long tos = -1L;
var stack = new ArrayDeque<long[]>();
for (var instruction : expr) {
switch (instruction.opcode()) {
case I32_ADD:
{
var x = (int) stack.pop()[0];
var y = (int) stack.pop()[0];
stack.push(new long[] {x + y});
break;
}
case I32_SUB:
{
var x = (int) stack.pop()[0];
var y = (int) stack.pop()[0];
stack.push(new long[] {y - x});
break;
}
case I32_MUL:
{
var x = (int) stack.pop()[0];
var y = (int) stack.pop()[0];
int res = x * y;
stack.push(new long[] {res});
break;
}
case I64_ADD:
{
var x = stack.pop()[0];
var y = stack.pop()[0];
stack.push(new long[] {x + y});
break;
}
case I64_SUB:
{
var x = stack.pop()[0];
var y = stack.pop()[0];
stack.push(new long[] {y - x});
break;
}
case I64_MUL:
{
var x = stack.pop()[0];
var y = stack.pop()[0];
stack.push(new long[] {x * y});
break;
}
case V128_CONST:
return new long[] {instruction.operand(0), instruction.operand(1)};
{
stack.push(new long[] {instruction.operand(0), instruction.operand(1)});
break;
}
case F32_CONST:
case F64_CONST:
case I32_CONST:
case I64_CONST:
case REF_FUNC:
{
tos = instruction.operand(0);
stack.push(new long[] {instruction.operand(0)});
break;
}
case REF_NULL:
{
tos = Value.REF_NULL_VALUE;
stack.push(new long[] {Value.REF_NULL_VALUE});
break;
}
case GLOBAL_GET:
{
var idx = (int) instruction.operand(0);
if (instance.global(idx).getType().equals(ValType.V128)) {
return new long[] {
instance.global(idx).getValueLow(),
instance.global(idx).getValueHigh()
};
stack.push(
new long[] {
instance.global(idx).getValueLow(),
instance.global(idx).getValueHigh()
});
} else {
return new long[] {instance.global(idx).getValueLow()};
stack.push(new long[] {instance.global(idx).getValueLow()});
}
break;
}
case END:
{
break;
}
default:
throw new MalformedException(
"Invalid instruction in constant value" + instruction);
}
}
return new long[] {tos};

return stack.pop();
}

public static Instance computeConstantInstance(Instance instance, List<Instruction> expr) {
Expand Down
64 changes: 33 additions & 31 deletions wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.dylibso.chicory.wasm.types.TagType;
import com.dylibso.chicory.wasm.types.ValType;
import com.dylibso.chicory.wasm.types.Value;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -526,57 +527,58 @@ void validateElements() {
void validateGlobals() {
for (Global g : module.globalSection().globals()) {
validateConstantExpression(g.initInstructions(), g.valueType());
if (g.mutabilityType() == MutabilityType.Const && g.initInstructions().size() > 1) {
throw new InvalidException("constant expression required");
}
}
}

private void validateConstantExpression(
List<? extends Instruction> expr, ValType expectedType) {
validateValueType(expectedType);
int allFuncCount = this.functionImports.size() + module.functionSection().functionCount();
int constInstrCount = 0;
var valTypeStack = new ArrayDeque<ValType>();
for (var instruction : expr) {
ValType exprType = null;

switch (instruction.opcode()) {
case I32_CONST:
exprType = ValType.I32;
constInstrCount++;
valTypeStack.push(ValType.I32);
break;
case I32_ADD:
case I32_SUB:
case I32_MUL:
valTypeStack.pop();
valTypeStack.pop();
valTypeStack.push(ValType.I32);
break;
case I64_CONST:
exprType = ValType.I64;
constInstrCount++;
valTypeStack.push(ValType.I64);
break;
case I64_ADD:
case I64_SUB:
case I64_MUL:
valTypeStack.pop();
valTypeStack.pop();
valTypeStack.push(ValType.I64);
break;
case F32_CONST:
exprType = ValType.F32;
constInstrCount++;
valTypeStack.push(ValType.F32);
break;
case F64_CONST:
exprType = ValType.F64;
constInstrCount++;
valTypeStack.push(ValType.F64);
break;
case V128_CONST:
exprType = ValType.V128;
constInstrCount++;
valTypeStack.push(ValType.V128);
break;
case REF_NULL:
{
int operand = (int) instruction.operand(0);
exprType = valType(ValType.ID.RefNull, operand);
constInstrCount++;
valTypeStack.push(valType(ValType.ID.RefNull, operand));
break;
}
case REF_FUNC:
{
constInstrCount++;
int idx = (int) instruction.operand(0);
exprType = valType(ValType.ID.Ref, getFunctionType(idx));
valTypeStack.push(valType(ValType.ID.Ref, getFunctionType(idx)));
if (idx < 0 || idx > allFuncCount) {
throw new InvalidException("unknown function " + idx);
}

break;
}
case GLOBAL_GET:
Expand All @@ -589,15 +591,14 @@ private void validateConstantExpression(
"constant expression required, initializer expression"
+ " cannot reference a mutable global");
}
exprType = global.valueType();
valTypeStack.push(global.valueType());
} else {
throw new InvalidException(
"unknown global "
+ idx
+ ", initializer expression can only reference"
+ " an imported global");
}
constInstrCount++;
break;
}
case END:
Expand All @@ -608,18 +609,19 @@ private void validateConstantExpression(
+ " encountered: "
+ instruction);
}
}

if (valTypeStack.size() < 1) {
throw new InvalidException("type mismatch, no constant expressions found");
}
if (valTypeStack.size() != 1) {
throw new InvalidException(
"type mismatch, values remaining on the stack after evaluation");
} else {
var exprType = valTypeStack.pop();
if (exprType != null && !ValType.matches(exprType, expectedType)) {
throw new InvalidException("type mismatch");
}

// There must be at most one constant instruction.
if (constInstrCount > 1) {
throw new InvalidException("type mismatch, multiple constant expressions found");
}
}
if (constInstrCount <= 0) {
throw new InvalidException("type mismatch, no constant expressions found");
}
}

Expand Down
Loading