diff options
Diffstat (limited to 'deps/v8/test/cctest/test-debug.cc')
-rw-r--r-- | deps/v8/test/cctest/test-debug.cc | 403 |
1 files changed, 278 insertions, 125 deletions
diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 1f55824e3a..f8f8e6a8a6 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -165,6 +165,8 @@ void CheckDebuggerUnloaded() { CHECK(!CcTest::i_isolate()->debug()->debug_info_list_); // Collect garbage to ensure weak handles are cleared. + i::DisableConservativeStackScanningScopeForTesting no_stack_scanning( + CcTest::heap()); CcTest::CollectAllGarbage(); CcTest::CollectAllGarbage(); @@ -253,8 +255,9 @@ class DebugEventBreak : public v8::debug::DebugDelegate { } }; +v8::debug::BreakReasons break_right_now_reasons = {}; static void BreakRightNow(v8::Isolate* isolate, void*) { - v8::debug::BreakRightNow(isolate); + v8::debug::BreakRightNow(isolate, break_right_now_reasons); } // Debug event handler which re-issues a debug break until a limit has been @@ -580,8 +583,6 @@ TEST(BreakPointApiIntrinsics) { DebugEventCounter delegate; v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate); - v8::Local<v8::Function> builtin; - // === Test that using API-exposed functions won't trigger breakpoints === { v8::Local<v8::Function> weakmap_get = @@ -2716,7 +2717,6 @@ TEST(DebugStepWith) { v8::Object::New(env->GetIsolate())) .FromJust()); v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo"); - v8::Local<v8::Value> result; SetBreakPoint(foo, 8); // "var a = {};" run_step.set_step_action(StepInto); @@ -3828,6 +3828,12 @@ void DebugBreakLoop(const char* loop_header, const char** loop_bodies, TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer); + // Also test with "Scheduled" break reason. + break_right_now_reasons = + v8::debug::BreakReasons{v8::debug::BreakReason::kScheduled}; + TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer); + break_right_now_reasons = v8::debug::BreakReasons{}; + // Get rid of the debug event listener. v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(); @@ -4202,6 +4208,12 @@ class ArchiveRestoreThread : public v8::base::Thread, // child.GetBreakCount() will return 1 if the debugger fails to stop // on the `next()` line after the grandchild thread returns. CHECK_EQ(child.GetBreakCount(), 5); + + // This test on purpose unlocks the isolate without exiting and + // re-entering. It must however update the stack start, which would have + // been done automatically if the isolate was properly re-entered. + reinterpret_cast<i::Isolate*>(isolate_)->heap()->SetStackStart( + v8::base::Stack::GetStackStart()); } } @@ -4565,7 +4577,7 @@ TEST(BuiltinsExceptionPrediction) { bool fail = false; for (i::Builtin builtin = i::Builtins::kFirst; builtin <= i::Builtins::kLast; ++builtin) { - i::CodeT code = builtins->code(builtin); + i::Code code = builtins->code(builtin); if (code.kind() != i::CodeKind::BUILTIN) continue; auto prediction = code.GetBuiltinCatchPrediction(); USE(prediction); @@ -4963,7 +4975,8 @@ TEST(GetPrivateFields) { .ToLocalChecked()); std::vector<v8::Local<v8::Value>> names; std::vector<v8::Local<v8::Value>> values; - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); + int filter = static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateFields); + CHECK(v8::debug::GetPrivateMembers(context, object, filter, &names, &values)); CHECK_EQ(names.size(), 2); for (int i = 0; i < 2; i++) { @@ -4995,7 +5008,7 @@ TEST(GetPrivateFields) { env->Global() ->Get(context, v8_str(env->GetIsolate(), "x")) .ToLocalChecked()); - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); + CHECK(v8::debug::GetPrivateMembers(context, object, filter, &names, &values)); CHECK_EQ(names.size(), 3); for (int i = 0; i < 3; i++) { @@ -5030,7 +5043,7 @@ TEST(GetPrivateFields) { env->Global() ->Get(context, v8_str(env->GetIsolate(), "x")) .ToLocalChecked()); - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); + CHECK(v8::debug::GetPrivateMembers(context, object, filter, &names, &values)); CHECK_EQ(names.size(), 2); for (int i = 0; i < 2; i++) { @@ -5069,31 +5082,46 @@ TEST(GetPrivateMethodsAndAccessors) { .ToLocalChecked()); std::vector<v8::Local<v8::Value>> names; std::vector<v8::Local<v8::Value>> values; - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); - CHECK_EQ(names.size(), 4); - for (int i = 0; i < 4; i++) { + int accessor_filter = + static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateAccessors); + int method_filter = + static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateMethods); + + CHECK(v8::debug::GetPrivateMembers(context, object, method_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; + CHECK(name->IsString()); + CHECK(v8_str("#method")->Equals(context, name.As<v8::String>()).FromJust()); + CHECK(value->IsFunction()); + } + + names.clear(); + values.clear(); + CHECK(v8::debug::GetPrivateMembers(context, object, accessor_filter, &names, + &values)); + CHECK_EQ(names.size(), 3); + for (int i = 0; i < 3; i++) { v8::Local<v8::Value> name = names[i]; v8::Local<v8::Value> value = values[i]; CHECK(name->IsString()); std::string name_str = FromString(v8_isolate, name.As<v8::String>()); - if (name_str == "#method") { - CHECK(value->IsFunction()); + CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); + v8::Local<v8::debug::AccessorPair> accessors = + value.As<v8::debug::AccessorPair>(); + if (name_str == "#accessor") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsFunction()); + } else if (name_str == "#readOnly") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsNull()); } else { - CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); - v8::Local<v8::debug::AccessorPair> accessors = - value.As<v8::debug::AccessorPair>(); - if (name_str == "#accessor") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsFunction()); - } else if (name_str == "#readOnly") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsNull()); - } else { - CHECK_EQ(name_str, "#writeOnly"); - CHECK(accessors->getter()->IsNull()); - CHECK(accessors->setter()->IsFunction()); - } + CHECK_EQ(name_str, "#writeOnly"); + CHECK(accessors->getter()->IsNull()); + CHECK(accessors->setter()->IsFunction()); } } @@ -5115,31 +5143,41 @@ TEST(GetPrivateMethodsAndAccessors) { env->Global() ->Get(context, v8_str(env->GetIsolate(), "x")) .ToLocalChecked()); - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); - CHECK_EQ(names.size(), 4); - for (int i = 0; i < 4; i++) { + CHECK(v8::debug::GetPrivateMembers(context, object, method_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; + CHECK(name->IsString()); + CHECK(v8_str("#method")->Equals(context, name.As<v8::String>()).FromJust()); + CHECK(value->IsFunction()); + } + + names.clear(); + values.clear(); + CHECK(v8::debug::GetPrivateMembers(context, object, accessor_filter, &names, + &values)); + CHECK_EQ(names.size(), 3); + for (int i = 0; i < 3; i++) { v8::Local<v8::Value> name = names[i]; v8::Local<v8::Value> value = values[i]; CHECK(name->IsString()); std::string name_str = FromString(v8_isolate, name.As<v8::String>()); - if (name_str == "#method") { - CHECK(value->IsFunction()); + CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); + v8::Local<v8::debug::AccessorPair> accessors = + value.As<v8::debug::AccessorPair>(); + if (name_str == "#accessor") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsFunction()); + } else if (name_str == "#readOnly") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsNull()); } else { - CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); - v8::Local<v8::debug::AccessorPair> accessors = - value.As<v8::debug::AccessorPair>(); - if (name_str == "#accessor") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsFunction()); - } else if (name_str == "#readOnly") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsNull()); - } else { - CHECK_EQ(name_str, "#writeOnly"); - CHECK(accessors->getter()->IsNull()); - CHECK(accessors->setter()->IsFunction()); - } + CHECK_EQ(name_str, "#writeOnly"); + CHECK(accessors->getter()->IsNull()); + CHECK(accessors->setter()->IsFunction()); } } @@ -5162,24 +5200,34 @@ TEST(GetPrivateMethodsAndAccessors) { env->Global() ->Get(context, v8_str(env->GetIsolate(), "x")) .ToLocalChecked()); - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); - CHECK_EQ(names.size(), 2); - for (int i = 0; i < 2; i++) { - v8::Local<v8::Value> name = names[i]; - v8::Local<v8::Value> value = values[i]; + CHECK(v8::debug::GetPrivateMembers(context, object, method_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; CHECK(name->IsString()); - std::string name_str = FromString(v8_isolate, name.As<v8::String>()); - if (name_str == "#method") { - CHECK(value->IsFunction()); - } else { - CHECK_EQ(name_str, "#accessor"); - CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); - v8::Local<v8::debug::AccessorPair> accessors = - value.As<v8::debug::AccessorPair>(); - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsFunction()); - } + CHECK(v8_str("#method")->Equals(context, name.As<v8::String>()).FromJust()); + CHECK(value->IsFunction()); + } + + names.clear(); + values.clear(); + CHECK(v8::debug::GetPrivateMembers(context, object, accessor_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; + CHECK(name->IsString()); + CHECK( + v8_str("#accessor")->Equals(context, name.As<v8::String>()).FromJust()); + CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); + v8::Local<v8::debug::AccessorPair> accessors = + value.As<v8::debug::AccessorPair>(); + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsFunction()); } } @@ -5204,31 +5252,48 @@ TEST(GetPrivateStaticMethodsAndAccessors) { .ToLocalChecked()); std::vector<v8::Local<v8::Value>> names; std::vector<v8::Local<v8::Value>> values; - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); - CHECK_EQ(names.size(), 4); - for (int i = 0; i < 4; i++) { + int accessor_filter = + static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateAccessors); + int method_filter = + static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateMethods); + + CHECK(v8::debug::GetPrivateMembers(context, object, method_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; + CHECK(name->IsString()); + CHECK(v8_str("#staticMethod") + ->Equals(context, name.As<v8::String>()) + .FromJust()); + CHECK(value->IsFunction()); + } + + names.clear(); + values.clear(); + CHECK(v8::debug::GetPrivateMembers(context, object, accessor_filter, &names, + &values)); + CHECK_EQ(names.size(), 3); + for (int i = 0; i < 3; i++) { v8::Local<v8::Value> name = names[i]; v8::Local<v8::Value> value = values[i]; CHECK(name->IsString()); std::string name_str = FromString(v8_isolate, name.As<v8::String>()); - if (name_str == "#staticMethod") { - CHECK(value->IsFunction()); + CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); + v8::Local<v8::debug::AccessorPair> accessors = + value.As<v8::debug::AccessorPair>(); + if (name_str == "#staticAccessor") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsFunction()); + } else if (name_str == "#staticReadOnly") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsNull()); } else { - CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); - v8::Local<v8::debug::AccessorPair> accessors = - value.As<v8::debug::AccessorPair>(); - if (name_str == "#staticAccessor") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsFunction()); - } else if (name_str == "#staticReadOnly") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsNull()); - } else { - CHECK_EQ(name_str, "#staticWriteOnly"); - CHECK(accessors->getter()->IsNull()); - CHECK(accessors->setter()->IsFunction()); - } + CHECK_EQ(name_str, "#staticWriteOnly"); + CHECK(accessors->getter()->IsNull()); + CHECK(accessors->setter()->IsFunction()); } } } @@ -5260,31 +5325,47 @@ TEST(GetPrivateStaticAndInstanceMethodsAndAccessors) { .ToLocalChecked()); std::vector<v8::Local<v8::Value>> names; std::vector<v8::Local<v8::Value>> values; - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); + int accessor_filter = + static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateAccessors); + int method_filter = + static_cast<int>(v8::debug::PrivateMemberFilter::kPrivateMethods); + + CHECK(v8::debug::GetPrivateMembers(context, object, method_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; + CHECK(name->IsString()); + CHECK(v8_str("#staticMethod") + ->Equals(context, name.As<v8::String>()) + .FromJust()); + CHECK(value->IsFunction()); + } - CHECK_EQ(names.size(), 4); - for (int i = 0; i < 4; i++) { + names.clear(); + values.clear(); + CHECK(v8::debug::GetPrivateMembers(context, object, accessor_filter, &names, + &values)); + CHECK_EQ(names.size(), 3); + for (int i = 0; i < 3; i++) { v8::Local<v8::Value> name = names[i]; v8::Local<v8::Value> value = values[i]; CHECK(name->IsString()); std::string name_str = FromString(v8_isolate, name.As<v8::String>()); - if (name_str == "#staticMethod") { - CHECK(value->IsFunction()); + CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); + v8::Local<v8::debug::AccessorPair> accessors = + value.As<v8::debug::AccessorPair>(); + if (name_str == "#staticAccessor") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsFunction()); + } else if (name_str == "#staticReadOnly") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsNull()); } else { - CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); - v8::Local<v8::debug::AccessorPair> accessors = - value.As<v8::debug::AccessorPair>(); - if (name_str == "#staticAccessor") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsFunction()); - } else if (name_str == "#staticReadOnly") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsNull()); - } else { - CHECK_EQ(name_str, "#staticWriteOnly"); - CHECK(accessors->getter()->IsNull()); - CHECK(accessors->setter()->IsFunction()); - } + CHECK_EQ(name_str, "#staticWriteOnly"); + CHECK(accessors->getter()->IsNull()); + CHECK(accessors->setter()->IsFunction()); } } @@ -5294,31 +5375,40 @@ TEST(GetPrivateStaticAndInstanceMethodsAndAccessors) { env->Global() ->Get(context, v8_str(env->GetIsolate(), "x")) .ToLocalChecked()); - CHECK(v8::debug::GetPrivateMembers(context, object, &names, &values)); + CHECK(v8::debug::GetPrivateMembers(context, object, method_filter, &names, + &values)); + CHECK_EQ(names.size(), 1); + { + v8::Local<v8::Value> name = names[0]; + v8::Local<v8::Value> value = values[0]; + CHECK(name->IsString()); + CHECK(v8_str("#method")->Equals(context, name.As<v8::String>()).FromJust()); + CHECK(value->IsFunction()); + } - CHECK_EQ(names.size(), 4); - for (int i = 0; i < 4; i++) { + names.clear(); + values.clear(); + CHECK(v8::debug::GetPrivateMembers(context, object, accessor_filter, &names, + &values)); + CHECK_EQ(names.size(), 3); + for (int i = 0; i < 3; i++) { v8::Local<v8::Value> name = names[i]; v8::Local<v8::Value> value = values[i]; CHECK(name->IsString()); std::string name_str = FromString(v8_isolate, name.As<v8::String>()); - if (name_str == "#method") { - CHECK(value->IsFunction()); + CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); + v8::Local<v8::debug::AccessorPair> accessors = + value.As<v8::debug::AccessorPair>(); + if (name_str == "#accessor") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsFunction()); + } else if (name_str == "#readOnly") { + CHECK(accessors->getter()->IsFunction()); + CHECK(accessors->setter()->IsNull()); } else { - CHECK(v8::debug::AccessorPair::IsAccessorPair(value)); - v8::Local<v8::debug::AccessorPair> accessors = - value.As<v8::debug::AccessorPair>(); - if (name_str == "#accessor") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsFunction()); - } else if (name_str == "#readOnly") { - CHECK(accessors->getter()->IsFunction()); - CHECK(accessors->setter()->IsNull()); - } else { - CHECK_EQ(name_str, "#writeOnly"); - CHECK(accessors->getter()->IsNull()); - CHECK(accessors->setter()->IsFunction()); - } + CHECK_EQ(name_str, "#writeOnly"); + CHECK(accessors->getter()->IsNull()); + CHECK(accessors->setter()->IsFunction()); } } } @@ -5924,8 +6014,8 @@ class ScopeListener : public v8::debug::DebugDelegate { const std::vector<v8::debug::BreakpointId>&, v8::debug::BreakReasons break_reasons) override { i::Isolate* isolate = CcTest::i_isolate(); - i::StackTraceFrameIterator iterator_(isolate, - isolate->debug()->break_frame_id()); + i::DebuggableStackFrameIterator iterator_( + isolate, isolate->debug()->break_frame_id()); // Go up one frame so we are on the script level. iterator_.Advance(); @@ -5944,8 +6034,6 @@ class ScopeListener : public v8::debug::DebugDelegate { } // namespace TEST(ScopeIteratorDoesNotCreateBlocklistForScriptScope) { - i::v8_flags.experimental_reuse_locals_blocklists = true; - LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -5987,8 +6075,6 @@ class DebugEvaluateListener : public v8::debug::DebugDelegate { // scope nested inside an eval scope with the exact same source positions. // This can confuse the blocklist mechanism if not handled correctly. TEST(DebugEvaluateInWrappedScript) { - i::v8_flags.experimental_reuse_locals_blocklists = true; - LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -6012,3 +6098,70 @@ TEST(DebugEvaluateInWrappedScript) { v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(); } + +namespace { + +class ConditionListener : public v8::debug::DebugDelegate { + public: + void BreakpointConditionEvaluated( + v8::Local<v8::Context> context, v8::debug::BreakpointId breakpoint_id_arg, + bool exception_thrown_arg, v8::Local<v8::Value> exception_arg) override { + breakpoint_id = breakpoint_id_arg; + exception_thrown = exception_thrown_arg; + exception = exception_arg; + } + + void BreakProgramRequested(v8::Local<v8::Context> context, + const std::vector<v8::debug::BreakpointId>&, + v8::debug::BreakReasons break_reasons) override { + break_point_hit_count++; + } + + v8::debug::BreakpointId breakpoint_id; + bool exception_thrown = false; + v8::Local<v8::Value> exception; +}; + +} // namespace + +TEST(SuccessfulBreakpointConditionEvaluationEvent) { + break_point_hit_count = 0; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + ConditionListener delegate; + v8::debug::SetDebugDelegate(isolate, &delegate); + + v8::Local<v8::Function> foo = + CompileFunction(&env, "function foo() { const x = 5; }", "foo"); + + i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0, "true"); + foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked(); + CHECK_EQ(1, break_point_hit_count); + CHECK_EQ(bp->id(), delegate.breakpoint_id); + CHECK(!delegate.exception_thrown); + CHECK(delegate.exception.IsEmpty()); +} + +// Checks that SyntaxErrors in breakpoint conditions are reported to the +// DebugDelegate. +TEST(FailedBreakpointConditoinEvaluationEvent) { + break_point_hit_count = 0; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + ConditionListener delegate; + v8::debug::SetDebugDelegate(isolate, &delegate); + + v8::Local<v8::Function> foo = + CompileFunction(&env, "function foo() { const x = 5; }", "foo"); + + i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0, "bar()."); + foo->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked(); + CHECK_EQ(0, break_point_hit_count); + CHECK_EQ(bp->id(), delegate.breakpoint_id); + CHECK(delegate.exception_thrown); + CHECK(!delegate.exception.IsEmpty()); +} |