summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm-interpreter.h67
-rw-r--r--test/lit/exec/strings.wast195
2 files changed, 261 insertions, 1 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 87b0e0c67..4615e8625 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1843,7 +1843,72 @@ public:
Flow visitStringMeasure(StringMeasure* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitStringEncode(StringEncode* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitStringConcat(StringConcat* curr) { WASM_UNREACHABLE("unimp"); }
- Flow visitStringEq(StringEq* curr) { WASM_UNREACHABLE("unimp"); }
+ Flow visitStringEq(StringEq* curr) {
+ NOTE_ENTER("StringEq");
+ Flow flow = visit(curr->left);
+ if (flow.breaking()) {
+ return flow;
+ }
+ auto left = flow.getSingleValue();
+ flow = visit(curr->right);
+ if (flow.breaking()) {
+ return flow;
+ }
+ auto right = flow.getSingleValue();
+ NOTE_EVAL2(left, right);
+ auto leftData = left.getGCData();
+ auto rightData = right.getGCData();
+ int32_t result;
+ switch (curr->op) {
+ case StringEqEqual: {
+ // They are equal if both are null, or both are non-null and equal.
+ result =
+ (!leftData && !rightData) ||
+ (leftData && rightData && leftData->values == rightData->values);
+ break;
+ }
+ case StringEqCompare: {
+ if (!leftData || !rightData) {
+ trap("null ref");
+ }
+ auto& leftValues = leftData->values;
+ auto& rightValues = rightData->values;
+ Index i = 0;
+ while (1) {
+ if (i == leftValues.size() && i == rightValues.size()) {
+ // We reached the end, and they are equal.
+ result = 0;
+ break;
+ } else if (i == leftValues.size()) {
+ // The left string is short.
+ result = -1;
+ break;
+ } else if (i == rightValues.size()) {
+ result = 1;
+ break;
+ }
+ auto left = leftValues[i].getInteger();
+ auto right = rightValues[i].getInteger();
+ if (left < right) {
+ // The left character is lower.
+ result = -1;
+ break;
+ } else if (left > right) {
+ result = 1;
+ break;
+ } else {
+ // Look further.
+ i++;
+ }
+ }
+ break;
+ }
+ default: {
+ WASM_UNREACHABLE("bad op");
+ }
+ }
+ return Literal(result);
+ }
Flow visitStringAs(StringAs* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitStringWTF8Advance(StringWTF8Advance* curr) {
WASM_UNREACHABLE("unimp");
diff --git a/test/lit/exec/strings.wast b/test/lit/exec/strings.wast
index 2852337c8..6aa9d7b8a 100644
--- a/test/lit/exec/strings.wast
+++ b/test/lit/exec/strings.wast
@@ -26,11 +26,206 @@
(func "const" (result stringref)
(string.const "world")
)
+
+ ;; CHECK: [fuzz-exec] calling eq.1
+ ;; CHECK-NEXT: [fuzz-exec] note result: eq.1 => 0
+ (func "eq.1" (result i32)
+ (string.eq
+ (string.const "hello")
+ (string.const "world")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling eq.2
+ ;; CHECK-NEXT: [fuzz-exec] note result: eq.2 => 1
+ (func "eq.2" (result i32)
+ (string.eq
+ (string.const "hello")
+ (string.const "hello")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling eq.3
+ ;; CHECK-NEXT: [fuzz-exec] note result: eq.3 => 0
+ (func "eq.3" (result i32)
+ (string.eq
+ (string.const "hello")
+ (ref.null string)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling eq.4
+ ;; CHECK-NEXT: [fuzz-exec] note result: eq.4 => 0
+ (func "eq.4" (result i32)
+ (string.eq
+ (ref.null string)
+ (string.const "world")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling eq.5
+ ;; CHECK-NEXT: [fuzz-exec] note result: eq.5 => 1
+ (func "eq.5" (result i32)
+ (string.eq
+ (ref.null string)
+ (ref.null string)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.1
+ ;; CHECK-NEXT: [trap null ref]
+ (func "compare.1" (result i32)
+ (string.compare
+ (string.const "hello")
+ (ref.null string)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.2
+ ;; CHECK-NEXT: [trap null ref]
+ (func "compare.2" (result i32)
+ (string.compare
+ (ref.null string)
+ (string.const "world")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.3
+ ;; CHECK-NEXT: [trap null ref]
+ (func "compare.3" (result i32)
+ (string.compare
+ (ref.null string)
+ (ref.null string)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.4
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.4 => 0
+ (func "compare.4" (result i32)
+ (string.compare
+ (string.const "hello")
+ (string.const "hello")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.5
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.5 => -1
+ (func "compare.5" (result i32)
+ (string.compare
+ (string.const "hello")
+ (string.const "hezlo")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.6
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.6 => 1
+ (func "compare.6" (result i32)
+ (string.compare
+ (string.const "hezlo")
+ (string.const "hello")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.7
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.7 => -1
+ (func "compare.7" (result i32)
+ (string.compare
+ (string.const "he")
+ (string.const "hello")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.8
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.8 => 1
+ (func "compare.8" (result i32)
+ (string.compare
+ (string.const "hello")
+ (string.const "he")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.9
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.9 => 1
+ (func "compare.9" (result i32)
+ (string.compare
+ (string.const "hf")
+ (string.const "hello")
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling compare.10
+ ;; CHECK-NEXT: [fuzz-exec] note result: compare.10 => -1
+ (func "compare.10" (result i32)
+ (string.compare
+ (string.const "hello")
+ (string.const "hf")
+ )
+ )
)
;; CHECK: [fuzz-exec] calling new_wtf16_array
;; CHECK-NEXT: [fuzz-exec] note result: new_wtf16_array => string("ello")
;; CHECK: [fuzz-exec] calling const
;; CHECK-NEXT: [fuzz-exec] note result: const => string("world")
+
+;; CHECK: [fuzz-exec] calling eq.1
+;; CHECK-NEXT: [fuzz-exec] note result: eq.1 => 0
+
+;; CHECK: [fuzz-exec] calling eq.2
+;; CHECK-NEXT: [fuzz-exec] note result: eq.2 => 1
+
+;; CHECK: [fuzz-exec] calling eq.3
+;; CHECK-NEXT: [fuzz-exec] note result: eq.3 => 0
+
+;; CHECK: [fuzz-exec] calling eq.4
+;; CHECK-NEXT: [fuzz-exec] note result: eq.4 => 0
+
+;; CHECK: [fuzz-exec] calling eq.5
+;; CHECK-NEXT: [fuzz-exec] note result: eq.5 => 1
+
+;; CHECK: [fuzz-exec] calling compare.1
+;; CHECK-NEXT: [trap null ref]
+
+;; CHECK: [fuzz-exec] calling compare.2
+;; CHECK-NEXT: [trap null ref]
+
+;; CHECK: [fuzz-exec] calling compare.3
+;; CHECK-NEXT: [trap null ref]
+
+;; CHECK: [fuzz-exec] calling compare.4
+;; CHECK-NEXT: [fuzz-exec] note result: compare.4 => 0
+
+;; CHECK: [fuzz-exec] calling compare.5
+;; CHECK-NEXT: [fuzz-exec] note result: compare.5 => -1
+
+;; CHECK: [fuzz-exec] calling compare.6
+;; CHECK-NEXT: [fuzz-exec] note result: compare.6 => 1
+
+;; CHECK: [fuzz-exec] calling compare.7
+;; CHECK-NEXT: [fuzz-exec] note result: compare.7 => -1
+
+;; CHECK: [fuzz-exec] calling compare.8
+;; CHECK-NEXT: [fuzz-exec] note result: compare.8 => 1
+
+;; CHECK: [fuzz-exec] calling compare.9
+;; CHECK-NEXT: [fuzz-exec] note result: compare.9 => 1
+
+;; CHECK: [fuzz-exec] calling compare.10
+;; CHECK-NEXT: [fuzz-exec] note result: compare.10 => -1
+;; CHECK-NEXT: [fuzz-exec] comparing compare.1
+;; CHECK-NEXT: [fuzz-exec] comparing compare.10
+;; CHECK-NEXT: [fuzz-exec] comparing compare.2
+;; CHECK-NEXT: [fuzz-exec] comparing compare.3
+;; CHECK-NEXT: [fuzz-exec] comparing compare.4
+;; CHECK-NEXT: [fuzz-exec] comparing compare.5
+;; CHECK-NEXT: [fuzz-exec] comparing compare.6
+;; CHECK-NEXT: [fuzz-exec] comparing compare.7
+;; CHECK-NEXT: [fuzz-exec] comparing compare.8
+;; CHECK-NEXT: [fuzz-exec] comparing compare.9
;; CHECK-NEXT: [fuzz-exec] comparing const
+;; CHECK-NEXT: [fuzz-exec] comparing eq.1
+;; CHECK-NEXT: [fuzz-exec] comparing eq.2
+;; CHECK-NEXT: [fuzz-exec] comparing eq.3
+;; CHECK-NEXT: [fuzz-exec] comparing eq.4
+;; CHECK-NEXT: [fuzz-exec] comparing eq.5
;; CHECK-NEXT: [fuzz-exec] comparing new_wtf16_array