summaryrefslogtreecommitdiff
path: root/Tests/LibJS
diff options
context:
space:
mode:
authorDaniel Bertalan <dani@danielbertalan.dev>2022-09-20 18:09:33 +0200
committerAndreas Kling <kling@serenityos.org>2022-09-21 11:55:57 +0200
commit2b69af2dfe9ae2abaadee320878742a5c216deb4 (patch)
tree74d394d2f4c3e192d4dbfa01f1078f3947d43197 /Tests/LibJS
parent62fed2a31d9ff4de881deb0cf92d6061b09a7696 (diff)
downloadserenity-2b69af2dfe9ae2abaadee320878742a5c216deb4.zip
AK+LibJS: Handle NaN-boxing pointers on AArch64
JS::Value stores 48 bit pointers to separately allocated objects in its payload. On x86-64, canonical addresses have their top 16 bits set to the same value as bit 47, effectively meaning that the value has to be sign-extended to get the pointer. AArch64, however, expects the topmost bits to be all zeros. This commit gates sign extension behind `#if ARCH(X86_64)`, and adds an `#error` for unsupported architectures, so that we do not forget to think about pointer handling when porting to a new architecture. Fixes #15290 Fixes SerenityOS/ladybird#56
Diffstat (limited to 'Tests/LibJS')
-rw-r--r--Tests/LibJS/test-value-js.cpp30
1 files changed, 16 insertions, 14 deletions
diff --git a/Tests/LibJS/test-value-js.cpp b/Tests/LibJS/test-value-js.cpp
index 2b0fbdd959..eac8c4463d 100644
--- a/Tests/LibJS/test-value-js.cpp
+++ b/Tests/LibJS/test-value-js.cpp
@@ -39,25 +39,18 @@ TEST_NULLPTR_INPUT(Accessor);
#undef TEST_NULLPTR_INPUT
-// Unfortunately we don't have a way to get the pointer without it being dereferenced
-// so we just use the same logic, this is dangerous if Value is ever changed!
-static u64 extract_pointer(u64 ptr)
-{
- return (u64)(((i64)(ptr << 16)) >> 16);
-}
-
TEST_CASE(valid_pointer_in_gives_same_pointer_out)
{
if (sizeof(void*) < sizeof(double))
return;
-#define EXPECT_POINTER_TO_SURVIVE(input) \
- { \
- JS::Value value(reinterpret_cast<Object*>(static_cast<u64>(input))); \
- EXPECT(value.is_object()); \
- EXPECT(!value.is_null()); \
- auto extracted_pointer = extract_pointer(value.encoded()); \
- EXPECT_EQ(static_cast<u64>(input), extracted_pointer); \
+#define EXPECT_POINTER_TO_SURVIVE(input) \
+ { \
+ JS::Value value(reinterpret_cast<Object*>(static_cast<u64>(input))); \
+ EXPECT(value.is_object()); \
+ EXPECT(!value.is_null()); \
+ auto extracted_pointer = JS::Value::extract_pointer_bits(value.encoded()); \
+ EXPECT_EQ(static_cast<u64>(input), extracted_pointer); \
}
EXPECT_POINTER_TO_SURVIVE(0x1);
@@ -66,9 +59,18 @@ TEST_CASE(valid_pointer_in_gives_same_pointer_out)
EXPECT_POINTER_TO_SURVIVE(0x00007fffffffffff);
EXPECT_POINTER_TO_SURVIVE(0x0000700000000000);
EXPECT_POINTER_TO_SURVIVE(0x0000100000000000);
+
+#if ARCH(X86_64)
+ // On x86-64, the top 16 bits of pointers are equal to bit 47.
EXPECT_POINTER_TO_SURVIVE(0xffff800000000000);
EXPECT_POINTER_TO_SURVIVE(0xffff800000000001);
EXPECT_POINTER_TO_SURVIVE(0xffff800000000010);
+#elif ARCH(AARCH64)
+ // ... but they should contain zeroes on AArch64.
+ EXPECT_POINTER_TO_SURVIVE(0x0000800000000000);
+ EXPECT_POINTER_TO_SURVIVE(0x0000800000000001);
+ EXPECT_POINTER_TO_SURVIVE(0x0000800000000010);
+#endif
#undef EXPECT_POINTER_TO_SURVIVE
}