diff options
author | Fedor Indutny <fedor.indutny@gmail.com> | 2013-01-01 12:28:07 +0400 |
---|---|---|
committer | Fedor Indutny <fedor.indutny@gmail.com> | 2013-01-01 16:07:02 +0400 |
commit | 7b4d95a976f1b76e6dcefb6ca91dff738c80ab7a (patch) | |
tree | 1eb943733a2e660fc0183778fd441443e06196e2 /deps/v8/test/cctest/test-api.cc | |
parent | 9e32c2ef3ede29ba0ae2086bdf658f6cd44182df (diff) | |
download | node-new-7b4d95a976f1b76e6dcefb6ca91dff738c80ab7a.tar.gz |
deps: update v8 to 3.15.11
Diffstat (limited to 'deps/v8/test/cctest/test-api.cc')
-rw-r--r-- | deps/v8/test/cctest/test-api.cc | 708 |
1 files changed, 652 insertions, 56 deletions
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 1e12652c0a..0a5583bb94 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -25,6 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// We want to test our deprecated API entries, too. +#define V8_DISABLE_DEPRECATIONS 1 + #include <limits.h> #ifndef WIN32 @@ -404,6 +407,10 @@ THREADED_TEST(ScriptUsingStringResource) { CHECK(source->IsExternal()); CHECK_EQ(resource, static_cast<TestResource*>(source->GetExternalStringResource())); + String::Encoding encoding = String::UNKNOWN_ENCODING; + CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), + source->GetExternalStringResourceBase(&encoding)); + CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); CHECK_EQ(0, dispose_count); } @@ -419,9 +426,16 @@ THREADED_TEST(ScriptUsingAsciiStringResource) { { v8::HandleScope scope; LocalContext env; - Local<String> source = - String::NewExternal(new TestAsciiResource(i::StrDup(c_source), - &dispose_count)); + TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source), + &dispose_count); + Local<String> source = String::NewExternal(resource); + CHECK(source->IsExternalAscii()); + CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), + source->GetExternalAsciiStringResource()); + String::Encoding encoding = String::UNKNOWN_ENCODING; + CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), + source->GetExternalStringResourceBase(&encoding)); + CHECK_EQ(String::ASCII_ENCODING, encoding); Local<Script> script = Script::Compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); @@ -445,6 +459,11 @@ THREADED_TEST(ScriptMakingExternalString) { // Trigger GCs so that the newly allocated string moves to old gen. HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now + CHECK_EQ(source->IsExternal(), false); + CHECK_EQ(source->IsExternalAscii(), false); + String::Encoding encoding = String::UNKNOWN_ENCODING; + CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding)); + CHECK_EQ(String::ASCII_ENCODING, encoding); bool success = source->MakeExternal(new TestResource(two_byte_source, &dispose_count)); CHECK(success); @@ -607,6 +626,8 @@ THREADED_TEST(UsingExternalAsciiString) { THREADED_TEST(ScavengeExternalString) { + i::FLAG_stress_compaction = false; + i::FLAG_gc_global = false; int dispose_count = 0; bool in_new_space = false; { @@ -627,6 +648,8 @@ THREADED_TEST(ScavengeExternalString) { THREADED_TEST(ScavengeExternalAsciiString) { + i::FLAG_stress_compaction = false; + i::FLAG_gc_global = false; int dispose_count = 0; bool in_new_space = false; { @@ -953,22 +976,33 @@ THREADED_TEST(FindInstanceInPrototypeChain) { THREADED_TEST(TinyInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + int32_t value = 239; Local<v8::Integer> value_obj = v8::Integer::New(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::New(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(BigSmiInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + int32_t value = i::Smi::kMaxValue; // We cannot add one to a Smi::kMaxValue without wrapping. if (i::kSmiValueSize < 32) { CHECK(i::Smi::IsValid(value)); CHECK(!i::Smi::IsValid(value + 1)); + Local<v8::Integer> value_obj = v8::Integer::New(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::New(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } } @@ -976,6 +1010,8 @@ THREADED_TEST(BigSmiInteger) { THREADED_TEST(BigInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // We cannot add one to a Smi::kMaxValue without wrapping. if (i::kSmiValueSize < 32) { // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. @@ -984,8 +1020,12 @@ THREADED_TEST(BigInteger) { static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); CHECK(value > i::Smi::kMaxValue); CHECK(!i::Smi::IsValid(value)); + Local<v8::Integer> value_obj = v8::Integer::New(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::New(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } } @@ -993,42 +1033,66 @@ THREADED_TEST(BigInteger) { THREADED_TEST(TinyUnsignedInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t value = 239; + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(BigUnsignedSmiInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); CHECK(i::Smi::IsValid(value)); CHECK(!i::Smi::IsValid(value + 1)); + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(BigUnsignedInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); CHECK(!i::Smi::IsValid(value)); + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(OutOfSignedRangeUnsignedInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; uint32_t value = INT32_MAX_AS_UINT + 1; CHECK(value > INT32_MAX_AS_UINT); // No overflow. + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } @@ -1999,6 +2063,99 @@ THREADED_TEST(InternalFieldsNativePointersAndExternal) { } +static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, + void* value) { + CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); + obj->SetPointerInInternalField(0, value); + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + CHECK_EQ(value, obj->GetPointerFromInternalField(0)); +} + + +THREADED_TEST(InternalFieldsAlignedPointers) { + v8::HandleScope scope; + LocalContext env; + + Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); + Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); + instance_templ->SetInternalFieldCount(1); + Local<v8::Object> obj = templ->GetFunction()->NewInstance(); + CHECK_EQ(1, obj->InternalFieldCount()); + + CheckAlignedPointerInInternalField(obj, NULL); + + int* heap_allocated = new int[100]; + CheckAlignedPointerInInternalField(obj, heap_allocated); + delete[] heap_allocated; + + int stack_allocated[100]; + CheckAlignedPointerInInternalField(obj, stack_allocated); + + void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); + CheckAlignedPointerInInternalField(obj, huge); +} + + +static void CheckAlignedPointerInEmbedderData(LocalContext* env, + int index, + void* value) { + CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); + (*env)->SetAlignedPointerInEmbedderData(index, value); + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); +} + + +static void* AlignedTestPointer(int i) { + return reinterpret_cast<void*>(i * 1234); +} + + +THREADED_TEST(EmbedderDataAlignedPointers) { + v8::HandleScope scope; + LocalContext env; + + CheckAlignedPointerInEmbedderData(&env, 0, NULL); + + int* heap_allocated = new int[100]; + CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); + delete[] heap_allocated; + + int stack_allocated[100]; + CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); + + void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); + CheckAlignedPointerInEmbedderData(&env, 3, huge); + + // Test growing of the embedder data's backing store. + for (int i = 0; i < 100; i++) { + env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); + } + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + for (int i = 0; i < 100; i++) { + CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); + } +} + + +static void CheckEmbedderData(LocalContext* env, + int index, + v8::Handle<Value> data) { + (*env)->SetEmbedderData(index, data); + CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); +} + +THREADED_TEST(EmbedderData) { + v8::HandleScope scope; + LocalContext env; + + CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps")); + CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog.")); + CheckEmbedderData(&env, 1, v8::Number::New(1.2345)); + CheckEmbedderData(&env, 0, v8::Boolean::New(true)); +} + + THREADED_TEST(IdentityHash) { v8::HandleScope scope; LocalContext env; @@ -2192,6 +2349,24 @@ THREADED_TEST(GlobalHandle) { } CHECK_EQ(global->Length(), 3); global.Dispose(); + + { + v8::HandleScope scope; + Local<String> str = v8_str("str"); + global = v8::Persistent<String>::New(str); + } + CHECK_EQ(global->Length(), 3); + global.Dispose(v8::Isolate::GetCurrent()); +} + + +THREADED_TEST(LocalHandle) { + v8::HandleScope scope; + v8::Local<String> local = v8::Local<String>::New(v8_str("str")); + CHECK_EQ(local->Length(), 3); + + local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str")); + CHECK_EQ(local->Length(), 3); } @@ -2312,23 +2487,41 @@ THREADED_TEST(ApiObjectGroupsCycle) { Persistent<Object> g2s2; Persistent<Object> g3s1; Persistent<Object> g3s2; + Persistent<Object> g4s1; + Persistent<Object> g4s2; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); { HandleScope scope; g1s1 = Persistent<Object>::New(Object::New()); g1s2 = Persistent<Object>::New(Object::New()); g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g1s1.IsWeak()); + CHECK(g1s2.IsWeak()); g2s1 = Persistent<Object>::New(Object::New()); g2s2 = Persistent<Object>::New(Object::New()); g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g2s1.IsWeak()); + CHECK(g2s2.IsWeak()); g3s1 = Persistent<Object>::New(Object::New()); g3s2 = Persistent<Object>::New(Object::New()); g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g3s1.IsWeak()); + CHECK(g3s2.IsWeak()); + + g4s1 = Persistent<Object>::New(Object::New()); + g4s2 = Persistent<Object>::New(Object::New()); + g4s1.MakeWeak(isolate, + reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g4s2.MakeWeak(isolate, + reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g4s1.IsWeak(isolate)); + CHECK(g4s2.IsWeak(isolate)); } Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root. @@ -2342,13 +2535,17 @@ THREADED_TEST(ApiObjectGroupsCycle) { Persistent<Value> g2_objects[] = { g2s1, g2s2 }; Persistent<Value> g2_children[] = { g3s1 }; Persistent<Value> g3_objects[] = { g3s1, g3s2 }; - Persistent<Value> g3_children[] = { g1s1 }; + Persistent<Value> g3_children[] = { g4s1 }; + Persistent<Value> g4_objects[] = { g4s1, g4s2 }; + Persistent<Value> g4_children[] = { g1s1 }; V8::AddObjectGroup(g1_objects, 2); V8::AddImplicitReferences(g1s1, g1_children, 1); V8::AddObjectGroup(g2_objects, 2); V8::AddImplicitReferences(g2s1, g2_children, 1); V8::AddObjectGroup(g3_objects, 2); V8::AddImplicitReferences(g3s1, g3_children, 1); + V8::AddObjectGroup(isolate, g4_objects, 2); + V8::AddImplicitReferences(g4s1, g4_children, 1); } // Do a single full GC HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); @@ -2366,17 +2563,117 @@ THREADED_TEST(ApiObjectGroupsCycle) { Persistent<Value> g2_objects[] = { g2s1, g2s2 }; Persistent<Value> g2_children[] = { g3s1 }; Persistent<Value> g3_objects[] = { g3s1, g3s2 }; - Persistent<Value> g3_children[] = { g1s1 }; + Persistent<Value> g3_children[] = { g4s1 }; + Persistent<Value> g4_objects[] = { g4s1, g4s2 }; + Persistent<Value> g4_children[] = { g1s1 }; V8::AddObjectGroup(g1_objects, 2); V8::AddImplicitReferences(g1s1, g1_children, 1); V8::AddObjectGroup(g2_objects, 2); V8::AddImplicitReferences(g2s1, g2_children, 1); V8::AddObjectGroup(g3_objects, 2); V8::AddImplicitReferences(g3s1, g3_children, 1); + V8::AddObjectGroup(g4_objects, 2); + V8::AddImplicitReferences(g4s1, g4_children, 1); } HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); + // All objects should be gone. 9 global handles in total. + CHECK_EQ(9, counter.NumberOfWeakCalls()); +} + + +// TODO(mstarzinger): This should be a THREADED_TEST but causes failures +// on the buildbots, so was made non-threaded for the time being. +TEST(ApiObjectGroupsCycleForScavenger) { + i::FLAG_stress_compaction = false; + i::FLAG_gc_global = false; + HandleScope scope; + LocalContext env; + + WeakCallCounter counter(1234); + + Persistent<Object> g1s1; + Persistent<Object> g1s2; + Persistent<Object> g2s1; + Persistent<Object> g2s2; + Persistent<Object> g3s1; + Persistent<Object> g3s2; + + { + HandleScope scope; + g1s1 = Persistent<Object>::New(Object::New()); + g1s2 = Persistent<Object>::New(Object::New()); + g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + + g2s1 = Persistent<Object>::New(Object::New()); + g2s2 = Persistent<Object>::New(Object::New()); + g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + + g3s1 = Persistent<Object>::New(Object::New()); + g3s2 = Persistent<Object>::New(Object::New()); + g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + } + + // Make a root. + Persistent<Object> root = Persistent<Object>::New(g1s1); + root.MarkPartiallyDependent(); + + // Connect groups. We're building the following cycle: + // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other + // groups. + { + g1s1.MarkPartiallyDependent(); + g1s2.MarkPartiallyDependent(); + g2s1.MarkPartiallyDependent(); + g2s2.MarkPartiallyDependent(); + g3s1.MarkPartiallyDependent(); + g3s2.MarkPartiallyDependent(); + Persistent<Value> g1_objects[] = { g1s1, g1s2 }; + Persistent<Value> g2_objects[] = { g2s1, g2s2 }; + Persistent<Value> g3_objects[] = { g3s1, g3s2 }; + V8::AddObjectGroup(g1_objects, 2); + g1s1->Set(v8_str("x"), g2s1); + V8::AddObjectGroup(g2_objects, 2); + g2s1->Set(v8_str("x"), g3s1); + V8::AddObjectGroup(g3_objects, 2); + g3s1->Set(v8_str("x"), g1s1); + } + + HEAP->CollectGarbage(i::NEW_SPACE); + + // All objects should be alive. + CHECK_EQ(0, counter.NumberOfWeakCalls()); + + // Weaken the root. + root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + root.MarkPartiallyDependent(); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // Groups are deleted, rebuild groups. + { + g1s1.MarkPartiallyDependent(isolate); + g1s2.MarkPartiallyDependent(isolate); + g2s1.MarkPartiallyDependent(isolate); + g2s2.MarkPartiallyDependent(isolate); + g3s1.MarkPartiallyDependent(isolate); + g3s2.MarkPartiallyDependent(isolate); + Persistent<Value> g1_objects[] = { g1s1, g1s2 }; + Persistent<Value> g2_objects[] = { g2s1, g2s2 }; + Persistent<Value> g3_objects[] = { g3s1, g3s2 }; + V8::AddObjectGroup(g1_objects, 2); + g1s1->Set(v8_str("x"), g2s1); + V8::AddObjectGroup(g2_objects, 2); + g2s1->Set(v8_str("x"), g3s1); + V8::AddObjectGroup(g3_objects, 2); + g3s1->Set(v8_str("x"), g1s1); + } + + HEAP->CollectGarbage(i::NEW_SPACE); + // All objects should be gone. 7 global handles in total. CHECK_EQ(7, counter.NumberOfWeakCalls()); } @@ -2395,23 +2692,34 @@ THREADED_TEST(ScriptException) { } +TEST(TryCatchCustomException) { + v8::HandleScope scope; + LocalContext env; + v8::TryCatch try_catch; + CompileRun("function CustomError() { this.a = 'b'; }" + "(function f() { throw new CustomError(); })();"); + CHECK(try_catch.HasCaught()); + CHECK(try_catch.Exception()->ToObject()-> + Get(v8_str("a"))->Equals(v8_str("b"))); +} + + bool message_received; -static void check_message(v8::Handle<v8::Message> message, - v8::Handle<Value> data) { - CHECK_EQ(5.76, data->NumberValue()); +static void check_message_0(v8::Handle<v8::Message> message, + v8::Handle<Value> data) { CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); message_received = true; } -THREADED_TEST(MessageHandlerData) { +THREADED_TEST(MessageHandler0) { message_received = false; v8::HandleScope scope; CHECK(!message_received); - v8::V8::AddMessageListener(check_message, v8_num(5.76)); + v8::V8::AddMessageListener(check_message_0); LocalContext context; v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("6.75")); @@ -2421,7 +2729,56 @@ THREADED_TEST(MessageHandlerData) { script->Run(); CHECK(message_received); // clear out the message listener - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(check_message_0); +} + + +static void check_message_1(v8::Handle<v8::Message> message, + v8::Handle<Value> data) { + CHECK(data->IsNumber()); + CHECK_EQ(1337, data->Int32Value()); + message_received = true; +} + + +TEST(MessageHandler1) { + message_received = false; + v8::HandleScope scope; + CHECK(!message_received); + v8::V8::AddMessageListener(check_message_1); + LocalContext context; + CompileRun("throw 1337;"); + CHECK(message_received); + // clear out the message listener + v8::V8::RemoveMessageListeners(check_message_1); +} + + +static void check_message_2(v8::Handle<v8::Message> message, + v8::Handle<Value> data) { + LocalContext context; + CHECK(data->IsObject()); + v8::Local<v8::Value> hidden_property = + v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key")); + CHECK(v8_str("hidden value")->Equals(hidden_property)); + message_received = true; +} + + +TEST(MessageHandler2) { + message_received = false; + v8::HandleScope scope; + CHECK(!message_received); + v8::V8::AddMessageListener(check_message_2); + LocalContext context; + v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); + v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"), + v8_str("hidden value")); + context->Global()->Set(v8_str("error"), error); + CompileRun("throw error;"); + CHECK(message_received); + // clear out the message listener + v8::V8::RemoveMessageListeners(check_message_2); } @@ -3062,7 +3419,7 @@ TEST(APIThrowMessageOverwrittenToString) { "Number.prototype.toString = function() { return 'Whoops'; };" "ReferenceError.prototype.toString = Object.prototype.toString;"); CompileRun("asdf;"); - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(check_reference_error_message); } @@ -3109,7 +3466,7 @@ TEST(APIThrowMessage) { LocalContext context(0, templ); CompileRun("ThrowFromC();"); CHECK(message_received); - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(receive_message); } @@ -3127,7 +3484,7 @@ TEST(APIThrowMessageAndVerboseTryCatch) { CHECK(try_catch.HasCaught()); CHECK(result.IsEmpty()); CHECK(message_received); - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(receive_message); } @@ -3399,6 +3756,30 @@ THREADED_TEST(TryCatchAndFinally) { } +static void TryCatchNestedHelper(int depth) { + if (depth > 0) { + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + TryCatchNestedHelper(depth - 1); + CHECK(try_catch.HasCaught()); + try_catch.ReThrow(); + } else { + v8::ThrowException(v8_str("back")); + } +} + + +TEST(TryCatchNested) { + v8::V8::Initialize(); + v8::HandleScope scope; + LocalContext context; + v8::TryCatch try_catch; + TryCatchNestedHelper(5); + CHECK(try_catch.HasCaught()); + CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back")); +} + + THREADED_TEST(Equality) { v8::HandleScope scope; LocalContext context; @@ -5092,7 +5473,6 @@ TEST(RegexpOutOfMemory) { static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, v8::Handle<Value> data) { - CHECK_EQ(v8::Undefined(), data); CHECK(message->GetScriptResourceName()->IsUndefined()); CHECK_EQ(v8::Undefined(), message->GetScriptResourceName()); message->GetLineNumber(); @@ -5204,18 +5584,28 @@ THREADED_TEST(IndependentWeakHandle) { v8::Persistent<Context> context = Context::New(); Context::Scope context_scope(context); - v8::Persistent<v8::Object> object_a; + v8::Persistent<v8::Object> object_a, object_b; { v8::HandleScope handle_scope; object_a = v8::Persistent<v8::Object>::New(v8::Object::New()); + object_b = v8::Persistent<v8::Object>::New(v8::Object::New()); } + v8::Isolate* isolate = v8::Isolate::GetCurrent(); bool object_a_disposed = false; + bool object_b_disposed = false; object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag); + object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag); + CHECK(!object_a.IsIndependent()); + CHECK(!object_b.IsIndependent(isolate)); object_a.MarkIndependent(); + object_b.MarkIndependent(isolate); + CHECK(object_a.IsIndependent()); + CHECK(object_b.IsIndependent(isolate)); HEAP->PerformScavenge(); CHECK(object_a_disposed); + CHECK(object_b_disposed); } @@ -7739,12 +8129,8 @@ THREADED_TEST(ShadowObject) { Local<ObjectTemplate> proto = t->PrototypeTemplate(); Local<ObjectTemplate> instance = t->InstanceTemplate(); - // Only allow calls of f on instances of t. - Local<v8::Signature> signature = v8::Signature::New(t); proto->Set(v8_str("f"), - v8::FunctionTemplate::New(ShadowFunctionCallback, - Local<Value>(), - signature)); + v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>())); proto->Set(v8_str("x"), v8_num(12)); instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); @@ -9609,6 +9995,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9639,6 +10026,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9675,6 +10063,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9711,6 +10100,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9750,6 +10140,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9812,6 +10203,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -9839,6 +10231,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -9871,6 +10264,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -9897,6 +10291,42 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); } +THREADED_TEST(CallICFastApi_SimpleSignature_TypeError) { + v8::HandleScope scope; + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); + v8::Handle<v8::FunctionTemplate> method_templ = + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, + v8_str("method_data"), + v8::Signature::New(fun_templ)); + v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); + proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); + v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); + CHECK(!templ.IsEmpty()); + LocalContext context; + v8::Handle<v8::Function> fun = fun_templ->GetFunction(); + GenerateSomeGarbage(); + context->Global()->Set(v8_str("o"), fun->NewInstance()); + v8::TryCatch try_catch; + CompileRun( + "o.foo = 17;" + "var receiver = {};" + "receiver.__proto__ = o;" + "var result = 0;" + "var saved_result = 0;" + "for (var i = 0; i < 100; i++) {" + " result = receiver.method(41);" + " if (i == 50) {" + " saved_result = result;" + " receiver = Object.create(receiver);" + " }" + "}"); + CHECK(try_catch.HasCaught()); + CHECK_EQ(v8_str("TypeError: Illegal invocation"), + try_catch.Exception()->ToString()); + CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); +} + v8::Handle<Value> keyed_call_ic_function; @@ -10824,18 +11254,21 @@ TEST(DontLeakGlobalObjects) { { v8::HandleScope scope; LocalContext context; } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope; LocalContext context; v8_compile("Date")->Run(); } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope; LocalContext context; v8_compile("/aaa/")->Run(); } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope; @@ -10844,6 +11277,7 @@ TEST(DontLeakGlobalObjects) { LocalContext context(&extensions); v8_compile("gc();")->Run(); } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); } } @@ -11044,6 +11478,7 @@ static void RunLoopInNewEnv() { TEST(SetFunctionEntryHook) { i::FLAG_allow_natives_syntax = true; + i::FLAG_use_inlining = false; // Test setting and resetting the entry hook. // Nulling it should always succeed. @@ -11176,10 +11611,6 @@ static void event_handler(const v8::JitCodeEvent* event) { } -// Implemented in the test-alloc.cc test suite. -void SimulateFullSpace(i::PagedSpace* space); - - static bool MatchPointers(void* key1, void* key2) { return key1 == key2; } @@ -12301,7 +12732,7 @@ static void MorphAString(i::String* string, AsciiVectorResource* ascii_resource, UC16VectorResource* uc16_resource) { CHECK(i::StringShape(string).IsExternal()); - if (string->IsAsciiRepresentation()) { + if (string->IsOneByteRepresentation()) { // Check old map is not symbol or long. CHECK(string->map() == HEAP->external_ascii_string_map()); // Morph external string to be TwoByte string. @@ -14436,6 +14867,89 @@ TEST(SourceURLInStackTrace) { } +v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL( + const v8::Arguments& args) { + v8::HandleScope scope; + v8::Handle<v8::StackTrace> stackTrace = + v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); + CHECK_EQ(4, stackTrace->GetFrameCount()); + v8::Handle<v8::String> url = v8_str("url"); + for (int i = 0; i < 3; i++) { + v8::Handle<v8::String> name = + stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); + CHECK(!name.IsEmpty()); + CHECK_EQ(url, name); + } + return v8::Undefined(); +} + + +TEST(InlineScriptWithSourceURLInStackTrace) { + v8::HandleScope scope; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), + v8::FunctionTemplate::New( + AnalyzeStackOfInlineScriptWithSourceURL)); + LocalContext context(0, templ); + + const char *source = + "function outer() {\n" + "function bar() {\n" + " AnalyzeStackOfInlineScriptWithSourceURL();\n" + "}\n" + "function foo() {\n" + "\n" + " bar();\n" + "}\n" + "foo();\n" + "}\n" + "outer()\n" + "//@ sourceURL=source_url"; + CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined()); +} + + +v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL( + const v8::Arguments& args) { + v8::HandleScope scope; + v8::Handle<v8::StackTrace> stackTrace = + v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); + CHECK_EQ(4, stackTrace->GetFrameCount()); + v8::Handle<v8::String> url = v8_str("source_url"); + for (int i = 0; i < 3; i++) { + v8::Handle<v8::String> name = + stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); + CHECK(!name.IsEmpty()); + CHECK_EQ(url, name); + } + return v8::Undefined(); +} + + +TEST(DynamicWithSourceURLInStackTrace) { + v8::HandleScope scope; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), + v8::FunctionTemplate::New( + AnalyzeStackOfDynamicScriptWithSourceURL)); + LocalContext context(0, templ); + + const char *source = + "function outer() {\n" + "function bar() {\n" + " AnalyzeStackOfDynamicScriptWithSourceURL();\n" + "}\n" + "function foo() {\n" + "\n" + " bar();\n" + "}\n" + "foo();\n" + "}\n" + "outer()\n" + "//@ sourceURL=source_url"; + CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined()); +} + static void CreateGarbageInOldSpace() { v8::HandleScope scope; i::AlwaysAllocateScope always_allocate; @@ -14623,11 +15137,12 @@ THREADED_TEST(GetHeapStatistics) { class VisitorImpl : public v8::ExternalResourceVisitor { public: - VisitorImpl(TestResource* r1, TestResource* r2) - : resource1_(r1), - resource2_(r2), - found_resource1_(false), - found_resource2_(false) {} + explicit VisitorImpl(TestResource** resource) { + for (int i = 0; i < 4; i++) { + resource_[i] = resource[i]; + found_resource_[i] = false; + } + } virtual ~VisitorImpl() {} virtual void VisitExternalString(v8::Handle<v8::String> string) { if (!string->IsExternal()) { @@ -14637,25 +15152,22 @@ class VisitorImpl : public v8::ExternalResourceVisitor { v8::String::ExternalStringResource* resource = string->GetExternalStringResource(); CHECK(resource); - if (resource1_ == resource) { - CHECK(!found_resource1_); - found_resource1_ = true; - } - if (resource2_ == resource) { - CHECK(!found_resource2_); - found_resource2_ = true; + for (int i = 0; i < 4; i++) { + if (resource_[i] == resource) { + CHECK(!found_resource_[i]); + found_resource_[i] = true; + } } } void CheckVisitedResources() { - CHECK(found_resource1_); - CHECK(found_resource2_); + for (int i = 0; i < 4; i++) { + CHECK(found_resource_[i]); + } } private: - v8::String::ExternalStringResource* resource1_; - v8::String::ExternalStringResource* resource2_; - bool found_resource1_; - bool found_resource2_; + v8::String::ExternalStringResource* resource_[4]; + bool found_resource_[4]; }; TEST(VisitExternalStrings) { @@ -14663,16 +15175,33 @@ TEST(VisitExternalStrings) { LocalContext env; const char* string = "Some string"; uint16_t* two_byte_string = AsciiToTwoByteString(string); - TestResource* resource1 = new TestResource(two_byte_string); - v8::Local<v8::String> string1 = v8::String::NewExternal(resource1); - TestResource* resource2 = new TestResource(two_byte_string); - v8::Local<v8::String> string2 = v8::String::NewExternal(resource2); - - // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7 + TestResource* resource[4]; + resource[0] = new TestResource(two_byte_string); + v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]); + resource[1] = new TestResource(two_byte_string); + v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]); + + // Externalized symbol. + resource[2] = new TestResource(two_byte_string); + v8::Local<v8::String> string2 = v8::String::NewSymbol(string); + CHECK(string2->MakeExternal(resource[2])); + + // Symbolized External. + resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); + v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]); + HEAP->CollectAllAvailableGarbage(); // Tenure string. + // Turn into a symbol. + i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); + CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure()); + CHECK(string3_i->IsSymbol()); + + // We need to add usages for string* to avoid warnings in GCC 4.7 + CHECK(string0->IsExternal()); CHECK(string1->IsExternal()); CHECK(string2->IsExternal()); + CHECK(string3->IsExternal()); - VisitorImpl visitor(resource1, resource2); + VisitorImpl visitor(resource); v8::V8::VisitExternalResources(&visitor); visitor.CheckVisitedResources(); } @@ -14907,6 +15436,7 @@ TEST(Regress528) { context->Exit(); } context.Dispose(); + v8::V8::ContextDisposedNotification(); for (gc_count = 1; gc_count < 10; gc_count++) { other_context->Enter(); CompileRun(source_exception); @@ -15361,13 +15891,13 @@ THREADED_TEST(TwoByteStringInAsciiCons) { CHECK(result->IsString()); i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); int length = string->length(); - CHECK(string->IsAsciiRepresentation()); + CHECK(string->IsOneByteRepresentation()); FlattenString(string); i::Handle<i::String> flat_string = FlattenGetString(string); - CHECK(string->IsAsciiRepresentation()); - CHECK(flat_string->IsAsciiRepresentation()); + CHECK(string->IsOneByteRepresentation()); + CHECK(flat_string->IsOneByteRepresentation()); // Create external resource. uint16_t* uc16_buffer = new uint16_t[length + 1]; @@ -15386,7 +15916,7 @@ THREADED_TEST(TwoByteStringInAsciiCons) { // ASCII characters). This is a valid sequence of steps, and it can happen // in real pages. - CHECK(string->IsAsciiRepresentation()); + CHECK(string->IsOneByteRepresentation()); i::ConsString* cons = i::ConsString::cast(*string); CHECK_EQ(0, cons->second()->length()); CHECK(cons->first()->IsTwoByteRepresentation()); @@ -16073,6 +16603,45 @@ TEST(DontDeleteCellLoadICAPI) { } +class Visitor42 : public v8::PersistentHandleVisitor { + public: + explicit Visitor42(v8::Persistent<v8::Object> object) + : counter_(0), object_(object) { } + + virtual void VisitPersistentHandle(Persistent<Value> value, + uint16_t class_id) { + if (class_id == 42) { + CHECK(value->IsObject()); + v8::Persistent<v8::Object> visited = + v8::Persistent<v8::Object>::Cast(value); + CHECK_EQ(42, visited.WrapperClassId()); + CHECK_EQ(object_, visited); + ++counter_; + } + } + + int counter_; + v8::Persistent<v8::Object> object_; +}; + + +TEST(PersistentHandleVisitor) { + v8::HandleScope scope; + LocalContext context; + v8::Persistent<v8::Object> object = + v8::Persistent<v8::Object>::New(v8::Object::New()); + CHECK_EQ(0, object.WrapperClassId()); + object.SetWrapperClassId(42); + CHECK_EQ(42, object.WrapperClassId()); + + Visitor42 visitor(object); + v8::V8::VisitHandlesWithClassIds(&visitor); + CHECK_EQ(1, visitor.counter_); + + object.Dispose(); +} + + TEST(RegExp) { v8::HandleScope scope; LocalContext context; @@ -16508,6 +17077,24 @@ THREADED_TEST(AllowCodeGenFromStrings) { } +TEST(SetErrorMessageForCodeGenFromStrings) { + v8::HandleScope scope; + LocalContext context; + TryCatch try_catch; + + Handle<String> message = v8_str("Message") ; + Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); + V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); + context->AllowCodeGenerationFromStrings(false); + context->SetErrorMessageForCodeGenerationFromStrings(message); + Handle<Value> result = CompileRun("eval('42')"); + CHECK(result.IsEmpty()); + CHECK(try_catch.HasCaught()); + Handle<String> actual_message = try_catch.Message()->Get(); + CHECK(expected_message->Equals(actual_message)); +} + + static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) { return v8::Undefined(); } @@ -17445,6 +18032,16 @@ THREADED_TEST(Regress149912) { } +THREADED_TEST(Regress157124) { + v8::HandleScope scope; + LocalContext context; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + Local<Object> obj = templ->NewInstance(); + obj->GetIdentityHash(); + obj->DeleteHiddenValue(v8_str("Bug")); +} + + #ifndef WIN32 class ThreadInterruptTest { public: @@ -17496,7 +18093,6 @@ class ThreadInterruptTest { private: ThreadInterruptTest* test_; - struct sigaction sa_; }; i::Semaphore* sem_; |