diff options
Diffstat (limited to 'deps/v8/test/cctest/test-api.cc')
-rw-r--r-- | deps/v8/test/cctest/test-api.cc | 798 |
1 files changed, 613 insertions, 185 deletions
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 484d2f3226..8317a06aa2 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -47,7 +47,7 @@ #include "src/execution.h" #include "src/futex-emulation.h" #include "src/objects.h" -#include "src/parsing/parser.h" +#include "src/parsing/preparse-data.h" #include "src/profiler/cpu-profiler.h" #include "src/unicode-inl.h" #include "src/utils.h" @@ -453,11 +453,11 @@ THREADED_TEST(ScriptUsingStringResource) { CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), source->GetExternalStringResourceBase(&encoding)); CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK_EQ(1, dispose_count); } @@ -484,11 +484,11 @@ THREADED_TEST(ScriptUsingOneByteStringResource) { Local<Value> value = script->Run(env.local()).ToLocalChecked(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK_EQ(1, dispose_count); } @@ -504,8 +504,8 @@ THREADED_TEST(ScriptMakingExternalString) { v8::NewStringType::kNormal) .ToLocalChecked(); // Trigger GCs so that the newly allocated string moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now CHECK_EQ(source->IsExternal(), false); CHECK_EQ(source->IsExternalOneByte(), false); String::Encoding encoding = String::UNKNOWN_ENCODING; @@ -518,11 +518,11 @@ THREADED_TEST(ScriptMakingExternalString) { Local<Value> value = script->Run(env.local()).ToLocalChecked(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(1, dispose_count); } @@ -535,8 +535,8 @@ THREADED_TEST(ScriptMakingExternalOneByteString) { v8::HandleScope scope(env->GetIsolate()); Local<String> source = v8_str(c_source); // Trigger GCs so that the newly allocated string moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now bool success = source->MakeExternal( new TestOneByteResource(i::StrDup(c_source), &dispose_count)); CHECK(success); @@ -544,11 +544,11 @@ THREADED_TEST(ScriptMakingExternalOneByteString) { Local<Value> value = script->Run(env.local()).ToLocalChecked(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(0, dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(1, dispose_count); } @@ -558,8 +558,8 @@ TEST(MakingExternalStringConditions) { v8::HandleScope scope(env->GetIsolate()); // Free some space in the new space so that we can check freshness. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); uint16_t* two_byte_string = AsciiToTwoByteString("s1"); Local<String> local_string = @@ -571,8 +571,8 @@ TEST(MakingExternalStringConditions) { // We should refuse to externalize new space strings. CHECK(!local_string->CanMakeExternal()); // Trigger GCs so that the newly allocated string moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now // Old space strings should be accepted. CHECK(local_string->CanMakeExternal()); } @@ -583,15 +583,15 @@ TEST(MakingExternalOneByteStringConditions) { v8::HandleScope scope(env->GetIsolate()); // Free some space in the new space so that we can check freshness. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); Local<String> local_string = v8_str("s1"); // We should refuse to externalize new space strings. CHECK(!local_string->CanMakeExternal()); // Trigger GCs so that the newly allocated string moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now // Old space strings should be accepted. CHECK(local_string->CanMakeExternal()); } @@ -612,8 +612,8 @@ TEST(MakingExternalUnalignedOneByteString) { // Trigger GCs so that the newly allocated string moves to old gen. i::heap::SimulateFullSpace(CcTest::heap()->old_space()); - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now // Turn into external string with unaligned resource data. const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; @@ -626,8 +626,8 @@ TEST(MakingExternalUnalignedOneByteString) { CHECK(success); // Trigger GCs and force evacuation. - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); } @@ -642,14 +642,14 @@ THREADED_TEST(UsingExternalString) { .ToLocalChecked(); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); // Trigger GCs so that the newly allocated string moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now i::Handle<i::String> isymbol = factory->InternalizeString(istring); CHECK(isymbol->IsInternalizedString()); } - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -665,14 +665,14 @@ THREADED_TEST(UsingExternalOneByteString) { .ToLocalChecked(); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); // Trigger GCs so that the newly allocated string moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now i::Handle<i::String> isymbol = factory->InternalizeString(istring); CHECK(isymbol->IsInternalizedString()); } - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -739,12 +739,12 @@ THREADED_TEST(ScavengeExternalString) { new TestResource(two_byte_string, &dispose_count)) .ToLocalChecked(); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); in_new_space = CcTest::heap()->InNewSpace(*istring); CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); CHECK_EQ(0, dispose_count); } - CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); + CcTest::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); CHECK_EQ(1, dispose_count); } @@ -763,12 +763,12 @@ THREADED_TEST(ScavengeExternalOneByteString) { new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count)) .ToLocalChecked(); i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); in_new_space = CcTest::heap()->InNewSpace(*istring); CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); CHECK_EQ(0, dispose_count); } - CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); + CcTest::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); CHECK_EQ(1, dispose_count); } @@ -812,11 +812,11 @@ TEST(ExternalStringWithDisposeHandling) { Local<Value> value = script->Run(env.local()).ToLocalChecked(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); @@ -835,11 +835,11 @@ TEST(ExternalStringWithDisposeHandling) { Local<Value> value = script->Run(env.local()).ToLocalChecked(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count); } @@ -897,8 +897,8 @@ THREADED_TEST(StringConcat) { CHECK_EQ(68, value->Int32Value(env.local()).FromJust()); } CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -1581,6 +1581,26 @@ THREADED_TEST(IsGeneratorFunctionOrObject) { CHECK(!func->IsGeneratorObject()); } +THREADED_TEST(IsAsyncFunction) { + i::FLAG_harmony_async_await = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + CompileRun("async function foo() {}"); + v8::Local<Value> foo = CompileRun("foo"); + + CHECK(foo->IsAsyncFunction()); + CHECK(foo->IsFunction()); + CHECK(!foo->IsGeneratorFunction()); + CHECK(!foo->IsGeneratorObject()); + + CompileRun("function bar() {}"); + v8::Local<Value> bar = CompileRun("bar"); + + CHECK(!bar->IsAsyncFunction()); + CHECK(bar->IsFunction()); +} THREADED_TEST(ArgumentsObject) { LocalContext env; @@ -2651,7 +2671,7 @@ static void CheckAlignedPointerInInternalField(Local<v8::Object> obj, void* value) { CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); obj->SetAlignedPointerInInternalField(0, value); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); } @@ -2707,14 +2727,14 @@ THREADED_TEST(SetAlignedPointerInInternalFields) { void* values[] = {heap_allocated_1, heap_allocated_2}; obj->SetAlignedPointerInInternalFields(2, indices, values); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(0)); CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(1)); indices[0] = 1; indices[1] = 0; obj->SetAlignedPointerInInternalFields(2, indices, values); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(0)); CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(1)); @@ -2726,7 +2746,7 @@ 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); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); } @@ -2756,7 +2776,7 @@ THREADED_TEST(EmbedderDataAlignedPointers) { for (int i = 0; i < 100; i++) { env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); } - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); for (int i = 0; i < 100; i++) { CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); } @@ -2788,7 +2808,7 @@ THREADED_TEST(IdentityHash) { // Ensure that the test starts with an fresh heap to test whether the hash // code is based on the address. - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); Local<v8::Object> obj = v8::Object::New(isolate); int hash = obj->GetIdentityHash(); int hash1 = obj->GetIdentityHash(); @@ -2798,7 +2818,7 @@ THREADED_TEST(IdentityHash) { // objects should not be assigned the same hash code. If the test below fails // the random number generator should be evaluated. CHECK_NE(hash, hash2); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); int hash3 = v8::Object::New(isolate)->GetIdentityHash(); // Make sure that the identity hash is not based on the initial address of // the object alone. If the test below fails the random number generator @@ -2874,7 +2894,7 @@ TEST(SymbolIdentityHash) { int hash = symbol->GetIdentityHash(); int hash1 = symbol->GetIdentityHash(); CHECK_EQ(hash, hash1); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); int hash3 = symbol->GetIdentityHash(); CHECK_EQ(hash, hash3); } @@ -2885,7 +2905,7 @@ TEST(SymbolIdentityHash) { int hash = js_symbol->GetIdentityHash(); int hash1 = js_symbol->GetIdentityHash(); CHECK_EQ(hash, hash1); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); int hash3 = js_symbol->GetIdentityHash(); CHECK_EQ(hash, hash3); } @@ -2901,7 +2921,7 @@ TEST(StringIdentityHash) { int hash = str->GetIdentityHash(); int hash1 = str->GetIdentityHash(); CHECK_EQ(hash, hash1); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); int hash3 = str->GetIdentityHash(); CHECK_EQ(hash, hash3); @@ -2921,7 +2941,7 @@ THREADED_TEST(SymbolProperties) { v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol")); v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3")); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Check basic symbol functionality. CHECK(sym1->IsSymbol()); @@ -2990,7 +3010,7 @@ THREADED_TEST(SymbolProperties) { CHECK_EQ(num_props + 1, obj->GetPropertyNames(env.local()).ToLocalChecked()->Length()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter, SymbolAccessorSetter) @@ -3100,7 +3120,7 @@ THREADED_TEST(PrivatePropertiesOnProxies) { v8::Local<v8::Private> priv2 = v8::Private::New(isolate, v8_str("my-private")); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK(priv2->Name() ->Equals(env.local(), @@ -3142,7 +3162,7 @@ THREADED_TEST(PrivatePropertiesOnProxies) { CHECK_EQ(num_props + 1, proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Add another property and delete it afterwards to force the object in // slow case. @@ -3194,7 +3214,7 @@ THREADED_TEST(PrivateProperties) { v8::Local<v8::Private> priv2 = v8::Private::New(isolate, v8_str("my-private")); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK(priv2->Name() ->Equals(env.local(), @@ -3236,7 +3256,7 @@ THREADED_TEST(PrivateProperties) { CHECK_EQ(num_props + 1, obj->GetPropertyNames(env.local()).ToLocalChecked()->Length()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Add another property and delete it afterwards to force the object in // slow case. @@ -3385,7 +3405,7 @@ THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { CheckInternalFieldsAreZero(ab); CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); CHECK(!ab->IsExternal()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); ScopedArrayBufferContents ab_contents(ab->Externalize()); CHECK(ab->IsExternal()); @@ -3661,7 +3681,7 @@ THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) { CheckInternalFieldsAreZero(ab); CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); CHECK(!ab->IsExternal()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); ScopedSharedArrayBufferContents ab_contents(ab->Externalize()); CHECK(ab->IsExternal()); @@ -3778,7 +3798,7 @@ THREADED_TEST(HiddenProperties) { v8::Local<v8::String> empty = v8_str(""); v8::Local<v8::String> prop_name = v8_str("prop_name"); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Make sure delete of a non-existent hidden value works obj->DeletePrivate(env.local(), key).FromJust(); @@ -3796,7 +3816,7 @@ THREADED_TEST(HiddenProperties) { ->Int32Value(env.local()) .FromJust()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Make sure we do not find the hidden property. CHECK(!obj->Has(env.local(), empty).FromJust()); @@ -3820,7 +3840,7 @@ THREADED_TEST(HiddenProperties) { ->Int32Value(env.local()) .FromJust()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Add another property and delete it afterwards to force the object in // slow case. @@ -3844,7 +3864,7 @@ THREADED_TEST(HiddenProperties) { ->Int32Value(env.local()) .FromJust()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002)) .FromJust()); @@ -4135,7 +4155,7 @@ void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { if (!trigger_gc) return; auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter); data_2->SetWeak(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -4156,7 +4176,7 @@ TEST(TwoPassPhantomCallbacks) { data->SetWeak(); } CHECK_EQ(static_cast<int>(kLength), instance_counter); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); EmptyMessageQueues(isolate); CHECK_EQ(0, instance_counter); } @@ -4175,7 +4195,7 @@ TEST(TwoPassPhantomCallbacksNestedGc) { array[10]->MarkTriggerGc(); array[15]->MarkTriggerGc(); CHECK_EQ(static_cast<int>(kLength), instance_counter); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); EmptyMessageQueues(isolate); CHECK_EQ(0, instance_counter); } @@ -4286,8 +4306,7 @@ void TestGlobalValueMap() { } CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); if (map.IsWeak()) { - CcTest::i_isolate()->heap()->CollectAllGarbage( - i::Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); } else { map.Clear(); } @@ -4518,9 +4537,7 @@ THREADED_TEST(ApiObjectGroups) { iso->SetReferenceFromGroup(id2, g2c1.handle); } // Do a single full GC, ensure incremental marking is stopped. - v8::internal::Heap* heap = - reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // All object should be alive. CHECK_EQ(0, counter.NumberOfWeakCalls()); @@ -4545,7 +4562,7 @@ THREADED_TEST(ApiObjectGroups) { iso->SetReferenceFromGroup(id2, g2c1.handle); } - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // All objects should be gone. 5 global handles in total. CHECK_EQ(5, counter.NumberOfWeakCalls()); @@ -4556,7 +4573,7 @@ THREADED_TEST(ApiObjectGroups) { g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, v8::WeakCallbackType::kParameter); - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(7, counter.NumberOfWeakCalls()); } @@ -4623,9 +4640,7 @@ THREADED_TEST(ApiObjectGroupsForSubtypes) { iso->SetReferenceFromGroup(id2, g2c1.handle); } // Do a single full GC, ensure incremental marking is stopped. - v8::internal::Heap* heap = - reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // All object should be alive. CHECK_EQ(0, counter.NumberOfWeakCalls()); @@ -4650,7 +4665,7 @@ THREADED_TEST(ApiObjectGroupsForSubtypes) { iso->SetReferenceFromGroup(id2, g2c1.handle); } - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // All objects should be gone. 5 global handles in total. CHECK_EQ(5, counter.NumberOfWeakCalls()); @@ -4661,7 +4676,7 @@ THREADED_TEST(ApiObjectGroupsForSubtypes) { g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, v8::WeakCallbackType::kParameter); - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(7, counter.NumberOfWeakCalls()); } @@ -4746,9 +4761,7 @@ THREADED_TEST(ApiObjectGroupsCycle) { iso->SetReferenceFromGroup(id4, g1s1.handle); } // Do a single full GC - v8::internal::Heap* heap = - reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // All object should be alive. CHECK_EQ(0, counter.NumberOfWeakCalls()); @@ -4777,7 +4790,7 @@ THREADED_TEST(ApiObjectGroupsCycle) { iso->SetReferenceFromGroup(id4, g1s1.handle); } - heap->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // All objects should be gone. 9 global handles in total. CHECK_EQ(9, counter.NumberOfWeakCalls()); @@ -5077,7 +5090,7 @@ TEST(NativeWeakMap) { CHECK(value->Equals(env.local(), weak_map->Get(obj2)).FromJust()); CHECK(value->Equals(env.local(), weak_map->Get(sym1)).FromJust()); } - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); { HandleScope scope(isolate); CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); @@ -5099,7 +5112,7 @@ TEST(NativeWeakMap) { s1.handle.SetWeak(&s1, &WeakPointerCallback, v8::WeakCallbackType::kParameter); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(3, counter.NumberOfWeakCalls()); CHECK(o1.handle.IsEmpty()); @@ -7458,13 +7471,11 @@ TEST(ExceptionExtensions) { CHECK(context.IsEmpty()); } - static const char* kNativeCallInExtensionSource = "function call_runtime_last_index_of(x) {" - " return %StringLastIndexOf(x, 'bob', 10);" + " return %StringLastIndexOf(x, 'bob');" "}"; - static const char* kNativeCallTest = "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; @@ -7478,7 +7489,7 @@ TEST(NativeCallInExtensions) { v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); Context::Scope lock(context); v8::Local<Value> result = CompileRun(kNativeCallTest); - CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 3)) + CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 24)) .FromJust()); } @@ -7770,9 +7781,9 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) { b->Set(context, v8_str("x"), a).FromJust(); } if (global_gc) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } else { - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); } // We are relying on this creating a big flag array and reserving the space // up front. @@ -7792,9 +7803,9 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) { object_b.handle.MarkIndependent(); CHECK(object_b.handle.IsIndependent()); if (global_gc) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } else { - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); } // A single GC should be enough to reclaim the memory, since we are using // phantom handles. @@ -7891,9 +7902,9 @@ void InternalFieldCallback(bool global_gc) { } } if (global_gc) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } else { - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); } CHECK_EQ(1729, t1->x()); @@ -7938,9 +7949,9 @@ void v8::internal::HeapTester::ResetWeakHandle(bool global_gc) { object_a.handle.Reset(iso, a); object_b.handle.Reset(iso, b); if (global_gc) { - CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } else { - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); } } @@ -7956,9 +7967,9 @@ void v8::internal::HeapTester::ResetWeakHandle(bool global_gc) { CHECK(object_b.handle.IsIndependent()); } if (global_gc) { - CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } else { - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); } CHECK(object_a.flag); CHECK(object_b.flag); @@ -7970,12 +7981,11 @@ THREADED_HEAP_TEST(ResetWeakHandle) { v8::internal::HeapTester::ResetWeakHandle(true); } +static void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); } -static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); } - - -static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); } - +static void InvokeMarkSweep() { + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); +} static void ForceScavenge2( const v8::WeakCallbackInfo<FlagAndPersistent>& data) { @@ -8051,7 +8061,7 @@ static void ArgumentsTestCallback( CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust()); CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust()); v8::HandleScope scope(args.GetIsolate()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -9381,7 +9391,7 @@ static bool security_check_with_gc_called; static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context, Local<v8::Object> accessed_object, Local<v8::Value> data) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); security_check_with_gc_called = true; return true; } @@ -12169,7 +12179,7 @@ static void InterceptorCallICFastApi( reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); ++(*call_count); if ((*call_count) % 20 == 0) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } } @@ -12226,8 +12236,8 @@ static void GenerateSomeGarbage() { void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { static int count = 0; if (count++ % 3 == 0) { - CcTest::heap()->CollectAllGarbage(); - // This should move the stub + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + // This should move the stub GenerateSomeGarbage(); // This should ensure the old stub memory is flushed } } @@ -12296,7 +12306,7 @@ static int p_getter_count_3; static Local<Value> DoDirectGetter() { if (++p_getter_count_3 % 3 == 0) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); GenerateSomeGarbage(); } return v8_str("Direct Getter Result"); @@ -14016,8 +14026,8 @@ static void CheckSurvivingGlobalObjectsCount(int expected) { // the first garbage collection but some of the maps have already // been marked at that point. Therefore some of the maps are not // collected until the second garbage collection. - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kMakeHeapIterableMask); int count = GetGlobalObjectsCount(); #ifdef DEBUG if (count != expected) CcTest::heap()->TracePathToGlobal(); @@ -14118,7 +14128,8 @@ TEST(WeakCallbackApi) { handle, WeakApiCallback, v8::WeakCallbackType::kParameter); } reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage( - i::Heap::kAbortIncrementalMarkingMask); + i::Heap::kAbortIncrementalMarkingMask, + i::GarbageCollectionReason::kTesting); // Verify disposed. CHECK_EQ(initial_handles, globals->global_handles_count()); } @@ -14160,7 +14171,7 @@ THREADED_TEST(NewPersistentHandleFromWeakCallback) { handle1.SetWeak(&handle1, NewPersistentHandleCallback1, v8::WeakCallbackType::kParameter); handle2.Reset(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -14170,7 +14181,7 @@ v8::Persistent<v8::Object> to_be_disposed; void DisposeAndForceGcCallback2( const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { to_be_disposed.Reset(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } @@ -14194,7 +14205,7 @@ THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { handle1.SetWeak(&handle1, DisposeAndForceGcCallback1, v8::WeakCallbackType::kParameter); to_be_disposed.Reset(isolate, handle2); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); } void DisposingCallback( @@ -14232,7 +14243,7 @@ THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { v8::WeakCallbackType::kParameter); handle3.SetWeak(&handle3, HandleCreatingCallback1, v8::WeakCallbackType::kParameter); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); EmptyMessageQueues(isolate); } @@ -14282,11 +14293,6 @@ THREADED_TEST(NestedHandleScopeAndContexts) { } -static bool MatchPointers(void* key1, void* key2) { - return key1 == key2; -} - - struct SymbolInfo { size_t id; size_t size; @@ -14793,14 +14799,14 @@ UNINITIALIZED_TEST(SetJitCodeEventHandler) { i::Heap* heap = i_isolate->heap(); // Start with a clean slate. - heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare"); + heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting); { v8::HandleScope scope(isolate); - v8::base::HashMap code(MatchPointers); + v8::base::HashMap code; code_map = &code; - v8::base::HashMap lineinfo(MatchPointers); + v8::base::HashMap lineinfo; jitcode_line_info = &lineinfo; saw_bar = 0; @@ -14837,7 +14843,7 @@ UNINITIALIZED_TEST(SetJitCodeEventHandler) { } // Force code movement. - heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move"); + heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting); isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); @@ -14863,10 +14869,10 @@ UNINITIALIZED_TEST(SetJitCodeEventHandler) { CompileRun(script); // Now get code through initial iteration. - v8::base::HashMap code(MatchPointers); + v8::base::HashMap code; code_map = &code; - v8::base::HashMap lineinfo(MatchPointers); + v8::base::HashMap lineinfo; jitcode_line_info = &lineinfo; isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, @@ -14887,8 +14893,7 @@ UNINITIALIZED_TEST(SetJitCodeEventHandler) { isolate->Dispose(); } - -THREADED_TEST(ExternalAllocatedMemory) { +TEST(ExternalAllocatedMemory) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope outer(isolate); v8::Local<Context> env(Context::New(isolate)); @@ -14899,7 +14904,8 @@ THREADED_TEST(ExternalAllocatedMemory) { isolate->AdjustAmountOfExternalAllocatedMemory(kSize)); CHECK_EQ(baseline, isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)); - const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1; + const int64_t kTriggerGCSize = + CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1; CHECK_EQ(baseline + kTriggerGCSize, isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize)); CHECK_EQ(baseline, @@ -14911,7 +14917,8 @@ TEST(Regress51719) { i::FLAG_incremental_marking = false; CcTest::InitializeVM(); - const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1; + const int64_t kTriggerGCSize = + CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1; v8::Isolate* isolate = CcTest::isolate(); isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize); } @@ -16004,6 +16011,292 @@ TEST(DefineOwnProperty) { } } +TEST(DefineProperty) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::Local<v8::Name> p; + + CompileRun( + "var a = {};" + "var b = [];" + "Object.defineProperty(a, 'v1', {value: 23});" + "Object.defineProperty(a, 'v2', {value: 23, configurable: true});"); + + v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast( + env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); + v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast( + env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); + + v8::PropertyDescriptor desc(v8_num(42)); + { + // Use a data descriptor. + + // Cannot change a non-configurable property. + p = v8_str("v1"); + v8::TryCatch try_catch(isolate); + CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); + + // Change a configurable property. + p = v8_str("v2"); + obj->DefineProperty(env.local(), p, desc).FromJust(); + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + + // Check that missing writable has default value false. + p = v8_str("v12"); + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + v8::PropertyDescriptor desc2(v8_num(43)); + CHECK(!obj->DefineProperty(env.local(), p, desc2).FromJust()); + val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + { + // Set a regular property. + p = v8_str("v3"); + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Set an indexed property. + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), v8_str("1"), desc).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // No special case when changing array length. + v8::TryCatch try_catch(isolate); + // Use a writable descriptor, otherwise the next test, that changes + // the array length will fail. + v8::PropertyDescriptor desc(v8_num(42), true); + CHECK(arr->DefineProperty(env.local(), v8_str("length"), desc).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + { + // Special cases for arrays: index exceeds the array's length. + v8::TryCatch try_catch(isolate); + CHECK(arr->DefineProperty(env.local(), v8_str("100"), desc).FromJust()); + CHECK(!try_catch.HasCaught()); + CHECK_EQ(101U, arr->Length()); + v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + + // Set an existing entry. + CHECK(arr->DefineProperty(env.local(), v8_str("0"), desc).FromJust()); + CHECK(!try_catch.HasCaught()); + val = arr->Get(env.local(), 0).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Use a generic descriptor. + v8::PropertyDescriptor desc_generic; + + p = v8_str("v4"); + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc_generic).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsUndefined()); + + obj->Set(env.local(), p, v8_num(1)).FromJust(); + CHECK(!try_catch.HasCaught()); + + val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsUndefined()); + CHECK(!try_catch.HasCaught()); + } + + { + // Use a data descriptor with undefined value. + v8::PropertyDescriptor desc_empty(v8::Undefined(isolate)); + + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsUndefined()); + CHECK(!try_catch.HasCaught()); + } + + { + // Use a descriptor with attribute == v8::ReadOnly. + v8::PropertyDescriptor desc_read_only(v8_num(42), false); + desc_read_only.set_enumerable(true); + desc_read_only.set_configurable(true); + + p = v8_str("v5"); + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc_read_only).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + CHECK_EQ(v8::ReadOnly, + obj->GetPropertyAttributes(env.local(), p).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + { + // Use an accessor descriptor with empty handles. + v8::PropertyDescriptor desc_empty(v8::Undefined(isolate), + v8::Undefined(isolate)); + + p = v8_str("v6"); + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsUndefined()); + CHECK(!try_catch.HasCaught()); + } + + { + // Use an accessor descriptor. + CompileRun( + "var set = function(x) {this.val = 2*x;};" + "var get = function() {return this.val || 0;};"); + + v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast( + env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked()); + v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast( + env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked()); + v8::PropertyDescriptor desc(get, set); + + p = v8_str("v7"); + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust()); + CHECK(!try_catch.HasCaught()); + + obj->Set(env.local(), p, v8_num(7)).FromJust(); + CHECK(!try_catch.HasCaught()); + + val = obj->Get(env.local(), p).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + { + // Redefine an existing property. + + // desc = {value: 42, enumerable: true} + v8::PropertyDescriptor desc(v8_num(42)); + desc.set_enumerable(true); + + p = v8_str("v8"); + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + + // desc = {enumerable: true} + v8::PropertyDescriptor desc_true((v8::Local<v8::Value>())); + desc_true.set_enumerable(true); + + // Successful redefinition because all present attributes have the same + // value as the current descriptor. + CHECK(obj->DefineProperty(env.local(), p, desc_true).FromJust()); + CHECK(!try_catch.HasCaught()); + + // desc = {} + v8::PropertyDescriptor desc_empty; + // Successful redefinition because no attributes are overwritten in the + // current descriptor. + CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust()); + CHECK(!try_catch.HasCaught()); + + // desc = {enumerable: false} + v8::PropertyDescriptor desc_false((v8::Local<v8::Value>())); + desc_false.set_enumerable(false); + // Not successful because we cannot define a different value for enumerable. + CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + { + // Redefine a property that has a getter. + CompileRun("var get = function() {};"); + v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast( + env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked()); + + // desc = {get: function() {}} + v8::PropertyDescriptor desc(get, v8::Local<v8::Function>()); + v8::TryCatch try_catch(isolate); + + p = v8_str("v9"); + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + + // desc_empty = {} + // Successful because we are not redefining the current getter. + v8::PropertyDescriptor desc_empty; + CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust()); + CHECK(!try_catch.HasCaught()); + + // desc = {get: function() {}} + // Successful because we redefine the getter with its current value. + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust()); + CHECK(!try_catch.HasCaught()); + + // desc = {get: undefined} + v8::PropertyDescriptor desc_undefined(v8::Undefined(isolate), + v8::Local<v8::Function>()); + // Not successful because we cannot redefine with the current value of get + // with undefined. + CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + CompileRun("Object.freeze(a);"); + { + // We cannot change non-extensible objects. + v8::TryCatch try_catch(isolate); + CHECK(!obj->DefineProperty(env.local(), v8_str("v10"), desc).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); + templ->SetAccessCheckCallback(AccessAlwaysBlocked); + v8::Local<v8::Object> access_checked = + templ->NewInstance(env.local()).ToLocalChecked(); + { + v8::TryCatch try_catch(isolate); + CHECK(access_checked->DefineProperty(env.local(), v8_str("v11"), desc) + .IsNothing()); + CHECK(try_catch.HasCaught()); + } +} THREADED_TEST(GetCurrentContextWhenNotInContext) { i::Isolate* isolate = CcTest::i_isolate(); @@ -16177,7 +16470,7 @@ static void ObjectWithExternalArrayTestHelper(Local<Context> context, "}" "sum;"); // Force GC to trigger verification. - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(28, result->Int32Value(context).FromJust()); // Make sure out-of-range loads do not throw. @@ -16393,12 +16686,12 @@ static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type, CHECK_EQ(FixedTypedArrayClass::kInstanceType, fixed_array->map()->instance_type()); CHECK_EQ(kElementCount, fixed_array->length()); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); for (int i = 0; i < kElementCount; i++) { fixed_array->set(i, static_cast<ElementType>(i)); } // Force GC to trigger verification. - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); for (int i = 0; i < kElementCount; i++) { CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)), static_cast<int64_t>(fixed_array->get_scalar(i))); @@ -16588,10 +16881,10 @@ THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) { Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8); // Should not crash - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now + CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); // Should not move the pointer CHECK_EQ(ab->GetContents().Data(), store_ptr); @@ -16609,15 +16902,15 @@ THREADED_TEST(SkipArrayBufferDuringScavenge) { reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp)); // Make `store_ptr` point to from space - CcTest::heap()->CollectGarbage(i::NEW_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::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + 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); @@ -17918,7 +18211,8 @@ TEST(TestIdleNotification) { bool finished = false; for (int i = 0; i < 200 && !finished; i++) { if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) { - CcTest::heap()->StartIdleIncrementalMarking(); + CcTest::heap()->StartIdleIncrementalMarking( + i::GarbageCollectionReason::kTesting); } finished = env->GetIsolate()->IdleNotificationDeadline( (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / @@ -17937,7 +18231,7 @@ TEST(TestIdleNotification) { TEST(Regress2333) { LocalContext env; for (int i = 0; i < 3; i++) { - CcTest::heap()->CollectGarbage(i::NEW_SPACE); + CcTest::CollectGarbage(i::NEW_SPACE); } } @@ -18075,7 +18369,7 @@ TEST(ExternalizeOldSpaceTwoByteCons) { ->ToString(env.local()) .ToLocalChecked(); CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons))); TestResource* resource = new TestResource( @@ -18099,7 +18393,7 @@ TEST(ExternalizeOldSpaceOneByteCons) { ->ToString(env.local()) .ToLocalChecked(); CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons))); TestOneByteResource* resource = @@ -18143,7 +18437,7 @@ TEST(VisitExternalStrings) { v8::Local<v8::String> string3 = v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3]) .ToLocalChecked(); - CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string. + CcTest::CollectAllAvailableGarbage(); // Tenure string. // Turn into a symbol. i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); CHECK(!CcTest::i_isolate()->factory()->InternalizeString( @@ -18230,7 +18524,7 @@ TEST(ExternalInternalizedStringCollectedAtGC) { // Garbage collector deals swift blows to evil. CcTest::i_isolate()->compilation_cache()->Clear(); - CcTest::heap()->CollectAllAvailableGarbage(); + CcTest::CollectAllAvailableGarbage(); // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. CHECK_EQ(1, destroyed); @@ -18431,7 +18725,7 @@ TEST(Regress528) { other_context->Enter(); CompileRun(source_simple); other_context->Exit(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); if (GetGlobalObjectsCount() == 1) break; } CHECK_GE(2, gc_count); @@ -18453,7 +18747,7 @@ TEST(Regress528) { other_context->Enter(); CompileRun(source_eval); other_context->Exit(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); if (GetGlobalObjectsCount() == 1) break; } CHECK_GE(2, gc_count); @@ -18480,7 +18774,7 @@ TEST(Regress528) { other_context->Enter(); CompileRun(source_exception); other_context->Exit(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); if (GetGlobalObjectsCount() == 1) break; } CHECK_GE(2, gc_count); @@ -19097,8 +19391,7 @@ void PrologueCallbackAlloc(v8::Isolate* isolate, Local<Object> obj = Object::New(isolate); CHECK(!obj.IsEmpty()); - CcTest::heap()->CollectAllGarbage( - i::Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); } @@ -19117,8 +19410,7 @@ void EpilogueCallbackAlloc(v8::Isolate* isolate, Local<Object> obj = Object::New(isolate); CHECK(!obj.IsEmpty()); - CcTest::heap()->CollectAllGarbage( - i::Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); } @@ -19131,26 +19423,26 @@ TEST(GCCallbacksOld) { context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback); CHECK_EQ(0, prologue_call_count); CHECK_EQ(0, epilogue_call_count); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(1, prologue_call_count); CHECK_EQ(1, epilogue_call_count); context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond); context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(2, prologue_call_count); CHECK_EQ(2, epilogue_call_count); CHECK_EQ(1, prologue_call_count_second); CHECK_EQ(1, epilogue_call_count_second); context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback); context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(2, prologue_call_count); CHECK_EQ(2, epilogue_call_count); CHECK_EQ(2, prologue_call_count_second); CHECK_EQ(2, epilogue_call_count_second); context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond); context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(2, prologue_call_count); CHECK_EQ(2, epilogue_call_count); CHECK_EQ(2, prologue_call_count_second); @@ -19166,26 +19458,26 @@ TEST(GCCallbacks) { isolate->AddGCEpilogueCallback(EpilogueCallback); CHECK_EQ(0, prologue_call_count); CHECK_EQ(0, epilogue_call_count); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(1, prologue_call_count); CHECK_EQ(1, epilogue_call_count); isolate->AddGCPrologueCallback(PrologueCallbackSecond); isolate->AddGCEpilogueCallback(EpilogueCallbackSecond); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(2, prologue_call_count); CHECK_EQ(2, epilogue_call_count); CHECK_EQ(1, prologue_call_count_second); CHECK_EQ(1, epilogue_call_count_second); isolate->RemoveGCPrologueCallback(PrologueCallback); isolate->RemoveGCEpilogueCallback(EpilogueCallback); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(2, prologue_call_count); CHECK_EQ(2, epilogue_call_count); CHECK_EQ(2, prologue_call_count_second); CHECK_EQ(2, epilogue_call_count_second); isolate->RemoveGCPrologueCallback(PrologueCallbackSecond); isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CHECK_EQ(2, prologue_call_count); CHECK_EQ(2, epilogue_call_count); CHECK_EQ(2, prologue_call_count_second); @@ -19195,8 +19487,7 @@ TEST(GCCallbacks) { CHECK_EQ(0, epilogue_call_count_alloc); isolate->AddGCPrologueCallback(PrologueCallbackAlloc); isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc); - CcTest::heap()->CollectAllGarbage( - i::Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); CHECK_EQ(1, prologue_call_count_alloc); CHECK_EQ(1, epilogue_call_count_alloc); isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc); @@ -19374,7 +19665,7 @@ TEST(ContainsOnlyOneByte) { void FailedAccessCheckCallbackGC(Local<v8::Object> target, v8::AccessType type, Local<v8::Value> data) { - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); CcTest::isolate()->ThrowException( v8::Exception::Error(v8_str("cross context"))); } @@ -19817,12 +20108,10 @@ class InitDefaultIsolateThread : public v8::base::Thread { void Run() { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - const intptr_t pageSizeMult = - v8::internal::Page::kPageSize / v8::internal::MB; switch (testCase_) { case SetResourceConstraints: { - create_params.constraints.set_max_semi_space_size(1 * pageSizeMult); - create_params.constraints.set_max_old_space_size(4 * pageSizeMult); + create_params.constraints.set_max_semi_space_size(1); + create_params.constraints.set_max_old_space_size(6); break; } default: @@ -19999,7 +20288,7 @@ TEST(DontDeleteCellLoadIC) { "})()", "ReferenceError: cell is not defined"); CompileRun("cell = \"new_second\";"); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); ExpectString("readCell()", "new_second"); ExpectString("readCell()", "new_second"); } @@ -20069,8 +20358,8 @@ TEST(PersistentHandleInNewSpaceVisitor) { object1.SetWrapperClassId(42); CHECK_EQ(42, object1.WrapperClassId()); - CcTest::heap()->CollectAllGarbage(); - CcTest::heap()->CollectAllGarbage(); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate)); CHECK_EQ(0, object2.WrapperClassId()); @@ -20747,7 +21036,7 @@ THREADED_TEST(Regress1516) { CHECK_LE(1, elements); // We have to abort incremental marking here to abandon black pages. - CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); + CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context())); } @@ -21488,12 +21777,15 @@ int* LookupCounter(const char* name) { const char* kMegamorphicTestProgram = "function CreateClass(name) {\n" " var src = \n" - " ` function ${name}() {};` +\n" + " ` function ${name}() { this.a = 0; };` +\n" " ` ${name}.prototype.foo = function() {};` +\n" " ` ${name};\\n`;\n" " return (0, eval)(src);\n" "}\n" - "function fooify(obj) { obj.foo(); };\n" + "function trigger_ics(obj, v) {\n" + " obj.foo();\n" + " obj.a = v;\n" + "};\n" "var objs = [];\n" "for (var i = 0; i < 50; i++) {\n" " var Class = CreateClass('Class' + i);\n" @@ -21502,7 +21794,7 @@ const char* kMegamorphicTestProgram = "}\n" "for (var i = 0; i < 1000; i++) {\n" " for (var obj of objs) {\n" - " fooify(obj);\n" + " trigger_ics(obj, 1);\n" " }\n" "}\n"; @@ -21538,6 +21830,7 @@ void TestStubCache(bool primary) { i::CodeStub::LoadICTF, i::CodeStub::LoadICTrampolineTF, i::CodeStub::KeyedLoadIC, i::CodeStub::KeyedLoadICTrampoline, i::CodeStub::StoreIC, i::CodeStub::StoreICTrampoline, + i::CodeStub::StoreICTF, i::CodeStub::StoreICTrampolineTF, i::CodeStub::KeyedStoreIC, i::CodeStub::KeyedStoreICTrampoline, }; i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); @@ -21558,17 +21851,18 @@ void TestStubCache(bool primary) { int updates = updates_counter - initial_updates; const int kClassesCount = 50; const int kIterationsCount = 1000; - CHECK_LE(kClassesCount, updates); + const int kICKinds = 2; // LoadIC and StoreIC + CHECK_LE(kClassesCount * kICKinds, updates); // Check that updates and misses counts are bounded. // If there are too many updates then most likely the stub cache does not // work properly. - CHECK_LE(updates, kClassesCount * 2); - CHECK_LE(1, misses); - CHECK_LE(misses, kClassesCount * 2); + CHECK_LE(updates, kClassesCount * 2 * kICKinds); + CHECK_LE(kICKinds, misses); + CHECK_LE(misses, kClassesCount * 2 * kICKinds); // 2 is for PREMONOMORPHIC and MONOMORPHIC states, // 4 is for POLYMORPHIC states, // and all the others probes are for MEGAMORPHIC state. - CHECK_EQ(kIterationsCount * kClassesCount - 2 - 4, probes); + CHECK_EQ((kIterationsCount * kClassesCount - 2 - 4) * kICKinds, probes); } isolate->Dispose(); } @@ -23339,6 +23633,140 @@ TEST(EventLogging) { CHECK_EQ(1, last_event_status); } +TEST(PropertyDescriptor) { + LocalContext context; + v8::Isolate* isolate = context->GetIsolate(); + v8::HandleScope scope(isolate); + + { // empty descriptor + v8::PropertyDescriptor desc; + CHECK(!desc.has_value()); + CHECK(!desc.has_set()); + CHECK(!desc.has_get()); + CHECK(!desc.has_enumerable()); + CHECK(!desc.has_configurable()); + CHECK(!desc.has_writable()); + } + { + // data descriptor + v8::PropertyDescriptor desc(v8_num(42)); + desc.set_enumerable(false); + CHECK(desc.value() == v8_num(42)); + CHECK(desc.has_value()); + CHECK(!desc.has_set()); + CHECK(!desc.has_get()); + CHECK(desc.has_enumerable()); + CHECK(!desc.enumerable()); + CHECK(!desc.has_configurable()); + CHECK(!desc.has_writable()); + } + { + // data descriptor + v8::PropertyDescriptor desc(v8_num(42)); + desc.set_configurable(true); + CHECK(desc.value() == v8_num(42)); + CHECK(desc.has_value()); + CHECK(!desc.has_set()); + CHECK(!desc.has_get()); + CHECK(desc.has_configurable()); + CHECK(desc.configurable()); + CHECK(!desc.has_enumerable()); + CHECK(!desc.has_writable()); + } + { + // data descriptor + v8::PropertyDescriptor desc(v8_num(42)); + desc.set_configurable(false); + CHECK(desc.value() == v8_num(42)); + CHECK(desc.has_value()); + CHECK(!desc.has_set()); + CHECK(!desc.has_get()); + CHECK(desc.has_configurable()); + CHECK(!desc.configurable()); + CHECK(!desc.has_enumerable()); + CHECK(!desc.has_writable()); + } + { + // data descriptor + v8::PropertyDescriptor desc(v8_num(42), false); + CHECK(desc.value() == v8_num(42)); + CHECK(desc.has_value()); + CHECK(!desc.has_set()); + CHECK(!desc.has_get()); + CHECK(!desc.has_enumerable()); + CHECK(!desc.has_configurable()); + CHECK(desc.has_writable()); + CHECK(!desc.writable()); + } + { + // data descriptor + v8::PropertyDescriptor desc(v8::Local<v8::Value>(), true); + CHECK(!desc.has_value()); + CHECK(!desc.has_set()); + CHECK(!desc.has_get()); + CHECK(!desc.has_enumerable()); + CHECK(!desc.has_configurable()); + CHECK(desc.has_writable()); + CHECK(desc.writable()); + } + { + // accessor descriptor + CompileRun("var set = function() {return 43;};"); + + v8::Local<v8::Function> set = + v8::Local<v8::Function>::Cast(context->Global() + ->Get(context.local(), v8_str("set")) + .ToLocalChecked()); + v8::PropertyDescriptor desc(v8::Undefined(isolate), set); + desc.set_configurable(false); + CHECK(!desc.has_value()); + CHECK(desc.has_get()); + CHECK(desc.get() == v8::Undefined(isolate)); + CHECK(desc.has_set()); + CHECK(desc.set() == set); + CHECK(!desc.has_enumerable()); + CHECK(desc.has_configurable()); + CHECK(!desc.configurable()); + CHECK(!desc.has_writable()); + } + { + // accessor descriptor with Proxy + CompileRun( + "var set = new Proxy(function() {}, {});" + "var get = undefined;"); + + v8::Local<v8::Value> get = + v8::Local<v8::Value>::Cast(context->Global() + ->Get(context.local(), v8_str("get")) + .ToLocalChecked()); + v8::Local<v8::Function> set = + v8::Local<v8::Function>::Cast(context->Global() + ->Get(context.local(), v8_str("set")) + .ToLocalChecked()); + v8::PropertyDescriptor desc(get, set); + desc.set_configurable(false); + CHECK(!desc.has_value()); + CHECK(desc.get() == v8::Undefined(isolate)); + CHECK(desc.has_get()); + CHECK(desc.set() == set); + CHECK(desc.has_set()); + CHECK(!desc.has_enumerable()); + CHECK(desc.has_configurable()); + CHECK(!desc.configurable()); + CHECK(!desc.has_writable()); + } + { + // accessor descriptor with empty function handle + v8::Local<v8::Function> get = v8::Local<v8::Function>(); + v8::PropertyDescriptor desc(get, get); + CHECK(!desc.has_value()); + CHECK(!desc.has_get()); + CHECK(!desc.has_set()); + CHECK(!desc.has_enumerable()); + CHECK(!desc.has_configurable()); + CHECK(!desc.has_writable()); + } +} TEST(Promises) { LocalContext context; @@ -24141,7 +24569,7 @@ TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) { TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) { // Test cases where a UTF-8 character is split over several chunks. Those // cases are not supported (the embedder should give the data in big enough - // chunks), but we shouldn't crash, just produce a parse error. + // chunks), but we shouldn't crash and parse this just fine. const char* reference = "\xec\x92\x81"; char chunk1[] = "function foo() {\n" @@ -24158,7 +24586,7 @@ TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) { chunk3[0] = reference[2]; const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; - RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); + RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); } |