From 6e29fadb7296984dfbbb121d54bfdeaa76f13add Mon Sep 17 00:00:00 2001 From: "yurys@chromium.org" Date: Mon, 25 May 2009 15:07:21 +0000 Subject: [PATCH] When inspecting a function with a native getter return result of execution of the getter function in the client context. This is useful for debugging DOM elements. Review URL: http://codereview.chromium.org/113821 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2044 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/runtime.cc | 24 ++++++++++----- test/cctest/test-debug.cc | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/src/runtime.cc b/src/runtime.cc index ed4f598..7875023 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -5486,7 +5486,8 @@ static int LocalPrototypeChainLength(JSObject* obj) { } -static Object* DebugLookupResultValue(Object* receiver, LookupResult* result, +static Object* DebugLookupResultValue(Object* receiver, String* name, + LookupResult* result, bool* caught_exception) { Object* value; switch (result->type()) { @@ -5511,11 +5512,18 @@ static Object* DebugLookupResultValue(Object* receiver, LookupResult* result, return result->GetConstantFunction(); case CALLBACKS: { Object* structure = result->GetCallbackObject(); - if (structure->IsProxy()) { - AccessorDescriptor* callback = - reinterpret_cast( - Proxy::cast(structure)->proxy()); - value = (callback->getter)(receiver, callback->data); + if (structure->IsProxy() || structure->IsAccessorInfo()) { + if (Debug::debugger_entry()) { + // SaveContext scope. It will restore debugger context after the + // getter execution. + SaveContext save; + Top::set_context(*Debug::debugger_entry()->GetContext()); + value = receiver->GetPropertyWithCallback( + receiver, structure, name, result->holder()); + } else { + value = receiver->GetPropertyWithCallback( + receiver, structure, name, result->holder()); + } if (value->IsException()) { value = Top::pending_exception(); Top::clear_pending_exception(); @@ -5596,7 +5604,7 @@ static Object* Runtime_DebugGetPropertyDetails(Arguments args) { if (result.IsProperty()) { bool caught_exception = false; - Object* value = DebugLookupResultValue(*obj, &result, + Object* value = DebugLookupResultValue(*obj, *name, &result, &caught_exception); if (value->IsFailure()) return value; Handle value_handle(value); @@ -5632,7 +5640,7 @@ static Object* Runtime_DebugGetProperty(Arguments args) { LookupResult result; obj->Lookup(*name, &result); if (result.IsProperty()) { - return DebugLookupResultValue(*obj, &result, NULL); + return DebugLookupResultValue(*obj, *name, &result, NULL); } return Heap::undefined_value(); } diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 1fb390c..be67776 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -3313,6 +3313,82 @@ TEST(HiddenPrototypePropertyMirror) { } +static v8::Handle ProtperyXNativeGetter( + v8::Local property, const v8::AccessorInfo& info) { + return v8::Integer::New(10); +} + + +TEST(NativeGetterPropertyMirror) { + // Create a V8 environment with debug access. + v8::HandleScope scope; + DebugLocalContext env; + env.ExposeDebug(); + + v8::Handle name = v8::String::New("x"); + // Create object with named accessor. + v8::Handle named = v8::ObjectTemplate::New(); + named->SetAccessor(name, &ProtperyXNativeGetter, NULL, + v8::Handle(), v8::DEFAULT, v8::None); + + // Create object with named property getter. + env->Global()->Set(v8::String::New("instance"), named->NewInstance()); + CHECK_EQ(10, CompileRun("instance.x")->Int32Value()); + + // Get mirror for the object with property getter. + CompileRun("instance_mirror = debug.MakeMirror(instance);"); + CHECK(CompileRun( + "instance_mirror instanceof debug.ObjectMirror")->BooleanValue()); + + CompileRun("named_names = instance_mirror.propertyNames();"); + CHECK_EQ(1, CompileRun("named_names.length")->Int32Value()); + CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue()); + CHECK(CompileRun( + "instance_mirror.property('x').value().isNumber()")->BooleanValue()); + CHECK(CompileRun( + "instance_mirror.property('x').value().value() == 10")->BooleanValue()); +} + + +static v8::Handle ProtperyXNativeGetterThrowingError( + v8::Local property, const v8::AccessorInfo& info) { + return CompileRun("throw new Error('Error message');"); +} + + +TEST(NativeGetterThrowingErrorPropertyMirror) { + // Create a V8 environment with debug access. + v8::HandleScope scope; + DebugLocalContext env; + env.ExposeDebug(); + + v8::Handle name = v8::String::New("x"); + // Create object with named accessor. + v8::Handle named = v8::ObjectTemplate::New(); + named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL, + v8::Handle(), v8::DEFAULT, v8::None); + + // Create object with named property getter. + env->Global()->Set(v8::String::New("instance"), named->NewInstance()); + + // Get mirror for the object with property getter. + CompileRun("instance_mirror = debug.MakeMirror(instance);"); + CHECK(CompileRun( + "instance_mirror instanceof debug.ObjectMirror")->BooleanValue()); + CompileRun("named_names = instance_mirror.propertyNames();"); + CHECK_EQ(1, CompileRun("named_names.length")->Int32Value()); + CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue()); + CHECK(CompileRun( + "instance_mirror.property('x').value().isError()")->BooleanValue()); + + // Check that the message is that passed to the Error constructor. + CHECK(CompileRun( + "instance_mirror.property('x').value().message() == 'Error message'")-> + BooleanValue()); +} + + + // Multithreaded tests of JSON debugger protocol // Support classes -- 2.7.4