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
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,74 @@
public final class ConstantEvaluators {
private ConstantEvaluators() {}

public static Value computeConstantValue(Instance instance, Instruction[] expr) {
public static long computeConstantValue(Instance instance, Instruction[] expr) {
return computeConstantValue(instance, Arrays.asList(expr));
}

public static Value computeConstantValue(Instance instance, List<Instruction> expr) {
Value tos = null;
public static long computeConstantValue(Instance instance, List<Instruction> expr) {
long tos = -1L;
for (var instruction : expr) {
switch (instruction.opcode()) {
case F32_CONST:
case F64_CONST:
case I32_CONST:
case I64_CONST:
case REF_FUNC:
{
tos = instruction.operand(0);
break;
}
case REF_NULL:
{
tos = Value.f32(instruction.operand(0));
tos = Value.REF_NULL_VALUE;
break;
}
case GLOBAL_GET:
{
var idx = (int) instruction.operand(0);
tos = instance.readGlobal(idx);
break;
}
case END:
{
break;
}
}
}
return tos;
}

public static ValueType computeConstantType(Instance instance, List<Instruction> expr) {
ValueType tos = null;
for (var instruction : expr) {
switch (instruction.opcode()) {
case F32_CONST:
{
tos = ValueType.F32;
break;
}
case F64_CONST:
{
tos = Value.f64(instruction.operand(0));
tos = ValueType.F64;
break;
}
case I32_CONST:
{
tos = Value.i32(instruction.operand(0));
tos = ValueType.I32;
break;
}
case I64_CONST:
{
tos = Value.i64(instruction.operand(0));
tos = ValueType.I64;
break;
}
case REF_NULL:
{
ValueType vt = ValueType.refTypeForId((int) instruction.operand(0));
if (vt == ValueType.ExternRef) {
tos = Value.EXTREF_NULL;
tos = ValueType.ExternRef;
} else if (vt == ValueType.FuncRef) {
tos = Value.FUNCREF_NULL;
tos = ValueType.FuncRef;
} else {
throw new IllegalStateException(
"Unexpected wrong type for ref.null instruction");
Expand All @@ -58,7 +91,7 @@ public static Value computeConstantValue(Instance instance, List<Instruction> ex
{
var idx = (int) instruction.operand(0);
instance.function(idx);
tos = Value.funcRef(idx);
tos = ValueType.FuncRef;
break;
}
case GLOBAL_GET:
Expand All @@ -71,15 +104,15 @@ public static Value computeConstantValue(Instance instance, List<Instruction> ex
"constant expression required, initializer expression"
+ " cannot reference a mutable global");
}
var t = instance.imports().global(idx).instance().getType();
return new Value(t, instance.readGlobal(idx));
tos = instance.imports().global(idx).instance().getType();
} else {
throw new InvalidException(
"unknown global "
+ idx
+ ", initializer expression can only reference"
+ " an imported global");
}
break;
}
case END:
{
Expand Down
46 changes: 21 additions & 25 deletions runtime/src/main/java/com/dylibso/chicory/runtime/Instance.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dylibso.chicory.runtime;

import static com.dylibso.chicory.runtime.ConstantEvaluators.computeConstantInstance;
import static com.dylibso.chicory.runtime.ConstantEvaluators.computeConstantType;
import static com.dylibso.chicory.runtime.ConstantEvaluators.computeConstantValue;
import static com.dylibso.chicory.wasm.types.ExternalType.FUNCTION;
import static com.dylibso.chicory.wasm.types.Value.REF_NULL_VALUE;
Expand Down Expand Up @@ -116,53 +117,46 @@ public Instance initialize(boolean start) {
if (el instanceof ActiveElement) {
var ae = (ActiveElement) el;
var table = table(ae.tableIndex());
int offset = (int) computeConstantValue(this, ae.offset());

if (ae.offset().size() > 1) {
throw new InvalidException(
"constant expression required, type mismatch, expected [] but found"
+ " extra instructions");
}
Value offset = computeConstantValue(this, ae.offset());
if (offset.type() != ValueType.I32) {
throw new InvalidException(
"type mismatch, invalid offset type in element " + offset.type());
}
List<List<Instruction>> initializers = ae.initializers();
if (offset.asInt() > table.limits().min()
|| (offset.asInt() + initializers.size() - 1) >= table.size()) {
if (offset > table.limits().min()
|| (offset + initializers.size() - 1) >= table.size()) {
throw new UninstantiableException("out of bounds table access");
}
for (int i = 0; i < initializers.size(); i++) {
final List<Instruction> init = initializers.get(i);
int index = offset.asInt() + i;
int index = offset + i;
if (init.stream().filter(e -> e.opcode() != OpCode.END).count() > 1L) {
throw new InvalidException(
"constant expression required, type mismatch, expected [] but found"
+ " extra instructions");
}
var value = computeConstantValue(this, init);
var inst = computeConstantInstance(this, init);
if (value.type() != ae.type() || table.elementType() != ae.type()) {
var valueType = computeConstantType(this, init);
if (valueType != ae.type() || table.elementType() != ae.type()) {
throw new InvalidException(
"type mismatch, element type: "
+ ae.type()
+ ", table type: "
+ table.elementType()
+ ", value type: "
+ value.type());
+ valueType);
}
var value = computeConstantValue(this, init);
var inst = computeConstantInstance(this, init);

if (ae.type() == ValueType.FuncRef) {
if (((int) value.raw()) != REF_NULL_VALUE) {
if (value != REF_NULL_VALUE) {
try {
function(value.raw());
function(value);
} catch (InvalidException e) {
throw new InvalidException("type mismatch, " + e.getMessage(), e);
}
}
table.setRef(index, (int) value.raw(), inst);
table.setRef(index, (int) value, inst);
} else {
assert ae.type() == ValueType.ExternRef;
table.setRef(index, (int) value.raw(), inst);
table.setRef(index, (int) value, inst);
}
}
} else if (el instanceof DeclarativeElement) {
Expand All @@ -179,12 +173,14 @@ public Instance initialize(boolean start) {
"constant expression required, type mismatch, expected [] but found extra"
+ " instructions");
}
var value = computeConstantValue(this, g.initInstructions());
if (g.valueType() != value.type()) {
var valueType = computeConstantType(this, g.initInstructions());
if (g.valueType() != valueType) {
throw new InvalidException(
"type mismatch, expected: " + g.valueType() + ", got: " + value.type());
"type mismatch, expected: " + g.valueType() + ", got: " + valueType);
}
globals[i] = new GlobalInstance(value, g.mutabilityType());
var value = computeConstantValue(this, g.initInstructions());

globals[i] = new GlobalInstance(new Value(valueType, value), g.mutabilityType());
globals[i].setInstance(this);
}

Expand Down
21 changes: 2 additions & 19 deletions runtime/src/main/java/com/dylibso/chicory/runtime/Memory.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@

import com.dylibso.chicory.runtime.exceptions.WASMRuntimeException;
import com.dylibso.chicory.wasm.exceptions.ChicoryException;
import com.dylibso.chicory.wasm.exceptions.InvalidException;
import com.dylibso.chicory.wasm.exceptions.UninstantiableException;
import com.dylibso.chicory.wasm.types.ActiveDataSegment;
import com.dylibso.chicory.wasm.types.DataSegment;
import com.dylibso.chicory.wasm.types.MemoryLimits;
import com.dylibso.chicory.wasm.types.PassiveDataSegment;
import com.dylibso.chicory.wasm.types.ValueType;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
Expand Down Expand Up @@ -106,25 +104,10 @@ public void initialize(Instance instance, DataSegment[] dataSegments) {
for (var s : dataSegments) {
if (s instanceof ActiveDataSegment) {
var segment = (ActiveDataSegment) s;
if (segment.index() != 0) {
throw new InvalidException("unknown memory " + segment.index());
}
var offsetExpr = segment.offsetInstructions();
if (offsetExpr.size() > 1) {
throw new InvalidException(
"type mismatch, constant expression required, expected only one"
+ " initialization instruction");
}
var data = segment.data();
var offsetValue = computeConstantValue(instance, offsetExpr);
if (offsetValue.type() != ValueType.I32) {
throw new InvalidException(
"type mismatch, expected I32 but found "
+ offsetValue.type()
+ " in offset memory initialization");
}
var offset = offsetValue.asInt();
write(offset, data);
var offset = computeConstantValue(instance, offsetExpr);
write((int) offset, data);
} else if (s instanceof PassiveDataSegment) {
// Passive segment should be skipped
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -856,16 +856,15 @@ public static void TABLE_INIT(

for (int i = offset; i < end; i++) {
var elem = instance.element(elementidx);
var val = computeConstantValue(instance, elem.initializers().get(elemidx++));
var rawValue = (int) val.raw();
var val = (int) computeConstantValue(instance, elem.initializers().get(elemidx++));
if (table.elementType() == ValueType.FuncRef) {
if (rawValue > instance.functionCount()) {
if (val > instance.functionCount()) {
throw new WASMRuntimeException("out of bounds table access");
}
table.setRef(i, rawValue, instance);
table.setRef(i, val, instance);
} else {
assert table.elementType() == ValueType.ExternRef;
table.setRef(i, rawValue, instance);
table.setRef(i, val, instance);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,9 @@ public void validateData() {
for (var ds : module.dataSection().dataSegments()) {
if (ds instanceof ActiveDataSegment) {
var ads = (ActiveDataSegment) ds;
if (ads.index() != 0) {
throw new InvalidException("unknown memory " + ads.index());
}
validateConstantExpression(ads.offsetInstructions(), ValueType.I32);
}
}
Expand Down Expand Up @@ -450,6 +453,9 @@ private void validateConstantExpression(
throw new InvalidException("type mismatch, multiple constant expressions found");
}
}
if (constInstrCount <= 0) {
throw new InvalidException("type mismatch, no constant expressions found");
}
}

public void validateFunctions() {
Expand Down
Loading