summaryrefslogtreecommitdiff
path: root/test_ffi/tests/test.js
diff options
context:
space:
mode:
Diffstat (limited to 'test_ffi/tests/test.js')
-rw-r--r--test_ffi/tests/test.js60
1 files changed, 52 insertions, 8 deletions
diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js
index 0af94b906..65cb974f9 100644
--- a/test_ffi/tests/test.js
+++ b/test_ffi/tests/test.js
@@ -3,7 +3,7 @@
// Run using cargo test or `--v8-options=--allow-natives-syntax`
-import { assertEquals } from "https://deno.land/std@0.149.0/testing/asserts.ts";
+import { assertEquals, assertNotEquals } from "https://deno.land/std@0.149.0/testing/asserts.ts";
import {
assertThrows,
assert,
@@ -50,7 +50,8 @@ const dylib = Deno.dlopen(libPath, {
result: "void",
},
"return_buffer": { parameters: [], result: "buffer" },
- "is_null_ptr": { parameters: ["pointer"], result: "u8" },
+ "is_null_ptr": { parameters: ["pointer"], result: "bool" },
+ "is_null_buf": { name: "is_null_ptr", parameters: ["buffer"], result: "bool" },
"add_u32": { parameters: ["u32", "u32"], result: "u32" },
"add_i32": { parameters: ["i32", "i32"], result: "i32" },
"add_u64": { parameters: ["u64", "u64"], result: "u64" },
@@ -251,13 +252,56 @@ const stringPtr = Deno.UnsafePointer.of(string);
const stringPtrview = new Deno.UnsafePointerView(stringPtr);
console.log(stringPtrview.getCString());
console.log(stringPtrview.getCString(11));
-console.log(Boolean(dylib.symbols.is_null_ptr(ptr0)));
-console.log(Boolean(dylib.symbols.is_null_ptr(null)));
-console.log(Boolean(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(into))));
-const emptyBuffer = new BigUint64Array(0);
-console.log(Boolean(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(emptyBuffer))));
+console.log(dylib.symbols.is_null_ptr(ptr0));
+console.log(dylib.symbols.is_null_ptr(null));
+console.log(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(into)));
+const emptyBuffer = new Uint8Array(0);
+console.log(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(emptyBuffer)));
const emptySlice = into.subarray(6);
-console.log(Boolean(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(emptySlice))));
+console.log(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(emptySlice)));
+
+const { is_null_buf } = symbols;
+function isNullBuffer(buffer) { return is_null_buf(buffer); };
+function isNullBufferDeopt(buffer) { return is_null_buf(buffer); };
+%PrepareFunctionForOptimization(isNullBuffer);
+isNullBuffer(emptyBuffer);
+%NeverOptimizeFunction(isNullBufferDeopt);
+%OptimizeFunctionOnNextCall(isNullBuffer);
+isNullBuffer(emptyBuffer);
+assertIsOptimized(isNullBuffer);
+
+// ==== ZERO LENGTH BUFFER TESTS ====
+assertEquals(isNullBuffer(emptyBuffer), true, "isNullBuffer(emptyBuffer) !== true");
+assertEquals(isNullBufferDeopt(emptyBuffer), true, "isNullBufferDeopt(emptyBuffer) !== true");
+assertEquals(isNullBuffer(emptySlice), false, "isNullBuffer(emptySlice) !== false");
+assertEquals(isNullBufferDeopt(emptySlice), false, "isNullBufferDeopt(emptySlice) !== false");
+assertEquals(isNullBufferDeopt(new Uint8Array()), true, "isNullBufferDeopt(new Uint8Array()) !== true");
+
+// ==== V8 ZERO LENGTH BUFFER ANOMALIES ====
+
+// V8 bug: inline Uint8Array creation to fast call sees non-null pointer
+// https://bugs.chromium.org/p/v8/issues/detail?id=13489
+assertEquals(isNullBuffer(new Uint8Array()), false, "isNullBuffer(new Uint8Array()) !== false");
+
+// Externally backed ArrayBuffer has a non-null data pointer, even though its length is zero.
+const externalZeroBuffer = new Uint8Array(Deno.UnsafePointerView.getArrayBuffer(ptr0, 0));
+// However: V8 Fast calls get null pointers for zero-sized buffers.
+assertEquals(isNullBuffer(externalZeroBuffer), true, "isNullBuffer(externalZeroBuffer) !== true");
+// Also: V8's `Local<ArrayBuffer>->Data()` method returns null pointers for zero-sized buffers.
+// Using `Local<ArrayBuffer>->GetBackingStore()->Data()` would give the original pointer.
+assertEquals(isNullBufferDeopt(externalZeroBuffer), true, "isNullBufferDeopt(externalZeroBuffer) !== true");
+
+// The same pointer with a non-zero byte length for the buffer will return non-null pointers in
+// both Fast call and V8 API calls.
+const externalOneBuffer = new Uint8Array(Deno.UnsafePointerView.getArrayBuffer(ptr0, 1));
+assertEquals(isNullBuffer(externalOneBuffer), false, "isNullBuffer(externalOneBuffer) !== false");
+assertEquals(isNullBufferDeopt(externalOneBuffer), false, "isNullBufferDeopt(externalOneBuffer) !== false");
+
+// Due to ops macro using `Local<ArrayBuffer>->Data()` to get the pointer for the slice that is then used to get
+// the pointer of an ArrayBuffer / TypedArray, the same effect can be seen where a zero byte length buffer returns
+// a null pointer as its pointer value.
+assertEquals(Deno.UnsafePointer.of(externalZeroBuffer), 0, "Deno.UnsafePointer.of(externalZeroBuffer) !== 0");
+assertNotEquals(Deno.UnsafePointer.of(externalOneBuffer), 0, "Deno.UnsafePointer.of(externalOneBuffer) !== 0");
const addU32Ptr = dylib.symbols.get_add_u32_ptr();
const addU32 = new Deno.UnsafeFnPointer(addU32Ptr, {