Revert "inspector: move injected script source to native"
This reverts commit 34686abe40
.
Reason for revert: Compile errors on several bots, e.g. https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Linux%20-%20debug%20builder/33299
Original change's description:
> inspector: move injected script source to native
>
> - introduced ValueMirror interface, this interface contains methods to generate
> different protocol entities,
> - introduced DebugPropertyIterator, this iterator iterates through object properties
> in the following order: exotic indices, enumerable strings, all other properties,
> - removed all injected script infra, e.g. closure compiler,
>
> R=dgozman@chromium.org
> TBR=yangguo@chromium.org
>
> Bug: chromium:595206
> Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
> Change-Id: I077c1879622aa0d9900d719b80d2ef5ba4221a22
> Reviewed-on: https://chromium-review.googlesource.com/c/1295550
> Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
> Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#57142}
TBR=dgozman@chromium.org,yangguo@chromium.org,kozyatinskiy@chromium.org
Change-Id: I6e4ccaf1d6b151fbc0ffe4f26daa584433321c77
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:595206
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Reviewed-on: https://chromium-review.googlesource.com/c/1307432
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57144}
This commit is contained in:
parent
3a85e0c602
commit
192bee6bac
2
BUILD.gn
2
BUILD.gn
@ -1937,8 +1937,6 @@ v8_source_set("v8_base") {
|
||||
"src/debug/debug-frames.cc",
|
||||
"src/debug/debug-frames.h",
|
||||
"src/debug/debug-interface.h",
|
||||
"src/debug/debug-property-iterator.cc",
|
||||
"src/debug/debug-property-iterator.h",
|
||||
"src/debug/debug-scope-iterator.cc",
|
||||
"src/debug/debug-scope-iterator.h",
|
||||
"src/debug/debug-scopes.cc",
|
||||
|
11
DEPS
11
DEPS
@ -245,6 +245,17 @@ hooks = [
|
||||
'-s', 'v8/test/wasm-spec-tests/tests.tar.gz.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'closure_compiler',
|
||||
'pattern': '.',
|
||||
'action': [ 'download_from_google_storage',
|
||||
'--no_resume',
|
||||
'--no_auth',
|
||||
'-u',
|
||||
'--bucket', 'chromium-v8-closure-compiler',
|
||||
'-s', 'v8/src/inspector/build/closure-compiler.tar.gz.sha1',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'sysroot_arm',
|
||||
'pattern': '.',
|
||||
|
56
src/api.cc
56
src/api.cc
@ -9556,8 +9556,20 @@ Local<Function> debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) {
|
||||
i::HandleScope handle_scope(isolate);
|
||||
i::Builtins::Name builtin_id;
|
||||
switch (builtin) {
|
||||
case kStringToLowerCase:
|
||||
builtin_id = i::Builtins::kStringPrototypeToLocaleLowerCase;
|
||||
case kObjectKeys:
|
||||
builtin_id = i::Builtins::kObjectKeys;
|
||||
break;
|
||||
case kObjectGetPrototypeOf:
|
||||
builtin_id = i::Builtins::kObjectGetPrototypeOf;
|
||||
break;
|
||||
case kObjectGetOwnPropertyDescriptor:
|
||||
builtin_id = i::Builtins::kObjectGetOwnPropertyDescriptor;
|
||||
break;
|
||||
case kObjectGetOwnPropertyNames:
|
||||
builtin_id = i::Builtins::kObjectGetOwnPropertyNames;
|
||||
break;
|
||||
case kObjectGetOwnPropertySymbols:
|
||||
builtin_id = i::Builtins::kObjectGetOwnPropertySymbols;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -9565,11 +9577,10 @@ Local<Function> debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) {
|
||||
|
||||
i::Handle<i::String> name = isolate->factory()->empty_string();
|
||||
i::NewFunctionArgs args = i::NewFunctionArgs::ForBuiltinWithoutPrototype(
|
||||
name, builtin_id, i::LanguageMode::kStrict);
|
||||
name, builtin_id, i::LanguageMode::kSloppy);
|
||||
i::Handle<i::JSFunction> fun = isolate->factory()->NewFunction(args);
|
||||
|
||||
fun->shared()->set_internal_formal_parameter_count(0);
|
||||
fun->shared()->set_length(0);
|
||||
fun->shared()->DontAdaptArguments();
|
||||
return Utils::ToLocal(handle_scope.CloseAndEscape(fun));
|
||||
}
|
||||
|
||||
@ -9694,6 +9705,41 @@ void debug::SetReturnValue(v8::Isolate* v8_isolate,
|
||||
isolate->debug()->set_return_value(*Utils::OpenHandle(*value));
|
||||
}
|
||||
|
||||
int debug::GetNativeAccessorDescriptor(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> v8_object,
|
||||
v8::Local<v8::Name> v8_name) {
|
||||
i::Handle<i::JSReceiver> object = Utils::OpenHandle(*v8_object);
|
||||
i::Handle<i::Name> name = Utils::OpenHandle(*v8_name);
|
||||
uint32_t index;
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
return static_cast<int>(debug::NativeAccessorType::None);
|
||||
}
|
||||
i::LookupIterator it = i::LookupIterator(object->GetIsolate(), object, name,
|
||||
i::LookupIterator::OWN);
|
||||
if (!it.IsFound()) return static_cast<int>(debug::NativeAccessorType::None);
|
||||
if (it.state() != i::LookupIterator::ACCESSOR) {
|
||||
return static_cast<int>(debug::NativeAccessorType::None);
|
||||
}
|
||||
i::Handle<i::Object> structure = it.GetAccessors();
|
||||
if (!structure->IsAccessorInfo()) {
|
||||
return static_cast<int>(debug::NativeAccessorType::None);
|
||||
}
|
||||
auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
|
||||
int result = 0;
|
||||
#define IS_BUILTIN_ACESSOR(_, name, ...) \
|
||||
if (*structure == *isolate->factory()->name##_accessor()) \
|
||||
result |= static_cast<int>(debug::NativeAccessorType::IsBuiltin);
|
||||
ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */)
|
||||
#undef IS_BUILTIN_ACESSOR
|
||||
i::Handle<i::AccessorInfo> accessor_info =
|
||||
i::Handle<i::AccessorInfo>::cast(structure);
|
||||
if (accessor_info->getter())
|
||||
result |= static_cast<int>(debug::NativeAccessorType::HasGetter);
|
||||
if (accessor_info->setter())
|
||||
result |= static_cast<int>(debug::NativeAccessorType::HasSetter);
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) {
|
||||
return reinterpret_cast<i::Isolate*>(v8_isolate)
|
||||
->random_number_generator()
|
||||
|
@ -193,7 +193,13 @@ void ResetBlackboxedStateCache(Isolate* isolate,
|
||||
|
||||
int EstimatedValueSize(Isolate* isolate, v8::Local<v8::Value> value);
|
||||
|
||||
enum Builtin { kStringToLowerCase };
|
||||
enum Builtin {
|
||||
kObjectKeys,
|
||||
kObjectGetPrototypeOf,
|
||||
kObjectGetOwnPropertyDescriptor,
|
||||
kObjectGetOwnPropertyNames,
|
||||
kObjectGetOwnPropertySymbols,
|
||||
};
|
||||
|
||||
Local<Function> GetBuiltin(Isolate* isolate, Builtin builtin);
|
||||
|
||||
@ -468,9 +474,14 @@ void SetReturnValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
|
||||
enum class NativeAccessorType {
|
||||
None = 0,
|
||||
HasGetter = 1 << 0,
|
||||
HasSetter = 1 << 1
|
||||
HasSetter = 1 << 1,
|
||||
IsBuiltin = 1 << 2
|
||||
};
|
||||
|
||||
int GetNativeAccessorDescriptor(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Name> name);
|
||||
|
||||
int64_t GetNextRandomInt64(v8::Isolate* isolate);
|
||||
|
||||
v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
|
||||
@ -507,39 +518,6 @@ class WeakMap : public v8::Object {
|
||||
private:
|
||||
WeakMap();
|
||||
};
|
||||
|
||||
struct PropertyDescriptor {
|
||||
bool enumerable : 1;
|
||||
bool has_enumerable : 1;
|
||||
bool configurable : 1;
|
||||
bool has_configurable : 1;
|
||||
bool writable : 1;
|
||||
bool has_writable : 1;
|
||||
v8::Local<v8::Value> value;
|
||||
v8::Local<v8::Value> get;
|
||||
v8::Local<v8::Value> set;
|
||||
};
|
||||
|
||||
class PropertyIterator {
|
||||
public:
|
||||
static std::unique_ptr<PropertyIterator> Create(v8::Local<v8::Object> object);
|
||||
|
||||
virtual ~PropertyIterator() = default;
|
||||
|
||||
virtual bool Done() const = 0;
|
||||
virtual void Advance() = 0;
|
||||
|
||||
virtual v8::Local<v8::Name> name() const = 0;
|
||||
|
||||
virtual bool is_native_accessor() = 0;
|
||||
virtual bool has_native_getter() = 0;
|
||||
virtual bool has_native_setter() = 0;
|
||||
virtual Maybe<PropertyAttribute> attributes() = 0;
|
||||
virtual Maybe<PropertyDescriptor> descriptor() = 0;
|
||||
|
||||
virtual bool is_own() = 0;
|
||||
virtual bool is_array_index() = 0;
|
||||
};
|
||||
} // namespace debug
|
||||
} // namespace v8
|
||||
|
||||
|
@ -1,213 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/debug/debug-property-iterator.h"
|
||||
|
||||
#include "src/api-inl.h"
|
||||
#include "src/base/flags.h"
|
||||
#include "src/keys.h"
|
||||
#include "src/objects/js-array-buffer-inl.h"
|
||||
#include "src/property-descriptor.h"
|
||||
#include "src/property-details.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
std::unique_ptr<debug::PropertyIterator> debug::PropertyIterator::Create(
|
||||
v8::Local<v8::Object> v8_object) {
|
||||
internal::Isolate* isolate =
|
||||
reinterpret_cast<internal::Isolate*>(v8_object->GetIsolate());
|
||||
return std::unique_ptr<debug::PropertyIterator>(
|
||||
new internal::DebugPropertyIterator(isolate,
|
||||
Utils::OpenHandle(*v8_object)));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate,
|
||||
Handle<JSReceiver> receiver)
|
||||
: isolate_(isolate),
|
||||
prototype_iterator_(isolate, receiver, kStartAtReceiver,
|
||||
PrototypeIterator::END_AT_NULL) {
|
||||
if (receiver->IsJSProxy()) {
|
||||
is_own_ = false;
|
||||
prototype_iterator_.AdvanceIgnoringProxies();
|
||||
}
|
||||
if (prototype_iterator_.IsAtEnd()) return;
|
||||
FillKeysForCurrentPrototypeAndStage();
|
||||
if (should_move_to_next_stage()) Advance();
|
||||
}
|
||||
|
||||
bool DebugPropertyIterator::Done() const {
|
||||
return prototype_iterator_.IsAtEnd();
|
||||
}
|
||||
|
||||
void DebugPropertyIterator::Advance() {
|
||||
++current_key_index_;
|
||||
calculated_native_accessor_flags_ = false;
|
||||
while (should_move_to_next_stage()) {
|
||||
switch (stage_) {
|
||||
case Stage::kExoticIndices:
|
||||
stage_ = Stage::kEnumerableStrings;
|
||||
break;
|
||||
case Stage::kEnumerableStrings:
|
||||
stage_ = Stage::kAllProperties;
|
||||
break;
|
||||
case Stage::kAllProperties:
|
||||
stage_ = kExoticIndices;
|
||||
is_own_ = false;
|
||||
prototype_iterator_.AdvanceIgnoringProxies();
|
||||
break;
|
||||
}
|
||||
FillKeysForCurrentPrototypeAndStage();
|
||||
}
|
||||
}
|
||||
|
||||
bool DebugPropertyIterator::is_native_accessor() {
|
||||
if (stage_ == kExoticIndices) return false;
|
||||
CalculateNativeAccessorFlags();
|
||||
return native_accessor_flags_;
|
||||
}
|
||||
|
||||
bool DebugPropertyIterator::has_native_getter() {
|
||||
if (stage_ == kExoticIndices) return false;
|
||||
CalculateNativeAccessorFlags();
|
||||
return native_accessor_flags_ &
|
||||
static_cast<int>(debug::NativeAccessorType::HasGetter);
|
||||
}
|
||||
|
||||
bool DebugPropertyIterator::has_native_setter() {
|
||||
if (stage_ == kExoticIndices) return false;
|
||||
CalculateNativeAccessorFlags();
|
||||
return native_accessor_flags_ &
|
||||
static_cast<int>(debug::NativeAccessorType::HasSetter);
|
||||
}
|
||||
|
||||
Handle<Name> DebugPropertyIterator::raw_name() const {
|
||||
DCHECK(!Done());
|
||||
if (stage_ == kExoticIndices) {
|
||||
return isolate_->factory()->Uint32ToString(current_key_index_);
|
||||
} else {
|
||||
return Handle<Name>::cast(
|
||||
FixedArray::get(*keys_, current_key_index_, isolate_));
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Name> DebugPropertyIterator::name() const {
|
||||
return Utils::ToLocal(raw_name());
|
||||
}
|
||||
|
||||
v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() {
|
||||
Handle<JSReceiver> receiver =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
|
||||
auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name());
|
||||
if (result.IsNothing()) return Nothing<v8::PropertyAttribute>();
|
||||
DCHECK(result.FromJust() != ABSENT);
|
||||
return Just(static_cast<v8::PropertyAttribute>(result.FromJust()));
|
||||
}
|
||||
|
||||
v8::Maybe<v8::debug::PropertyDescriptor> DebugPropertyIterator::descriptor() {
|
||||
Handle<JSReceiver> receiver =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
|
||||
|
||||
PropertyDescriptor descriptor;
|
||||
Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
|
||||
isolate_, receiver, raw_name(), &descriptor);
|
||||
if (did_get_descriptor.IsNothing()) {
|
||||
return Nothing<v8::debug::PropertyDescriptor>();
|
||||
}
|
||||
DCHECK(did_get_descriptor.FromJust());
|
||||
return Just(v8::debug::PropertyDescriptor{
|
||||
descriptor.enumerable(), descriptor.has_enumerable(),
|
||||
descriptor.configurable(), descriptor.has_configurable(),
|
||||
descriptor.writable(), descriptor.has_writable(),
|
||||
descriptor.has_value() ? Utils::ToLocal(descriptor.value())
|
||||
: v8::Local<v8::Value>(),
|
||||
descriptor.has_get() ? Utils::ToLocal(descriptor.get())
|
||||
: v8::Local<v8::Value>(),
|
||||
descriptor.has_set() ? Utils::ToLocal(descriptor.set())
|
||||
: v8::Local<v8::Value>(),
|
||||
});
|
||||
}
|
||||
|
||||
bool DebugPropertyIterator::is_own() { return is_own_; }
|
||||
|
||||
bool DebugPropertyIterator::is_array_index() {
|
||||
if (stage_ == kExoticIndices) return true;
|
||||
uint32_t index = 0;
|
||||
return raw_name()->AsArrayIndex(&index);
|
||||
}
|
||||
|
||||
void DebugPropertyIterator::FillKeysForCurrentPrototypeAndStage() {
|
||||
current_key_index_ = 0;
|
||||
exotic_length_ = 0;
|
||||
keys_ = Handle<FixedArray>::null();
|
||||
if (prototype_iterator_.IsAtEnd()) return;
|
||||
Handle<JSReceiver> receiver =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
|
||||
bool has_exotic_indices = receiver->IsJSTypedArray();
|
||||
if (stage_ == kExoticIndices) {
|
||||
if (!has_exotic_indices) return;
|
||||
exotic_length_ = static_cast<uint32_t>(
|
||||
Handle<JSTypedArray>::cast(receiver)->length_value());
|
||||
return;
|
||||
}
|
||||
bool skip_indices = has_exotic_indices;
|
||||
PropertyFilter filter =
|
||||
stage_ == kEnumerableStrings ? ENUMERABLE_STRINGS : ALL_PROPERTIES;
|
||||
if (!KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
|
||||
GetKeysConversion::kConvertToString, false,
|
||||
skip_indices)
|
||||
.ToHandle(&keys_)) {
|
||||
keys_ = Handle<FixedArray>::null();
|
||||
}
|
||||
}
|
||||
|
||||
bool DebugPropertyIterator::should_move_to_next_stage() const {
|
||||
if (prototype_iterator_.IsAtEnd()) return false;
|
||||
if (stage_ == kExoticIndices) return current_key_index_ >= exotic_length_;
|
||||
return keys_.is_null() ||
|
||||
current_key_index_ >= static_cast<uint32_t>(keys_->length());
|
||||
}
|
||||
|
||||
namespace {
|
||||
base::Flags<debug::NativeAccessorType, int> GetNativeAccessorDescriptorInternal(
|
||||
Handle<JSReceiver> object, Handle<Name> name) {
|
||||
uint32_t index;
|
||||
if (name->AsArrayIndex(&index)) return debug::NativeAccessorType::None;
|
||||
LookupIterator it =
|
||||
LookupIterator(object->GetIsolate(), object, name, LookupIterator::OWN);
|
||||
if (!it.IsFound()) return debug::NativeAccessorType::None;
|
||||
if (it.state() != LookupIterator::ACCESSOR) {
|
||||
return debug::NativeAccessorType::None;
|
||||
}
|
||||
Handle<Object> structure = it.GetAccessors();
|
||||
if (!structure->IsAccessorInfo()) return debug::NativeAccessorType::None;
|
||||
auto isolate = object->GetIsolate();
|
||||
base::Flags<debug::NativeAccessorType, int> result;
|
||||
#define IS_BUILTIN_ACESSOR(_, name, ...) \
|
||||
if (*structure == *isolate->factory()->name##_accessor()) \
|
||||
return debug::NativeAccessorType::None;
|
||||
ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */)
|
||||
#undef IS_BUILTIN_ACESSOR
|
||||
Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
|
||||
if (accessor_info->getter()) {
|
||||
result |= debug::NativeAccessorType::HasGetter;
|
||||
}
|
||||
if (accessor_info->setter()) {
|
||||
result |= debug::NativeAccessorType::HasSetter;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void DebugPropertyIterator::CalculateNativeAccessorFlags() {
|
||||
if (calculated_native_accessor_flags_) return;
|
||||
Handle<JSReceiver> receiver =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(prototype_iterator_);
|
||||
native_accessor_flags_ =
|
||||
GetNativeAccessorDescriptorInternal(receiver, raw_name());
|
||||
calculated_native_accessor_flags_ = true;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,62 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_DEBUG_DEBUG_PROPERTY_ITERATOR_H_
|
||||
#define V8_DEBUG_DEBUG_PROPERTY_ITERATOR_H_
|
||||
|
||||
#include "src/debug/debug-interface.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/prototype.h"
|
||||
|
||||
#include "include/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class JSReceiver;
|
||||
|
||||
class DebugPropertyIterator final : public debug::PropertyIterator {
|
||||
public:
|
||||
DebugPropertyIterator(Isolate* isolate, Handle<JSReceiver> receiver);
|
||||
~DebugPropertyIterator() override = default;
|
||||
|
||||
bool Done() const override;
|
||||
void Advance() override;
|
||||
|
||||
v8::Local<v8::Name> name() const override;
|
||||
bool is_native_accessor() override;
|
||||
bool has_native_getter() override;
|
||||
bool has_native_setter() override;
|
||||
v8::Maybe<v8::PropertyAttribute> attributes() override;
|
||||
v8::Maybe<v8::debug::PropertyDescriptor> descriptor() override;
|
||||
|
||||
bool is_own() override;
|
||||
bool is_array_index() override;
|
||||
|
||||
private:
|
||||
void FillKeysForCurrentPrototypeAndStage();
|
||||
bool should_move_to_next_stage() const;
|
||||
void CalculateNativeAccessorFlags();
|
||||
Handle<Name> raw_name() const;
|
||||
|
||||
Isolate* isolate_;
|
||||
PrototypeIterator prototype_iterator_;
|
||||
enum Stage { kExoticIndices = 0, kEnumerableStrings = 1, kAllProperties = 2 };
|
||||
Stage stage_ = kExoticIndices;
|
||||
|
||||
uint32_t current_key_index_ = 0;
|
||||
Handle<FixedArray> keys_;
|
||||
uint32_t exotic_length_ = 0;
|
||||
|
||||
bool calculated_native_accessor_flags_ = false;
|
||||
int native_accessor_flags_ = 0;
|
||||
bool is_own_ = true;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DebugPropertyIterator);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_DEBUG_DEBUG_PROPERTY_ITERATOR_H_
|
@ -61,6 +61,22 @@ inspector_protocol_generate("protocol_generated_sources") {
|
||||
outputs = _protocol_generated
|
||||
}
|
||||
|
||||
action("inspector_injected_script") {
|
||||
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
||||
script = "build/xxd.py"
|
||||
inputs = [
|
||||
"injected-script-source.js",
|
||||
]
|
||||
outputs = [
|
||||
"$target_gen_dir/injected-script-source.h",
|
||||
]
|
||||
args = [
|
||||
"InjectedScriptSource_js",
|
||||
rebase_path("injected-script-source.js", root_build_dir),
|
||||
rebase_path("$target_gen_dir/injected-script-source.h", root_build_dir),
|
||||
]
|
||||
}
|
||||
|
||||
config("inspector_config") {
|
||||
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
||||
if (is_component_build) {
|
||||
@ -70,6 +86,7 @@ config("inspector_config") {
|
||||
|
||||
v8_source_set("inspector") {
|
||||
deps = [
|
||||
":inspector_injected_script",
|
||||
":protocol_generated_sources",
|
||||
]
|
||||
configs = [ ":inspector_config" ]
|
||||
@ -84,6 +101,7 @@ v8_source_set("inspector") {
|
||||
"../../include/v8-inspector-protocol.h",
|
||||
"../../include/v8-inspector.h",
|
||||
]
|
||||
sources += get_target_outputs(":inspector_injected_script")
|
||||
sources += [
|
||||
"custom-preview.cc",
|
||||
"custom-preview.h",
|
||||
@ -113,12 +131,18 @@ v8_source_set("inspector") {
|
||||
"v8-debugger-script.h",
|
||||
"v8-debugger.cc",
|
||||
"v8-debugger.h",
|
||||
"v8-function-call.cc",
|
||||
"v8-function-call.h",
|
||||
"v8-heap-profiler-agent-impl.cc",
|
||||
"v8-heap-profiler-agent-impl.h",
|
||||
"v8-injected-script-host.cc",
|
||||
"v8-injected-script-host.h",
|
||||
"v8-inspector-impl.cc",
|
||||
"v8-inspector-impl.h",
|
||||
"v8-inspector-session-impl.cc",
|
||||
"v8-inspector-session-impl.h",
|
||||
"v8-internal-value-type.cc",
|
||||
"v8-internal-value-type.h",
|
||||
"v8-profiler-agent-impl.cc",
|
||||
"v8-profiler-agent-impl.h",
|
||||
"v8-regex.cc",
|
||||
@ -131,8 +155,6 @@ v8_source_set("inspector") {
|
||||
"v8-stack-trace-impl.h",
|
||||
"v8-value-utils.cc",
|
||||
"v8-value-utils.h",
|
||||
"value-mirror.cc",
|
||||
"value-mirror.h",
|
||||
"wasm-translation.cc",
|
||||
"wasm-translation.h",
|
||||
]
|
||||
|
53
src/inspector/PRESUBMIT.py
Normal file
53
src/inspector/PRESUBMIT.py
Normal file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2016 the V8 project authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""v8_inspect presubmit script
|
||||
|
||||
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
|
||||
for more details about the presubmit API built into gcl.
|
||||
"""
|
||||
|
||||
compile_note = "Be sure to run your patch by the compile-scripts.py script prior to committing!"
|
||||
|
||||
|
||||
def _CompileScripts(input_api, output_api):
|
||||
local_paths = [f.LocalPath() for f in input_api.AffectedFiles()]
|
||||
|
||||
compilation_related_files = [
|
||||
"js_protocol.json"
|
||||
"compile-scripts.js",
|
||||
"injected-script-source.js",
|
||||
"injected_script_externs.js",
|
||||
"check_injected_script_source.js"
|
||||
]
|
||||
|
||||
for file in compilation_related_files:
|
||||
if (any(file in path for path in local_paths)):
|
||||
script_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
|
||||
"build", "compile-scripts.py")
|
||||
proc = input_api.subprocess.Popen(
|
||||
[input_api.python_executable, script_path],
|
||||
stdout=input_api.subprocess.PIPE,
|
||||
stderr=input_api.subprocess.STDOUT)
|
||||
out, _ = proc.communicate()
|
||||
if "ERROR" in out or "WARNING" in out or proc.returncode:
|
||||
return [output_api.PresubmitError(out)]
|
||||
if "NOTE" in out:
|
||||
return [output_api.PresubmitPromptWarning(out + compile_note)]
|
||||
return []
|
||||
return []
|
||||
|
||||
|
||||
def CheckChangeOnUpload(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CompileScripts(input_api, output_api))
|
||||
return results
|
||||
|
||||
|
||||
def CheckChangeOnCommit(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CompileScripts(input_api, output_api))
|
||||
return results
|
88
src/inspector/build/check_injected_script_source.py
Normal file
88
src/inspector/build/check_injected_script_source.py
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Copied from blink:
|
||||
# WebKit/Source/devtools/scripts/check_injected_script_source.py
|
||||
#
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def validate_injected_script(fileName):
|
||||
f = open(fileName, "r")
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
proto_functions = "|".join([
|
||||
# Array.prototype.*
|
||||
"concat", "every", "filter", "forEach", "indexOf", "join", "lastIndexOf", "map", "pop",
|
||||
"push", "reduce", "reduceRight", "reverse", "shift", "slice", "some", "sort", "splice", "toLocaleString", "toString", "unshift",
|
||||
# Function.prototype.*
|
||||
"apply", "bind", "call", "isGenerator", "toSource",
|
||||
# Object.prototype.*
|
||||
"toString",
|
||||
])
|
||||
|
||||
global_functions = "|".join([
|
||||
"eval", "uneval", "isFinite", "isNaN", "parseFloat", "parseInt", "decodeURI", "decodeURIComponent",
|
||||
"encodeURI", "encodeURIComponent", "escape", "unescape", "Map", "Set"
|
||||
])
|
||||
|
||||
# Black list:
|
||||
# - instanceof, since e.g. "obj instanceof Error" may throw if Error is overridden and is not a function
|
||||
# - Object.prototype.toString()
|
||||
# - Array.prototype.*
|
||||
# - Function.prototype.*
|
||||
# - Math.*
|
||||
# - Global functions
|
||||
black_list_call_regex = re.compile(r"\sinstanceof\s+\w*|\bMath\.\w+\(|(?<!InjectedScriptHost)\.(" + proto_functions + r")\(|[^\.]\b(" + global_functions + r")\(")
|
||||
|
||||
errors_found = False
|
||||
for i, line in enumerate(lines):
|
||||
if line.find("suppressBlacklist") != -1:
|
||||
continue
|
||||
for match in re.finditer(black_list_call_regex, line):
|
||||
errors_found = True
|
||||
print "ERROR: Black listed expression in %s at line %02d column %02d: %s" % (os.path.basename(fileName), i + 1, match.start(), match.group(0))
|
||||
|
||||
if not errors_found:
|
||||
print "OK"
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) < 2:
|
||||
print('ERROR: Usage: %s path/to/injected-script-source.js' % argv[0])
|
||||
return 1
|
||||
|
||||
validate_injected_script(argv[1])
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
1
src/inspector/build/closure-compiler.tar.gz.sha1
Normal file
1
src/inspector/build/closure-compiler.tar.gz.sha1
Normal file
@ -0,0 +1 @@
|
||||
69937d3c239ca63e4c9045718886ddd096ffc054
|
150
src/inspector/build/compile-scripts.py
Executable file
150
src/inspector/build/compile-scripts.py
Executable file
@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2016 the V8 project authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import os
|
||||
import os.path as path
|
||||
import generate_protocol_externs
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 2 and sys.argv[1] == '--help':
|
||||
print("Usage: %s" % path.basename(sys.argv[0]))
|
||||
sys.exit(0)
|
||||
|
||||
java_required_major = 1
|
||||
java_required_minor = 7
|
||||
|
||||
v8_inspector_path = path.dirname(path.dirname(path.abspath(__file__)))
|
||||
|
||||
protocol_externs_file = path.join(v8_inspector_path, 'protocol_externs.js')
|
||||
injected_script_source_name = path.join(v8_inspector_path,
|
||||
'injected-script-source.js')
|
||||
injected_script_externs_file = path.join(v8_inspector_path,
|
||||
'injected_script_externs.js')
|
||||
|
||||
generate_protocol_externs.generate_protocol_externs(protocol_externs_file,
|
||||
path.join(v8_inspector_path, 'js_protocol.json'))
|
||||
|
||||
error_warning_regex = re.compile(r'WARNING|ERROR')
|
||||
|
||||
closure_compiler_jar = path.join(v8_inspector_path, 'build',
|
||||
'closure-compiler', 'closure-compiler.jar')
|
||||
|
||||
common_closure_args = [
|
||||
'--checks_only',
|
||||
'--warning_level', 'VERBOSE'
|
||||
]
|
||||
|
||||
# Error reporting and checking.
|
||||
errors_found = False
|
||||
|
||||
def popen(arguments):
|
||||
return subprocess.Popen(arguments, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
def error_excepthook(exctype, value, traceback):
|
||||
print 'ERROR:'
|
||||
sys.__excepthook__(exctype, value, traceback)
|
||||
sys.excepthook = error_excepthook
|
||||
|
||||
def has_errors(output):
|
||||
return re.search(error_warning_regex, output) != None
|
||||
|
||||
# Find java. Based on
|
||||
# http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python.
|
||||
def which(program):
|
||||
def is_exe(fpath):
|
||||
return path.isfile(fpath) and os.access(fpath, os.X_OK)
|
||||
|
||||
fpath, fname = path.split(program)
|
||||
if fpath:
|
||||
if is_exe(program):
|
||||
return program
|
||||
else:
|
||||
for part in os.environ['PATH'].split(os.pathsep):
|
||||
part = part.strip('"')
|
||||
exe_file = path.join(part, program)
|
||||
if is_exe(exe_file):
|
||||
return exe_file
|
||||
return None
|
||||
|
||||
def find_java():
|
||||
exec_command = None
|
||||
has_server_jvm = True
|
||||
java_path = which('java')
|
||||
if not java_path:
|
||||
java_path = which('java.exe')
|
||||
|
||||
if not java_path:
|
||||
print 'NOTE: No Java executable found in $PATH.'
|
||||
sys.exit(0)
|
||||
|
||||
is_ok = False
|
||||
java_version_out, _ = popen([java_path, '-version']).communicate()
|
||||
java_build_regex = re.compile(r'^\w+ version "(\d+)\.(\d+)')
|
||||
# pylint: disable=E1103
|
||||
match = re.search(java_build_regex, java_version_out)
|
||||
if match:
|
||||
major = int(match.group(1))
|
||||
minor = int(match.group(2))
|
||||
is_ok = major >= java_required_major and minor >= java_required_minor
|
||||
if is_ok:
|
||||
exec_command = [java_path, '-Xms1024m', '-server',
|
||||
'-XX:+TieredCompilation']
|
||||
check_server_proc = popen(exec_command + ['-version'])
|
||||
check_server_proc.communicate()
|
||||
if check_server_proc.returncode != 0:
|
||||
# Not all Java installs have server JVMs.
|
||||
exec_command = exec_command.remove('-server')
|
||||
has_server_jvm = False
|
||||
|
||||
if not is_ok:
|
||||
print 'NOTE: Java executable version %d.%d or above not found in $PATH.' % (java_required_major, java_required_minor)
|
||||
sys.exit(0)
|
||||
print 'Java executable: %s%s' % (java_path, '' if has_server_jvm else ' (no server JVM)')
|
||||
return exec_command
|
||||
|
||||
java_exec = find_java()
|
||||
|
||||
spawned_compiler_command = java_exec + [
|
||||
'-jar',
|
||||
closure_compiler_jar
|
||||
] + common_closure_args
|
||||
|
||||
print 'Compiling injected-script-source.js...'
|
||||
|
||||
command = spawned_compiler_command + [
|
||||
'--externs', injected_script_externs_file,
|
||||
'--externs', protocol_externs_file,
|
||||
'--js', injected_script_source_name
|
||||
]
|
||||
|
||||
injected_script_compile_proc = popen(command)
|
||||
|
||||
print 'Validating injected-script-source.js...'
|
||||
injectedscript_check_script_path = path.join(v8_inspector_path, 'build',
|
||||
'check_injected_script_source.py')
|
||||
validate_injected_script_proc = popen([sys.executable,
|
||||
injectedscript_check_script_path, injected_script_source_name])
|
||||
|
||||
print
|
||||
|
||||
(injected_script_compile_out, _) = injected_script_compile_proc.communicate()
|
||||
print 'injected-script-source.js compilation output:%s' % os.linesep
|
||||
print injected_script_compile_out
|
||||
errors_found |= has_errors(injected_script_compile_out)
|
||||
|
||||
(validate_injected_script_out, _) = validate_injected_script_proc.communicate()
|
||||
print 'Validate injected-script-source.js output:%s' % os.linesep
|
||||
print validate_injected_script_out if validate_injected_script_out else '<empty>'
|
||||
errors_found |= has_errors(validate_injected_script_out)
|
||||
|
||||
os.remove(protocol_externs_file)
|
||||
|
||||
if errors_found:
|
||||
print 'ERRORS DETECTED'
|
||||
sys.exit(1)
|
246
src/inspector/build/generate_protocol_externs.py
Executable file
246
src/inspector/build/generate_protocol_externs.py
Executable file
@ -0,0 +1,246 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
|
||||
type_traits = {
|
||||
"any": "*",
|
||||
"string": "string",
|
||||
"integer": "number",
|
||||
"number": "number",
|
||||
"boolean": "boolean",
|
||||
"array": "!Array.<*>",
|
||||
"object": "!Object",
|
||||
}
|
||||
|
||||
promisified_domains = {
|
||||
"Accessibility",
|
||||
"Animation",
|
||||
"CSS",
|
||||
"Emulation",
|
||||
"Profiler"
|
||||
}
|
||||
|
||||
ref_types = {}
|
||||
|
||||
def full_qualified_type_id(domain_name, type_id):
|
||||
if type_id.find(".") == -1:
|
||||
return "%s.%s" % (domain_name, type_id)
|
||||
return type_id
|
||||
|
||||
|
||||
def fix_camel_case(name):
|
||||
prefix = ""
|
||||
if name[0] == "-":
|
||||
prefix = "Negative"
|
||||
name = name[1:]
|
||||
refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
|
||||
refined = to_title_case(refined)
|
||||
return prefix + re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), refined)
|
||||
|
||||
|
||||
def to_title_case(name):
|
||||
return name[:1].upper() + name[1:]
|
||||
|
||||
|
||||
def generate_enum(name, json):
|
||||
enum_members = []
|
||||
for member in json["enum"]:
|
||||
enum_members.append(" %s: \"%s\"" % (fix_camel_case(member), member))
|
||||
return "\n/** @enum {string} */\n%s = {\n%s\n};\n" % (name, (",\n".join(enum_members)))
|
||||
|
||||
|
||||
def param_type(domain_name, param):
|
||||
if "type" in param:
|
||||
if param["type"] == "array":
|
||||
items = param["items"]
|
||||
return "!Array.<%s>" % param_type(domain_name, items)
|
||||
else:
|
||||
return type_traits[param["type"]]
|
||||
if "$ref" in param:
|
||||
type_id = full_qualified_type_id(domain_name, param["$ref"])
|
||||
if type_id in ref_types:
|
||||
return ref_types[type_id]
|
||||
else:
|
||||
print "Type not found: " + type_id
|
||||
return "!! Type not found: " + type_id
|
||||
|
||||
|
||||
def load_schema(file, domains):
|
||||
input_file = open(file, "r")
|
||||
json_string = input_file.read()
|
||||
parsed_json = json.loads(json_string)
|
||||
domains.extend(parsed_json["domains"])
|
||||
|
||||
|
||||
def generate_protocol_externs(output_path, file1):
|
||||
domains = []
|
||||
load_schema(file1, domains)
|
||||
output_file = open(output_path, "w")
|
||||
|
||||
output_file.write(
|
||||
"""
|
||||
var InspectorBackend = {}
|
||||
|
||||
var Protocol = {};
|
||||
/** @typedef {string}*/
|
||||
Protocol.Error;
|
||||
""")
|
||||
|
||||
for domain in domains:
|
||||
domain_name = domain["domain"]
|
||||
if "types" in domain:
|
||||
for type in domain["types"]:
|
||||
type_id = full_qualified_type_id(domain_name, type["id"])
|
||||
ref_types[type_id] = "%sAgent.%s" % (domain_name, type["id"])
|
||||
|
||||
for domain in domains:
|
||||
domain_name = domain["domain"]
|
||||
promisified = domain_name in promisified_domains
|
||||
|
||||
output_file.write("\n\n/**\n * @constructor\n*/\n")
|
||||
output_file.write("Protocol.%sAgent = function(){};\n" % domain_name)
|
||||
|
||||
if "commands" in domain:
|
||||
for command in domain["commands"]:
|
||||
output_file.write("\n/**\n")
|
||||
params = []
|
||||
has_return_value = "returns" in command
|
||||
explicit_parameters = promisified and has_return_value
|
||||
if ("parameters" in command):
|
||||
for in_param in command["parameters"]:
|
||||
# All parameters are not optional in case of promisified domain with return value.
|
||||
if (not explicit_parameters and "optional" in in_param):
|
||||
params.append("opt_%s" % in_param["name"])
|
||||
output_file.write(" * @param {%s=} opt_%s\n" % (param_type(domain_name, in_param), in_param["name"]))
|
||||
else:
|
||||
params.append(in_param["name"])
|
||||
output_file.write(" * @param {%s} %s\n" % (param_type(domain_name, in_param), in_param["name"]))
|
||||
returns = []
|
||||
returns.append("?Protocol.Error")
|
||||
if ("error" in command):
|
||||
returns.append("%s=" % param_type(domain_name, command["error"]))
|
||||
if (has_return_value):
|
||||
for out_param in command["returns"]:
|
||||
if ("optional" in out_param):
|
||||
returns.append("%s=" % param_type(domain_name, out_param))
|
||||
else:
|
||||
returns.append("%s" % param_type(domain_name, out_param))
|
||||
callback_return_type = "void="
|
||||
if explicit_parameters:
|
||||
callback_return_type = "T"
|
||||
elif promisified:
|
||||
callback_return_type = "T="
|
||||
output_file.write(" * @param {function(%s):%s} opt_callback\n" % (", ".join(returns), callback_return_type))
|
||||
if (promisified):
|
||||
output_file.write(" * @return {!Promise.<T>}\n")
|
||||
output_file.write(" * @template T\n")
|
||||
params.append("opt_callback")
|
||||
|
||||
output_file.write(" */\n")
|
||||
output_file.write("Protocol.%sAgent.prototype.%s = function(%s) {}\n" % (domain_name, command["name"], ", ".join(params)))
|
||||
output_file.write("/** @param {function(%s):void=} opt_callback */\n" % ", ".join(returns))
|
||||
output_file.write("Protocol.%sAgent.prototype.invoke_%s = function(obj, opt_callback) {}\n" % (domain_name, command["name"]))
|
||||
|
||||
output_file.write("\n\n\nvar %sAgent = function(){};\n" % domain_name)
|
||||
|
||||
if "types" in domain:
|
||||
for type in domain["types"]:
|
||||
if type["type"] == "object":
|
||||
typedef_args = []
|
||||
if "properties" in type:
|
||||
for property in type["properties"]:
|
||||
suffix = ""
|
||||
if ("optional" in property):
|
||||
suffix = "|undefined"
|
||||
if "enum" in property:
|
||||
enum_name = "%sAgent.%s%s" % (domain_name, type["id"], to_title_case(property["name"]))
|
||||
output_file.write(generate_enum(enum_name, property))
|
||||
typedef_args.append("%s:(%s%s)" % (property["name"], enum_name, suffix))
|
||||
else:
|
||||
typedef_args.append("%s:(%s%s)" % (property["name"], param_type(domain_name, property), suffix))
|
||||
if (typedef_args):
|
||||
output_file.write("\n/** @typedef {!{%s}} */\n%sAgent.%s;\n" % (", ".join(typedef_args), domain_name, type["id"]))
|
||||
else:
|
||||
output_file.write("\n/** @typedef {!Object} */\n%sAgent.%s;\n" % (domain_name, type["id"]))
|
||||
elif type["type"] == "string" and "enum" in type:
|
||||
output_file.write(generate_enum("%sAgent.%s" % (domain_name, type["id"]), type))
|
||||
elif type["type"] == "array":
|
||||
output_file.write("\n/** @typedef {!Array.<!%s>} */\n%sAgent.%s;\n" % (param_type(domain_name, type["items"]), domain_name, type["id"]))
|
||||
else:
|
||||
output_file.write("\n/** @typedef {%s} */\n%sAgent.%s;\n" % (type_traits[type["type"]], domain_name, type["id"]))
|
||||
|
||||
output_file.write("/** @interface */\n")
|
||||
output_file.write("%sAgent.Dispatcher = function() {};\n" % domain_name)
|
||||
if "events" in domain:
|
||||
for event in domain["events"]:
|
||||
params = []
|
||||
if ("parameters" in event):
|
||||
output_file.write("/**\n")
|
||||
for param in event["parameters"]:
|
||||
if ("optional" in param):
|
||||
params.append("opt_%s" % param["name"])
|
||||
output_file.write(" * @param {%s=} opt_%s\n" % (param_type(domain_name, param), param["name"]))
|
||||
else:
|
||||
params.append(param["name"])
|
||||
output_file.write(" * @param {%s} %s\n" % (param_type(domain_name, param), param["name"]))
|
||||
output_file.write(" */\n")
|
||||
output_file.write("%sAgent.Dispatcher.prototype.%s = function(%s) {};\n" % (domain_name, event["name"], ", ".join(params)))
|
||||
|
||||
output_file.write("\n/** @constructor\n * @param {!Object.<string, !Object>} agentsMap\n */\n")
|
||||
output_file.write("Protocol.Agents = function(agentsMap){this._agentsMap;};\n")
|
||||
output_file.write("/**\n * @param {string} domain\n * @param {!Object} dispatcher\n */\n")
|
||||
output_file.write("Protocol.Agents.prototype.registerDispatcher = function(domain, dispatcher){};\n")
|
||||
for domain in domains:
|
||||
domain_name = domain["domain"]
|
||||
uppercase_length = 0
|
||||
while uppercase_length < len(domain_name) and domain_name[uppercase_length].isupper():
|
||||
uppercase_length += 1
|
||||
|
||||
output_file.write("/** @return {!Protocol.%sAgent}*/\n" % domain_name)
|
||||
output_file.write("Protocol.Agents.prototype.%s = function(){};\n" % (domain_name[:uppercase_length].lower() + domain_name[uppercase_length:] + "Agent"))
|
||||
|
||||
output_file.write("/**\n * @param {!%sAgent.Dispatcher} dispatcher\n */\n" % domain_name)
|
||||
output_file.write("Protocol.Agents.prototype.register%sDispatcher = function(dispatcher) {}\n" % domain_name)
|
||||
|
||||
|
||||
output_file.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import os.path
|
||||
program_name = os.path.basename(__file__)
|
||||
if len(sys.argv) < 4 or sys.argv[1] != "-o":
|
||||
sys.stderr.write("Usage: %s -o OUTPUT_FILE INPUT_FILE\n" % program_name)
|
||||
exit(1)
|
||||
output_path = sys.argv[2]
|
||||
input_path = sys.argv[3]
|
||||
generate_protocol_externs(output_path, input_path)
|
295
src/inspector/build/rjsmin.py
Executable file
295
src/inspector/build/rjsmin.py
Executable file
@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2011 - 2013
|
||||
# Andr\xe9 Malo or his licensors, as applicable
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
r"""
|
||||
=====================
|
||||
Javascript Minifier
|
||||
=====================
|
||||
|
||||
rJSmin is a javascript minifier written in python.
|
||||
|
||||
The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
The module is a re-implementation aiming for speed, so it can be used at
|
||||
runtime (rather than during a preprocessing step). Usually it produces the
|
||||
same results as the original ``jsmin.c``. It differs in the following ways:
|
||||
|
||||
- there is no error detection: unterminated string, regex and comment
|
||||
literals are treated as regular javascript code and minified as such.
|
||||
- Control characters inside string and regex literals are left untouched; they
|
||||
are not converted to spaces (nor to \n)
|
||||
- Newline characters are not allowed inside string and regex literals, except
|
||||
for line continuations in string literals (ECMA-5).
|
||||
- "return /regex/" is recognized correctly.
|
||||
- "+ +" and "- -" sequences are not collapsed to '++' or '--'
|
||||
- Newlines before ! operators are removed more sensibly
|
||||
- rJSmin does not handle streams, but only complete strings. (However, the
|
||||
module provides a "streamy" interface).
|
||||
|
||||
Since most parts of the logic are handled by the regex engine it's way
|
||||
faster than the original python port of ``jsmin.c`` by Baruch Even. The speed
|
||||
factor varies between about 6 and 55 depending on input and python version
|
||||
(it gets faster the more compressed the input already is). Compared to the
|
||||
speed-refactored python port by Dave St.Germain the performance gain is less
|
||||
dramatic but still between 1.2 and 7. See the docs/BENCHMARKS file for
|
||||
details.
|
||||
|
||||
rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more.
|
||||
|
||||
Both python 2 and python 3 are supported.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
"""
|
||||
__author__ = "Andr\xe9 Malo"
|
||||
__author__ = getattr(__author__, 'decode', lambda x: __author__)('latin-1')
|
||||
__docformat__ = "restructuredtext en"
|
||||
__license__ = "Apache License, Version 2.0"
|
||||
__version__ = '1.0.7'
|
||||
__all__ = ['jsmin']
|
||||
|
||||
import re as _re
|
||||
|
||||
|
||||
def _make_jsmin(python_only=False):
|
||||
"""
|
||||
Generate JS minifier based on `jsmin.c by Douglas Crockford`_
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
:Parameters:
|
||||
`python_only` : ``bool``
|
||||
Use only the python variant. If true, the c extension is not even
|
||||
tried to be loaded.
|
||||
|
||||
:Return: Minifier
|
||||
:Rtype: ``callable``
|
||||
"""
|
||||
# pylint: disable = R0912, R0914, W0612
|
||||
if not python_only:
|
||||
try:
|
||||
import _rjsmin
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return _rjsmin.jsmin
|
||||
try:
|
||||
xrange
|
||||
except NameError:
|
||||
xrange = range # pylint: disable = W0622
|
||||
|
||||
space_chars = r'[\000-\011\013\014\016-\040]'
|
||||
|
||||
line_comment = r'(?://[^\r\n]*)'
|
||||
space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)'
|
||||
string1 = \
|
||||
r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)'
|
||||
string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")'
|
||||
strings = r'(?:%s|%s)' % (string1, string2)
|
||||
|
||||
charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])'
|
||||
nospecial = r'[^/\\\[\r\n]'
|
||||
regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % (
|
||||
nospecial, charclass, nospecial)
|
||||
space = r'(?:%s|%s)' % (space_chars, space_comment)
|
||||
newline = r'(?:%s?[\r\n])' % line_comment
|
||||
|
||||
def fix_charclass(result):
|
||||
""" Fixup string of chars to fit into a regex char class """
|
||||
pos = result.find('-')
|
||||
if pos >= 0:
|
||||
result = r'%s%s-' % (result[:pos], result[pos + 1:])
|
||||
|
||||
def sequentize(string):
|
||||
"""
|
||||
Notate consecutive characters as sequence
|
||||
|
||||
(1-4 instead of 1234)
|
||||
"""
|
||||
first, last, result = None, None, []
|
||||
for char in map(ord, string):
|
||||
if last is None:
|
||||
first = last = char
|
||||
elif last + 1 == char:
|
||||
last = char
|
||||
else:
|
||||
result.append((first, last))
|
||||
first = last = char
|
||||
if last is not None:
|
||||
result.append((first, last))
|
||||
return ''.join(['%s%s%s' % (
|
||||
chr(first),
|
||||
last > first + 1 and '-' or '',
|
||||
last != first and chr(last) or '') for first, last in result])
|
||||
|
||||
return _re.sub(r'([\000-\040\047])', # for better portability
|
||||
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
|
||||
.replace('\\', '\\\\')
|
||||
.replace('[', '\\[')
|
||||
.replace(']', '\\]')))
|
||||
|
||||
def id_literal_(what):
|
||||
""" Make id_literal like char class """
|
||||
match = _re.compile(what).match
|
||||
result = ''.join([chr(c) for c in xrange(127) if not match(chr(c))])
|
||||
return '[^%s]' % fix_charclass(result)
|
||||
|
||||
def not_id_literal_(keep):
|
||||
""" Make negated id_literal like char class """
|
||||
match = _re.compile(id_literal_(keep)).match
|
||||
result = ''.join([chr(c) for c in xrange(127) if not match(chr(c))])
|
||||
return r'[%s]' % fix_charclass(result)
|
||||
|
||||
not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]')
|
||||
preregex1 = r'[(,=:\[!&|?{};\r\n]'
|
||||
preregex2 = r'%(not_id_literal)sreturn' % locals()
|
||||
|
||||
id_literal = id_literal_(r'[a-zA-Z0-9_$]')
|
||||
id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]')
|
||||
id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]')
|
||||
|
||||
dull = r'[^\047"/\000-\040]'
|
||||
|
||||
space_sub = _re.compile((
|
||||
r'(%(dull)s+)'
|
||||
r'|(%(strings)s%(dull)s*)'
|
||||
r'|(?<=%(preregex1)s)'
|
||||
r'%(space)s*(?:%(newline)s%(space)s*)*'
|
||||
r'(%(regex)s%(dull)s*)'
|
||||
r'|(?<=%(preregex2)s)'
|
||||
r'%(space)s*(?:%(newline)s%(space)s)*'
|
||||
r'(%(regex)s%(dull)s*)'
|
||||
r'|(?<=%(id_literal_close)s)'
|
||||
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
|
||||
r'(?=%(id_literal_open)s)'
|
||||
r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)'
|
||||
r'|(?<=\+)(%(space)s)+(?=\+)'
|
||||
r'|(?<=-)(%(space)s)+(?=-)'
|
||||
r'|%(space)s+'
|
||||
r'|(?:%(newline)s%(space)s*)+') % locals()).sub
|
||||
#print space_sub.__self__.pattern
|
||||
|
||||
def space_subber(match):
|
||||
""" Substitution callback """
|
||||
# pylint: disable = C0321, R0911
|
||||
groups = match.groups()
|
||||
if groups[0]:
|
||||
return groups[0]
|
||||
elif groups[1]:
|
||||
return groups[1]
|
||||
elif groups[2]:
|
||||
return groups[2]
|
||||
elif groups[3]:
|
||||
return groups[3]
|
||||
elif groups[4]:
|
||||
return '\n'
|
||||
elif groups[5] or groups[6] or groups[7]:
|
||||
return ' '
|
||||
else:
|
||||
return ''
|
||||
|
||||
def jsmin(script): # pylint: disable = W0621
|
||||
r"""
|
||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
Instead of parsing the stream char by char, it uses a regular
|
||||
expression approach which minifies the whole script with one big
|
||||
substitution regex.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
:Parameters:
|
||||
`script` : ``str``
|
||||
Script to minify
|
||||
|
||||
:Return: Minified script
|
||||
:Rtype: ``str``
|
||||
"""
|
||||
return space_sub(space_subber, '\n%s\n' % script).strip()
|
||||
|
||||
return jsmin
|
||||
|
||||
jsmin = _make_jsmin()
|
||||
|
||||
|
||||
def jsmin_for_posers(script):
|
||||
r"""
|
||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
||||
|
||||
Instead of parsing the stream char by char, it uses a regular
|
||||
expression approach which minifies the whole script with one big
|
||||
substitution regex.
|
||||
|
||||
.. _jsmin.c by Douglas Crockford:
|
||||
http://www.crockford.com/javascript/jsmin.c
|
||||
|
||||
:Warning: This function is the digest of a _make_jsmin() call. It just
|
||||
utilizes the resulting regex. It's just for fun here and may
|
||||
vanish any time. Use the `jsmin` function instead.
|
||||
|
||||
:Parameters:
|
||||
`script` : ``str``
|
||||
Script to minify
|
||||
|
||||
:Return: Minified script
|
||||
:Rtype: ``str``
|
||||
"""
|
||||
def subber(match):
|
||||
""" Substitution callback """
|
||||
groups = match.groups()
|
||||
return (
|
||||
groups[0] or
|
||||
groups[1] or
|
||||
groups[2] or
|
||||
groups[3] or
|
||||
(groups[4] and '\n') or
|
||||
(groups[5] and ' ') or
|
||||
(groups[6] and ' ') or
|
||||
(groups[7] and ' ') or
|
||||
'')
|
||||
|
||||
return _re.sub(
|
||||
r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?'
|
||||
r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|'
|
||||
r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?'
|
||||
r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*'
|
||||
r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*'
|
||||
r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:('
|
||||
r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\['
|
||||
r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return'
|
||||
r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
|
||||
r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:'
|
||||
r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?'
|
||||
r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/'
|
||||
r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|'
|
||||
r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)'
|
||||
r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]'
|
||||
r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./'
|
||||
r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01'
|
||||
r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:'
|
||||
r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*'
|
||||
r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-'
|
||||
r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013'
|
||||
r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^'
|
||||
r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^'
|
||||
r'/*][^*]*\*+)*/))*)+', subber, '\n%s\n' % script).strip()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys as _sys
|
||||
_sys.stdout.write(jsmin(_sys.stdin.read()))
|
28
src/inspector/build/xxd.py
Normal file
28
src/inspector/build/xxd.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Copyright 2016 the V8 project authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Represent a file as a C++ constant string.
|
||||
|
||||
Usage:
|
||||
python xxd.py VAR SOURCE DEST
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import rjsmin
|
||||
|
||||
|
||||
def main():
|
||||
variable_name, input_filename, output_filename = sys.argv[1:]
|
||||
with open(input_filename) as input_file:
|
||||
input_text = input_file.read()
|
||||
input_text = rjsmin.jsmin(input_text)
|
||||
hex_values = ['0x{0:02x}'.format(ord(char)) for char in input_text]
|
||||
const_declaration = 'const char %s[] = {\n%s\n};\n' % (
|
||||
variable_name, ', '.join(hex_values))
|
||||
with open(output_filename, 'w') as output_file:
|
||||
output_file.write(const_declaration)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -113,7 +113,7 @@ bool substituteObjectTags(int sessionId, const String16& groupName,
|
||||
}
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapper;
|
||||
protocol::Response response =
|
||||
injectedScript->wrapObject(originValue, groupName, WrapMode::kNoPreview,
|
||||
injectedScript->wrapObject(originValue, groupName, false, false,
|
||||
configValue, maxDepth - 1, &wrapper);
|
||||
if (!response.isSuccess() || !wrapper) {
|
||||
reportError(context, tryCatch, "cannot wrap value");
|
||||
@ -379,8 +379,13 @@ void generateCustomPreview(int sessionId, const String16& groupName,
|
||||
reportError(context, tryCatch, "cannot find context with specified id");
|
||||
return;
|
||||
}
|
||||
(*preview)->setBodyGetterId(
|
||||
injectedScript->bindObject(bodyFunction, groupName));
|
||||
(*preview)->setBodyGetterId(String16::concat(
|
||||
"{\"injectedScriptId\":",
|
||||
String16::fromInteger(InspectedContext::contextId(context)),
|
||||
",\"id\":",
|
||||
String16::fromInteger(
|
||||
injectedScript->bindObject(bodyFunction, groupName)),
|
||||
"}"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
1009
src/inspector/injected-script-source.js
Normal file
1009
src/inspector/injected-script-source.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,9 +30,6 @@
|
||||
|
||||
#include "src/inspector/injected-script.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "src/inspector/custom-preview.h"
|
||||
#include "src/inspector/injected-script-source.h"
|
||||
#include "src/inspector/inspected-context.h"
|
||||
@ -40,17 +37,19 @@
|
||||
#include "src/inspector/remote-object-id.h"
|
||||
#include "src/inspector/string-util.h"
|
||||
#include "src/inspector/v8-console.h"
|
||||
#include "src/inspector/v8-function-call.h"
|
||||
#include "src/inspector/v8-injected-script-host.h"
|
||||
#include "src/inspector/v8-inspector-impl.h"
|
||||
#include "src/inspector/v8-inspector-session-impl.h"
|
||||
#include "src/inspector/v8-stack-trace-impl.h"
|
||||
#include "src/inspector/v8-value-utils.h"
|
||||
#include "src/inspector/value-mirror.h"
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
namespace {
|
||||
static const char privateKeyName[] = "v8-inspector#injectedScript";
|
||||
static const char kGlobalHandleLabel[] = "DevTools console";
|
||||
static bool isResolvableNumberLike(String16 query) {
|
||||
return query == "Infinity" || query == "-Infinity" || query == "NaN";
|
||||
@ -68,7 +67,8 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
static bool add(V8InspectorSessionImpl* session,
|
||||
v8::Local<v8::Context> context, v8::Local<v8::Value> value,
|
||||
int executionContextId, const String16& objectGroup,
|
||||
WrapMode wrapMode, EvaluateCallback* callback) {
|
||||
bool returnByValue, bool generatePreview,
|
||||
EvaluateCallback* callback) {
|
||||
v8::Local<v8::Promise::Resolver> resolver;
|
||||
if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
|
||||
callback->sendFailure(Response::InternalError());
|
||||
@ -81,8 +81,9 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
|
||||
v8::Local<v8::Promise> promise = resolver->GetPromise();
|
||||
V8InspectorImpl* inspector = session->inspector();
|
||||
ProtocolPromiseHandler* handler = new ProtocolPromiseHandler(
|
||||
session, executionContextId, objectGroup, wrapMode, callback);
|
||||
ProtocolPromiseHandler* handler =
|
||||
new ProtocolPromiseHandler(session, executionContextId, objectGroup,
|
||||
returnByValue, generatePreview, callback);
|
||||
v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
|
||||
v8::Local<v8::Function> thenCallbackFunction =
|
||||
v8::Function::New(context, thenCallback, wrapper, 0,
|
||||
@ -130,13 +131,15 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
|
||||
ProtocolPromiseHandler(V8InspectorSessionImpl* session,
|
||||
int executionContextId, const String16& objectGroup,
|
||||
WrapMode wrapMode, EvaluateCallback* callback)
|
||||
bool returnByValue, bool generatePreview,
|
||||
EvaluateCallback* callback)
|
||||
: m_inspector(session->inspector()),
|
||||
m_sessionId(session->sessionId()),
|
||||
m_contextGroupId(session->contextGroupId()),
|
||||
m_executionContextId(executionContextId),
|
||||
m_objectGroup(objectGroup),
|
||||
m_wrapMode(wrapMode),
|
||||
m_returnByValue(returnByValue),
|
||||
m_generatePreview(generatePreview),
|
||||
m_callback(std::move(callback)),
|
||||
m_wrapper(m_inspector->isolate(),
|
||||
v8::External::New(m_inspector->isolate(), this)) {
|
||||
@ -168,8 +171,9 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
scope.injectedScript()->takeEvaluateCallback(m_callback);
|
||||
if (!callback) return;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
|
||||
response = scope.injectedScript()->wrapObject(result, m_objectGroup,
|
||||
m_wrapMode, &wrappedValue);
|
||||
response = scope.injectedScript()->wrapObject(
|
||||
result, m_objectGroup, m_returnByValue, m_generatePreview,
|
||||
&wrappedValue);
|
||||
if (!response.isSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
@ -189,8 +193,9 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
scope.injectedScript()->takeEvaluateCallback(m_callback);
|
||||
if (!callback) return;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
|
||||
response = scope.injectedScript()->wrapObject(result, m_objectGroup,
|
||||
m_wrapMode, &wrappedValue);
|
||||
response = scope.injectedScript()->wrapObject(
|
||||
result, m_objectGroup, m_returnByValue, m_generatePreview,
|
||||
&wrappedValue);
|
||||
if (!response.isSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
@ -248,127 +253,116 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
int m_contextGroupId;
|
||||
int m_executionContextId;
|
||||
String16 m_objectGroup;
|
||||
WrapMode m_wrapMode;
|
||||
bool m_returnByValue;
|
||||
bool m_generatePreview;
|
||||
EvaluateCallback* m_callback;
|
||||
v8::Global<v8::External> m_wrapper;
|
||||
};
|
||||
|
||||
InjectedScript::InjectedScript(InspectedContext* context, int sessionId)
|
||||
: m_context(context), m_sessionId(sessionId) {}
|
||||
std::unique_ptr<InjectedScript> InjectedScript::create(
|
||||
InspectedContext* inspectedContext, int sessionId) {
|
||||
v8::Isolate* isolate = inspectedContext->isolate();
|
||||
v8::HandleScope handles(isolate);
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
v8::Local<v8::Context> context = inspectedContext->context();
|
||||
v8::debug::PostponeInterruptsScope postponeInterrupts(isolate);
|
||||
v8::Context::Scope scope(context);
|
||||
v8::MicrotasksScope microtasksScope(isolate,
|
||||
v8::MicrotasksScope::kDoNotRunMicrotasks);
|
||||
|
||||
// Inject javascript into the context. The compiled script is supposed to
|
||||
// evaluate into
|
||||
// a single anonymous function(it's anonymous to avoid cluttering the global
|
||||
// object with
|
||||
// inspector's stuff) the function is called a few lines below with
|
||||
// InjectedScriptHost wrapper,
|
||||
// injected script id and explicit reference to the inspected global object.
|
||||
// The function is expected
|
||||
// to create and configure InjectedScript instance that is going to be used by
|
||||
// the inspector.
|
||||
StringView injectedScriptSource(
|
||||
reinterpret_cast<const uint8_t*>(InjectedScriptSource_js),
|
||||
sizeof(InjectedScriptSource_js));
|
||||
v8::Local<v8::Value> value;
|
||||
if (!inspectedContext->inspector()
|
||||
->compileAndRunInternalScript(
|
||||
context, toV8String(isolate, injectedScriptSource))
|
||||
.ToLocal(&value)) {
|
||||
return nullptr;
|
||||
}
|
||||
DCHECK(value->IsFunction());
|
||||
v8::Local<v8::Object> scriptHostWrapper =
|
||||
V8InjectedScriptHost::create(context, inspectedContext->inspector());
|
||||
v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);
|
||||
v8::Local<v8::Object> windowGlobal = context->Global();
|
||||
v8::Local<v8::Value> info[] = {
|
||||
scriptHostWrapper, windowGlobal,
|
||||
v8::Number::New(isolate, inspectedContext->contextId())};
|
||||
|
||||
int contextGroupId = inspectedContext->contextGroupId();
|
||||
int contextId = inspectedContext->contextId();
|
||||
V8InspectorImpl* inspector = inspectedContext->inspector();
|
||||
v8::Local<v8::Value> injectedScriptValue;
|
||||
if (!function->Call(context, windowGlobal, arraysize(info), info)
|
||||
.ToLocal(&injectedScriptValue))
|
||||
return nullptr;
|
||||
if (inspector->getContext(contextGroupId, contextId) != inspectedContext)
|
||||
return nullptr;
|
||||
if (!injectedScriptValue->IsObject()) return nullptr;
|
||||
|
||||
std::unique_ptr<InjectedScript> injectedScript(new InjectedScript(
|
||||
inspectedContext, injectedScriptValue.As<v8::Object>(), sessionId));
|
||||
v8::Local<v8::Private> privateKey = v8::Private::ForApi(
|
||||
isolate, v8::String::NewFromUtf8(isolate, privateKeyName,
|
||||
v8::NewStringType::kInternalized)
|
||||
.ToLocalChecked());
|
||||
scriptHostWrapper->SetPrivate(
|
||||
context, privateKey, v8::External::New(isolate, injectedScript.get()));
|
||||
return injectedScript;
|
||||
}
|
||||
|
||||
InjectedScript::InjectedScript(InspectedContext* context,
|
||||
v8::Local<v8::Object> object, int sessionId)
|
||||
: m_context(context),
|
||||
m_value(context->isolate(), object),
|
||||
m_sessionId(sessionId) {}
|
||||
|
||||
InjectedScript::~InjectedScript() { discardEvaluateCallbacks(); }
|
||||
|
||||
namespace {
|
||||
class PropertyAccumulator : public ValueMirror::PropertyAccumulator {
|
||||
public:
|
||||
explicit PropertyAccumulator(std::vector<PropertyMirror>* mirrors)
|
||||
: m_mirrors(mirrors) {}
|
||||
bool Add(PropertyMirror mirror) override {
|
||||
m_mirrors->push_back(std::move(mirror));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<PropertyMirror>* m_mirrors;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
Response InjectedScript::getProperties(
|
||||
v8::Local<v8::Object> object, const String16& groupName, bool ownProperties,
|
||||
bool accessorPropertiesOnly, WrapMode wrapMode,
|
||||
bool accessorPropertiesOnly, bool generatePreview,
|
||||
std::unique_ptr<Array<PropertyDescriptor>>* properties,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
|
||||
v8::HandleScope handles(m_context->isolate());
|
||||
v8::Local<v8::Context> context = m_context->context();
|
||||
v8::Isolate* isolate = m_context->isolate();
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
V8FunctionCall function(m_context->inspector(), m_context->context(),
|
||||
v8Value(), "getProperties");
|
||||
function.appendArgument(object);
|
||||
function.appendArgument(groupName);
|
||||
function.appendArgument(ownProperties);
|
||||
function.appendArgument(accessorPropertiesOnly);
|
||||
function.appendArgument(generatePreview);
|
||||
|
||||
*properties = Array<PropertyDescriptor>::create();
|
||||
std::vector<PropertyMirror> mirrors;
|
||||
PropertyAccumulator accumulator(&mirrors);
|
||||
if (!ValueMirror::getProperties(context, object, ownProperties,
|
||||
accessorPropertiesOnly, &accumulator)) {
|
||||
return createExceptionDetails(tryCatch, groupName, wrapMode,
|
||||
exceptionDetails);
|
||||
}
|
||||
for (const PropertyMirror& mirror : mirrors) {
|
||||
std::unique_ptr<PropertyDescriptor> descriptor =
|
||||
PropertyDescriptor::create()
|
||||
.setName(mirror.name)
|
||||
.setConfigurable(mirror.configurable)
|
||||
.setEnumerable(mirror.enumerable)
|
||||
.setIsOwn(mirror.isOwn)
|
||||
.build();
|
||||
Response response;
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
if (mirror.value) {
|
||||
response =
|
||||
mirror.value->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(mirror.value->v8Value(), groupName,
|
||||
remoteObject.get());
|
||||
descriptor->setValue(std::move(remoteObject));
|
||||
descriptor->setWritable(mirror.writable);
|
||||
}
|
||||
if (mirror.getter) {
|
||||
response =
|
||||
mirror.getter->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(mirror.getter->v8Value(), groupName,
|
||||
remoteObject.get());
|
||||
descriptor->setGet(std::move(remoteObject));
|
||||
}
|
||||
if (mirror.setter) {
|
||||
response =
|
||||
mirror.setter->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(mirror.setter->v8Value(), groupName,
|
||||
remoteObject.get());
|
||||
descriptor->setSet(std::move(remoteObject));
|
||||
}
|
||||
if (mirror.symbol) {
|
||||
response =
|
||||
mirror.symbol->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(mirror.symbol->v8Value(), groupName,
|
||||
remoteObject.get());
|
||||
descriptor->setSymbol(std::move(remoteObject));
|
||||
}
|
||||
if (mirror.exception) {
|
||||
response =
|
||||
mirror.exception->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(mirror.exception->v8Value(), groupName,
|
||||
remoteObject.get());
|
||||
descriptor->setValue(std::move(remoteObject));
|
||||
descriptor->setWasThrown(true);
|
||||
}
|
||||
(*properties)->addItem(std::move(descriptor));
|
||||
}
|
||||
return Response::OK();
|
||||
}
|
||||
|
||||
Response InjectedScript::getInternalProperties(
|
||||
v8::Local<v8::Value> value, const String16& groupName,
|
||||
std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>* result) {
|
||||
*result = protocol::Array<InternalPropertyDescriptor>::create();
|
||||
std::vector<InternalPropertyMirror> wrappers;
|
||||
if (value->IsObject()) {
|
||||
ValueMirror::getInternalProperties(m_context->context(),
|
||||
value.As<v8::Object>(), &wrappers);
|
||||
}
|
||||
for (size_t i = 0; i < wrappers.size(); ++i) {
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
Response response = wrappers[i].value->buildRemoteObject(
|
||||
m_context->context(), WrapMode::kNoPreview, &remoteObject);
|
||||
v8::TryCatch tryCatch(m_context->isolate());
|
||||
v8::Local<v8::Value> resultValue = function.callWithoutExceptionHandling();
|
||||
if (tryCatch.HasCaught()) {
|
||||
Response response = createExceptionDetails(
|
||||
tryCatch, groupName, generatePreview, exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(wrappers[i].value->v8Value(), groupName,
|
||||
remoteObject.get());
|
||||
(*result)->addItem(InternalPropertyDescriptor::create()
|
||||
.setName(wrappers[i].name)
|
||||
.setValue(std::move(remoteObject))
|
||||
.build());
|
||||
// FIXME: make properties optional
|
||||
*properties = Array<PropertyDescriptor>::create();
|
||||
return Response::OK();
|
||||
}
|
||||
if (resultValue.IsEmpty()) return Response::InternalError();
|
||||
std::unique_ptr<protocol::Value> protocolValue;
|
||||
Response response = toProtocolValue(context, resultValue, &protocolValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
protocol::ErrorSupport errors;
|
||||
std::unique_ptr<Array<PropertyDescriptor>> result =
|
||||
Array<PropertyDescriptor>::fromValue(protocolValue.get(), &errors);
|
||||
if (errors.hasErrors()) return Response::Error(errors.errors());
|
||||
*properties = std::move(result);
|
||||
return Response::OK();
|
||||
}
|
||||
|
||||
@ -385,25 +379,37 @@ void InjectedScript::releaseObject(const String16& objectId) {
|
||||
}
|
||||
|
||||
Response InjectedScript::wrapObject(
|
||||
v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
|
||||
return wrapObject(value, groupName, wrapMode, v8::MaybeLocal<v8::Value>(),
|
||||
kMaxCustomPreviewDepth, result);
|
||||
v8::Local<v8::Value> value, const String16& groupName, bool forceValueType,
|
||||
bool generatePreview,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) const {
|
||||
return wrapObject(value, groupName, forceValueType, generatePreview,
|
||||
v8::MaybeLocal<v8::Value>(), kMaxCustomPreviewDepth,
|
||||
result);
|
||||
}
|
||||
|
||||
Response InjectedScript::wrapObject(
|
||||
v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode,
|
||||
v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
|
||||
v8::Local<v8::Value> value, const String16& groupName, bool forceValueType,
|
||||
bool generatePreview, v8::MaybeLocal<v8::Value> customPreviewConfig,
|
||||
int maxCustomPreviewDepth,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) const {
|
||||
v8::HandleScope handles(m_context->isolate());
|
||||
v8::Local<v8::Value> wrappedObject;
|
||||
v8::Local<v8::Context> context = m_context->context();
|
||||
v8::Context::Scope contextScope(context);
|
||||
|
||||
int customPreviewEnabled = m_customPreviewEnabled;
|
||||
int sessionId = m_sessionId;
|
||||
auto obj = ValueMirror::create(m_context->context(), value);
|
||||
if (!obj) return Response::InternalError();
|
||||
Response response = obj->buildRemoteObject(context, wrapMode, result);
|
||||
|
||||
Response response = wrapValue(value, groupName, forceValueType,
|
||||
generatePreview, &wrappedObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
bindRemoteObjectIfNeeded(value, groupName, result->get());
|
||||
protocol::ErrorSupport errors;
|
||||
std::unique_ptr<protocol::Value> protocolValue;
|
||||
response = toProtocolValue(context, wrappedObject, &protocolValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
|
||||
*result =
|
||||
protocol::Runtime::RemoteObject::fromValue(protocolValue.get(), &errors);
|
||||
if (!result->get()) return Response::Error(errors.errors());
|
||||
if (customPreviewEnabled && value->IsObject()) {
|
||||
std::unique_ptr<protocol::Runtime::CustomPreview> customPreview;
|
||||
generateCustomPreview(sessionId, groupName, context, value.As<v8::Object>(),
|
||||
@ -414,65 +420,47 @@ Response InjectedScript::wrapObject(
|
||||
return Response::OK();
|
||||
}
|
||||
|
||||
Response InjectedScript::wrapValue(v8::Local<v8::Value> value,
|
||||
const String16& groupName,
|
||||
bool forceValueType, bool generatePreview,
|
||||
v8::Local<v8::Value>* result) const {
|
||||
V8FunctionCall function(m_context->inspector(), m_context->context(),
|
||||
v8Value(), "wrapObject");
|
||||
function.appendArgument(value);
|
||||
function.appendArgument(groupName);
|
||||
function.appendArgument(forceValueType);
|
||||
function.appendArgument(generatePreview);
|
||||
bool hadException = false;
|
||||
*result = function.call(hadException);
|
||||
if (hadException || result->IsEmpty()) return Response::InternalError();
|
||||
return Response::OK();
|
||||
}
|
||||
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
|
||||
v8::Local<v8::Object> table, v8::MaybeLocal<v8::Array> maybeColumns) {
|
||||
using protocol::Runtime::RemoteObject;
|
||||
using protocol::Runtime::ObjectPreview;
|
||||
using protocol::Runtime::PropertyPreview;
|
||||
using protocol::Array;
|
||||
|
||||
v8::Isolate* isolate = m_context->isolate();
|
||||
v8::HandleScope handles(isolate);
|
||||
v8::Local<v8::Value> table, v8::Local<v8::Value> columns) const {
|
||||
v8::HandleScope handles(m_context->isolate());
|
||||
v8::Local<v8::Context> context = m_context->context();
|
||||
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
Response response =
|
||||
wrapObject(table, "console", WrapMode::kNoPreview, &remoteObject);
|
||||
if (!remoteObject || !response.isSuccess()) return nullptr;
|
||||
|
||||
auto mirror = ValueMirror::create(context, table);
|
||||
std::unique_ptr<ObjectPreview> preview;
|
||||
int limit = 100;
|
||||
mirror->buildObjectPreview(context, true /* generatePreviewForProperties */,
|
||||
&limit, &limit, &preview);
|
||||
|
||||
Array<PropertyPreview>* columns = preview->getProperties();
|
||||
std::unordered_set<String16> selectedColumns;
|
||||
v8::Local<v8::Array> v8Columns;
|
||||
if (maybeColumns.ToLocal(&v8Columns)) {
|
||||
for (uint32_t i = 0; i < v8Columns->Length(); ++i) {
|
||||
v8::Local<v8::Value> column;
|
||||
if (v8Columns->Get(context, i).ToLocal(&column) && column->IsString()) {
|
||||
selectedColumns.insert(
|
||||
toProtocolString(isolate, column.As<v8::String>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!selectedColumns.empty()) {
|
||||
for (size_t i = 0; i < columns->length(); ++i) {
|
||||
ObjectPreview* columnPreview = columns->get(i)->getValuePreview(nullptr);
|
||||
if (!columnPreview) continue;
|
||||
|
||||
std::unique_ptr<Array<PropertyPreview>> filtered =
|
||||
Array<PropertyPreview>::create();
|
||||
Array<PropertyPreview>* columns = columnPreview->getProperties();
|
||||
for (size_t j = 0; j < columns->length(); ++j) {
|
||||
PropertyPreview* property = columns->get(j);
|
||||
if (selectedColumns.find(property->getName()) !=
|
||||
selectedColumns.end()) {
|
||||
filtered->addItem(property->clone());
|
||||
}
|
||||
}
|
||||
columnPreview->setProperties(std::move(filtered));
|
||||
}
|
||||
}
|
||||
remoteObject->setPreview(std::move(preview));
|
||||
return remoteObject;
|
||||
V8FunctionCall function(m_context->inspector(), context, v8Value(),
|
||||
"wrapTable");
|
||||
function.appendArgument(table);
|
||||
if (columns.IsEmpty())
|
||||
function.appendArgument(false);
|
||||
else
|
||||
function.appendArgument(columns);
|
||||
bool hadException = false;
|
||||
v8::Local<v8::Value> r = function.call(hadException);
|
||||
if (hadException || r.IsEmpty()) return nullptr;
|
||||
std::unique_ptr<protocol::Value> protocolValue;
|
||||
Response response = toProtocolValue(context, r, &protocolValue);
|
||||
if (!response.isSuccess()) return nullptr;
|
||||
protocol::ErrorSupport errors;
|
||||
return protocol::Runtime::RemoteObject::fromValue(protocolValue.get(),
|
||||
&errors);
|
||||
}
|
||||
|
||||
void InjectedScript::addPromiseCallback(
|
||||
V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
|
||||
const String16& objectGroup, WrapMode wrapMode,
|
||||
const String16& objectGroup, bool returnByValue, bool generatePreview,
|
||||
std::unique_ptr<EvaluateCallback> callback) {
|
||||
if (value.IsEmpty()) {
|
||||
callback->sendFailure(Response::InternalError());
|
||||
@ -482,7 +470,8 @@ void InjectedScript::addPromiseCallback(
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
if (ProtocolPromiseHandler::add(
|
||||
session, m_context->context(), value.ToLocalChecked(),
|
||||
m_context->contextId(), objectGroup, wrapMode, callback.get())) {
|
||||
m_context->contextId(), objectGroup, returnByValue, generatePreview,
|
||||
callback.get())) {
|
||||
m_evaluateCallbacks.insert(callback.release());
|
||||
}
|
||||
}
|
||||
@ -532,6 +521,10 @@ void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) {
|
||||
m_customPreviewEnabled = enabled;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> InjectedScript::v8Value() const {
|
||||
return m_value.Get(m_context->isolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const {
|
||||
if (m_lastEvaluationResult.IsEmpty())
|
||||
return v8::Undefined(m_context->isolate());
|
||||
@ -583,7 +576,7 @@ Response InjectedScript::resolveCallArgument(
|
||||
|
||||
Response InjectedScript::createExceptionDetails(
|
||||
const v8::TryCatch& tryCatch, const String16& objectGroup,
|
||||
WrapMode wrapMode, Maybe<protocol::Runtime::ExceptionDetails>* result) {
|
||||
bool generatePreview, Maybe<protocol::Runtime::ExceptionDetails>* result) {
|
||||
if (!tryCatch.HasCaught()) return Response::InternalError();
|
||||
v8::Local<v8::Message> message = tryCatch.Message();
|
||||
v8::Local<v8::Value> exception = tryCatch.Exception();
|
||||
@ -619,10 +612,8 @@ Response InjectedScript::createExceptionDetails(
|
||||
if (!exception.IsEmpty()) {
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
|
||||
Response response =
|
||||
wrapObject(exception, objectGroup,
|
||||
exception->IsNativeError() ? WrapMode::kNoPreview
|
||||
: WrapMode::kWithPreview,
|
||||
&wrapped);
|
||||
wrapObject(exception, objectGroup, false /* forceValueType */,
|
||||
generatePreview && !exception->IsNativeError(), &wrapped);
|
||||
if (!response.isSuccess()) return response;
|
||||
exceptionDetails->setException(std::move(wrapped));
|
||||
}
|
||||
@ -632,14 +623,15 @@ Response InjectedScript::createExceptionDetails(
|
||||
|
||||
Response InjectedScript::wrapEvaluateResult(
|
||||
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch,
|
||||
const String16& objectGroup, WrapMode wrapMode,
|
||||
const String16& objectGroup, bool returnByValue, bool generatePreview,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
|
||||
v8::Local<v8::Value> resultValue;
|
||||
if (!tryCatch.HasCaught()) {
|
||||
if (!maybeResultValue.ToLocal(&resultValue))
|
||||
return Response::InternalError();
|
||||
Response response = wrapObject(resultValue, objectGroup, wrapMode, result);
|
||||
Response response = wrapObject(resultValue, objectGroup, returnByValue,
|
||||
generatePreview, result);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (objectGroup == "console") {
|
||||
m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
|
||||
@ -651,14 +643,12 @@ Response InjectedScript::wrapEvaluateResult(
|
||||
}
|
||||
v8::Local<v8::Value> exception = tryCatch.Exception();
|
||||
Response response =
|
||||
wrapObject(exception, objectGroup,
|
||||
exception->IsNativeError() ? WrapMode::kNoPreview
|
||||
: WrapMode::kWithPreview,
|
||||
result);
|
||||
wrapObject(exception, objectGroup, false,
|
||||
generatePreview && !exception->IsNativeError(), result);
|
||||
if (!response.isSuccess()) return response;
|
||||
// We send exception in result for compatibility reasons, even though it's
|
||||
// accessible through exceptionDetails.exception.
|
||||
response = createExceptionDetails(tryCatch, objectGroup, wrapMode,
|
||||
response = createExceptionDetails(tryCatch, objectGroup, generatePreview,
|
||||
exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
}
|
||||
@ -807,31 +797,33 @@ Response InjectedScript::CallFrameScope::findInjectedScript(
|
||||
return session->findInjectedScript(remoteId.get(), m_injectedScript);
|
||||
}
|
||||
|
||||
String16 InjectedScript::bindObject(v8::Local<v8::Value> value,
|
||||
const String16& groupName) {
|
||||
InjectedScript* InjectedScript::fromInjectedScriptHost(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> injectedScriptObject) {
|
||||
v8::HandleScope handleScope(isolate);
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Private> privateKey = v8::Private::ForApi(
|
||||
isolate, v8::String::NewFromUtf8(isolate, privateKeyName,
|
||||
v8::NewStringType::kInternalized)
|
||||
.ToLocalChecked());
|
||||
v8::Local<v8::Value> value =
|
||||
injectedScriptObject->GetPrivate(context, privateKey).ToLocalChecked();
|
||||
DCHECK(value->IsExternal());
|
||||
v8::Local<v8::External> external = value.As<v8::External>();
|
||||
return static_cast<InjectedScript*>(external->Value());
|
||||
}
|
||||
|
||||
int InjectedScript::bindObject(v8::Local<v8::Value> value,
|
||||
const String16& groupName) {
|
||||
if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1;
|
||||
int id = m_lastBoundObjectId++;
|
||||
m_idToWrappedObject[id].Reset(m_context->isolate(), value);
|
||||
m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel);
|
||||
|
||||
if (!groupName.isEmpty() && id > 0) {
|
||||
m_idToObjectGroupName[id] = groupName;
|
||||
m_nameToObjectGroup[groupName].push_back(id);
|
||||
}
|
||||
// TODO(dgozman): get rid of "injectedScript" notion.
|
||||
return String16::concat(
|
||||
"{\"injectedScriptId\":", String16::fromInteger(m_context->contextId()),
|
||||
",\"id\":", String16::fromInteger(id), "}");
|
||||
}
|
||||
|
||||
void InjectedScript::bindRemoteObjectIfNeeded(
|
||||
v8::Local<v8::Value> value, const String16& groupName,
|
||||
protocol::Runtime::RemoteObject* remoteObject) {
|
||||
if (!remoteObject) return;
|
||||
if (remoteObject->hasValue()) return;
|
||||
if (remoteObject->hasUnserializableValue()) return;
|
||||
if (remoteObject->getType() != RemoteObject::TypeEnum::Undefined) {
|
||||
remoteObject->setObjectId(bindObject(value, groupName));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void InjectedScript::unbindObject(int id) {
|
||||
|
@ -46,9 +46,9 @@
|
||||
namespace v8_inspector {
|
||||
|
||||
class RemoteObjectId;
|
||||
class V8FunctionCall;
|
||||
class V8InspectorImpl;
|
||||
class V8InspectorSessionImpl;
|
||||
enum class WrapMode;
|
||||
|
||||
using protocol::Maybe;
|
||||
using protocol::Response;
|
||||
@ -65,40 +65,38 @@ class EvaluateCallback {
|
||||
|
||||
class InjectedScript final {
|
||||
public:
|
||||
InjectedScript(InspectedContext*, int sessionId);
|
||||
static std::unique_ptr<InjectedScript> create(InspectedContext*,
|
||||
int sessionId);
|
||||
~InjectedScript();
|
||||
static InjectedScript* fromInjectedScriptHost(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object>);
|
||||
|
||||
InspectedContext* context() const { return m_context; }
|
||||
|
||||
Response getProperties(
|
||||
v8::Local<v8::Object>, const String16& groupName, bool ownProperties,
|
||||
bool accessorPropertiesOnly, WrapMode wrapMode,
|
||||
bool accessorPropertiesOnly, bool generatePreview,
|
||||
std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
|
||||
result,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>*);
|
||||
|
||||
Response getInternalProperties(
|
||||
v8::Local<v8::Value>, const String16& groupName,
|
||||
std::unique_ptr<
|
||||
protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>*
|
||||
result);
|
||||
|
||||
void releaseObject(const String16& objectId);
|
||||
|
||||
Response wrapObject(v8::Local<v8::Value>, const String16& groupName,
|
||||
WrapMode wrapMode,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result);
|
||||
Response wrapObject(v8::Local<v8::Value>, const String16& groupName,
|
||||
WrapMode wrapMode,
|
||||
v8::MaybeLocal<v8::Value> customPreviewConfig,
|
||||
int maxCustomPreviewDepth,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result);
|
||||
Response wrapObject(
|
||||
v8::Local<v8::Value>, const String16& groupName, bool forceValueType,
|
||||
bool generatePreview,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) const;
|
||||
Response wrapObject(
|
||||
v8::Local<v8::Value>, const String16& groupName, bool forceValueType,
|
||||
bool generatePreview, v8::MaybeLocal<v8::Value> customPreviewConfig,
|
||||
int maxCustomPreviewDepth,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) const;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapTable(
|
||||
v8::Local<v8::Object> table, v8::MaybeLocal<v8::Array> columns);
|
||||
v8::Local<v8::Value> table, v8::Local<v8::Value> columns) const;
|
||||
|
||||
void addPromiseCallback(V8InspectorSessionImpl* session,
|
||||
v8::MaybeLocal<v8::Value> value,
|
||||
const String16& objectGroup, WrapMode wrapMode,
|
||||
const String16& objectGroup, bool returnByValue,
|
||||
bool generatePreview,
|
||||
std::unique_ptr<EvaluateCallback> callback);
|
||||
|
||||
Response findObject(const RemoteObjectId&, v8::Local<v8::Value>*) const;
|
||||
@ -109,16 +107,18 @@ class InjectedScript final {
|
||||
v8::Local<v8::Value>* result);
|
||||
|
||||
Response createExceptionDetails(
|
||||
const v8::TryCatch&, const String16& groupName, WrapMode wrapMode,
|
||||
const v8::TryCatch&, const String16& groupName, bool generatePreview,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>* result);
|
||||
Response wrapEvaluateResult(
|
||||
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&,
|
||||
const String16& objectGroup, WrapMode wrapMode,
|
||||
const String16& objectGroup, bool returnByValue, bool generatePreview,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>*);
|
||||
v8::Local<v8::Value> lastEvaluationResult() const;
|
||||
void setLastEvaluationResult(v8::Local<v8::Value> result);
|
||||
|
||||
int bindObject(v8::Local<v8::Value>, const String16& groupName);
|
||||
|
||||
class Scope {
|
||||
public:
|
||||
Response initialize();
|
||||
@ -196,21 +196,23 @@ class InjectedScript final {
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CallFrameScope);
|
||||
};
|
||||
String16 bindObject(v8::Local<v8::Value>, const String16& groupName);
|
||||
|
||||
private:
|
||||
InjectedScript(InspectedContext*, v8::Local<v8::Object>, int sessionId);
|
||||
v8::Local<v8::Value> v8Value() const;
|
||||
Response wrapValue(v8::Local<v8::Value>, const String16& groupName,
|
||||
bool forceValueType, bool generatePreview,
|
||||
v8::Local<v8::Value>* result) const;
|
||||
v8::Local<v8::Object> commandLineAPI();
|
||||
void unbindObject(int id);
|
||||
|
||||
void bindRemoteObjectIfNeeded(v8::Local<v8::Value>, const String16& groupName,
|
||||
protocol::Runtime::RemoteObject* remoteObject);
|
||||
|
||||
class ProtocolPromiseHandler;
|
||||
void discardEvaluateCallbacks();
|
||||
std::unique_ptr<EvaluateCallback> takeEvaluateCallback(
|
||||
EvaluateCallback* callback);
|
||||
|
||||
InspectedContext* m_context;
|
||||
v8::Global<v8::Value> m_value;
|
||||
int m_sessionId;
|
||||
v8::Global<v8::Value> m_lastEvaluationResult;
|
||||
v8::Global<v8::Object> m_commandLineAPI;
|
||||
|
122
src/inspector/injected_script_externs.js
Normal file
122
src/inspector/injected_script_externs.js
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/** @interface */
|
||||
function InjectedScriptHostClass()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.nullifyPrototype = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
* @param {string} name
|
||||
* @return {*}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.getProperty = function(obj, name) {}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
* @return {string}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.internalConstructorName = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
* @param {function()|undefined} func
|
||||
* @return {boolean}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.formatAccessorsAsProperties = function(obj, func) {}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
* @return {string}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.subtype = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
* @return {boolean}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.isTypedArray = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {*} obj
|
||||
* @return {!Array.<*>}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.getInternalProperties = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} object
|
||||
* @param {string} propertyName
|
||||
* @return {boolean}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.objectHasOwnProperty = function(object, propertyName) {}
|
||||
|
||||
/**
|
||||
* @param {*} value
|
||||
* @param {string} groupName
|
||||
* @return {number}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.bind = function(value, groupName) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} object
|
||||
* @return {!Object}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.proxyTargetValue = function(object) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.keys = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @return {Object}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.getPrototypeOf = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @param {string} prop
|
||||
* @return {Object}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.getOwnPropertyDescriptor = function(obj, prop) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.getOwnPropertyNames = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @return {!Array<symbol>}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.getOwnPropertySymbols = function(obj) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @param {string|symbol} name
|
||||
* @return {{isBuiltin:boolean, hasGetter:boolean, hasSetter:boolean}|undefined}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.nativeAccessorDescriptor = function(obj, name) {}
|
||||
|
||||
/**
|
||||
* @param {!Object} arrayBuffer
|
||||
* @return {Array<Object>|undefined}
|
||||
*/
|
||||
InjectedScriptHostClass.prototype.typedArrayProperties = function(arrayBuffer) {}
|
||||
|
||||
/** @type {!InjectedScriptHostClass} */
|
||||
var InjectedScriptHost;
|
||||
/** @type {!Window} */
|
||||
var inspectedGlobalObject;
|
||||
/** @type {number} */
|
||||
var injectedScriptId;
|
@ -109,12 +109,14 @@ InjectedScript* InspectedContext::getInjectedScript(int sessionId) {
|
||||
return it == m_injectedScripts.end() ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
InjectedScript* InspectedContext::createInjectedScript(int sessionId) {
|
||||
bool InspectedContext::createInjectedScript(int sessionId) {
|
||||
std::unique_ptr<InjectedScript> injectedScript =
|
||||
v8::base::make_unique<InjectedScript>(this, sessionId);
|
||||
InjectedScript::create(this, sessionId);
|
||||
// InjectedScript::create can destroy |this|.
|
||||
if (!injectedScript) return false;
|
||||
CHECK(m_injectedScripts.find(sessionId) == m_injectedScripts.end());
|
||||
m_injectedScripts[sessionId] = std::move(injectedScript);
|
||||
return getInjectedScript(sessionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void InspectedContext::discardInjectedScript(int sessionId) {
|
||||
|
@ -40,7 +40,7 @@ class InspectedContext {
|
||||
V8InspectorImpl* inspector() const { return m_inspector; }
|
||||
|
||||
InjectedScript* getInjectedScript(int sessionId);
|
||||
InjectedScript* createInjectedScript(int sessionId);
|
||||
bool createInjectedScript(int sessionId);
|
||||
void discardInjectedScript(int sessionId);
|
||||
|
||||
private:
|
||||
|
@ -1890,9 +1890,7 @@
|
||||
"error",
|
||||
"proxy",
|
||||
"promise",
|
||||
"typedarray",
|
||||
"arraybuffer",
|
||||
"dataview"
|
||||
"typedarray"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -887,8 +887,6 @@ domain Runtime
|
||||
proxy
|
||||
promise
|
||||
typedarray
|
||||
arraybuffer
|
||||
dataview
|
||||
# Object class (constructor) name. Specified for `object` type values only.
|
||||
optional string className
|
||||
# Remote object value in case of primitive values or JSON values (if it was requested).
|
||||
|
@ -259,33 +259,19 @@ V8ConsoleMessage::wrapArguments(V8InspectorSessionImpl* session,
|
||||
|
||||
std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>> args =
|
||||
protocol::Array<protocol::Runtime::RemoteObject>::create();
|
||||
|
||||
v8::Local<v8::Value> value = m_arguments[0]->Get(isolate);
|
||||
if (value->IsObject() && m_type == ConsoleAPIType::kTable &&
|
||||
generatePreview) {
|
||||
v8::MaybeLocal<v8::Array> columns;
|
||||
if (m_arguments.size() > 1) {
|
||||
v8::Local<v8::Value> secondArgument = m_arguments[1]->Get(isolate);
|
||||
if (secondArgument->IsArray()) {
|
||||
columns = v8::Local<v8::Array>::Cast(secondArgument);
|
||||
} else if (secondArgument->IsString()) {
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
v8::Local<v8::Array> array = v8::Array::New(isolate);
|
||||
if (array->Set(context, 0, secondArgument).IsJust()) {
|
||||
columns = array;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_type == ConsoleAPIType::kTable && generatePreview) {
|
||||
v8::Local<v8::Value> table = m_arguments[0]->Get(isolate);
|
||||
v8::Local<v8::Value> columns = m_arguments.size() > 1
|
||||
? m_arguments[1]->Get(isolate)
|
||||
: v8::Local<v8::Value>();
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped =
|
||||
session->wrapTable(context, v8::Local<v8::Object>::Cast(value),
|
||||
columns);
|
||||
session->wrapTable(context, table, columns);
|
||||
inspectedContext = inspector->getContext(contextGroupId, contextId);
|
||||
if (!inspectedContext) return nullptr;
|
||||
if (wrapped) {
|
||||
if (wrapped)
|
||||
args->addItem(std::move(wrapped));
|
||||
} else {
|
||||
else
|
||||
args = nullptr;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < m_arguments.size(); ++i) {
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped =
|
||||
|
@ -600,8 +600,9 @@ static void inspectImpl(const v8::FunctionCallbackInfo<v8::Value>& info,
|
||||
InjectedScript* injectedScript = helper.injectedScript(sessionId);
|
||||
if (!injectedScript) return;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedObject;
|
||||
protocol::Response response = injectedScript->wrapObject(
|
||||
value, "", WrapMode::kNoPreview, &wrappedObject);
|
||||
protocol::Response response =
|
||||
injectedScript->wrapObject(value, "", false /** forceValueType */,
|
||||
false /** generatePreview */, &wrappedObject);
|
||||
if (!response.isSuccess()) return;
|
||||
|
||||
std::unique_ptr<protocol::DictionaryValue> hints =
|
||||
|
@ -260,9 +260,8 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
|
||||
|
||||
for (; !iterator->Done(); iterator->Advance()) {
|
||||
std::unique_ptr<RemoteObject> object;
|
||||
Response result =
|
||||
injectedScript->wrapObject(iterator->GetObject(), kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &object);
|
||||
Response result = injectedScript->wrapObject(
|
||||
iterator->GetObject(), kBacktraceObjectGroup, false, false, &object);
|
||||
if (!result.isSuccess()) return result;
|
||||
|
||||
auto scope = Scope::create()
|
||||
@ -1086,12 +1085,10 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame(
|
||||
// context or session.
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview;
|
||||
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
|
||||
return scope.injectedScript()->wrapEvaluateResult(
|
||||
maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode,
|
||||
result, exceptionDetails);
|
||||
maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""),
|
||||
returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), result,
|
||||
exceptionDetails);
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setVariableValue(
|
||||
@ -1271,9 +1268,8 @@ Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
if (injectedScript) {
|
||||
v8::Local<v8::Value> receiver;
|
||||
if (iterator->GetReceiver().ToLocal(&receiver)) {
|
||||
res =
|
||||
injectedScript->wrapObject(receiver, kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &protocolReceiver);
|
||||
res = injectedScript->wrapObject(receiver, kBacktraceObjectGroup, false,
|
||||
false, &protocolReceiver);
|
||||
if (!res.isSuccess()) return res;
|
||||
}
|
||||
}
|
||||
@ -1324,7 +1320,7 @@ Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
if (!returnValue.IsEmpty() && injectedScript) {
|
||||
std::unique_ptr<RemoteObject> value;
|
||||
res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &value);
|
||||
false, false, &value);
|
||||
if (!res.isSuccess()) return res;
|
||||
frame->setReturnValue(std::move(value));
|
||||
}
|
||||
@ -1532,8 +1528,8 @@ void V8DebuggerAgentImpl::didPause(
|
||||
? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
|
||||
: protocol::Debugger::Paused::ReasonEnum::Exception;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> obj;
|
||||
injectedScript->wrapObject(exception, kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &obj);
|
||||
injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false,
|
||||
&obj);
|
||||
std::unique_ptr<protocol::DictionaryValue> breakAuxData;
|
||||
if (obj) {
|
||||
breakAuxData = obj->toValue();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/inspector/v8-debugger-agent-impl.h"
|
||||
#include "src/inspector/v8-inspector-impl.h"
|
||||
#include "src/inspector/v8-inspector-session-impl.h"
|
||||
#include "src/inspector/v8-internal-value-type.h"
|
||||
#include "src/inspector/v8-runtime-agent-impl.h"
|
||||
#include "src/inspector/v8-stack-trace-impl.h"
|
||||
#include "src/inspector/v8-value-utils.h"
|
||||
@ -23,6 +24,102 @@ namespace {
|
||||
static const int kMaxAsyncTaskStacks = 128 * 1024;
|
||||
static const int kNoBreakpointId = 0;
|
||||
|
||||
v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Array> entries;
|
||||
bool isKeyValue = false;
|
||||
if (!value->IsObject() ||
|
||||
!value.As<v8::Object>()->PreviewEntries(&isKeyValue).ToLocal(&entries)) {
|
||||
return v8::MaybeLocal<v8::Array>();
|
||||
}
|
||||
|
||||
v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate);
|
||||
CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0);
|
||||
if (!wrappedEntries->SetPrototype(context, v8::Null(isolate))
|
||||
.FromMaybe(false))
|
||||
return v8::MaybeLocal<v8::Array>();
|
||||
for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
|
||||
v8::Local<v8::Value> item;
|
||||
if (!entries->Get(context, i).ToLocal(&item)) continue;
|
||||
v8::Local<v8::Value> value;
|
||||
if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue;
|
||||
v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
|
||||
if (!wrapper->SetPrototype(context, v8::Null(isolate)).FromMaybe(false))
|
||||
continue;
|
||||
createDataProperty(
|
||||
context, wrapper,
|
||||
toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item);
|
||||
if (isKeyValue) {
|
||||
createDataProperty(context, wrapper,
|
||||
toV8StringInternalized(isolate, "value"), value);
|
||||
}
|
||||
createDataProperty(context, wrappedEntries, wrappedEntries->Length(),
|
||||
wrapper);
|
||||
}
|
||||
if (!markArrayEntriesAsInternal(context, wrappedEntries,
|
||||
V8InternalValueType::kEntry)) {
|
||||
return v8::MaybeLocal<v8::Array>();
|
||||
}
|
||||
return wrappedEntries;
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Object> buildLocation(v8::Local<v8::Context> context,
|
||||
int scriptId, int lineNumber,
|
||||
int columnNumber) {
|
||||
if (scriptId == v8::UnboundScript::kNoScriptId)
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
if (lineNumber == v8::Function::kLineOffsetNotFound ||
|
||||
columnNumber == v8::Function::kLineOffsetNotFound) {
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
}
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Object> location = v8::Object::New(isolate);
|
||||
if (!location->SetPrototype(context, v8::Null(isolate)).FromMaybe(false)) {
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
}
|
||||
if (!createDataProperty(context, location,
|
||||
toV8StringInternalized(isolate, "scriptId"),
|
||||
toV8String(isolate, String16::fromInteger(scriptId)))
|
||||
.FromMaybe(false)) {
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
}
|
||||
if (!createDataProperty(context, location,
|
||||
toV8StringInternalized(isolate, "lineNumber"),
|
||||
v8::Integer::New(isolate, lineNumber))
|
||||
.FromMaybe(false)) {
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
}
|
||||
if (!createDataProperty(context, location,
|
||||
toV8StringInternalized(isolate, "columnNumber"),
|
||||
v8::Integer::New(isolate, columnNumber))
|
||||
.FromMaybe(false)) {
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
}
|
||||
if (!markAsInternal(context, location, V8InternalValueType::kLocation)) {
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Object> generatorObjectLocation(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
|
||||
if (!value->IsGeneratorObject()) return v8::MaybeLocal<v8::Object>();
|
||||
v8::Local<v8::debug::GeneratorObject> generatorObject =
|
||||
v8::debug::GeneratorObject::Cast(value);
|
||||
if (!generatorObject->IsSuspended()) {
|
||||
v8::Local<v8::Function> func = generatorObject->Function();
|
||||
return buildLocation(context, func->ScriptId(), func->GetScriptLineNumber(),
|
||||
func->GetScriptColumnNumber());
|
||||
}
|
||||
v8::Local<v8::debug::Script> script;
|
||||
if (!generatorObject->Script().ToLocal(&script))
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
v8::debug::Location suspendedLocation = generatorObject->SuspendedLocation();
|
||||
return buildLocation(context, script->Id(), suspendedLocation.GetLineNumber(),
|
||||
suspendedLocation.GetColumnNumber());
|
||||
}
|
||||
|
||||
template <typename Map>
|
||||
void cleanupExpiredWeakPointers(Map& map) {
|
||||
for (auto it = map.begin(); it != map.end();) {
|
||||
@ -617,52 +714,28 @@ v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
|
||||
|
||||
for (; !iterator->Done(); iterator->Advance()) {
|
||||
v8::Local<v8::Object> scope = v8::Object::New(m_isolate);
|
||||
if (!addInternalObject(context, scope, V8InternalValueType::kScope)) {
|
||||
if (!markAsInternal(context, scope, V8InternalValueType::kScope)) {
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
}
|
||||
String16 nameSuffix = toProtocolStringWithTypeCheck(
|
||||
m_isolate, iterator->GetFunctionDebugName());
|
||||
String16 description;
|
||||
if (nameSuffix.length()) nameSuffix = " (" + nameSuffix + ")";
|
||||
switch (iterator->GetType()) {
|
||||
case v8::debug::ScopeIterator::ScopeTypeGlobal:
|
||||
description = "Global" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeLocal:
|
||||
description = "Local" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeWith:
|
||||
description = "With Block" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeClosure:
|
||||
description = "Closure" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeCatch:
|
||||
description = "Catch" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeBlock:
|
||||
description = "Block" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeScript:
|
||||
description = "Script" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeEval:
|
||||
description = "Eval" + nameSuffix;
|
||||
break;
|
||||
case v8::debug::ScopeIterator::ScopeTypeModule:
|
||||
description = "Module" + nameSuffix;
|
||||
break;
|
||||
String16 type = v8_inspector::scopeType(iterator->GetType());
|
||||
String16 name;
|
||||
v8::Local<v8::Value> maybe_name = iterator->GetFunctionDebugName();
|
||||
if (!maybe_name->IsUndefined()) {
|
||||
name = toProtocolStringWithTypeCheck(m_isolate, maybe_name);
|
||||
}
|
||||
v8::Local<v8::Object> object = iterator->GetObject();
|
||||
createDataProperty(context, scope,
|
||||
toV8StringInternalized(m_isolate, "description"),
|
||||
toV8String(m_isolate, description));
|
||||
toV8StringInternalized(m_isolate, "type"),
|
||||
toV8String(m_isolate, type));
|
||||
createDataProperty(context, scope,
|
||||
toV8StringInternalized(m_isolate, "name"),
|
||||
toV8String(m_isolate, name));
|
||||
createDataProperty(context, scope,
|
||||
toV8StringInternalized(m_isolate, "object"), object);
|
||||
createDataProperty(context, result, result->Length(), scope);
|
||||
}
|
||||
if (!addInternalObject(context, v8::Local<v8::Array>::Cast(result),
|
||||
V8InternalValueType::kScopeList))
|
||||
if (!markAsInternal(context, v8::Local<v8::Array>::Cast(result),
|
||||
V8InternalValueType::kScopeList))
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
return result;
|
||||
}
|
||||
@ -677,45 +750,6 @@ v8::MaybeLocal<v8::Value> V8Debugger::generatorScopes(
|
||||
return getTargetScopes(context, generator, GENERATOR);
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Array> V8Debugger::collectionsEntries(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Array> entries;
|
||||
bool isKeyValue = false;
|
||||
if (!value->IsObject() ||
|
||||
!value.As<v8::Object>()->PreviewEntries(&isKeyValue).ToLocal(&entries)) {
|
||||
return v8::MaybeLocal<v8::Array>();
|
||||
}
|
||||
|
||||
v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate);
|
||||
CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0);
|
||||
if (!wrappedEntries->SetPrototype(context, v8::Null(isolate))
|
||||
.FromMaybe(false))
|
||||
return v8::MaybeLocal<v8::Array>();
|
||||
for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
|
||||
v8::Local<v8::Value> item;
|
||||
if (!entries->Get(context, i).ToLocal(&item)) continue;
|
||||
v8::Local<v8::Value> value;
|
||||
if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue;
|
||||
v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
|
||||
if (!wrapper->SetPrototype(context, v8::Null(isolate)).FromMaybe(false))
|
||||
continue;
|
||||
createDataProperty(
|
||||
context, wrapper,
|
||||
toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item);
|
||||
if (isKeyValue) {
|
||||
createDataProperty(context, wrapper,
|
||||
toV8StringInternalized(isolate, "value"), value);
|
||||
}
|
||||
if (!addInternalObject(context, wrapper, V8InternalValueType::kEntry)) {
|
||||
continue;
|
||||
}
|
||||
createDataProperty(context, wrappedEntries, wrappedEntries->Length(),
|
||||
wrapper);
|
||||
}
|
||||
return wrappedEntries;
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Uint32> V8Debugger::stableObjectId(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
|
||||
DCHECK(value->IsObject());
|
||||
@ -747,6 +781,25 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
|
||||
createDataProperty(context, properties, properties->Length(), id);
|
||||
}
|
||||
}
|
||||
if (value->IsFunction()) {
|
||||
v8::Local<v8::Function> function = value.As<v8::Function>();
|
||||
v8::Local<v8::Object> location;
|
||||
if (buildLocation(context, function->ScriptId(),
|
||||
function->GetScriptLineNumber(),
|
||||
function->GetScriptColumnNumber())
|
||||
.ToLocal(&location)) {
|
||||
createDataProperty(
|
||||
context, properties, properties->Length(),
|
||||
toV8StringInternalized(m_isolate, "[[FunctionLocation]]"));
|
||||
createDataProperty(context, properties, properties->Length(), location);
|
||||
}
|
||||
if (function->IsGeneratorFunction()) {
|
||||
createDataProperty(context, properties, properties->Length(),
|
||||
toV8StringInternalized(m_isolate, "[[IsGenerator]]"));
|
||||
createDataProperty(context, properties, properties->Length(),
|
||||
v8::True(m_isolate));
|
||||
}
|
||||
}
|
||||
v8::Local<v8::Array> entries;
|
||||
if (collectionsEntries(context, value).ToLocal(&entries)) {
|
||||
createDataProperty(context, properties, properties->Length(),
|
||||
@ -754,6 +807,13 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
|
||||
createDataProperty(context, properties, properties->Length(), entries);
|
||||
}
|
||||
if (value->IsGeneratorObject()) {
|
||||
v8::Local<v8::Object> location;
|
||||
if (generatorObjectLocation(context, value).ToLocal(&location)) {
|
||||
createDataProperty(
|
||||
context, properties, properties->Length(),
|
||||
toV8StringInternalized(m_isolate, "[[GeneratorLocation]]"));
|
||||
createDataProperty(context, properties, properties->Length(), location);
|
||||
}
|
||||
v8::Local<v8::Value> scopes;
|
||||
if (generatorScopes(context, value).ToLocal(&scopes)) {
|
||||
createDataProperty(context, properties, properties->Length(),
|
||||
@ -1136,31 +1196,6 @@ std::pair<int64_t, int64_t> V8Debugger::debuggerIdFor(
|
||||
return std::make_pair(0, 0);
|
||||
}
|
||||
|
||||
bool V8Debugger::addInternalObject(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object,
|
||||
V8InternalValueType type) {
|
||||
if (m_internalObjects.IsEmpty()) {
|
||||
m_internalObjects.Reset(m_isolate, v8::debug::WeakMap::New(m_isolate));
|
||||
}
|
||||
return !m_internalObjects.Get(m_isolate)
|
||||
->Set(context, object,
|
||||
v8::Integer::New(m_isolate, static_cast<int>(type)))
|
||||
.IsEmpty();
|
||||
}
|
||||
|
||||
V8InternalValueType V8Debugger::getInternalType(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object) {
|
||||
if (m_internalObjects.IsEmpty()) return V8InternalValueType::kNone;
|
||||
v8::Local<v8::Value> typeValue;
|
||||
if (!m_internalObjects.Get(m_isolate)
|
||||
->Get(context, object)
|
||||
.ToLocal(&typeValue) ||
|
||||
!typeValue->IsUint32()) {
|
||||
return V8InternalValueType::kNone;
|
||||
}
|
||||
return static_cast<V8InternalValueType>(typeValue.As<v8::Int32>()->Value());
|
||||
}
|
||||
|
||||
void V8Debugger::dumpAsyncTaskStacksStateForTest() {
|
||||
fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
|
||||
fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
|
||||
|
@ -30,9 +30,6 @@ class V8InspectorImpl;
|
||||
class V8StackTraceImpl;
|
||||
struct V8StackTraceId;
|
||||
|
||||
enum class WrapMode { kForceValue, kNoPreview, kWithPreview };
|
||||
enum class V8InternalValueType { kNone, kEntry, kScope, kScopeList };
|
||||
|
||||
using protocol::Response;
|
||||
using ScheduleStepIntoAsyncCallback =
|
||||
protocol::Debugger::Backend::ScheduleStepIntoAsyncCallback;
|
||||
@ -137,12 +134,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
|
||||
std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId,
|
||||
const V8StackTraceId& id);
|
||||
|
||||
bool addInternalObject(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object,
|
||||
V8InternalValueType type);
|
||||
V8InternalValueType getInternalType(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object);
|
||||
|
||||
private:
|
||||
void clearContinueToLocation();
|
||||
bool shouldContinueToCurrentLocation();
|
||||
@ -169,8 +160,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
|
||||
v8::Local<v8::Function>);
|
||||
v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>,
|
||||
v8::Local<v8::Value>);
|
||||
v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value);
|
||||
|
||||
void asyncTaskScheduledForStack(const String16& taskName, void* task,
|
||||
bool recurring);
|
||||
@ -264,8 +253,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
|
||||
uint32_t m_lastStableObjectId = 0;
|
||||
v8::Global<v8::debug::WeakMap> m_stableObjectId;
|
||||
|
||||
v8::Global<v8::debug::WeakMap> m_internalObjects;
|
||||
|
||||
WasmTranslation m_wasmTranslation;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(V8Debugger);
|
||||
|
115
src/inspector/v8-function-call.cc
Normal file
115
src/inspector/v8-function-call.cc
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "src/inspector/v8-function-call.h"
|
||||
|
||||
#include "src/inspector/inspected-context.h"
|
||||
#include "src/inspector/string-util.h"
|
||||
#include "src/inspector/v8-debugger.h"
|
||||
#include "src/inspector/v8-inspector-impl.h"
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
V8FunctionCall::V8FunctionCall(V8InspectorImpl* inspector,
|
||||
v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value, const String16& name)
|
||||
: m_inspector(inspector),
|
||||
m_context(context),
|
||||
m_name(toV8String(context->GetIsolate(), name)),
|
||||
m_value(value) {}
|
||||
|
||||
void V8FunctionCall::appendArgument(v8::Local<v8::Value> value) {
|
||||
m_arguments.push_back(value);
|
||||
}
|
||||
|
||||
void V8FunctionCall::appendArgument(const String16& argument) {
|
||||
m_arguments.push_back(toV8String(m_context->GetIsolate(), argument));
|
||||
}
|
||||
|
||||
void V8FunctionCall::appendArgument(int argument) {
|
||||
m_arguments.push_back(v8::Number::New(m_context->GetIsolate(), argument));
|
||||
}
|
||||
|
||||
void V8FunctionCall::appendArgument(bool argument) {
|
||||
m_arguments.push_back(argument ? v8::True(m_context->GetIsolate())
|
||||
: v8::False(m_context->GetIsolate()));
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8FunctionCall::call(bool& hadException,
|
||||
bool reportExceptions) {
|
||||
v8::TryCatch tryCatch(m_context->GetIsolate());
|
||||
tryCatch.SetVerbose(reportExceptions);
|
||||
|
||||
v8::Local<v8::Value> result = callWithoutExceptionHandling();
|
||||
hadException = tryCatch.HasCaught();
|
||||
return result;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8FunctionCall::callWithoutExceptionHandling() {
|
||||
v8::Context::Scope contextScope(m_context);
|
||||
|
||||
v8::Local<v8::Object> thisObject = v8::Local<v8::Object>::Cast(m_value);
|
||||
v8::Local<v8::Value> value;
|
||||
if (!thisObject->Get(m_context, m_name).ToLocal(&value))
|
||||
return v8::Local<v8::Value>();
|
||||
|
||||
DCHECK(value->IsFunction());
|
||||
|
||||
v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);
|
||||
std::unique_ptr<v8::Local<v8::Value>[]> info(
|
||||
new v8::Local<v8::Value>[m_arguments.size()]);
|
||||
for (size_t i = 0; i < m_arguments.size(); ++i) {
|
||||
info[i] = m_arguments[i];
|
||||
DCHECK(!info[i].IsEmpty());
|
||||
}
|
||||
|
||||
int contextGroupId = m_inspector->contextGroupId(m_context);
|
||||
if (contextGroupId) {
|
||||
m_inspector->client()->muteMetrics(contextGroupId);
|
||||
m_inspector->muteExceptions(contextGroupId);
|
||||
}
|
||||
v8::MicrotasksScope microtasksScope(m_context->GetIsolate(),
|
||||
v8::MicrotasksScope::kDoNotRunMicrotasks);
|
||||
v8::Isolate::AllowJavascriptExecutionScope(m_context->GetIsolate());
|
||||
v8::MaybeLocal<v8::Value> maybeResult = function->Call(
|
||||
m_context, thisObject, static_cast<int>(m_arguments.size()), info.get());
|
||||
if (contextGroupId) {
|
||||
m_inspector->client()->unmuteMetrics(contextGroupId);
|
||||
m_inspector->unmuteExceptions(contextGroupId);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> result;
|
||||
if (!maybeResult.ToLocal(&result)) return v8::Local<v8::Value>();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
65
src/inspector/v8-function-call.h
Normal file
65
src/inspector/v8-function-call.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef V8_INSPECTOR_V8_FUNCTION_CALL_H_
|
||||
#define V8_INSPECTOR_V8_FUNCTION_CALL_H_
|
||||
|
||||
#include "src/inspector/string-16.h"
|
||||
|
||||
#include "include/v8.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
class V8InspectorImpl;
|
||||
|
||||
class V8FunctionCall {
|
||||
public:
|
||||
V8FunctionCall(V8InspectorImpl*, v8::Local<v8::Context>, v8::Local<v8::Value>,
|
||||
const String16& name);
|
||||
|
||||
void appendArgument(v8::Local<v8::Value>);
|
||||
void appendArgument(const String16&);
|
||||
void appendArgument(int);
|
||||
void appendArgument(bool);
|
||||
|
||||
v8::Local<v8::Value> call(bool& hadException, bool reportExceptions = true);
|
||||
v8::Local<v8::Value> callWithoutExceptionHandling();
|
||||
|
||||
protected:
|
||||
V8InspectorImpl* m_inspector;
|
||||
v8::Local<v8::Context> m_context;
|
||||
std::vector<v8::Local<v8::Value>> m_arguments;
|
||||
v8::Local<v8::String> m_name;
|
||||
v8::Local<v8::Value> m_value;
|
||||
};
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
#endif // V8_INSPECTOR_V8_FUNCTION_CALL_H_
|
427
src/inspector/v8-injected-script-host.cc
Normal file
427
src/inspector/v8-injected-script-host.cc
Normal file
@ -0,0 +1,427 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/inspector/v8-injected-script-host.h"
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/debug/debug-interface.h"
|
||||
#include "src/inspector/injected-script.h"
|
||||
#include "src/inspector/string-util.h"
|
||||
#include "src/inspector/v8-debugger.h"
|
||||
#include "src/inspector/v8-inspector-impl.h"
|
||||
#include "src/inspector/v8-internal-value-type.h"
|
||||
#include "src/inspector/v8-value-utils.h"
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
namespace {
|
||||
|
||||
void setFunctionProperty(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> obj, const char* name,
|
||||
v8::FunctionCallback callback,
|
||||
v8::Local<v8::External> external) {
|
||||
v8::Local<v8::String> funcName =
|
||||
toV8StringInternalized(context->GetIsolate(), name);
|
||||
v8::Local<v8::Function> func;
|
||||
if (!v8::Function::New(context, callback, external, 0,
|
||||
v8::ConstructorBehavior::kThrow)
|
||||
.ToLocal(&func))
|
||||
return;
|
||||
func->SetName(funcName);
|
||||
createDataProperty(context, obj, funcName, func);
|
||||
}
|
||||
|
||||
V8InspectorImpl* unwrapInspector(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
DCHECK(!info.Data().IsEmpty());
|
||||
DCHECK(info.Data()->IsExternal());
|
||||
V8InspectorImpl* inspector =
|
||||
static_cast<V8InspectorImpl*>(info.Data().As<v8::External>()->Value());
|
||||
DCHECK(inspector);
|
||||
return inspector;
|
||||
}
|
||||
|
||||
template <typename TypedArray>
|
||||
void addTypedArrayProperty(std::vector<v8::Local<v8::Value>>* props,
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::ArrayBuffer> arraybuffer,
|
||||
String16 name, size_t length) {
|
||||
props->push_back(toV8String(isolate, name));
|
||||
props->push_back(TypedArray::New(arraybuffer, 0, length));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
v8::Local<v8::Object> V8InjectedScriptHost::create(
|
||||
v8::Local<v8::Context> context, V8InspectorImpl* inspector) {
|
||||
v8::Isolate* isolate = inspector->isolate();
|
||||
v8::Local<v8::Object> injectedScriptHost = v8::Object::New(isolate);
|
||||
bool success = injectedScriptHost->SetPrototype(context, v8::Null(isolate))
|
||||
.FromMaybe(false);
|
||||
DCHECK(success);
|
||||
USE(success);
|
||||
v8::Local<v8::External> debuggerExternal =
|
||||
v8::External::New(isolate, inspector);
|
||||
setFunctionProperty(context, injectedScriptHost, "nullifyPrototype",
|
||||
V8InjectedScriptHost::nullifyPrototypeCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "getProperty",
|
||||
V8InjectedScriptHost::getPropertyCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "internalConstructorName",
|
||||
V8InjectedScriptHost::internalConstructorNameCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(
|
||||
context, injectedScriptHost, "formatAccessorsAsProperties",
|
||||
V8InjectedScriptHost::formatAccessorsAsProperties, debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "subtype",
|
||||
V8InjectedScriptHost::subtypeCallback, debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "getInternalProperties",
|
||||
V8InjectedScriptHost::getInternalPropertiesCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "objectHasOwnProperty",
|
||||
V8InjectedScriptHost::objectHasOwnPropertyCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "bind",
|
||||
V8InjectedScriptHost::bindCallback, debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "proxyTargetValue",
|
||||
V8InjectedScriptHost::proxyTargetValueCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "nativeAccessorDescriptor",
|
||||
V8InjectedScriptHost::nativeAccessorDescriptorCallback,
|
||||
debuggerExternal);
|
||||
setFunctionProperty(context, injectedScriptHost, "typedArrayProperties",
|
||||
V8InjectedScriptHost::typedArrayPropertiesCallback,
|
||||
debuggerExternal);
|
||||
createDataProperty(context, injectedScriptHost,
|
||||
toV8StringInternalized(isolate, "keys"),
|
||||
v8::debug::GetBuiltin(isolate, v8::debug::kObjectKeys));
|
||||
createDataProperty(
|
||||
context, injectedScriptHost,
|
||||
toV8StringInternalized(isolate, "getPrototypeOf"),
|
||||
v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetPrototypeOf));
|
||||
createDataProperty(
|
||||
context, injectedScriptHost,
|
||||
toV8StringInternalized(isolate, "getOwnPropertyDescriptor"),
|
||||
v8::debug::GetBuiltin(isolate,
|
||||
v8::debug::kObjectGetOwnPropertyDescriptor));
|
||||
createDataProperty(
|
||||
context, injectedScriptHost,
|
||||
toV8StringInternalized(isolate, "getOwnPropertyNames"),
|
||||
v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetOwnPropertyNames));
|
||||
createDataProperty(
|
||||
context, injectedScriptHost,
|
||||
toV8StringInternalized(isolate, "getOwnPropertySymbols"),
|
||||
v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetOwnPropertySymbols));
|
||||
return injectedScriptHost;
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::nullifyPrototypeCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
CHECK_EQ(1, info.Length());
|
||||
DCHECK(info[0]->IsObject());
|
||||
if (!info[0]->IsObject()) return;
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
info[0]
|
||||
.As<v8::Object>()
|
||||
->SetPrototype(isolate->GetCurrentContext(), v8::Null(isolate))
|
||||
.ToChecked();
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::getPropertyCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
CHECK(info.Length() == 2 && info[1]->IsString());
|
||||
if (!info[0]->IsObject()) return;
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
v8::Isolate::DisallowJavascriptExecutionScope throwJs(
|
||||
isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
|
||||
v8::Local<v8::Value> property;
|
||||
if (info[0]
|
||||
.As<v8::Object>()
|
||||
->Get(context, v8::Local<v8::String>::Cast(info[1]))
|
||||
.ToLocal(&property)) {
|
||||
info.GetReturnValue().Set(property);
|
||||
}
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::internalConstructorNameCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
if (info.Length() < 1 || !info[0]->IsObject()) return;
|
||||
|
||||
v8::Local<v8::Object> object = info[0].As<v8::Object>();
|
||||
info.GetReturnValue().Set(object->GetConstructorName());
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::formatAccessorsAsProperties(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
DCHECK_EQ(info.Length(), 2);
|
||||
info.GetReturnValue().Set(false);
|
||||
if (!info[1]->IsFunction()) return;
|
||||
// Check that function is user-defined.
|
||||
if (info[1].As<v8::Function>()->ScriptId() != v8::UnboundScript::kNoScriptId)
|
||||
return;
|
||||
info.GetReturnValue().Set(
|
||||
unwrapInspector(info)->client()->formatAccessorsAsProperties(info[0]));
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::subtypeCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
if (info.Length() < 1) return;
|
||||
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
v8::Local<v8::Value> value = info[0];
|
||||
if (value->IsObject()) {
|
||||
v8::Local<v8::Value> internalType = v8InternalValueTypeFrom(
|
||||
isolate->GetCurrentContext(), v8::Local<v8::Object>::Cast(value));
|
||||
if (internalType->IsString()) {
|
||||
info.GetReturnValue().Set(internalType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (value->IsArray() || value->IsArgumentsObject()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "array"));
|
||||
return;
|
||||
}
|
||||
if (value->IsTypedArray()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "typedarray"));
|
||||
return;
|
||||
}
|
||||
if (value->IsDate()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "date"));
|
||||
return;
|
||||
}
|
||||
if (value->IsRegExp()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "regexp"));
|
||||
return;
|
||||
}
|
||||
if (value->IsMap()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "map"));
|
||||
return;
|
||||
}
|
||||
if (value->IsWeakMap()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "weakmap"));
|
||||
return;
|
||||
}
|
||||
if (value->IsSet()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "set"));
|
||||
return;
|
||||
}
|
||||
if (value->IsWeakSet()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "weakset"));
|
||||
return;
|
||||
}
|
||||
if (value->IsMapIterator() || value->IsSetIterator()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "iterator"));
|
||||
return;
|
||||
}
|
||||
if (value->IsGeneratorObject()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "generator"));
|
||||
return;
|
||||
}
|
||||
if (value->IsNativeError()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "error"));
|
||||
return;
|
||||
}
|
||||
if (value->IsProxy()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "proxy"));
|
||||
return;
|
||||
}
|
||||
if (value->IsPromise()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "promise"));
|
||||
return;
|
||||
}
|
||||
if (value->IsArrayBuffer() || value->IsSharedArrayBuffer()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "arraybuffer"));
|
||||
return;
|
||||
}
|
||||
if (value->IsDataView()) {
|
||||
info.GetReturnValue().Set(toV8StringInternalized(isolate, "dataview"));
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<StringBuffer> subtype =
|
||||
unwrapInspector(info)->client()->valueSubtype(value);
|
||||
if (subtype) {
|
||||
info.GetReturnValue().Set(toV8String(isolate, subtype->string()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::getInternalPropertiesCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
if (info.Length() < 1) return;
|
||||
|
||||
std::unordered_set<String16> allowedProperties;
|
||||
if (info[0]->IsBooleanObject() || info[0]->IsNumberObject() ||
|
||||
info[0]->IsStringObject() || info[0]->IsSymbolObject() ||
|
||||
info[0]->IsBigIntObject()) {
|
||||
allowedProperties.insert(String16("[[PrimitiveValue]]"));
|
||||
} else if (info[0]->IsPromise()) {
|
||||
allowedProperties.insert(String16("[[PromiseStatus]]"));
|
||||
allowedProperties.insert(String16("[[PromiseValue]]"));
|
||||
} else if (info[0]->IsGeneratorObject()) {
|
||||
allowedProperties.insert(String16("[[GeneratorStatus]]"));
|
||||
} else if (info[0]->IsMap() || info[0]->IsWeakMap() || info[0]->IsSet() ||
|
||||
info[0]->IsWeakSet() || info[0]->IsMapIterator() ||
|
||||
info[0]->IsSetIterator()) {
|
||||
allowedProperties.insert(String16("[[Entries]]"));
|
||||
}
|
||||
if (!allowedProperties.size()) return;
|
||||
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
v8::Local<v8::Array> allProperties;
|
||||
if (!unwrapInspector(info)
|
||||
->debugger()
|
||||
->internalProperties(isolate->GetCurrentContext(), info[0])
|
||||
.ToLocal(&allProperties) ||
|
||||
!allProperties->IsArray() || allProperties->Length() % 2 != 0)
|
||||
return;
|
||||
|
||||
{
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
v8::Isolate::DisallowJavascriptExecutionScope throwJs(
|
||||
isolate,
|
||||
v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
|
||||
|
||||
v8::Local<v8::Array> properties = v8::Array::New(isolate);
|
||||
if (tryCatch.HasCaught()) return;
|
||||
|
||||
uint32_t outputIndex = 0;
|
||||
for (uint32_t i = 0; i < allProperties->Length(); i += 2) {
|
||||
v8::Local<v8::Value> key;
|
||||
if (!allProperties->Get(context, i).ToLocal(&key)) continue;
|
||||
if (tryCatch.HasCaught()) {
|
||||
tryCatch.Reset();
|
||||
continue;
|
||||
}
|
||||
String16 keyString = toProtocolStringWithTypeCheck(isolate, key);
|
||||
if (keyString.isEmpty() ||
|
||||
allowedProperties.find(keyString) == allowedProperties.end())
|
||||
continue;
|
||||
v8::Local<v8::Value> value;
|
||||
if (!allProperties->Get(context, i + 1).ToLocal(&value)) continue;
|
||||
if (tryCatch.HasCaught()) {
|
||||
tryCatch.Reset();
|
||||
continue;
|
||||
}
|
||||
createDataProperty(context, properties, outputIndex++, key);
|
||||
createDataProperty(context, properties, outputIndex++, value);
|
||||
}
|
||||
info.GetReturnValue().Set(properties);
|
||||
}
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::objectHasOwnPropertyCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
if (info.Length() < 2 || !info[0]->IsObject() || !info[1]->IsString()) return;
|
||||
bool result = info[0]
|
||||
.As<v8::Object>()
|
||||
->HasOwnProperty(info.GetIsolate()->GetCurrentContext(),
|
||||
v8::Local<v8::String>::Cast(info[1]))
|
||||
.FromMaybe(false);
|
||||
info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), result));
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::bindCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
if (info.Length() < 2 || !info[1]->IsString()) return;
|
||||
InjectedScript* injectedScript =
|
||||
InjectedScript::fromInjectedScriptHost(info.GetIsolate(), info.Holder());
|
||||
if (!injectedScript) return;
|
||||
|
||||
v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
|
||||
v8::Local<v8::String> v8groupName =
|
||||
info[1]->ToString(context).ToLocalChecked();
|
||||
String16 groupName =
|
||||
toProtocolStringWithTypeCheck(info.GetIsolate(), v8groupName);
|
||||
int id = injectedScript->bindObject(info[0], groupName);
|
||||
info.GetReturnValue().Set(id);
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::proxyTargetValueCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
if (info.Length() != 1 || !info[0]->IsProxy()) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
v8::Local<v8::Value> target = info[0].As<v8::Proxy>();
|
||||
while (target->IsProxy())
|
||||
target = v8::Local<v8::Proxy>::Cast(target)->GetTarget();
|
||||
info.GetReturnValue().Set(target);
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::nativeAccessorDescriptorCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
if (info.Length() != 2 || !info[0]->IsObject() || !info[1]->IsName()) {
|
||||
info.GetReturnValue().Set(v8::Undefined(isolate));
|
||||
return;
|
||||
}
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
int flags = v8::debug::GetNativeAccessorDescriptor(
|
||||
context, v8::Local<v8::Object>::Cast(info[0]),
|
||||
v8::Local<v8::Name>::Cast(info[1]));
|
||||
if (flags == static_cast<int>(v8::debug::NativeAccessorType::None)) {
|
||||
info.GetReturnValue().Set(v8::Undefined(isolate));
|
||||
return;
|
||||
}
|
||||
|
||||
bool isBuiltin =
|
||||
flags & static_cast<int>(v8::debug::NativeAccessorType::IsBuiltin);
|
||||
bool hasGetter =
|
||||
flags & static_cast<int>(v8::debug::NativeAccessorType::HasGetter);
|
||||
bool hasSetter =
|
||||
flags & static_cast<int>(v8::debug::NativeAccessorType::HasSetter);
|
||||
v8::Local<v8::Object> result = v8::Object::New(isolate);
|
||||
result->SetPrototype(context, v8::Null(isolate)).ToChecked();
|
||||
createDataProperty(context, result, toV8String(isolate, "isBuiltin"),
|
||||
v8::Boolean::New(isolate, isBuiltin));
|
||||
createDataProperty(context, result, toV8String(isolate, "hasGetter"),
|
||||
v8::Boolean::New(isolate, hasGetter));
|
||||
createDataProperty(context, result, toV8String(isolate, "hasSetter"),
|
||||
v8::Boolean::New(isolate, hasSetter));
|
||||
info.GetReturnValue().Set(result);
|
||||
}
|
||||
|
||||
void V8InjectedScriptHost::typedArrayPropertiesCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
if (info.Length() != 1 || !info[0]->IsArrayBuffer()) return;
|
||||
|
||||
v8::TryCatch tryCatch(isolate);
|
||||
v8::Isolate::DisallowJavascriptExecutionScope throwJs(
|
||||
isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
|
||||
v8::Local<v8::ArrayBuffer> arrayBuffer = info[0].As<v8::ArrayBuffer>();
|
||||
size_t length = arrayBuffer->ByteLength();
|
||||
if (length == 0) return;
|
||||
std::vector<v8::Local<v8::Value>> arrays_vector;
|
||||
addTypedArrayProperty<v8::Int8Array>(&arrays_vector, isolate, arrayBuffer,
|
||||
"[[Int8Array]]", length);
|
||||
addTypedArrayProperty<v8::Uint8Array>(&arrays_vector, isolate, arrayBuffer,
|
||||
"[[Uint8Array]]", length);
|
||||
|
||||
if (length % 2 == 0) {
|
||||
addTypedArrayProperty<v8::Int16Array>(&arrays_vector, isolate, arrayBuffer,
|
||||
"[[Int16Array]]", length / 2);
|
||||
}
|
||||
if (length % 4 == 0) {
|
||||
addTypedArrayProperty<v8::Int32Array>(&arrays_vector, isolate, arrayBuffer,
|
||||
"[[Int32Array]]", length / 4);
|
||||
}
|
||||
|
||||
if (tryCatch.HasCaught()) return;
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Array> arrays =
|
||||
v8::Array::New(isolate, static_cast<uint32_t>(arrays_vector.size()));
|
||||
for (uint32_t i = 0; i < static_cast<uint32_t>(arrays_vector.size()); i++)
|
||||
createDataProperty(context, arrays, i, arrays_vector[i]);
|
||||
if (tryCatch.HasCaught()) return;
|
||||
info.GetReturnValue().Set(arrays);
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
53
src/inspector/v8-injected-script-host.h
Normal file
53
src/inspector/v8-injected-script-host.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_INSPECTOR_V8_INJECTED_SCRIPT_HOST_H_
|
||||
#define V8_INSPECTOR_V8_INJECTED_SCRIPT_HOST_H_
|
||||
|
||||
#include "include/v8.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
class V8InspectorImpl;
|
||||
|
||||
// SECURITY NOTE: Although the InjectedScriptHost is intended for use solely by
|
||||
// the inspector,
|
||||
// a reference to the InjectedScriptHost may be leaked to the page being
|
||||
// inspected. Thus, the
|
||||
// InjectedScriptHost must never implemment methods that have more power over
|
||||
// the page than the
|
||||
// page already has itself (e.g. origin restriction bypasses).
|
||||
|
||||
class V8InjectedScriptHost {
|
||||
public:
|
||||
// We expect that debugger outlives any JS context and thus
|
||||
// V8InjectedScriptHost (owned by JS)
|
||||
// is destroyed before inspector.
|
||||
static v8::Local<v8::Object> create(v8::Local<v8::Context>, V8InspectorImpl*);
|
||||
|
||||
private:
|
||||
static void nullifyPrototypeCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void getPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void internalConstructorNameCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void formatAccessorsAsProperties(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void subtypeCallback(const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void getInternalPropertiesCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void objectHasOwnPropertyCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void bindCallback(const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void proxyTargetValueCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void nativeAccessorDescriptorCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
static void typedArrayPropertiesCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>&);
|
||||
};
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
#endif // V8_INSPECTOR_V8_INJECTED_SCRIPT_HOST_H_
|
@ -203,7 +203,12 @@ Response V8InspectorSessionImpl::findInjectedScript(
|
||||
if (!context) return Response::Error("Cannot find context with specified id");
|
||||
injectedScript = context->getInjectedScript(m_sessionId);
|
||||
if (!injectedScript) {
|
||||
injectedScript = context->createInjectedScript(m_sessionId);
|
||||
if (!context->createInjectedScript(m_sessionId)) {
|
||||
if (m_inspector->isolate()->IsExecutionTerminating())
|
||||
return Response::Error("Execution was terminated");
|
||||
return Response::Error("Cannot access specified execution context");
|
||||
}
|
||||
injectedScript = context->getInjectedScript(m_sessionId);
|
||||
if (m_customObjectFormatterEnabled)
|
||||
injectedScript->setCustomObjectFormatterEnabled(true);
|
||||
}
|
||||
@ -280,16 +285,14 @@ V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
|
||||
findInjectedScript(InspectedContext::contextId(context), injectedScript);
|
||||
if (!injectedScript) return nullptr;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> result;
|
||||
injectedScript->wrapObject(
|
||||
value, groupName,
|
||||
generatePreview ? WrapMode::kWithPreview : WrapMode::kNoPreview, &result);
|
||||
injectedScript->wrapObject(value, groupName, false, generatePreview, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>
|
||||
V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> table,
|
||||
v8::MaybeLocal<v8::Array> columns) {
|
||||
v8::Local<v8::Value> table,
|
||||
v8::Local<v8::Value> columns) {
|
||||
InjectedScript* injectedScript = nullptr;
|
||||
findInjectedScript(InspectedContext::contextId(context), injectedScript);
|
||||
if (!injectedScript) return nullptr;
|
||||
|
@ -55,8 +55,8 @@ class V8InspectorSessionImpl : public V8InspectorSession,
|
||||
v8::Local<v8::Context>, v8::Local<v8::Value>, const String16& groupName,
|
||||
bool generatePreview);
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapTable(
|
||||
v8::Local<v8::Context>, v8::Local<v8::Object> table,
|
||||
v8::MaybeLocal<v8::Array> columns);
|
||||
v8::Local<v8::Context>, v8::Local<v8::Value> table,
|
||||
v8::Local<v8::Value> columns);
|
||||
std::vector<std::unique_ptr<protocol::Schema::Domain>> supportedDomainsImpl();
|
||||
Response unwrapObject(const String16& objectId, v8::Local<v8::Value>*,
|
||||
v8::Local<v8::Context>*, String16* objectGroup);
|
||||
|
75
src/inspector/v8-internal-value-type.cc
Normal file
75
src/inspector/v8-internal-value-type.cc
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/inspector/v8-internal-value-type.h"
|
||||
|
||||
#include "src/inspector/string-util.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
namespace {
|
||||
|
||||
v8::Local<v8::Private> internalSubtypePrivate(v8::Isolate* isolate) {
|
||||
return v8::Private::ForApi(
|
||||
isolate,
|
||||
toV8StringInternalized(isolate, "V8InternalType#internalSubtype"));
|
||||
}
|
||||
|
||||
v8::Local<v8::String> subtypeForInternalType(v8::Isolate* isolate,
|
||||
V8InternalValueType type) {
|
||||
switch (type) {
|
||||
case V8InternalValueType::kEntry:
|
||||
return toV8StringInternalized(isolate, "internal#entry");
|
||||
case V8InternalValueType::kLocation:
|
||||
return toV8StringInternalized(isolate, "internal#location");
|
||||
case V8InternalValueType::kScope:
|
||||
return toV8StringInternalized(isolate, "internal#scope");
|
||||
case V8InternalValueType::kScopeList:
|
||||
return toV8StringInternalized(isolate, "internal#scopeList");
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool markAsInternal(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object, V8InternalValueType type) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Private> privateValue = internalSubtypePrivate(isolate);
|
||||
v8::Local<v8::String> subtype = subtypeForInternalType(isolate, type);
|
||||
return object->SetPrivate(context, privateValue, subtype).FromMaybe(false);
|
||||
}
|
||||
|
||||
bool markArrayEntriesAsInternal(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Array> array,
|
||||
V8InternalValueType type) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Private> privateValue = internalSubtypePrivate(isolate);
|
||||
v8::Local<v8::String> subtype = subtypeForInternalType(isolate, type);
|
||||
for (uint32_t i = 0; i < array->Length(); ++i) {
|
||||
v8::Local<v8::Value> entry;
|
||||
if (!array->Get(context, i).ToLocal(&entry) || !entry->IsObject())
|
||||
return false;
|
||||
if (!entry.As<v8::Object>()
|
||||
->SetPrivate(context, privateValue, subtype)
|
||||
.FromMaybe(false))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> v8InternalValueTypeFrom(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Private> privateValue = internalSubtypePrivate(isolate);
|
||||
if (!object->HasPrivate(context, privateValue).FromMaybe(false))
|
||||
return v8::Null(isolate);
|
||||
v8::Local<v8::Value> subtypeValue;
|
||||
if (!object->GetPrivate(context, privateValue).ToLocal(&subtypeValue) ||
|
||||
!subtypeValue->IsString())
|
||||
return v8::Null(isolate);
|
||||
return subtypeValue;
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
23
src/inspector/v8-internal-value-type.h
Normal file
23
src/inspector/v8-internal-value-type.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_INSPECTOR_V8_INTERNAL_VALUE_TYPE_H_
|
||||
#define V8_INSPECTOR_V8_INTERNAL_VALUE_TYPE_H_
|
||||
|
||||
#include "include/v8.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
enum class V8InternalValueType { kEntry, kLocation, kScope, kScopeList };
|
||||
|
||||
bool markAsInternal(v8::Local<v8::Context>, v8::Local<v8::Object>,
|
||||
V8InternalValueType);
|
||||
bool markArrayEntriesAsInternal(v8::Local<v8::Context>, v8::Local<v8::Array>,
|
||||
V8InternalValueType);
|
||||
v8::Local<v8::Value> v8InternalValueTypeFrom(v8::Local<v8::Context>,
|
||||
v8::Local<v8::Object>);
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
#endif // V8_INSPECTOR_V8_INTERNAL_VALUE_TYPE_H_
|
@ -90,14 +90,14 @@ template <typename ProtocolCallback>
|
||||
bool wrapEvaluateResultAsync(InjectedScript* injectedScript,
|
||||
v8::MaybeLocal<v8::Value> maybeResultValue,
|
||||
const v8::TryCatch& tryCatch,
|
||||
const String16& objectGroup, WrapMode wrapMode,
|
||||
ProtocolCallback* callback) {
|
||||
const String16& objectGroup, bool returnByValue,
|
||||
bool generatePreview, ProtocolCallback* callback) {
|
||||
std::unique_ptr<RemoteObject> result;
|
||||
Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
|
||||
|
||||
Response response = injectedScript->wrapEvaluateResult(
|
||||
maybeResultValue, tryCatch, objectGroup, wrapMode, &result,
|
||||
&exceptionDetails);
|
||||
maybeResultValue, tryCatch, objectGroup, returnByValue, generatePreview,
|
||||
&result, &exceptionDetails);
|
||||
if (response.isSuccess()) {
|
||||
callback->sendSuccess(std::move(result), std::move(exceptionDetails));
|
||||
return true;
|
||||
@ -110,8 +110,8 @@ void innerCallFunctionOn(
|
||||
V8InspectorSessionImpl* session, InjectedScript::Scope& scope,
|
||||
v8::Local<v8::Value> recv, const String16& expression,
|
||||
Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments,
|
||||
bool silent, WrapMode wrapMode, bool userGesture, bool awaitPromise,
|
||||
const String16& objectGroup,
|
||||
bool silent, bool returnByValue, bool generatePreview, bool userGesture,
|
||||
bool awaitPromise, const String16& objectGroup,
|
||||
std::unique_ptr<V8RuntimeAgentImpl::CallFunctionOnCallback> callback) {
|
||||
V8InspectorImpl* inspector = session->inspector();
|
||||
|
||||
@ -159,7 +159,7 @@ void innerCallFunctionOn(
|
||||
|
||||
if (scope.tryCatch().HasCaught()) {
|
||||
wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue,
|
||||
scope.tryCatch(), objectGroup, WrapMode::kNoPreview,
|
||||
scope.tryCatch(), objectGroup, false, false,
|
||||
callback.get());
|
||||
return;
|
||||
}
|
||||
@ -189,13 +189,13 @@ void innerCallFunctionOn(
|
||||
|
||||
if (!awaitPromise || scope.tryCatch().HasCaught()) {
|
||||
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
|
||||
scope.tryCatch(), objectGroup, wrapMode,
|
||||
callback.get());
|
||||
scope.tryCatch(), objectGroup, returnByValue,
|
||||
generatePreview, callback.get());
|
||||
return;
|
||||
}
|
||||
|
||||
scope.injectedScript()->addPromiseCallback(
|
||||
session, maybeResultValue, objectGroup, wrapMode,
|
||||
session, maybeResultValue, objectGroup, returnByValue, generatePreview,
|
||||
EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap(
|
||||
std::move(callback)));
|
||||
}
|
||||
@ -284,17 +284,16 @@ void V8RuntimeAgentImpl::evaluate(
|
||||
return;
|
||||
}
|
||||
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview;
|
||||
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
|
||||
if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
|
||||
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
|
||||
scope.tryCatch(), objectGroup.fromMaybe(""), mode,
|
||||
callback.get());
|
||||
scope.tryCatch(), objectGroup.fromMaybe(""),
|
||||
returnByValue.fromMaybe(false),
|
||||
generatePreview.fromMaybe(false), callback.get());
|
||||
return;
|
||||
}
|
||||
scope.injectedScript()->addPromiseCallback(
|
||||
m_session, maybeResultValue, objectGroup.fromMaybe(""), mode,
|
||||
m_session, maybeResultValue, objectGroup.fromMaybe(""),
|
||||
returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
|
||||
EvaluateCallbackWrapper<EvaluateCallback>::wrap(std::move(callback)));
|
||||
}
|
||||
|
||||
@ -313,11 +312,9 @@ void V8RuntimeAgentImpl::awaitPromise(
|
||||
Response::Error("Could not find promise with given id"));
|
||||
return;
|
||||
}
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview;
|
||||
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
|
||||
scope.injectedScript()->addPromiseCallback(
|
||||
m_session, scope.object(), scope.objectGroupName(), mode,
|
||||
m_session, scope.object(), scope.objectGroupName(),
|
||||
returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
|
||||
EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback)));
|
||||
}
|
||||
|
||||
@ -338,9 +335,6 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
"Either ObjectId or executionContextId must be specified"));
|
||||
return;
|
||||
}
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview;
|
||||
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
|
||||
if (objectId.isJust()) {
|
||||
InjectedScript::ObjectScope scope(m_session, objectId.fromJust());
|
||||
Response response = scope.initialize();
|
||||
@ -348,13 +342,14 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
innerCallFunctionOn(m_session, scope, scope.object(), expression,
|
||||
std::move(optionalArguments), silent.fromMaybe(false),
|
||||
mode, userGesture.fromMaybe(false),
|
||||
awaitPromise.fromMaybe(false),
|
||||
objectGroup.isJust() ? objectGroup.fromMaybe(String16())
|
||||
: scope.objectGroupName(),
|
||||
std::move(callback));
|
||||
innerCallFunctionOn(
|
||||
m_session, scope, scope.object(), expression,
|
||||
std::move(optionalArguments), silent.fromMaybe(false),
|
||||
returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
|
||||
userGesture.fromMaybe(false), awaitPromise.fromMaybe(false),
|
||||
objectGroup.isJust() ? objectGroup.fromMaybe(String16())
|
||||
: scope.objectGroupName(),
|
||||
std::move(callback));
|
||||
} else {
|
||||
int contextId = 0;
|
||||
Response response =
|
||||
@ -370,11 +365,12 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
innerCallFunctionOn(m_session, scope, scope.context()->Global(), expression,
|
||||
std::move(optionalArguments), silent.fromMaybe(false),
|
||||
mode, userGesture.fromMaybe(false),
|
||||
awaitPromise.fromMaybe(false),
|
||||
objectGroup.fromMaybe(""), std::move(callback));
|
||||
innerCallFunctionOn(
|
||||
m_session, scope, scope.context()->Global(), expression,
|
||||
std::move(optionalArguments), silent.fromMaybe(false),
|
||||
returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
|
||||
userGesture.fromMaybe(false), awaitPromise.fromMaybe(false),
|
||||
objectGroup.fromMaybe(""), std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,18 +397,40 @@ Response V8RuntimeAgentImpl::getProperties(
|
||||
v8::Local<v8::Object> object = scope.object().As<v8::Object>();
|
||||
response = scope.injectedScript()->getProperties(
|
||||
object, scope.objectGroupName(), ownProperties.fromMaybe(false),
|
||||
accessorPropertiesOnly.fromMaybe(false),
|
||||
generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview,
|
||||
accessorPropertiesOnly.fromMaybe(false), generatePreview.fromMaybe(false),
|
||||
result, exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false))
|
||||
return Response::OK();
|
||||
v8::Local<v8::Array> propertiesArray;
|
||||
if (!m_inspector->debugger()
|
||||
->internalProperties(scope.context(), scope.object())
|
||||
.ToLocal(&propertiesArray)) {
|
||||
return Response::InternalError();
|
||||
}
|
||||
std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>
|
||||
propertiesProtocolArray;
|
||||
response = scope.injectedScript()->getInternalProperties(
|
||||
object, scope.objectGroupName(), &propertiesProtocolArray);
|
||||
if (!response.isSuccess()) return response;
|
||||
propertiesProtocolArray =
|
||||
protocol::Array<InternalPropertyDescriptor>::create();
|
||||
for (uint32_t i = 0; i < propertiesArray->Length(); i += 2) {
|
||||
v8::Local<v8::Value> name;
|
||||
if (!propertiesArray->Get(scope.context(), i).ToLocal(&name) ||
|
||||
!name->IsString()) {
|
||||
return Response::InternalError();
|
||||
}
|
||||
v8::Local<v8::Value> value;
|
||||
if (!propertiesArray->Get(scope.context(), i + 1).ToLocal(&value))
|
||||
return Response::InternalError();
|
||||
std::unique_ptr<RemoteObject> wrappedValue;
|
||||
protocol::Response response = scope.injectedScript()->wrapObject(
|
||||
value, scope.objectGroupName(), false, false, &wrappedValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
propertiesProtocolArray->addItem(
|
||||
InternalPropertyDescriptor::create()
|
||||
.setName(
|
||||
toProtocolString(m_inspector->isolate(), name.As<v8::String>()))
|
||||
.setValue(std::move(wrappedValue))
|
||||
.build());
|
||||
}
|
||||
if (propertiesProtocolArray->length())
|
||||
*internalProperties = std::move(propertiesProtocolArray);
|
||||
return Response::OK();
|
||||
@ -481,7 +499,7 @@ Response V8RuntimeAgentImpl::compileScript(
|
||||
if (!isOk) {
|
||||
if (scope.tryCatch().HasCaught()) {
|
||||
response = scope.injectedScript()->createExceptionDetails(
|
||||
scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails);
|
||||
scope.tryCatch(), String16(), false, exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
return Response::OK();
|
||||
} else {
|
||||
@ -559,18 +577,17 @@ void V8RuntimeAgentImpl::runScript(
|
||||
return;
|
||||
}
|
||||
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview;
|
||||
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
|
||||
if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
|
||||
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
|
||||
scope.tryCatch(), objectGroup.fromMaybe(""), mode,
|
||||
callback.get());
|
||||
scope.tryCatch(), objectGroup.fromMaybe(""),
|
||||
returnByValue.fromMaybe(false),
|
||||
generatePreview.fromMaybe(false), callback.get());
|
||||
return;
|
||||
}
|
||||
scope.injectedScript()->addPromiseCallback(
|
||||
m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""),
|
||||
mode,
|
||||
m_session, maybeResultValue.ToLocalChecked(),
|
||||
objectGroup.fromMaybe(""), returnByValue.fromMaybe(false),
|
||||
generatePreview.fromMaybe(false),
|
||||
EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback)));
|
||||
}
|
||||
|
||||
@ -586,8 +603,8 @@ Response V8RuntimeAgentImpl::queryObjects(
|
||||
v8::Local<v8::Array> resultArray = m_inspector->debugger()->queryObjects(
|
||||
scope.context(), v8::Local<v8::Object>::Cast(scope.object()));
|
||||
return scope.injectedScript()->wrapObject(
|
||||
resultArray, objectGroup.fromMaybe(scope.objectGroupName()),
|
||||
WrapMode::kNoPreview, objects);
|
||||
resultArray, objectGroup.fromMaybe(scope.objectGroupName()), false, false,
|
||||
objects);
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::globalLexicalScopeNames(
|
||||
|
@ -6,6 +6,102 @@
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
namespace {
|
||||
|
||||
protocol::Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value, int maxDepth,
|
||||
std::unique_ptr<protocol::Value>* result) {
|
||||
using protocol::Response;
|
||||
if (value.IsEmpty()) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (!maxDepth) return Response::Error("Object reference chain is too long");
|
||||
maxDepth--;
|
||||
|
||||
if (value->IsNull() || value->IsUndefined()) {
|
||||
*result = protocol::Value::null();
|
||||
return Response::OK();
|
||||
}
|
||||
if (value->IsBoolean()) {
|
||||
*result =
|
||||
protocol::FundamentalValue::create(value.As<v8::Boolean>()->Value());
|
||||
return Response::OK();
|
||||
}
|
||||
if (value->IsNumber()) {
|
||||
double doubleValue = value.As<v8::Number>()->Value();
|
||||
int intValue = static_cast<int>(doubleValue);
|
||||
if (intValue == doubleValue) {
|
||||
*result = protocol::FundamentalValue::create(intValue);
|
||||
return Response::OK();
|
||||
}
|
||||
*result = protocol::FundamentalValue::create(doubleValue);
|
||||
return Response::OK();
|
||||
}
|
||||
if (value->IsString()) {
|
||||
*result = protocol::StringValue::create(
|
||||
toProtocolString(context->GetIsolate(), value.As<v8::String>()));
|
||||
return Response::OK();
|
||||
}
|
||||
if (value->IsArray()) {
|
||||
v8::Local<v8::Array> array = value.As<v8::Array>();
|
||||
std::unique_ptr<protocol::ListValue> inspectorArray =
|
||||
protocol::ListValue::create();
|
||||
uint32_t length = array->Length();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
v8::Local<v8::Value> value;
|
||||
if (!array->Get(context, i).ToLocal(&value))
|
||||
return Response::InternalError();
|
||||
std::unique_ptr<protocol::Value> element;
|
||||
Response response = toProtocolValue(context, value, maxDepth, &element);
|
||||
if (!response.isSuccess()) return response;
|
||||
inspectorArray->pushValue(std::move(element));
|
||||
}
|
||||
*result = std::move(inspectorArray);
|
||||
return Response::OK();
|
||||
}
|
||||
if (value->IsObject()) {
|
||||
std::unique_ptr<protocol::DictionaryValue> jsonObject =
|
||||
protocol::DictionaryValue::create();
|
||||
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value);
|
||||
v8::Local<v8::Array> propertyNames;
|
||||
if (!object->GetPropertyNames(context).ToLocal(&propertyNames))
|
||||
return Response::InternalError();
|
||||
uint32_t length = propertyNames->Length();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
v8::Local<v8::Value> name;
|
||||
if (!propertyNames->Get(context, i).ToLocal(&name))
|
||||
return Response::InternalError();
|
||||
// FIXME(yurys): v8::Object should support GetOwnPropertyNames
|
||||
if (name->IsString()) {
|
||||
v8::Maybe<bool> hasRealNamedProperty = object->HasRealNamedProperty(
|
||||
context, v8::Local<v8::String>::Cast(name));
|
||||
if (hasRealNamedProperty.IsNothing() ||
|
||||
!hasRealNamedProperty.FromJust())
|
||||
continue;
|
||||
}
|
||||
v8::Local<v8::String> propertyName;
|
||||
if (!name->ToString(context).ToLocal(&propertyName)) continue;
|
||||
v8::Local<v8::Value> property;
|
||||
if (!object->Get(context, name).ToLocal(&property))
|
||||
return Response::InternalError();
|
||||
if (property->IsUndefined()) continue;
|
||||
std::unique_ptr<protocol::Value> propertyValue;
|
||||
Response response =
|
||||
toProtocolValue(context, property, maxDepth, &propertyValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
jsonObject->setValue(
|
||||
toProtocolString(context->GetIsolate(), propertyName),
|
||||
std::move(propertyValue));
|
||||
}
|
||||
*result = std::move(jsonObject);
|
||||
return Response::OK();
|
||||
}
|
||||
return Response::Error("Object couldn't be returned by value");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object,
|
||||
v8::Local<v8::Name> key,
|
||||
@ -26,4 +122,11 @@ v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
|
||||
v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
|
||||
return array->CreateDataProperty(context, index, value);
|
||||
}
|
||||
|
||||
protocol::Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value,
|
||||
std::unique_ptr<protocol::Value>* result) {
|
||||
return toProtocolValue(context, value, 1000, result);
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
@ -18,6 +18,9 @@ v8::Maybe<bool> createDataProperty(v8::Local<v8::Context>,
|
||||
v8::Maybe<bool> createDataProperty(v8::Local<v8::Context>, v8::Local<v8::Array>,
|
||||
int index, v8::Local<v8::Value>);
|
||||
|
||||
protocol::Response toProtocolValue(v8::Local<v8::Context>, v8::Local<v8::Value>,
|
||||
std::unique_ptr<protocol::Value>* result);
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
#endif // V8_INSPECTOR_V8_VALUE_UTILS_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,79 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_INSPECTOR_VALUE_MIRROR_H_
|
||||
#define V8_INSPECTOR_VALUE_MIRROR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/inspector/protocol/Protocol.h"
|
||||
#include "src/inspector/protocol/Runtime.h"
|
||||
#include "src/inspector/string-16.h"
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
#include "include/v8.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
class ValueMirror;
|
||||
enum class WrapMode;
|
||||
|
||||
struct InternalPropertyMirror {
|
||||
String16 name;
|
||||
std::unique_ptr<ValueMirror> value;
|
||||
};
|
||||
|
||||
struct PropertyMirror {
|
||||
String16 name;
|
||||
bool writable;
|
||||
bool configurable;
|
||||
bool enumerable;
|
||||
bool isOwn;
|
||||
bool isIndex;
|
||||
std::unique_ptr<ValueMirror> value;
|
||||
std::unique_ptr<ValueMirror> getter;
|
||||
std::unique_ptr<ValueMirror> setter;
|
||||
std::unique_ptr<ValueMirror> symbol;
|
||||
std::unique_ptr<ValueMirror> exception;
|
||||
};
|
||||
|
||||
class ValueMirror {
|
||||
public:
|
||||
virtual ~ValueMirror();
|
||||
|
||||
static std::unique_ptr<ValueMirror> create(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value);
|
||||
virtual protocol::Response buildRemoteObject(
|
||||
v8::Local<v8::Context> context, WrapMode mode,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) = 0;
|
||||
virtual void buildPropertyPreview(
|
||||
v8::Local<v8::Context> context, const String16& name,
|
||||
std::unique_ptr<protocol::Runtime::PropertyPreview>*) {}
|
||||
virtual void buildObjectPreview(
|
||||
v8::Local<v8::Context> context, bool generatePreviewForProperties,
|
||||
int* nameLimit, int* indexLimit,
|
||||
std::unique_ptr<protocol::Runtime::ObjectPreview>*) {}
|
||||
virtual void buildEntryPreview(
|
||||
v8::Local<v8::Context> context, bool generatePreviewForProperties,
|
||||
int* nameLimit, int* indexLimit,
|
||||
std::unique_ptr<protocol::Runtime::ObjectPreview>*) {}
|
||||
virtual v8::Local<v8::Value> v8Value() = 0;
|
||||
|
||||
class PropertyAccumulator {
|
||||
public:
|
||||
virtual ~PropertyAccumulator() = default;
|
||||
virtual bool Add(PropertyMirror mirror) = 0;
|
||||
};
|
||||
static bool getProperties(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object, bool ownProperties,
|
||||
bool accessorPropertiesOnly,
|
||||
PropertyAccumulator* accumulator);
|
||||
static void getInternalProperties(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::Object> object,
|
||||
std::vector<InternalPropertyMirror>* mirrors);
|
||||
};
|
||||
} // namespace v8_inspector
|
||||
|
||||
#endif // V8_INSPECTOR_VALUE_MIRROR_H_
|
@ -44,6 +44,7 @@ v8_executable("inspector-test") {
|
||||
"sessions/",
|
||||
"testcfg.py",
|
||||
"type-profiler/",
|
||||
"../../src/inspector/injected-script-source.js",
|
||||
]
|
||||
|
||||
cflags = []
|
||||
|
@ -26,7 +26,18 @@ expression: Object(Symbol(42))
|
||||
{
|
||||
name : [[PrimitiveValue]]
|
||||
type : symbol
|
||||
value : Symbol(42)
|
||||
valuePreview : {
|
||||
description : Symbol
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
name : description
|
||||
type : string
|
||||
value : 42
|
||||
}
|
||||
]
|
||||
type : object
|
||||
}
|
||||
}
|
||||
|
||||
expression: Object(BigInt(2))
|
||||
|
@ -0,0 +1,2 @@
|
||||
Tests that stepping ignores injected script
|
||||
InjectedSciptSource was not reached
|
21
test/inspector/debugger/stepping-ignores-injected-script.js
Normal file
21
test/inspector/debugger/stepping-ignores-injected-script.js
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
let {session, contextGroup, Protocol} = InspectorTest.start('Tests that stepping ignores injected script');
|
||||
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
let url = session._scriptMap.get(message.params.callFrames[0].location.scriptId).url;
|
||||
if (url !== 'test.js') {
|
||||
InspectorTest.log('InjectedSciptSource on stack.');
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
Protocol.Debugger.stepInto();
|
||||
});
|
||||
|
||||
session.setupScriptMap();
|
||||
Protocol.Debugger.enable();
|
||||
Protocol.Debugger.pause();
|
||||
Protocol.Runtime.evaluate({expression: 'console.log(42)//# sourceURL=test.js'})
|
||||
.then(() => InspectorTest.log('InjectedSciptSource was not reached'))
|
||||
.then(InspectorTest.completeTest);
|
@ -0,0 +1,2 @@
|
||||
Tests that stepping does not ignore injected script when passed a flag
|
||||
InjectedSciptSource on stack.
|
@ -0,0 +1,22 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// Flags: --expose-inspector-scripts
|
||||
|
||||
let {session, contextGroup, Protocol} = InspectorTest.start('Tests that stepping does not ignore injected script when passed a flag');
|
||||
|
||||
Protocol.Debugger.onPaused(message => {
|
||||
let url = session._scriptMap.get(message.params.callFrames[0].location.scriptId).url;
|
||||
if (url !== 'test.js') {
|
||||
InspectorTest.log('InjectedSciptSource on stack.');
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
Protocol.Debugger.stepInto();
|
||||
});
|
||||
|
||||
session.setupScriptMap();
|
||||
Protocol.Debugger.enable();
|
||||
Protocol.Debugger.pause();
|
||||
Protocol.Runtime.evaluate({expression: 'console.log(42)//# sourceURL=test.js'})
|
||||
.then(() => InspectorTest.log('InjectedSciptSource was not reached'))
|
||||
.then(InspectorTest.completeTest);
|
@ -17,6 +17,8 @@
|
||||
|
||||
##############################################################################
|
||||
['system == android', {
|
||||
# https://crbug.com/v8/8160
|
||||
'debugger/stepping-with-exposed-injected-script': [FAIL],
|
||||
# https://crbug.com/v8/8197
|
||||
'debugger/get-possible-breakpoints-class-fields': [SKIP],
|
||||
}], # 'system == android'
|
||||
|
@ -176,6 +176,8 @@ InspectorTest.ContextGroup = class {
|
||||
|
||||
if (session) {
|
||||
InspectorTest.log('WARNING: setupInjectedScriptEnvironment with debug flag for debugging only and should not be landed.');
|
||||
InspectorTest.log('WARNING: run test with --expose-inspector-scripts flag to get more details.');
|
||||
InspectorTest.log('WARNING: you can additionally comment rjsmin in xxd.py to get unminified injected-script-source.js.');
|
||||
session.setupScriptMap();
|
||||
session.Protocol.Debugger.enable();
|
||||
session.Protocol.Debugger.onPaused(message => {
|
||||
|
@ -239,7 +239,6 @@ Checks console methods
|
||||
name : 0
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
overflow : false
|
||||
@ -263,7 +262,6 @@ Checks console methods
|
||||
name : 1
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
overflow : false
|
||||
@ -330,7 +328,6 @@ Checks console methods
|
||||
name : 0
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
overflow : false
|
||||
@ -349,7 +346,6 @@ Checks console methods
|
||||
name : 1
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
overflow : false
|
||||
|
@ -47,9 +47,8 @@ console.table
|
||||
name : 0
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -71,9 +70,8 @@ console.table
|
||||
name : 1
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -95,9 +93,8 @@ console.table
|
||||
name : 2
|
||||
subtype : array
|
||||
type : object
|
||||
value : Array(2)
|
||||
valuePreview : {
|
||||
description : Array(2)
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -126,9 +123,8 @@ console.table
|
||||
[0] : {
|
||||
name : 0
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -142,15 +138,15 @@ console.table
|
||||
value : Smith
|
||||
}
|
||||
]
|
||||
subtype : array
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : 1
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -164,15 +160,15 @@ console.table
|
||||
value : Doe
|
||||
}
|
||||
]
|
||||
subtype : array
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : 2
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -186,6 +182,7 @@ console.table
|
||||
value : Jones
|
||||
}
|
||||
]
|
||||
subtype : array
|
||||
type : object
|
||||
}
|
||||
}
|
||||
@ -200,9 +197,8 @@ console.table
|
||||
[0] : {
|
||||
name : mother
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Object
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -222,9 +218,8 @@ console.table
|
||||
[1] : {
|
||||
name : father
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Object
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -244,9 +239,8 @@ console.table
|
||||
[2] : {
|
||||
name : daughter
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Object
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -273,9 +267,8 @@ console.table
|
||||
[0] : {
|
||||
name : 0
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -284,15 +277,15 @@ console.table
|
||||
value : John
|
||||
}
|
||||
]
|
||||
subtype : array
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : 1
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -301,15 +294,15 @@ console.table
|
||||
value : Jane
|
||||
}
|
||||
]
|
||||
subtype : array
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : 2
|
||||
type : object
|
||||
value : Person
|
||||
valuePreview : {
|
||||
description : Person
|
||||
description : Array(3)
|
||||
overflow : false
|
||||
properties : [
|
||||
[0] : {
|
||||
@ -318,6 +311,7 @@ console.table
|
||||
value : Emily
|
||||
}
|
||||
]
|
||||
subtype : array
|
||||
type : object
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,10 @@ expression: (function* foo() { yield 1 })
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[1] : {
|
||||
name : [[FunctionLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -19,17 +23,13 @@ expression: (function* foo() { yield 1 })
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
[2] : {
|
||||
name : [[IsGenerator]]
|
||||
value : {
|
||||
type : boolean
|
||||
value : true
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[3] : {
|
||||
name : [[Scopes]]
|
||||
value : {
|
||||
@ -51,6 +51,10 @@ expression: (function foo() {})
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[1] : {
|
||||
name : [[FunctionLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -63,10 +67,6 @@ expression: (function foo() {})
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[2] : {
|
||||
name : [[Scopes]]
|
||||
value : {
|
||||
@ -242,6 +242,35 @@ expression: gen1
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[4] : {
|
||||
name : [[GeneratorLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -254,35 +283,6 @@ expression: gen1
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[4] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[5] : {
|
||||
name : [[Scopes]]
|
||||
value : {
|
||||
@ -302,6 +302,35 @@ expression: gen1.next();gen1
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[4] : {
|
||||
name : [[GeneratorLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -314,35 +343,6 @@ expression: gen1.next();gen1
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[4] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[5] : {
|
||||
name : [[Scopes]]
|
||||
value : {
|
||||
@ -362,6 +362,35 @@ expression: gen1.next();gen1
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : closed
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[4] : {
|
||||
name : [[GeneratorLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -374,35 +403,6 @@ expression: gen1.next();gen1
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : closed
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[4] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -414,6 +414,35 @@ expression: gen2
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[4] : {
|
||||
name : [[GeneratorLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -426,35 +455,6 @@ expression: gen2
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[4] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[5] : {
|
||||
name : [[Scopes]]
|
||||
value : {
|
||||
@ -474,6 +474,35 @@ expression: gen2.next();gen2
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[4] : {
|
||||
name : [[GeneratorLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -486,35 +515,6 @@ expression: gen2.next();gen2
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : suspended
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[4] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[5] : {
|
||||
name : [[Scopes]]
|
||||
value : {
|
||||
@ -534,6 +534,35 @@ expression: gen2.next();gen2
|
||||
result : {
|
||||
internalProperties : [
|
||||
[0] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : closed
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
[4] : {
|
||||
name : [[GeneratorLocation]]
|
||||
value : {
|
||||
description : Object
|
||||
@ -546,35 +575,6 @@ expression: gen2.next();gen2
|
||||
}
|
||||
}
|
||||
}
|
||||
[1] : {
|
||||
name : [[GeneratorStatus]]
|
||||
value : {
|
||||
type : string
|
||||
value : closed
|
||||
}
|
||||
}
|
||||
[2] : {
|
||||
name : [[GeneratorFunction]]
|
||||
value : {
|
||||
className : GeneratorFunction
|
||||
description : function* foo() { yield 1; }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
[3] : {
|
||||
name : [[GeneratorReceiver]]
|
||||
value : {
|
||||
className : global
|
||||
description : global
|
||||
objectId : <objectId>
|
||||
type : object
|
||||
}
|
||||
}
|
||||
[4] : {
|
||||
name : [[StableObjectId]]
|
||||
value : <StablectObjectId>
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -589,6 +589,8 @@ Running test: testMap
|
||||
objectId : <objectId>
|
||||
preview : {
|
||||
description : Map(0)
|
||||
entries : [
|
||||
]
|
||||
overflow : false
|
||||
properties : [
|
||||
]
|
||||
@ -816,6 +818,8 @@ Running test: testMap
|
||||
objectId : <objectId>
|
||||
preview : {
|
||||
description : MapIterator
|
||||
entries : [
|
||||
]
|
||||
overflow : false
|
||||
properties : [
|
||||
]
|
||||
@ -893,6 +897,8 @@ Running test: testMap
|
||||
objectId : <objectId>
|
||||
preview : {
|
||||
description : MapIterator
|
||||
entries : [
|
||||
]
|
||||
overflow : false
|
||||
properties : [
|
||||
]
|
||||
@ -1110,6 +1116,8 @@ Running test: testWeakMap
|
||||
objectId : <objectId>
|
||||
preview : {
|
||||
description : WeakMap
|
||||
entries : [
|
||||
]
|
||||
overflow : false
|
||||
properties : [
|
||||
]
|
||||
@ -1194,6 +1202,8 @@ Running test: testWeakSet
|
||||
objectId : <objectId>
|
||||
preview : {
|
||||
description : WeakSet
|
||||
entries : [
|
||||
]
|
||||
overflow : false
|
||||
properties : [
|
||||
]
|
||||
|
@ -1,11 +1,11 @@
|
||||
Runtime.getProperties for objects with accessor
|
||||
title property with getter and setter:
|
||||
{
|
||||
configurable : true
|
||||
enumerable : true
|
||||
configurable : false
|
||||
enumerable : false
|
||||
get : {
|
||||
className : Function
|
||||
description : function () { [native code] }
|
||||
description : function nativeGetter() { [native code] }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
@ -13,18 +13,18 @@ title property with getter and setter:
|
||||
name : title
|
||||
set : {
|
||||
className : Function
|
||||
description : function () { [native code] }
|
||||
description : function nativeSetter() { [native code] }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
}
|
||||
title property with getter only:
|
||||
{
|
||||
configurable : true
|
||||
enumerable : true
|
||||
configurable : false
|
||||
enumerable : false
|
||||
get : {
|
||||
className : Function
|
||||
description : function () { [native code] }
|
||||
description : function nativeGetter() { [native code] }
|
||||
objectId : <objectId>
|
||||
type : function
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ Terminate first evaluation (it forces injected-script-source compilation)
|
||||
{
|
||||
error : {
|
||||
code : -32000
|
||||
message : Execution was terminated
|
||||
message : Cannot access specified execution context
|
||||
}
|
||||
id : <messageId>
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ class TestCase(testcase.TestCase):
|
||||
|
||||
def _get_resources(self):
|
||||
return [
|
||||
os.path.join('src', 'inspector', 'injected-script-source.js'),
|
||||
os.path.join(
|
||||
'test', 'inspector', 'debugger', 'resources', 'break-locations.js'),
|
||||
]
|
||||
|
@ -412,15 +412,21 @@ class SourceProcessor(SourceFileProcessor):
|
||||
|
||||
IGNORE_COPYRIGHTS = ['box2d.js',
|
||||
'cpplint.py',
|
||||
'check_injected_script_source.py',
|
||||
'copy.js',
|
||||
'corrections.js',
|
||||
'crypto.js',
|
||||
'daemon.py',
|
||||
'debugger-script.js',
|
||||
'earley-boyer.js',
|
||||
'fannkuch.js',
|
||||
'fasta.js',
|
||||
'generate_protocol_externs.py',
|
||||
'injected-script.cc',
|
||||
'injected-script.h',
|
||||
'injected-script-source.js',
|
||||
'java-script-call-frame.cc',
|
||||
'java-script-call-frame.h',
|
||||
'jsmin.py',
|
||||
'libraries.cc',
|
||||
'libraries-empty.cc',
|
||||
@ -432,11 +438,14 @@ class SourceProcessor(SourceFileProcessor):
|
||||
'raytrace.js',
|
||||
'regexp-pcre.js',
|
||||
'resources-123.js',
|
||||
'rjsmin.py',
|
||||
'sqlite.js',
|
||||
'sqlite-change-heap.js',
|
||||
'sqlite-pointer-masking.js',
|
||||
'sqlite-safe-heap.js',
|
||||
'v8-debugger-script.h',
|
||||
'v8-function-call.cc',
|
||||
'v8-function-call.h',
|
||||
'v8-inspector-impl.cc',
|
||||
'v8-inspector-impl.h',
|
||||
'v8-runtime-agent-impl.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user