diff options
Diffstat (limited to 'test_ffi/tests/test.js')
-rw-r--r-- | test_ffi/tests/test.js | 60 |
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, { |