Commit d05871bf authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

[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: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62219}
parent c7d57dd3
......@@ -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",
......
// 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);
}
// 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));
}
}
......@@ -3649,469 +3649,6 @@ THREADED_TEST(GlobalPrivates) {
CHECK(!obj->Has(env.local(), intern).FromJust());
}
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_;
};
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());
}
}
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());
}
static void CheckDataViewIsDetached(v8::Local<v8::DataView> dv) {
CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
}
static 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()));
}
static 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>
static 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;
}
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());
}
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_;
};
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(HiddenProperties) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
......@@ -15704,606 +15241,6 @@ THREADED_TEST(ReplaceConstantFunction) {
CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
}
static 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>
static 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);
}
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(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);
}
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
THREADED_TEST(ScriptContextDependence) {
LocalContext c1;
v8::HandleScope scope(c1->GetIsolate());
......@@ -25654,30 +24591,6 @@ TEST(FutexInterruption) {
timeout_thread.Join();
}
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());
}
static int nb_uncaught_exception_callback_calls = 0;
......@@ -26329,34 +25242,6 @@ THREADED_TEST(MutableProtoGlobal) {
.FromJust());
}
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));
}
}
TEST(SetPrototypeTemplate) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
......@@ -27963,3 +26848,5 @@ UNINITIALIZED_TEST(NestedIsolates) {
isolate_1->Dispose();
isolate_2->Dispose();
}
#undef THREADED_PROFILED_TEST
......@@ -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_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment