diff options
Diffstat (limited to 'deps/v8/test/cctest/test-api.cc')
-rw-r--r-- | deps/v8/test/cctest/test-api.cc | 1517 |
1 files changed, 388 insertions, 1129 deletions
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 63c980cf61..73bea08d08 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -58,7 +58,9 @@ #include "src/objects/js-array-inl.h" #include "src/objects/js-promise-inl.h" #include "src/objects/lookup.h" +#include "src/objects/module-inl.h" #include "src/objects/objects-inl.h" +#include "src/objects/string-inl.h" #include "src/profiler/cpu-profiler.h" #include "src/strings/unicode-inl.h" #include "src/utils/utils.h" @@ -3649,469 +3651,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(); @@ -9308,17 +8847,16 @@ TEST(ApiUncaughtException) { static const char* script_resource_name = "ExceptionInNativeScript.js"; static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message, v8::Local<Value>) { + v8::Isolate* isolate = message->GetIsolate(); v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName(); CHECK(!name_val.IsEmpty() && name_val->IsString()); - v8::String::Utf8Value name(v8::Isolate::GetCurrent(), + v8::String::Utf8Value name(isolate, message->GetScriptOrigin().ResourceName()); CHECK_EQ(0, strcmp(script_resource_name, *name)); - v8::Local<v8::Context> context = - v8::Isolate::GetCurrent()->GetCurrentContext(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); CHECK_EQ(3, message->GetLineNumber(context).FromJust()); v8::String::Utf8Value source_line( - v8::Isolate::GetCurrent(), - message->GetSourceLine(context).ToLocalChecked()); + isolate, message->GetSourceLine(context).ToLocalChecked()); CHECK_EQ(0, strcmp(" new o.foo();", *source_line)); } @@ -10715,6 +10253,63 @@ static void GlobalObjectInstancePropertiesGet( ApiTestFuzzer::Fuzz(); } +static int script_execution_count = 0; +static void ScriptExecutionCallback(v8::Isolate* isolate, + Local<Context> context) { + script_execution_count++; +} + +THREADED_TEST(ContextScriptExecutionCallback) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext context; + + { + v8::TryCatch try_catch(isolate); + script_execution_count = 0; + ExpectTrue("1 + 1 == 2"); + CHECK_EQ(0, script_execution_count); + CHECK(!try_catch.HasCaught()); + } + + context->SetAbortScriptExecution(ScriptExecutionCallback); + + { // Function binding does not trigger callback. + v8::Local<v8::FunctionTemplate> function_template = + v8::FunctionTemplate::New(isolate, DummyCallHandler); + v8::Local<v8::Function> function = + function_template->GetFunction(context.local()).ToLocalChecked(); + + v8::TryCatch try_catch(isolate); + script_execution_count = 0; + + CHECK_EQ(13.4, + function->Call(context.local(), v8::Undefined(isolate), 0, nullptr) + .ToLocalChecked() + ->NumberValue(context.local()) + .FromJust()); + CHECK_EQ(0, script_execution_count); + CHECK(!try_catch.HasCaught()); + } + + { // Script execution triggers callback. + v8::TryCatch try_catch(isolate); + script_execution_count = 0; + CHECK(CompileRun(context.local(), "2 + 2 == 4").IsEmpty()); + CHECK_EQ(1, script_execution_count); + CHECK(try_catch.HasCaught()); + } + + context->SetAbortScriptExecution(nullptr); + + { // Script execution no longer triggers callback. + v8::TryCatch try_catch(isolate); + script_execution_count = 0; + ExpectTrue("2 + 2 == 4"); + CHECK_EQ(0, script_execution_count); + CHECK(!try_catch.HasCaught()); + } +} THREADED_TEST(GlobalObjectInstanceProperties) { v8::Isolate* isolate = CcTest::isolate(); @@ -13115,9 +12710,9 @@ TEST(ObjectProtoToStringES6) { Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol"); Local<v8::Function> valueFunction = CompileRun("(function fn() {})").As<v8::Function>(); - Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent()); - Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent()); - Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent()); + Local<v8::Object> valueObject = v8::Object::New(isolate); + Local<v8::Primitive> valueNull = v8::Null(isolate); + Local<v8::Primitive> valueUndef = v8::Undefined(isolate); #define TEST_TOSTRINGTAG(type, tagValue, expected) \ do { \ @@ -13610,9 +13205,9 @@ THREADED_TEST(LockUnlockLock) { static int GetGlobalObjectsCount() { int count = 0; - i::HeapIterator it(CcTest::heap()); - for (i::HeapObject object = it.next(); !object.is_null(); - object = it.next()) { + i::HeapObjectIterator it(CcTest::heap()); + for (i::HeapObject object = it.Next(); !object.is_null(); + object = it.Next()) { if (object.IsJSGlobalObject()) { i::JSGlobalObject g = i::JSGlobalObject::cast(object); // Skip dummy global object. @@ -15647,606 +15242,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()); @@ -19313,9 +18308,9 @@ TEST(RunTwoIsolatesOnSingleThread) { } { - v8::HandleScope scope(v8::Isolate::GetCurrent()); + v8::HandleScope scope(isolate1); v8::Local<v8::Context> context = - v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); + v8::Local<v8::Context>::New(isolate1, context1); v8::Context::Scope context_scope(context); ExpectString("function f() { return foo; }; f()", "isolate 1"); } @@ -20208,6 +19203,21 @@ bool CodeGenerationDisallowed(Local<Context> context, Local<String> source) { return false; } +v8::MaybeLocal<String> ModifyCodeGeneration(Local<Context> context, + Local<Value> source) { + // For testing purposes, deny all odd-length strings and replace '2' with '3' + String::Utf8Value utf8(context->GetIsolate(), source); + DCHECK(utf8.length()); + if (utf8.length() == 0 || utf8.length() % 2 != 0) + return v8::MaybeLocal<String>(); + + for (char* i = *utf8; *i != '\0'; i++) { + if (*i == '2') *i = '3'; + } + return String::NewFromUtf8(context->GetIsolate(), *utf8, + v8::NewStringType::kNormal) + .ToLocalChecked(); +} THREADED_TEST(AllowCodeGenFromStrings) { LocalContext context; @@ -20240,6 +19250,36 @@ THREADED_TEST(AllowCodeGenFromStrings) { CheckCodeGenerationDisallowed(); } +TEST(ModifyCodeGenFromStrings) { + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + context->AllowCodeGenerationFromStrings(false); + context->GetIsolate()->SetModifyCodeGenerationFromStringsCallback( + &ModifyCodeGeneration); + + // Test 'allowed' case in different modes (direct eval, indirect eval, + // Function constructor, Function contructor with arguments). + Local<Value> result = CompileRun("eval('42')"); + CHECK_EQ(43, result->Int32Value(context.local()).FromJust()); + + result = CompileRun("(function(e) { return e('42'); })(eval)"); + CHECK_EQ(43, result->Int32Value(context.local()).FromJust()); + + result = CompileRun("var f = new Function('return 42;'); f()"); + CHECK_EQ(43, result->Int32Value(context.local()).FromJust()); + + // Test 'disallowed' cases. + TryCatch try_catch(CcTest::isolate()); + result = CompileRun("eval('123')"); + CHECK(result.IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); + + result = CompileRun("new Function('a', 'return 42;')(123)"); + CHECK(result.IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); +} TEST(SetErrorMessageForCodeGenFromStrings) { LocalContext context; @@ -24526,6 +23566,33 @@ v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context, CHECK_WITH_MSG(false, "Unexpected call to resolve callback"); } +v8::MaybeLocal<Value> UnexpectedSyntheticModuleEvaluationStepsCallback( + Local<Context> context, Local<Module> module) { + CHECK_WITH_MSG(false, "Unexpected call to synthetic module re callback"); +} + +static int synthetic_module_callback_count; + +v8::MaybeLocal<Value> SyntheticModuleEvaluationStepsCallback( + Local<Context> context, Local<Module> module) { + synthetic_module_callback_count++; + return v8::Undefined(reinterpret_cast<v8::Isolate*>(context->GetIsolate())); +} + +v8::MaybeLocal<Value> SyntheticModuleEvaluationStepsCallbackFail( + Local<Context> context, Local<Module> module) { + synthetic_module_callback_count++; + context->GetIsolate()->ThrowException( + v8_str("SyntheticModuleEvaluationStepsCallbackFail exception")); + return v8::MaybeLocal<Value>(); +} + +v8::MaybeLocal<Value> SyntheticModuleEvaluationStepsCallbackSetExport( + Local<Context> context, Local<Module> module) { + module->SetSyntheticModuleExport(v8_str("test_export"), v8_num(42)); + return v8::Undefined(reinterpret_cast<v8::Isolate*>(context->GetIsolate())); +} + namespace { Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate, @@ -24548,6 +23615,18 @@ Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate, return module; } +Local<Module> CreateAndInstantiateSyntheticModule( + v8::Isolate* isolate, Local<String> module_name, Local<Context> context, + std::vector<v8::Local<v8::String>> export_names, + v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) { + Local<Module> module = v8::Module::CreateSyntheticModule( + isolate, module_name, export_names, evaluation_steps); + module->InstantiateModule(context, UnexpectedModuleResolveCallback) + .ToChecked(); + + return module; +} + Local<Module> CompileAndInstantiateModuleFromCache( v8::Isolate* isolate, Local<Context> context, const char* resource_name, const char* source, v8::ScriptCompiler::CachedData* cache) { @@ -24571,6 +23650,28 @@ Local<Module> CompileAndInstantiateModuleFromCache( } // namespace +v8::MaybeLocal<Module> SyntheticModuleResolveCallback(Local<Context> context, + Local<String> specifier, + Local<Module> referrer) { + std::vector<v8::Local<v8::String>> export_names{v8_str("test_export")}; + Local<Module> module = CreateAndInstantiateSyntheticModule( + context->GetIsolate(), + v8_str("SyntheticModuleResolveCallback-TestSyntheticModule"), context, + export_names, SyntheticModuleEvaluationStepsCallbackSetExport); + return v8::MaybeLocal<Module>(module); +} + +v8::MaybeLocal<Module> SyntheticModuleThatThrowsDuringEvaluateResolveCallback( + Local<Context> context, Local<String> specifier, Local<Module> referrer) { + std::vector<v8::Local<v8::String>> export_names{v8_str("test_export")}; + Local<Module> module = CreateAndInstantiateSyntheticModule( + context->GetIsolate(), + v8_str("SyntheticModuleThatThrowsDuringEvaluateResolveCallback-" + "TestSyntheticModule"), + context, export_names, SyntheticModuleEvaluationStepsCallbackFail); + return v8::MaybeLocal<Module>(module); +} + TEST(ModuleCodeCache) { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -24636,6 +23737,214 @@ TEST(ModuleCodeCache) { } } +TEST(CreateSyntheticModule) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + auto i_isolate = reinterpret_cast<i::Isolate*>(isolate); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope cscope(context); + + std::vector<v8::Local<v8::String>> export_names{v8_str("default")}; + + Local<Module> module = CreateAndInstantiateSyntheticModule( + isolate, v8_str("CreateSyntheticModule-TestSyntheticModule"), context, + export_names, UnexpectedSyntheticModuleEvaluationStepsCallback); + i::Handle<i::SyntheticModule> i_module = + i::Handle<i::SyntheticModule>::cast(v8::Utils::OpenHandle(*module)); + i::Handle<i::ObjectHashTable> exports(i_module->exports(), i_isolate); + i::Handle<i::String> default_name = + i_isolate->factory()->NewStringFromAsciiChecked("default"); + + CHECK( + i::Handle<i::Object>(exports->Lookup(default_name), i_isolate)->IsCell()); + CHECK(i::Handle<i::Cell>::cast( + i::Handle<i::Object>(exports->Lookup(default_name), i_isolate)) + ->value() + .IsUndefined()); + CHECK_EQ(i_module->export_names().length(), 1); + CHECK(i::String::cast(i_module->export_names().get(0)).Equals(*default_name)); + CHECK_EQ(i_module->status(), i::Module::kInstantiated); +} + +TEST(SyntheticModuleSetExports) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + auto i_isolate = reinterpret_cast<i::Isolate*>(isolate); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope cscope(context); + + Local<String> foo_string = v8_str("foo"); + Local<String> bar_string = v8_str("bar"); + std::vector<v8::Local<v8::String>> export_names{foo_string}; + + Local<Module> module = CreateAndInstantiateSyntheticModule( + isolate, v8_str("SyntheticModuleSetExports-TestSyntheticModule"), context, + export_names, UnexpectedSyntheticModuleEvaluationStepsCallback); + + i::Handle<i::SyntheticModule> i_module = + i::Handle<i::SyntheticModule>::cast(v8::Utils::OpenHandle(*module)); + i::Handle<i::ObjectHashTable> exports(i_module->exports(), i_isolate); + + i::Handle<i::Cell> foo_cell = i::Handle<i::Cell>::cast(i::Handle<i::Object>( + exports->Lookup(v8::Utils::OpenHandle(*foo_string)), i_isolate)); + + // During Instantiation there should be a Cell for the export initialized to + // undefined. + CHECK(foo_cell->value().IsUndefined()); + + module->SetSyntheticModuleExport(foo_string, bar_string); + + // After setting the export the Cell should still have the same idenitity. + CHECK_EQ(exports->Lookup(v8::Utils::OpenHandle(*foo_string)), *foo_cell); + + // Test that the export value was actually set. + CHECK(i::Handle<i::String>::cast( + i::Handle<i::Object>(foo_cell->value(), i_isolate)) + ->Equals(*v8::Utils::OpenHandle(*bar_string))); +} + +TEST(SyntheticModuleEvaluationStepsNoThrow) { + synthetic_module_callback_count = 0; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope cscope(context); + + std::vector<v8::Local<v8::String>> export_names{v8_str("default")}; + + Local<Module> module = CreateAndInstantiateSyntheticModule( + isolate, + v8_str("SyntheticModuleEvaluationStepsNoThrow-TestSyntheticModule"), + context, export_names, SyntheticModuleEvaluationStepsCallback); + CHECK_EQ(synthetic_module_callback_count, 0); + Local<Value> completion_value = module->Evaluate(context).ToLocalChecked(); + CHECK(completion_value->IsUndefined()); + CHECK_EQ(synthetic_module_callback_count, 1); + CHECK_EQ(module->GetStatus(), Module::kEvaluated); +} + +TEST(SyntheticModuleEvaluationStepsThrow) { + synthetic_module_callback_count = 0; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); + v8::Context::Scope cscope(context); + + std::vector<v8::Local<v8::String>> export_names{v8_str("default")}; + + Local<Module> module = CreateAndInstantiateSyntheticModule( + isolate, + v8_str("SyntheticModuleEvaluationStepsThrow-TestSyntheticModule"), + context, export_names, SyntheticModuleEvaluationStepsCallbackFail); + TryCatch try_catch(isolate); + CHECK_EQ(synthetic_module_callback_count, 0); + v8::MaybeLocal<Value> completion_value = module->Evaluate(context); + CHECK(completion_value.IsEmpty()); + CHECK_EQ(synthetic_module_callback_count, 1); + CHECK_EQ(module->GetStatus(), Module::kErrored); + CHECK(try_catch.HasCaught()); +} + +TEST(SyntheticModuleEvaluationStepsSetExport) { + synthetic_module_callback_count = 0; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + auto i_isolate = reinterpret_cast<i::Isolate*>(isolate); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope cscope(context); + + Local<String> test_export_string = v8_str("test_export"); + std::vector<v8::Local<v8::String>> export_names{test_export_string}; + + Local<Module> module = CreateAndInstantiateSyntheticModule( + isolate, + v8_str("SyntheticModuleEvaluationStepsSetExport-TestSyntheticModule"), + context, export_names, SyntheticModuleEvaluationStepsCallbackSetExport); + + i::Handle<i::SyntheticModule> i_module = + i::Handle<i::SyntheticModule>::cast(v8::Utils::OpenHandle(*module)); + i::Handle<i::ObjectHashTable> exports(i_module->exports(), i_isolate); + + i::Handle<i::Cell> test_export_cell = + i::Handle<i::Cell>::cast(i::Handle<i::Object>( + exports->Lookup(v8::Utils::OpenHandle(*test_export_string)), + i_isolate)); + CHECK(test_export_cell->value().IsUndefined()); + + Local<Value> completion_value = module->Evaluate(context).ToLocalChecked(); + CHECK(completion_value->IsUndefined()); + CHECK_EQ(42, test_export_cell->value().Number()); + CHECK_EQ(module->GetStatus(), Module::kEvaluated); +} + +TEST(ImportFromSyntheticModule) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope cscope(context); + + Local<String> url = v8_str("www.test.com"); + Local<String> source_text = v8_str( + "import {test_export} from './synthetic.module';" + "(function() { return test_export; })();"); + v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(), + Local<v8::Boolean>(), Local<v8::Integer>(), + Local<v8::Value>(), Local<v8::Boolean>(), + Local<v8::Boolean>(), True(isolate)); + v8::ScriptCompiler::Source source(source_text, origin); + Local<Module> module = + v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); + module->InstantiateModule(context, SyntheticModuleResolveCallback) + .ToChecked(); + + Local<Value> completion_value = module->Evaluate(context).ToLocalChecked(); + CHECK_EQ(42, completion_value->Int32Value(context).FromJust()); +} + +TEST(ImportFromSyntheticModuleThrow) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::Isolate::Scope iscope(isolate); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope cscope(context); + + Local<String> url = v8_str("www.test.com"); + Local<String> source_text = v8_str( + "import {test_export} from './synthetic.module';" + "(function() { return test_export; })();"); + v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(), + Local<v8::Boolean>(), Local<v8::Integer>(), + Local<v8::Value>(), Local<v8::Boolean>(), + Local<v8::Boolean>(), True(isolate)); + v8::ScriptCompiler::Source source(source_text, origin); + Local<Module> module = + v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); + module + ->InstantiateModule( + context, SyntheticModuleThatThrowsDuringEvaluateResolveCallback) + .ToChecked(); + + CHECK_EQ(module->GetStatus(), Module::kInstantiated); + TryCatch try_catch(isolate); + v8::MaybeLocal<Value> completion_value = module->Evaluate(context); + CHECK(completion_value.IsEmpty()); + CHECK_EQ(module->GetStatus(), Module::kErrored); + CHECK(try_catch.HasCaught()); +} + // Tests that the code cache does not confuse the same source code compiled as a // script and as a module. TEST(CodeCacheModuleScriptMismatch) { @@ -25552,30 +24861,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; @@ -26227,34 +25512,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(); @@ -26483,7 +25740,7 @@ TEST(ImportMeta) { v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked(); i::Handle<i::Object> meta = i_isolate->RunHostInitializeImportMetaObjectCallback( - v8::Utils::OpenHandle(*module)); + i::Handle<i::SourceTextModule>::cast(v8::Utils::OpenHandle(*module))); CHECK(meta->IsJSObject()); Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta)); CHECK(meta_obj->Get(context.local(), v8_str("foo")) @@ -27861,3 +27118,5 @@ UNINITIALIZED_TEST(NestedIsolates) { isolate_1->Dispose(); isolate_2->Dispose(); } + +#undef THREADED_PROFILED_TEST |