[test-api] Extract arraybufs and typed arrays
Extract tests related to array buffers and typed arrays to their own .cc files. R=mstarzinger@chromium.org Change-Id: Ic80205d02b62db1565670ecf2bb4c0dbe52fab49 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1662301 Commit-Queue: Ben Titzer <titzer@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#62219}
This commit is contained in:
parent
c7d57dd309
commit
d05871bf08
@ -163,8 +163,10 @@ v8_source_set("cctest_sources") {
|
||||
"test-accessors.cc",
|
||||
"test-allocation.cc",
|
||||
"test-api-accessors.cc",
|
||||
"test-api-array-buffer.cc",
|
||||
"test-api-interceptors.cc",
|
||||
"test-api-stack-traces.cc",
|
||||
"test-api-typed-array.cc",
|
||||
"test-api.cc",
|
||||
"test-api.h",
|
||||
"test-array-list.cc",
|
||||
|
529
test/cctest/test-api-array-buffer.cc
Normal file
529
test/cctest/test-api-array-buffer.cc
Normal file
@ -0,0 +1,529 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "test/cctest/test-api.h"
|
||||
|
||||
#include "src/api/api-inl.h"
|
||||
|
||||
using ::v8::Array;
|
||||
using ::v8::Context;
|
||||
using ::v8::Local;
|
||||
using ::v8::Value;
|
||||
|
||||
namespace {
|
||||
|
||||
class ScopedArrayBufferContents {
|
||||
public:
|
||||
explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
|
||||
: contents_(contents) {}
|
||||
~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
|
||||
void* Data() const { return contents_.Data(); }
|
||||
size_t ByteLength() const { return contents_.ByteLength(); }
|
||||
|
||||
void* AllocationBase() const { return contents_.AllocationBase(); }
|
||||
size_t AllocationLength() const { return contents_.AllocationLength(); }
|
||||
v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
|
||||
return contents_.AllocationMode();
|
||||
}
|
||||
|
||||
private:
|
||||
const v8::ArrayBuffer::Contents contents_;
|
||||
};
|
||||
|
||||
class ScopedSharedArrayBufferContents {
|
||||
public:
|
||||
explicit ScopedSharedArrayBufferContents(
|
||||
const v8::SharedArrayBuffer::Contents& contents)
|
||||
: contents_(contents) {}
|
||||
~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
|
||||
void* Data() const { return contents_.Data(); }
|
||||
size_t ByteLength() const { return contents_.ByteLength(); }
|
||||
|
||||
void* AllocationBase() const { return contents_.AllocationBase(); }
|
||||
size_t AllocationLength() const { return contents_.AllocationLength(); }
|
||||
v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
|
||||
return contents_.AllocationMode();
|
||||
}
|
||||
|
||||
private:
|
||||
const v8::SharedArrayBuffer::Contents contents_;
|
||||
};
|
||||
|
||||
void CheckDataViewIsDetached(v8::Local<v8::DataView> dv) {
|
||||
CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
|
||||
CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
|
||||
}
|
||||
|
||||
void CheckIsDetached(v8::Local<v8::TypedArray> ta) {
|
||||
CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
|
||||
CHECK_EQ(0, static_cast<int>(ta->Length()));
|
||||
CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
|
||||
}
|
||||
|
||||
void CheckIsTypedArrayVarDetached(const char* name) {
|
||||
i::ScopedVector<char> source(1024);
|
||||
i::SNPrintF(source,
|
||||
"%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
|
||||
name, name, name);
|
||||
CHECK(CompileRun(source.begin())->IsTrue());
|
||||
v8::Local<v8::TypedArray> ta =
|
||||
v8::Local<v8::TypedArray>::Cast(CompileRun(name));
|
||||
CheckIsDetached(ta);
|
||||
}
|
||||
|
||||
template <typename TypedArray, int kElementSize>
|
||||
Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab, int byteOffset,
|
||||
int length) {
|
||||
v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
|
||||
CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
|
||||
CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
|
||||
CHECK_EQ(length, static_cast<int>(ta->Length()));
|
||||
CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
|
||||
return ta;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
|
||||
CheckInternalFieldsAreZero(ab);
|
||||
CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
|
||||
CHECK(!ab->IsExternal());
|
||||
CcTest::CollectAllGarbage();
|
||||
|
||||
ScopedArrayBufferContents ab_contents(ab->Externalize());
|
||||
CHECK(ab->IsExternal());
|
||||
|
||||
CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
|
||||
uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
|
||||
CHECK_NOT_NULL(data);
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("ab.byteLength");
|
||||
CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var u8 = new Uint8Array(ab);"
|
||||
"u8[0] = 0xFF;"
|
||||
"u8[1] = 0xAA;"
|
||||
"u8.length");
|
||||
CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(0xFF, data[0]);
|
||||
CHECK_EQ(0xAA, data[1]);
|
||||
data[0] = 0xCC;
|
||||
data[1] = 0x11;
|
||||
result = CompileRun("u8[0] + u8[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun(
|
||||
"var ab1 = new ArrayBuffer(2);"
|
||||
"var u8_a = new Uint8Array(ab1);"
|
||||
"u8_a[0] = 0xAA;"
|
||||
"u8_a[1] = 0xFF; u8_a.buffer");
|
||||
Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
|
||||
CheckInternalFieldsAreZero(ab1);
|
||||
CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
|
||||
CHECK(!ab1->IsExternal());
|
||||
ScopedArrayBufferContents ab1_contents(ab1->Externalize());
|
||||
CHECK(ab1->IsExternal());
|
||||
|
||||
result = CompileRun("ab1.byteLength");
|
||||
CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun("u8_a[0]");
|
||||
CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun("u8_a[1]");
|
||||
CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun(
|
||||
"var u8_b = new Uint8Array(ab1);"
|
||||
"u8_b[0] = 0xBB;"
|
||||
"u8_a[0]");
|
||||
CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun("u8_b[1]");
|
||||
CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
|
||||
uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
|
||||
CHECK_EQ(0xBB, ab1_data[0]);
|
||||
CHECK_EQ(0xFF, ab1_data[1]);
|
||||
ab1_data[0] = 0xCC;
|
||||
ab1_data[1] = 0x11;
|
||||
result = CompileRun("u8_a[0] + u8_a[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_External) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> my_data(100);
|
||||
memset(my_data.begin(), 0, 100);
|
||||
Local<v8::ArrayBuffer> ab3 =
|
||||
v8::ArrayBuffer::New(isolate, my_data.begin(), 100);
|
||||
CheckInternalFieldsAreZero(ab3);
|
||||
CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
|
||||
CHECK(ab3->IsExternal());
|
||||
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var u8_b = new Uint8Array(ab3);"
|
||||
"u8_b[0] = 0xBB;"
|
||||
"u8_b[1] = 0xCC;"
|
||||
"u8_b.length");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(0xBB, my_data[0]);
|
||||
CHECK_EQ(0xCC, my_data[1]);
|
||||
my_data[0] = 0xCC;
|
||||
my_data[1] = 0x11;
|
||||
result = CompileRun("u8_b[0] + u8_b[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_DisableDetach) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> my_data(100);
|
||||
memset(my_data.begin(), 0, 100);
|
||||
Local<v8::ArrayBuffer> ab =
|
||||
v8::ArrayBuffer::New(isolate, my_data.begin(), 100);
|
||||
CHECK(ab->IsDetachable());
|
||||
|
||||
i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
|
||||
buf->set_is_detachable(false);
|
||||
|
||||
CHECK(!ab->IsDetachable());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_DetachingApi) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
|
||||
|
||||
v8::Local<v8::Uint8Array> u8a =
|
||||
CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
|
||||
v8::Local<v8::Uint8ClampedArray> u8c =
|
||||
CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
|
||||
v8::Local<v8::Int8Array> i8a =
|
||||
CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
|
||||
|
||||
v8::Local<v8::Uint16Array> u16a =
|
||||
CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
|
||||
v8::Local<v8::Int16Array> i16a =
|
||||
CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
|
||||
|
||||
v8::Local<v8::Uint32Array> u32a =
|
||||
CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
|
||||
v8::Local<v8::Int32Array> i32a =
|
||||
CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
|
||||
|
||||
v8::Local<v8::Float32Array> f32a =
|
||||
CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
|
||||
v8::Local<v8::Float64Array> f64a =
|
||||
CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
|
||||
|
||||
v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
|
||||
CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
|
||||
CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
|
||||
CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
|
||||
|
||||
ScopedArrayBufferContents contents(buffer->Externalize());
|
||||
buffer->Detach();
|
||||
CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
|
||||
CheckIsDetached(u8a);
|
||||
CheckIsDetached(u8c);
|
||||
CheckIsDetached(i8a);
|
||||
CheckIsDetached(u16a);
|
||||
CheckIsDetached(i16a);
|
||||
CheckIsDetached(u32a);
|
||||
CheckIsDetached(i32a);
|
||||
CheckIsDetached(f32a);
|
||||
CheckIsDetached(f64a);
|
||||
CheckDataViewIsDetached(dv);
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_DetachingScript) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
CompileRun(
|
||||
"var ab = new ArrayBuffer(1024);"
|
||||
"var u8a = new Uint8Array(ab, 1, 1023);"
|
||||
"var u8c = new Uint8ClampedArray(ab, 1, 1023);"
|
||||
"var i8a = new Int8Array(ab, 1, 1023);"
|
||||
"var u16a = new Uint16Array(ab, 2, 511);"
|
||||
"var i16a = new Int16Array(ab, 2, 511);"
|
||||
"var u32a = new Uint32Array(ab, 4, 255);"
|
||||
"var i32a = new Int32Array(ab, 4, 255);"
|
||||
"var f32a = new Float32Array(ab, 4, 255);"
|
||||
"var f64a = new Float64Array(ab, 8, 127);"
|
||||
"var dv = new DataView(ab, 1, 1023);");
|
||||
|
||||
v8::Local<v8::ArrayBuffer> ab =
|
||||
Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
|
||||
|
||||
v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
|
||||
|
||||
ScopedArrayBufferContents contents(ab->Externalize());
|
||||
ab->Detach();
|
||||
CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
|
||||
CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
|
||||
|
||||
CheckIsTypedArrayVarDetached("u8a");
|
||||
CheckIsTypedArrayVarDetached("u8c");
|
||||
CheckIsTypedArrayVarDetached("i8a");
|
||||
CheckIsTypedArrayVarDetached("u16a");
|
||||
CheckIsTypedArrayVarDetached("i16a");
|
||||
CheckIsTypedArrayVarDetached("u32a");
|
||||
CheckIsTypedArrayVarDetached("i32a");
|
||||
CheckIsTypedArrayVarDetached("f32a");
|
||||
CheckIsTypedArrayVarDetached("f64a");
|
||||
|
||||
CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
|
||||
CheckDataViewIsDetached(dv);
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_AllocationInformation) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
const size_t ab_size = 1024;
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
|
||||
ScopedArrayBufferContents contents(ab->Externalize());
|
||||
|
||||
// Array buffers should have normal allocation mode.
|
||||
CHECK_EQ(contents.AllocationMode(),
|
||||
v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
|
||||
// The allocation must contain the buffer (normally they will be equal, but
|
||||
// this is not required by the contract).
|
||||
CHECK_NOT_NULL(contents.AllocationBase());
|
||||
const uintptr_t alloc =
|
||||
reinterpret_cast<uintptr_t>(contents.AllocationBase());
|
||||
const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
|
||||
CHECK_LE(alloc, data);
|
||||
CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
|
||||
}
|
||||
|
||||
THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 0);
|
||||
CheckInternalFieldsAreZero(ab);
|
||||
CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
|
||||
CHECK(!ab->IsExternal());
|
||||
|
||||
// Externalize the buffer (taking ownership of the backing store memory).
|
||||
ScopedArrayBufferContents ab_contents(ab->Externalize());
|
||||
|
||||
Local<v8::Uint8Array> u8a = v8::Uint8Array::New(ab, 0, 0);
|
||||
// Calling Buffer() will materialize the ArrayBuffer (transitioning it from
|
||||
// on-heap to off-heap if need be). This should not affect whether it is
|
||||
// marked as is_external or not.
|
||||
USE(u8a->Buffer());
|
||||
|
||||
CHECK(ab->IsExternal());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
|
||||
CheckInternalFieldsAreZero(ab);
|
||||
CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
|
||||
CHECK(!ab->IsExternal());
|
||||
CcTest::CollectAllGarbage();
|
||||
|
||||
ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
|
||||
CHECK(ab->IsExternal());
|
||||
|
||||
CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
|
||||
uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
|
||||
CHECK_NOT_NULL(data);
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("ab.byteLength");
|
||||
CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var u8 = new Uint8Array(ab);"
|
||||
"u8[0] = 0xFF;"
|
||||
"u8[1] = 0xAA;"
|
||||
"u8.length");
|
||||
CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(0xFF, data[0]);
|
||||
CHECK_EQ(0xAA, data[1]);
|
||||
data[0] = 0xCC;
|
||||
data[1] = 0x11;
|
||||
result = CompileRun("u8[0] + u8[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun(
|
||||
"var ab1 = new SharedArrayBuffer(2);"
|
||||
"var u8_a = new Uint8Array(ab1);"
|
||||
"u8_a[0] = 0xAA;"
|
||||
"u8_a[1] = 0xFF; u8_a.buffer");
|
||||
Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
|
||||
CheckInternalFieldsAreZero(ab1);
|
||||
CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
|
||||
CHECK(!ab1->IsExternal());
|
||||
ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
|
||||
CHECK(ab1->IsExternal());
|
||||
|
||||
result = CompileRun("ab1.byteLength");
|
||||
CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun("u8_a[0]");
|
||||
CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun("u8_a[1]");
|
||||
CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun(
|
||||
"var u8_b = new Uint8Array(ab1);"
|
||||
"u8_b[0] = 0xBB;"
|
||||
"u8_a[0]");
|
||||
CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
|
||||
result = CompileRun("u8_b[1]");
|
||||
CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
|
||||
uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
|
||||
CHECK_EQ(0xBB, ab1_data[0]);
|
||||
CHECK_EQ(0xFF, ab1_data[1]);
|
||||
ab1_data[0] = 0xCC;
|
||||
ab1_data[1] = 0x11;
|
||||
result = CompileRun("u8_a[0] + u8_a[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_External) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
i::ScopedVector<uint8_t> my_data(100);
|
||||
memset(my_data.begin(), 0, 100);
|
||||
Local<v8::SharedArrayBuffer> ab3 =
|
||||
v8::SharedArrayBuffer::New(isolate, my_data.begin(), 100);
|
||||
CheckInternalFieldsAreZero(ab3);
|
||||
CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
|
||||
CHECK(ab3->IsExternal());
|
||||
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var u8_b = new Uint8Array(ab3);"
|
||||
"u8_b[0] = 0xBB;"
|
||||
"u8_b[1] = 0xCC;"
|
||||
"u8_b.length");
|
||||
CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(0xBB, my_data[0]);
|
||||
CHECK_EQ(0xCC, my_data[1]);
|
||||
my_data[0] = 0xCC;
|
||||
my_data[1] = 0x11;
|
||||
result = CompileRun("u8_b[0] + u8_b[1]");
|
||||
CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
const size_t ab_size = 1024;
|
||||
Local<v8::SharedArrayBuffer> ab =
|
||||
v8::SharedArrayBuffer::New(isolate, ab_size);
|
||||
ScopedSharedArrayBufferContents contents(ab->Externalize());
|
||||
|
||||
// Array buffers should have normal allocation mode.
|
||||
CHECK_EQ(contents.AllocationMode(),
|
||||
v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
|
||||
// The allocation must contain the buffer (normally they will be equal, but
|
||||
// this is not required by the contract).
|
||||
CHECK_NOT_NULL(contents.AllocationBase());
|
||||
const uintptr_t alloc =
|
||||
reinterpret_cast<uintptr_t>(contents.AllocationBase());
|
||||
const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
|
||||
CHECK_LE(alloc, data);
|
||||
CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
|
||||
}
|
||||
|
||||
THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
// Make sure the pointer looks like a heap object
|
||||
uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
|
||||
|
||||
// Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
|
||||
|
||||
// Should not crash
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
|
||||
CcTest::CollectAllGarbage();
|
||||
CcTest::CollectAllGarbage();
|
||||
|
||||
// Should not move the pointer
|
||||
CHECK_EQ(ab->GetContents().Data(), store_ptr);
|
||||
}
|
||||
|
||||
THREADED_TEST(SkipArrayBufferDuringScavenge) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
// Make sure the pointer looks like a heap object
|
||||
Local<v8::Object> tmp = v8::Object::New(isolate);
|
||||
uint8_t* store_ptr =
|
||||
reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
|
||||
|
||||
// Make `store_ptr` point to from space
|
||||
CcTest::CollectGarbage(i::NEW_SPACE);
|
||||
|
||||
// Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
|
||||
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
|
||||
|
||||
// Should not crash,
|
||||
// i.e. backing store pointer should not be treated as a heap object pointer
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
|
||||
|
||||
// Use `ab` to silence compiler warning
|
||||
CHECK_EQ(ab->GetContents().Data(), store_ptr);
|
||||
}
|
579
test/cctest/test-api-typed-array.cc
Normal file
579
test/cctest/test-api-typed-array.cc
Normal file
@ -0,0 +1,579 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "test/cctest/test-api.h"
|
||||
|
||||
#include "src/api/api-inl.h"
|
||||
|
||||
using ::v8::Array;
|
||||
using ::v8::Context;
|
||||
using ::v8::Local;
|
||||
using ::v8::Value;
|
||||
|
||||
namespace {
|
||||
|
||||
void CheckElementValue(i::Isolate* isolate, int expected,
|
||||
i::Handle<i::Object> obj, int offset) {
|
||||
i::Object element =
|
||||
*i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
|
||||
CHECK_EQ(expected, i::Smi::ToInt(element));
|
||||
}
|
||||
|
||||
template <class ElementType>
|
||||
void ObjectWithExternalArrayTestHelper(Local<Context> context,
|
||||
v8::Local<v8::TypedArray> obj,
|
||||
int element_count,
|
||||
i::ExternalArrayType array_type,
|
||||
int64_t low, int64_t high) {
|
||||
i::Handle<i::JSTypedArray> jsobj = v8::Utils::OpenHandle(*obj);
|
||||
v8::Isolate* v8_isolate = context->GetIsolate();
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
obj->Set(context, v8_str("field"), v8::Int32::New(v8_isolate, 1503))
|
||||
.FromJust();
|
||||
CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
|
||||
v8::Local<v8::Value> result = CompileRun("ext_array.field");
|
||||
CHECK_EQ(1503, result->Int32Value(context).FromJust());
|
||||
result = CompileRun("ext_array[1]");
|
||||
CHECK_EQ(1, result->Int32Value(context).FromJust());
|
||||
|
||||
// Check assigned smis
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = i;"
|
||||
"}"
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" sum += ext_array[i];"
|
||||
"}"
|
||||
"sum;");
|
||||
|
||||
CHECK_EQ(28, result->Int32Value(context).FromJust());
|
||||
// Check pass through of assigned smis
|
||||
result = CompileRun(
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" sum += ext_array[i] = ext_array[i] = -i;"
|
||||
"}"
|
||||
"sum;");
|
||||
CHECK_EQ(-28, result->Int32Value(context).FromJust());
|
||||
|
||||
// Check assigned smis in reverse order
|
||||
result = CompileRun(
|
||||
"for (var i = 8; --i >= 0; ) {"
|
||||
" ext_array[i] = i;"
|
||||
"}"
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" sum += ext_array[i];"
|
||||
"}"
|
||||
"sum;");
|
||||
CHECK_EQ(28, result->Int32Value(context).FromJust());
|
||||
|
||||
// Check pass through of assigned HeapNumbers
|
||||
result = CompileRun(
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 16; i+=2) {"
|
||||
" sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
|
||||
"}"
|
||||
"sum;");
|
||||
CHECK_EQ(-28, result->Int32Value(context).FromJust());
|
||||
|
||||
// Check assigned HeapNumbers
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 16; i+=2) {"
|
||||
" ext_array[i] = (i * 0.5);"
|
||||
"}"
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 16; i+=2) {"
|
||||
" sum += ext_array[i];"
|
||||
"}"
|
||||
"sum;");
|
||||
CHECK_EQ(28, result->Int32Value(context).FromJust());
|
||||
|
||||
// Check assigned HeapNumbers in reverse order
|
||||
result = CompileRun(
|
||||
"for (var i = 14; i >= 0; i-=2) {"
|
||||
" ext_array[i] = (i * 0.5);"
|
||||
"}"
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 16; i+=2) {"
|
||||
" sum += ext_array[i];"
|
||||
"}"
|
||||
"sum;");
|
||||
CHECK_EQ(28, result->Int32Value(context).FromJust());
|
||||
|
||||
i::ScopedVector<char> test_buf(1024);
|
||||
|
||||
// Check legal boundary conditions.
|
||||
// The repeated loads and stores ensure the ICs are exercised.
|
||||
const char* boundary_program =
|
||||
"var res = 0;"
|
||||
"for (var i = 0; i < 16; i++) {"
|
||||
" ext_array[i] = %lld;"
|
||||
" if (i > 8) {"
|
||||
" res = ext_array[i];"
|
||||
" }"
|
||||
"}"
|
||||
"res;";
|
||||
i::SNPrintF(test_buf, boundary_program, low);
|
||||
result = CompileRun(test_buf.begin());
|
||||
CHECK_EQ(low, result->IntegerValue(context).FromJust());
|
||||
|
||||
i::SNPrintF(test_buf, boundary_program, high);
|
||||
result = CompileRun(test_buf.begin());
|
||||
CHECK_EQ(high, result->IntegerValue(context).FromJust());
|
||||
|
||||
// Check misprediction of type in IC.
|
||||
result = CompileRun(
|
||||
"var tmp_array = ext_array;"
|
||||
"var sum = 0;"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" tmp_array[i] = i;"
|
||||
" sum += tmp_array[i];"
|
||||
" if (i == 4) {"
|
||||
" tmp_array = {};"
|
||||
" }"
|
||||
"}"
|
||||
"sum;");
|
||||
// Force GC to trigger verification.
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK_EQ(28, result->Int32Value(context).FromJust());
|
||||
|
||||
// Make sure out-of-range loads do not throw.
|
||||
i::SNPrintF(test_buf,
|
||||
"var caught_exception = false;"
|
||||
"try {"
|
||||
" ext_array[%d];"
|
||||
"} catch (e) {"
|
||||
" caught_exception = true;"
|
||||
"}"
|
||||
"caught_exception;",
|
||||
element_count);
|
||||
result = CompileRun(test_buf.begin());
|
||||
CHECK(!result->BooleanValue(v8_isolate));
|
||||
|
||||
// Make sure out-of-range stores do not throw.
|
||||
i::SNPrintF(test_buf,
|
||||
"var caught_exception = false;"
|
||||
"try {"
|
||||
" ext_array[%d] = 1;"
|
||||
"} catch (e) {"
|
||||
" caught_exception = true;"
|
||||
"}"
|
||||
"caught_exception;",
|
||||
element_count);
|
||||
result = CompileRun(test_buf.begin());
|
||||
CHECK(!result->BooleanValue(v8_isolate));
|
||||
|
||||
// Check other boundary conditions, values and operations.
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[7] = undefined;"
|
||||
"}"
|
||||
"ext_array[7];");
|
||||
CHECK_EQ(0, result->Int32Value(context).FromJust());
|
||||
if (array_type == i::kExternalFloat64Array ||
|
||||
array_type == i::kExternalFloat32Array) {
|
||||
CHECK(std::isnan(
|
||||
i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
|
||||
} else {
|
||||
CheckElementValue(isolate, 0, jsobj, 7);
|
||||
}
|
||||
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[6] = '2.3';"
|
||||
"}"
|
||||
"ext_array[6];");
|
||||
CHECK_EQ(2, result->Int32Value(context).FromJust());
|
||||
CHECK_EQ(2, static_cast<int>(i::Object::GetElement(isolate, jsobj, 6)
|
||||
.ToHandleChecked()
|
||||
->Number()));
|
||||
|
||||
if (array_type != i::kExternalFloat32Array &&
|
||||
array_type != i::kExternalFloat64Array) {
|
||||
// Though the specification doesn't state it, be explicit about
|
||||
// converting NaNs and +/-Infinity to zero.
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = 5;"
|
||||
"}"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = NaN;"
|
||||
"}"
|
||||
"ext_array[5];");
|
||||
CHECK_EQ(0, result->Int32Value(context).FromJust());
|
||||
CheckElementValue(isolate, 0, jsobj, 5);
|
||||
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = 5;"
|
||||
"}"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = Infinity;"
|
||||
"}"
|
||||
"ext_array[5];");
|
||||
int expected_value =
|
||||
(array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
|
||||
CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
|
||||
CheckElementValue(isolate, expected_value, jsobj, 5);
|
||||
|
||||
result = CompileRun(
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = 5;"
|
||||
"}"
|
||||
"for (var i = 0; i < 8; i++) {"
|
||||
" ext_array[i] = -Infinity;"
|
||||
"}"
|
||||
"ext_array[5];");
|
||||
CHECK_EQ(0, result->Int32Value(context).FromJust());
|
||||
CheckElementValue(isolate, 0, jsobj, 5);
|
||||
|
||||
// Check truncation behavior of integral arrays.
|
||||
const char* unsigned_data =
|
||||
"var source_data = [0.6, 10.6];"
|
||||
"var expected_results = [0, 10];";
|
||||
const char* signed_data =
|
||||
"var source_data = [0.6, 10.6, -0.6, -10.6];"
|
||||
"var expected_results = [0, 10, 0, -10];";
|
||||
const char* pixel_data =
|
||||
"var source_data = [0.6, 10.6];"
|
||||
"var expected_results = [1, 11];";
|
||||
bool is_unsigned = (array_type == i::kExternalUint8Array ||
|
||||
array_type == i::kExternalUint16Array ||
|
||||
array_type == i::kExternalUint32Array);
|
||||
bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
|
||||
|
||||
i::SNPrintF(test_buf,
|
||||
"%s"
|
||||
"var all_passed = true;"
|
||||
"for (var i = 0; i < source_data.length; i++) {"
|
||||
" for (var j = 0; j < 8; j++) {"
|
||||
" ext_array[j] = source_data[i];"
|
||||
" }"
|
||||
" all_passed = all_passed &&"
|
||||
" (ext_array[5] == expected_results[i]);"
|
||||
"}"
|
||||
"all_passed;",
|
||||
(is_unsigned ? unsigned_data
|
||||
: (is_pixel_data ? pixel_data : signed_data)));
|
||||
result = CompileRun(test_buf.begin());
|
||||
CHECK(result->BooleanValue(v8_isolate));
|
||||
}
|
||||
|
||||
{
|
||||
ElementType* data_ptr = static_cast<ElementType*>(jsobj->DataPtr());
|
||||
for (int i = 0; i < element_count; i++) {
|
||||
data_ptr[i] = static_cast<ElementType>(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool old_natives_flag_sentry = i::FLAG_allow_natives_syntax;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
|
||||
// Test complex assignments
|
||||
result = CompileRun(
|
||||
"function ee_op_test_complex_func(sum) {"
|
||||
" for (var i = 0; i < 40; ++i) {"
|
||||
" sum += (ext_array[i] += 1);"
|
||||
" sum += (ext_array[i] -= 1);"
|
||||
" } "
|
||||
" return sum;"
|
||||
"};"
|
||||
"%PrepareFunctionForOptimization(ee_op_test_complex_func);"
|
||||
"sum=0;"
|
||||
"sum=ee_op_test_complex_func(sum);"
|
||||
"sum=ee_op_test_complex_func(sum);"
|
||||
"%OptimizeFunctionOnNextCall(ee_op_test_complex_func);"
|
||||
"sum=ee_op_test_complex_func(sum);"
|
||||
"sum;");
|
||||
CHECK_EQ(4800, result->Int32Value(context).FromJust());
|
||||
|
||||
// Test count operations
|
||||
result = CompileRun(
|
||||
"function ee_op_test_count_func(sum) {"
|
||||
" for (var i = 0; i < 40; ++i) {"
|
||||
" sum += (++ext_array[i]);"
|
||||
" sum += (--ext_array[i]);"
|
||||
" } "
|
||||
" return sum;"
|
||||
"};"
|
||||
"%PrepareFunctionForOptimization(ee_op_test_count_func);"
|
||||
"sum=0;"
|
||||
"sum=ee_op_test_count_func(sum);"
|
||||
"sum=ee_op_test_count_func(sum);"
|
||||
"%OptimizeFunctionOnNextCall(ee_op_test_count_func);"
|
||||
"sum=ee_op_test_count_func(sum);"
|
||||
"sum;");
|
||||
CHECK_EQ(4800, result->Int32Value(context).FromJust());
|
||||
|
||||
i::FLAG_allow_natives_syntax = old_natives_flag_sentry;
|
||||
|
||||
result = CompileRun(
|
||||
"ext_array[3] = 33;"
|
||||
"delete ext_array[3];"
|
||||
"ext_array[3];");
|
||||
CHECK_EQ(33, result->Int32Value(context).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"ext_array[0] = 10; ext_array[1] = 11;"
|
||||
"ext_array[2] = 12; ext_array[3] = 13;"
|
||||
"try { ext_array.__defineGetter__('2', function() { return 120; }); }"
|
||||
"catch (e) { }"
|
||||
"ext_array[2];");
|
||||
CHECK_EQ(12, result->Int32Value(context).FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"var js_array = new Array(40);"
|
||||
"js_array[0] = 77;"
|
||||
"js_array;");
|
||||
CHECK_EQ(77, v8::Object::Cast(*result)
|
||||
->Get(context, v8_str("0"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context)
|
||||
.FromJust());
|
||||
|
||||
result = CompileRun(
|
||||
"ext_array[1] = 23;"
|
||||
"ext_array.__proto__ = [];"
|
||||
"js_array.__proto__ = ext_array;"
|
||||
"js_array.concat(ext_array);");
|
||||
CHECK_EQ(77, v8::Object::Cast(*result)
|
||||
->Get(context, v8_str("0"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context)
|
||||
.FromJust());
|
||||
CHECK_EQ(23, v8::Object::Cast(*result)
|
||||
->Get(context, v8_str("1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context)
|
||||
.FromJust());
|
||||
|
||||
result = CompileRun("ext_array[1] = 23;");
|
||||
CHECK_EQ(23, result->Int32Value(context).FromJust());
|
||||
}
|
||||
|
||||
template <typename ElementType, typename TypedArray, class ArrayBufferType>
|
||||
void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
|
||||
int64_t high) {
|
||||
const int kElementCount = 50;
|
||||
|
||||
i::ScopedVector<ElementType> backing_store(kElementCount + 2);
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
Local<ArrayBufferType> ab =
|
||||
ArrayBufferType::New(isolate, backing_store.begin(),
|
||||
(kElementCount + 2) * sizeof(ElementType));
|
||||
Local<TypedArray> ta =
|
||||
TypedArray::New(ab, 2 * sizeof(ElementType), kElementCount);
|
||||
CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
|
||||
CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
|
||||
CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
|
||||
CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
|
||||
CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
|
||||
|
||||
ElementType* data = backing_store.begin() + 2;
|
||||
for (int i = 0; i < kElementCount; i++) {
|
||||
data[i] = static_cast<ElementType>(i);
|
||||
}
|
||||
|
||||
ObjectWithExternalArrayTestHelper<ElementType>(env.local(), ta, kElementCount,
|
||||
array_type, low, high);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
THREADED_TEST(Uint8Array) {
|
||||
TypedArrayTestHelper<uint8_t, v8::Uint8Array, v8::ArrayBuffer>(
|
||||
i::kExternalUint8Array, 0, 0xFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(Int8Array) {
|
||||
TypedArrayTestHelper<int8_t, v8::Int8Array, v8::ArrayBuffer>(
|
||||
i::kExternalInt8Array, -0x80, 0x7F);
|
||||
}
|
||||
|
||||
THREADED_TEST(Uint16Array) {
|
||||
TypedArrayTestHelper<uint16_t, v8::Uint16Array, v8::ArrayBuffer>(
|
||||
i::kExternalUint16Array, 0, 0xFFFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(Int16Array) {
|
||||
TypedArrayTestHelper<int16_t, v8::Int16Array, v8::ArrayBuffer>(
|
||||
i::kExternalInt16Array, -0x8000, 0x7FFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(Uint32Array) {
|
||||
TypedArrayTestHelper<uint32_t, v8::Uint32Array, v8::ArrayBuffer>(
|
||||
i::kExternalUint32Array, 0, UINT_MAX);
|
||||
}
|
||||
|
||||
THREADED_TEST(Int32Array) {
|
||||
TypedArrayTestHelper<int32_t, v8::Int32Array, v8::ArrayBuffer>(
|
||||
i::kExternalInt32Array, INT_MIN, INT_MAX);
|
||||
}
|
||||
|
||||
THREADED_TEST(Float32Array) {
|
||||
TypedArrayTestHelper<float, v8::Float32Array, v8::ArrayBuffer>(
|
||||
i::kExternalFloat32Array, -500, 500);
|
||||
}
|
||||
|
||||
THREADED_TEST(Float64Array) {
|
||||
TypedArrayTestHelper<double, v8::Float64Array, v8::ArrayBuffer>(
|
||||
i::kExternalFloat64Array, -500, 500);
|
||||
}
|
||||
|
||||
THREADED_TEST(Uint8ClampedArray) {
|
||||
TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, v8::ArrayBuffer>(
|
||||
i::kExternalUint8ClampedArray, 0, 0xFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(DataView) {
|
||||
const int kSize = 50;
|
||||
|
||||
i::ScopedVector<uint8_t> backing_store(kSize + 2);
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
Local<v8::ArrayBuffer> ab =
|
||||
v8::ArrayBuffer::New(isolate, backing_store.begin(), 2 + kSize);
|
||||
Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
|
||||
CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
|
||||
CHECK_EQ(2u, dv->ByteOffset());
|
||||
CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
|
||||
CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedUint8Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<uint8_t, v8::Uint8Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalUint8Array, 0, 0xFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedInt8Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<int8_t, v8::Int8Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalInt8Array, -0x80, 0x7F);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedUint16Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<uint16_t, v8::Uint16Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalUint16Array, 0, 0xFFFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedInt16Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<int16_t, v8::Int16Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalInt16Array, -0x8000, 0x7FFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedUint32Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<uint32_t, v8::Uint32Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalUint32Array, 0, UINT_MAX);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedInt32Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<int32_t, v8::Int32Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalInt32Array, INT_MIN, INT_MAX);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedFloat32Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<float, v8::Float32Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalFloat32Array, -500, 500);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedFloat64Array) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<double, v8::Float64Array, v8::SharedArrayBuffer>(
|
||||
i::kExternalFloat64Array, -500, 500);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedUint8ClampedArray) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, v8::SharedArrayBuffer>(
|
||||
i::kExternalUint8ClampedArray, 0, 0xFF);
|
||||
}
|
||||
|
||||
THREADED_TEST(SharedDataView) {
|
||||
i::FLAG_harmony_sharedarraybuffer = true;
|
||||
const int kSize = 50;
|
||||
|
||||
i::ScopedVector<uint8_t> backing_store(kSize + 2);
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
Local<v8::SharedArrayBuffer> ab =
|
||||
v8::SharedArrayBuffer::New(isolate, backing_store.begin(), 2 + kSize);
|
||||
Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
|
||||
CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
|
||||
CHECK_EQ(2u, dv->ByteOffset());
|
||||
CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
|
||||
CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
|
||||
}
|
||||
|
||||
#define IS_ARRAY_BUFFER_VIEW_TEST(View) \
|
||||
THREADED_TEST(Is##View) { \
|
||||
LocalContext env; \
|
||||
v8::Isolate* isolate = env->GetIsolate(); \
|
||||
v8::HandleScope handle_scope(isolate); \
|
||||
\
|
||||
Local<Value> result = CompileRun( \
|
||||
"var ab = new ArrayBuffer(128);" \
|
||||
"new " #View "(ab)"); \
|
||||
CHECK(result->IsArrayBufferView()); \
|
||||
CHECK(result->Is##View()); \
|
||||
CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
|
||||
}
|
||||
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
|
||||
IS_ARRAY_BUFFER_VIEW_TEST(DataView)
|
||||
|
||||
#undef IS_ARRAY_BUFFER_VIEW_TEST
|
||||
|
||||
TEST(InternalFieldsOnTypedArray) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Context> context = env.local();
|
||||
Context::Scope context_scope(context);
|
||||
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
|
||||
v8::Local<v8::Uint8Array> array = v8::Uint8Array::New(buffer, 0, 1);
|
||||
for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
|
||||
CHECK_EQ(static_cast<void*>(nullptr),
|
||||
array->GetAlignedPointerFromInternalField(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InternalFieldsOnDataView) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Context> context = env.local();
|
||||
Context::Scope context_scope(context);
|
||||
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
|
||||
v8::Local<v8::DataView> array = v8::DataView::New(buffer, 0, 1);
|
||||
for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
|
||||
CHECK_EQ(static_cast<void*>(nullptr),
|
||||
array->GetAlignedPointerFromInternalField(i));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -42,4 +42,14 @@ static void CheckReturnValue(const T& t, i::Address callback) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void CheckInternalFieldsAreZero(v8::Local<T> value) {
|
||||
CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
|
||||
for (int i = 0; i < value->InternalFieldCount(); i++) {
|
||||
CHECK_EQ(0, value->GetInternalField(i)
|
||||
->Int32Value(CcTest::isolate()->GetCurrentContext())
|
||||
.FromJust());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // V8_TEST_CCTEST_TEST_API_H_
|
||||
|
Loading…
Reference in New Issue
Block a user