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:
Clemens Hammacher 2018-10-30 17:04:42 +00:00 committed by Commit Bot
parent 3a85e0c602
commit 192bee6bac
57 changed files with 3733 additions and 2692 deletions

View File

@ -1937,8 +1937,6 @@ v8_source_set("v8_base") {
"src/debug/debug-frames.cc", "src/debug/debug-frames.cc",
"src/debug/debug-frames.h", "src/debug/debug-frames.h",
"src/debug/debug-interface.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.cc",
"src/debug/debug-scope-iterator.h", "src/debug/debug-scope-iterator.h",
"src/debug/debug-scopes.cc", "src/debug/debug-scopes.cc",

11
DEPS
View File

@ -245,6 +245,17 @@ hooks = [
'-s', 'v8/test/wasm-spec-tests/tests.tar.gz.sha1', '-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', 'name': 'sysroot_arm',
'pattern': '.', 'pattern': '.',

View File

@ -9556,8 +9556,20 @@ Local<Function> debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) {
i::HandleScope handle_scope(isolate); i::HandleScope handle_scope(isolate);
i::Builtins::Name builtin_id; i::Builtins::Name builtin_id;
switch (builtin) { switch (builtin) {
case kStringToLowerCase: case kObjectKeys:
builtin_id = i::Builtins::kStringPrototypeToLocaleLowerCase; 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; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -9565,11 +9577,10 @@ Local<Function> debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) {
i::Handle<i::String> name = isolate->factory()->empty_string(); i::Handle<i::String> name = isolate->factory()->empty_string();
i::NewFunctionArgs args = i::NewFunctionArgs::ForBuiltinWithoutPrototype( 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); i::Handle<i::JSFunction> fun = isolate->factory()->NewFunction(args);
fun->shared()->set_internal_formal_parameter_count(0); fun->shared()->DontAdaptArguments();
fun->shared()->set_length(0);
return Utils::ToLocal(handle_scope.CloseAndEscape(fun)); 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)); 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) { int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) {
return reinterpret_cast<i::Isolate*>(v8_isolate) return reinterpret_cast<i::Isolate*>(v8_isolate)
->random_number_generator() ->random_number_generator()

View File

@ -193,7 +193,13 @@ void ResetBlackboxedStateCache(Isolate* isolate,
int EstimatedValueSize(Isolate* isolate, v8::Local<v8::Value> value); 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); Local<Function> GetBuiltin(Isolate* isolate, Builtin builtin);
@ -468,9 +474,14 @@ void SetReturnValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
enum class NativeAccessorType { enum class NativeAccessorType {
None = 0, None = 0,
HasGetter = 1 << 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); int64_t GetNextRandomInt64(v8::Isolate* isolate);
v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate, v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
@ -507,39 +518,6 @@ class WeakMap : public v8::Object {
private: private:
WeakMap(); 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 debug
} // namespace v8 } // namespace v8

View File

@ -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

View File

@ -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_

View File

@ -61,6 +61,22 @@ inspector_protocol_generate("protocol_generated_sources") {
outputs = _protocol_generated 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") { config("inspector_config") {
visibility = [ ":*" ] # Only targets in this file can depend on this. visibility = [ ":*" ] # Only targets in this file can depend on this.
if (is_component_build) { if (is_component_build) {
@ -70,6 +86,7 @@ config("inspector_config") {
v8_source_set("inspector") { v8_source_set("inspector") {
deps = [ deps = [
":inspector_injected_script",
":protocol_generated_sources", ":protocol_generated_sources",
] ]
configs = [ ":inspector_config" ] configs = [ ":inspector_config" ]
@ -84,6 +101,7 @@ v8_source_set("inspector") {
"../../include/v8-inspector-protocol.h", "../../include/v8-inspector-protocol.h",
"../../include/v8-inspector.h", "../../include/v8-inspector.h",
] ]
sources += get_target_outputs(":inspector_injected_script")
sources += [ sources += [
"custom-preview.cc", "custom-preview.cc",
"custom-preview.h", "custom-preview.h",
@ -113,12 +131,18 @@ v8_source_set("inspector") {
"v8-debugger-script.h", "v8-debugger-script.h",
"v8-debugger.cc", "v8-debugger.cc",
"v8-debugger.h", "v8-debugger.h",
"v8-function-call.cc",
"v8-function-call.h",
"v8-heap-profiler-agent-impl.cc", "v8-heap-profiler-agent-impl.cc",
"v8-heap-profiler-agent-impl.h", "v8-heap-profiler-agent-impl.h",
"v8-injected-script-host.cc",
"v8-injected-script-host.h",
"v8-inspector-impl.cc", "v8-inspector-impl.cc",
"v8-inspector-impl.h", "v8-inspector-impl.h",
"v8-inspector-session-impl.cc", "v8-inspector-session-impl.cc",
"v8-inspector-session-impl.h", "v8-inspector-session-impl.h",
"v8-internal-value-type.cc",
"v8-internal-value-type.h",
"v8-profiler-agent-impl.cc", "v8-profiler-agent-impl.cc",
"v8-profiler-agent-impl.h", "v8-profiler-agent-impl.h",
"v8-regex.cc", "v8-regex.cc",
@ -131,8 +155,6 @@ v8_source_set("inspector") {
"v8-stack-trace-impl.h", "v8-stack-trace-impl.h",
"v8-value-utils.cc", "v8-value-utils.cc",
"v8-value-utils.h", "v8-value-utils.h",
"value-mirror.cc",
"value-mirror.h",
"wasm-translation.cc", "wasm-translation.cc",
"wasm-translation.h", "wasm-translation.h",
] ]

View 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

View 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))

View File

@ -0,0 +1 @@
69937d3c239ca63e4c9045718886ddd096ffc054

View 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)

View 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
View 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()))

View 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())

View File

@ -113,7 +113,7 @@ bool substituteObjectTags(int sessionId, const String16& groupName,
} }
std::unique_ptr<protocol::Runtime::RemoteObject> wrapper; std::unique_ptr<protocol::Runtime::RemoteObject> wrapper;
protocol::Response response = protocol::Response response =
injectedScript->wrapObject(originValue, groupName, WrapMode::kNoPreview, injectedScript->wrapObject(originValue, groupName, false, false,
configValue, maxDepth - 1, &wrapper); configValue, maxDepth - 1, &wrapper);
if (!response.isSuccess() || !wrapper) { if (!response.isSuccess() || !wrapper) {
reportError(context, tryCatch, "cannot wrap value"); 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"); reportError(context, tryCatch, "cannot find context with specified id");
return; return;
} }
(*preview)->setBodyGetterId( (*preview)->setBodyGetterId(String16::concat(
injectedScript->bindObject(bodyFunction, groupName)); "{\"injectedScriptId\":",
String16::fromInteger(InspectedContext::contextId(context)),
",\"id\":",
String16::fromInteger(
injectedScript->bindObject(bodyFunction, groupName)),
"}"));
} }
return; return;
} }

File diff suppressed because it is too large Load Diff

View File

@ -30,9 +30,6 @@
#include "src/inspector/injected-script.h" #include "src/inspector/injected-script.h"
#include <cmath>
#include <unordered_set>
#include "src/inspector/custom-preview.h" #include "src/inspector/custom-preview.h"
#include "src/inspector/injected-script-source.h" #include "src/inspector/injected-script-source.h"
#include "src/inspector/inspected-context.h" #include "src/inspector/inspected-context.h"
@ -40,17 +37,19 @@
#include "src/inspector/remote-object-id.h" #include "src/inspector/remote-object-id.h"
#include "src/inspector/string-util.h" #include "src/inspector/string-util.h"
#include "src/inspector/v8-console.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-impl.h"
#include "src/inspector/v8-inspector-session-impl.h" #include "src/inspector/v8-inspector-session-impl.h"
#include "src/inspector/v8-stack-trace-impl.h" #include "src/inspector/v8-stack-trace-impl.h"
#include "src/inspector/v8-value-utils.h" #include "src/inspector/v8-value-utils.h"
#include "src/inspector/value-mirror.h"
#include "include/v8-inspector.h" #include "include/v8-inspector.h"
namespace v8_inspector { namespace v8_inspector {
namespace { namespace {
static const char privateKeyName[] = "v8-inspector#injectedScript";
static const char kGlobalHandleLabel[] = "DevTools console"; static const char kGlobalHandleLabel[] = "DevTools console";
static bool isResolvableNumberLike(String16 query) { static bool isResolvableNumberLike(String16 query) {
return query == "Infinity" || query == "-Infinity" || query == "NaN"; return query == "Infinity" || query == "-Infinity" || query == "NaN";
@ -68,7 +67,8 @@ class InjectedScript::ProtocolPromiseHandler {
static bool add(V8InspectorSessionImpl* session, static bool add(V8InspectorSessionImpl* session,
v8::Local<v8::Context> context, v8::Local<v8::Value> value, v8::Local<v8::Context> context, v8::Local<v8::Value> value,
int executionContextId, const String16& objectGroup, int executionContextId, const String16& objectGroup,
WrapMode wrapMode, EvaluateCallback* callback) { bool returnByValue, bool generatePreview,
EvaluateCallback* callback) {
v8::Local<v8::Promise::Resolver> resolver; v8::Local<v8::Promise::Resolver> resolver;
if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) { if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
callback->sendFailure(Response::InternalError()); callback->sendFailure(Response::InternalError());
@ -81,8 +81,9 @@ class InjectedScript::ProtocolPromiseHandler {
v8::Local<v8::Promise> promise = resolver->GetPromise(); v8::Local<v8::Promise> promise = resolver->GetPromise();
V8InspectorImpl* inspector = session->inspector(); V8InspectorImpl* inspector = session->inspector();
ProtocolPromiseHandler* handler = new ProtocolPromiseHandler( ProtocolPromiseHandler* handler =
session, executionContextId, objectGroup, wrapMode, callback); new ProtocolPromiseHandler(session, executionContextId, objectGroup,
returnByValue, generatePreview, callback);
v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate()); v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
v8::Local<v8::Function> thenCallbackFunction = v8::Local<v8::Function> thenCallbackFunction =
v8::Function::New(context, thenCallback, wrapper, 0, v8::Function::New(context, thenCallback, wrapper, 0,
@ -130,13 +131,15 @@ class InjectedScript::ProtocolPromiseHandler {
ProtocolPromiseHandler(V8InspectorSessionImpl* session, ProtocolPromiseHandler(V8InspectorSessionImpl* session,
int executionContextId, const String16& objectGroup, int executionContextId, const String16& objectGroup,
WrapMode wrapMode, EvaluateCallback* callback) bool returnByValue, bool generatePreview,
EvaluateCallback* callback)
: m_inspector(session->inspector()), : m_inspector(session->inspector()),
m_sessionId(session->sessionId()), m_sessionId(session->sessionId()),
m_contextGroupId(session->contextGroupId()), m_contextGroupId(session->contextGroupId()),
m_executionContextId(executionContextId), m_executionContextId(executionContextId),
m_objectGroup(objectGroup), m_objectGroup(objectGroup),
m_wrapMode(wrapMode), m_returnByValue(returnByValue),
m_generatePreview(generatePreview),
m_callback(std::move(callback)), m_callback(std::move(callback)),
m_wrapper(m_inspector->isolate(), m_wrapper(m_inspector->isolate(),
v8::External::New(m_inspector->isolate(), this)) { v8::External::New(m_inspector->isolate(), this)) {
@ -168,8 +171,9 @@ class InjectedScript::ProtocolPromiseHandler {
scope.injectedScript()->takeEvaluateCallback(m_callback); scope.injectedScript()->takeEvaluateCallback(m_callback);
if (!callback) return; if (!callback) return;
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue; std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
response = scope.injectedScript()->wrapObject(result, m_objectGroup, response = scope.injectedScript()->wrapObject(
m_wrapMode, &wrappedValue); result, m_objectGroup, m_returnByValue, m_generatePreview,
&wrappedValue);
if (!response.isSuccess()) { if (!response.isSuccess()) {
callback->sendFailure(response); callback->sendFailure(response);
return; return;
@ -189,8 +193,9 @@ class InjectedScript::ProtocolPromiseHandler {
scope.injectedScript()->takeEvaluateCallback(m_callback); scope.injectedScript()->takeEvaluateCallback(m_callback);
if (!callback) return; if (!callback) return;
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue; std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
response = scope.injectedScript()->wrapObject(result, m_objectGroup, response = scope.injectedScript()->wrapObject(
m_wrapMode, &wrappedValue); result, m_objectGroup, m_returnByValue, m_generatePreview,
&wrappedValue);
if (!response.isSuccess()) { if (!response.isSuccess()) {
callback->sendFailure(response); callback->sendFailure(response);
return; return;
@ -248,127 +253,116 @@ class InjectedScript::ProtocolPromiseHandler {
int m_contextGroupId; int m_contextGroupId;
int m_executionContextId; int m_executionContextId;
String16 m_objectGroup; String16 m_objectGroup;
WrapMode m_wrapMode; bool m_returnByValue;
bool m_generatePreview;
EvaluateCallback* m_callback; EvaluateCallback* m_callback;
v8::Global<v8::External> m_wrapper; v8::Global<v8::External> m_wrapper;
}; };
InjectedScript::InjectedScript(InspectedContext* context, int sessionId) std::unique_ptr<InjectedScript> InjectedScript::create(
: m_context(context), m_sessionId(sessionId) {} 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(); } 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( Response InjectedScript::getProperties(
v8::Local<v8::Object> object, const String16& groupName, bool ownProperties, v8::Local<v8::Object> object, const String16& groupName, bool ownProperties,
bool accessorPropertiesOnly, WrapMode wrapMode, bool accessorPropertiesOnly, bool generatePreview,
std::unique_ptr<Array<PropertyDescriptor>>* properties, std::unique_ptr<Array<PropertyDescriptor>>* properties,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
v8::HandleScope handles(m_context->isolate()); v8::HandleScope handles(m_context->isolate());
v8::Local<v8::Context> context = m_context->context(); v8::Local<v8::Context> context = m_context->context();
v8::Isolate* isolate = m_context->isolate(); V8FunctionCall function(m_context->inspector(), m_context->context(),
v8::TryCatch tryCatch(isolate); v8Value(), "getProperties");
function.appendArgument(object);
function.appendArgument(groupName);
function.appendArgument(ownProperties);
function.appendArgument(accessorPropertiesOnly);
function.appendArgument(generatePreview);
*properties = Array<PropertyDescriptor>::create(); v8::TryCatch tryCatch(m_context->isolate());
std::vector<PropertyMirror> mirrors; v8::Local<v8::Value> resultValue = function.callWithoutExceptionHandling();
PropertyAccumulator accumulator(&mirrors); if (tryCatch.HasCaught()) {
if (!ValueMirror::getProperties(context, object, ownProperties, Response response = createExceptionDetails(
accessorPropertiesOnly, &accumulator)) { tryCatch, groupName, generatePreview, exceptionDetails);
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);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
bindRemoteObjectIfNeeded(wrappers[i].value->v8Value(), groupName, // FIXME: make properties optional
remoteObject.get()); *properties = Array<PropertyDescriptor>::create();
(*result)->addItem(InternalPropertyDescriptor::create() return Response::OK();
.setName(wrappers[i].name)
.setValue(std::move(remoteObject))
.build());
} }
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(); return Response::OK();
} }
@ -385,25 +379,37 @@ void InjectedScript::releaseObject(const String16& objectId) {
} }
Response InjectedScript::wrapObject( Response InjectedScript::wrapObject(
v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode, v8::Local<v8::Value> value, const String16& groupName, bool forceValueType,
std::unique_ptr<protocol::Runtime::RemoteObject>* result) { bool generatePreview,
return wrapObject(value, groupName, wrapMode, v8::MaybeLocal<v8::Value>(), std::unique_ptr<protocol::Runtime::RemoteObject>* result) const {
kMaxCustomPreviewDepth, result); return wrapObject(value, groupName, forceValueType, generatePreview,
v8::MaybeLocal<v8::Value>(), kMaxCustomPreviewDepth,
result);
} }
Response InjectedScript::wrapObject( Response InjectedScript::wrapObject(
v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode, v8::Local<v8::Value> value, const String16& groupName, bool forceValueType,
v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth, bool generatePreview, v8::MaybeLocal<v8::Value> customPreviewConfig,
std::unique_ptr<protocol::Runtime::RemoteObject>* result) { 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::Local<v8::Context> context = m_context->context();
v8::Context::Scope contextScope(context);
int customPreviewEnabled = m_customPreviewEnabled; int customPreviewEnabled = m_customPreviewEnabled;
int sessionId = m_sessionId; int sessionId = m_sessionId;
auto obj = ValueMirror::create(m_context->context(), value);
if (!obj) return Response::InternalError(); Response response = wrapValue(value, groupName, forceValueType,
Response response = obj->buildRemoteObject(context, wrapMode, result); generatePreview, &wrappedObject);
if (!response.isSuccess()) return response; 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()) { if (customPreviewEnabled && value->IsObject()) {
std::unique_ptr<protocol::Runtime::CustomPreview> customPreview; std::unique_ptr<protocol::Runtime::CustomPreview> customPreview;
generateCustomPreview(sessionId, groupName, context, value.As<v8::Object>(), generateCustomPreview(sessionId, groupName, context, value.As<v8::Object>(),
@ -414,65 +420,47 @@ Response InjectedScript::wrapObject(
return Response::OK(); 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( std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
v8::Local<v8::Object> table, v8::MaybeLocal<v8::Array> maybeColumns) { v8::Local<v8::Value> table, v8::Local<v8::Value> columns) const {
using protocol::Runtime::RemoteObject; v8::HandleScope handles(m_context->isolate());
using protocol::Runtime::ObjectPreview;
using protocol::Runtime::PropertyPreview;
using protocol::Array;
v8::Isolate* isolate = m_context->isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = m_context->context(); v8::Local<v8::Context> context = m_context->context();
V8FunctionCall function(m_context->inspector(), context, v8Value(),
std::unique_ptr<RemoteObject> remoteObject; "wrapTable");
Response response = function.appendArgument(table);
wrapObject(table, "console", WrapMode::kNoPreview, &remoteObject); if (columns.IsEmpty())
if (!remoteObject || !response.isSuccess()) return nullptr; function.appendArgument(false);
else
auto mirror = ValueMirror::create(context, table); function.appendArgument(columns);
std::unique_ptr<ObjectPreview> preview; bool hadException = false;
int limit = 100; v8::Local<v8::Value> r = function.call(hadException);
mirror->buildObjectPreview(context, true /* generatePreviewForProperties */, if (hadException || r.IsEmpty()) return nullptr;
&limit, &limit, &preview); std::unique_ptr<protocol::Value> protocolValue;
Response response = toProtocolValue(context, r, &protocolValue);
Array<PropertyPreview>* columns = preview->getProperties(); if (!response.isSuccess()) return nullptr;
std::unordered_set<String16> selectedColumns; protocol::ErrorSupport errors;
v8::Local<v8::Array> v8Columns; return protocol::Runtime::RemoteObject::fromValue(protocolValue.get(),
if (maybeColumns.ToLocal(&v8Columns)) { &errors);
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;
} }
void InjectedScript::addPromiseCallback( void InjectedScript::addPromiseCallback(
V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value, V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, bool returnByValue, bool generatePreview,
std::unique_ptr<EvaluateCallback> callback) { std::unique_ptr<EvaluateCallback> callback) {
if (value.IsEmpty()) { if (value.IsEmpty()) {
callback->sendFailure(Response::InternalError()); callback->sendFailure(Response::InternalError());
@ -482,7 +470,8 @@ void InjectedScript::addPromiseCallback(
v8::MicrotasksScope::kRunMicrotasks); v8::MicrotasksScope::kRunMicrotasks);
if (ProtocolPromiseHandler::add( if (ProtocolPromiseHandler::add(
session, m_context->context(), value.ToLocalChecked(), 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()); m_evaluateCallbacks.insert(callback.release());
} }
} }
@ -532,6 +521,10 @@ void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) {
m_customPreviewEnabled = 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 { v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const {
if (m_lastEvaluationResult.IsEmpty()) if (m_lastEvaluationResult.IsEmpty())
return v8::Undefined(m_context->isolate()); return v8::Undefined(m_context->isolate());
@ -583,7 +576,7 @@ Response InjectedScript::resolveCallArgument(
Response InjectedScript::createExceptionDetails( Response InjectedScript::createExceptionDetails(
const v8::TryCatch& tryCatch, const String16& objectGroup, 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(); if (!tryCatch.HasCaught()) return Response::InternalError();
v8::Local<v8::Message> message = tryCatch.Message(); v8::Local<v8::Message> message = tryCatch.Message();
v8::Local<v8::Value> exception = tryCatch.Exception(); v8::Local<v8::Value> exception = tryCatch.Exception();
@ -619,10 +612,8 @@ Response InjectedScript::createExceptionDetails(
if (!exception.IsEmpty()) { if (!exception.IsEmpty()) {
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped; std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
Response response = Response response =
wrapObject(exception, objectGroup, wrapObject(exception, objectGroup, false /* forceValueType */,
exception->IsNativeError() ? WrapMode::kNoPreview generatePreview && !exception->IsNativeError(), &wrapped);
: WrapMode::kWithPreview,
&wrapped);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
exceptionDetails->setException(std::move(wrapped)); exceptionDetails->setException(std::move(wrapped));
} }
@ -632,14 +623,15 @@ Response InjectedScript::createExceptionDetails(
Response InjectedScript::wrapEvaluateResult( Response InjectedScript::wrapEvaluateResult(
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch, 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, std::unique_ptr<protocol::Runtime::RemoteObject>* result,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
v8::Local<v8::Value> resultValue; v8::Local<v8::Value> resultValue;
if (!tryCatch.HasCaught()) { if (!tryCatch.HasCaught()) {
if (!maybeResultValue.ToLocal(&resultValue)) if (!maybeResultValue.ToLocal(&resultValue))
return Response::InternalError(); return Response::InternalError();
Response response = wrapObject(resultValue, objectGroup, wrapMode, result); Response response = wrapObject(resultValue, objectGroup, returnByValue,
generatePreview, result);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
if (objectGroup == "console") { if (objectGroup == "console") {
m_lastEvaluationResult.Reset(m_context->isolate(), resultValue); m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
@ -651,14 +643,12 @@ Response InjectedScript::wrapEvaluateResult(
} }
v8::Local<v8::Value> exception = tryCatch.Exception(); v8::Local<v8::Value> exception = tryCatch.Exception();
Response response = Response response =
wrapObject(exception, objectGroup, wrapObject(exception, objectGroup, false,
exception->IsNativeError() ? WrapMode::kNoPreview generatePreview && !exception->IsNativeError(), result);
: WrapMode::kWithPreview,
result);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
// We send exception in result for compatibility reasons, even though it's // We send exception in result for compatibility reasons, even though it's
// accessible through exceptionDetails.exception. // accessible through exceptionDetails.exception.
response = createExceptionDetails(tryCatch, objectGroup, wrapMode, response = createExceptionDetails(tryCatch, objectGroup, generatePreview,
exceptionDetails); exceptionDetails);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
} }
@ -807,31 +797,33 @@ Response InjectedScript::CallFrameScope::findInjectedScript(
return session->findInjectedScript(remoteId.get(), m_injectedScript); return session->findInjectedScript(remoteId.get(), m_injectedScript);
} }
String16 InjectedScript::bindObject(v8::Local<v8::Value> value, InjectedScript* InjectedScript::fromInjectedScriptHost(
const String16& groupName) { 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; if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1;
int id = m_lastBoundObjectId++; int id = m_lastBoundObjectId++;
m_idToWrappedObject[id].Reset(m_context->isolate(), value); m_idToWrappedObject[id].Reset(m_context->isolate(), value);
m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel); m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel);
if (!groupName.isEmpty() && id > 0) { if (!groupName.isEmpty() && id > 0) {
m_idToObjectGroupName[id] = groupName; m_idToObjectGroupName[id] = groupName;
m_nameToObjectGroup[groupName].push_back(id); m_nameToObjectGroup[groupName].push_back(id);
} }
// TODO(dgozman): get rid of "injectedScript" notion. return id;
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));
}
} }
void InjectedScript::unbindObject(int id) { void InjectedScript::unbindObject(int id) {

View File

@ -46,9 +46,9 @@
namespace v8_inspector { namespace v8_inspector {
class RemoteObjectId; class RemoteObjectId;
class V8FunctionCall;
class V8InspectorImpl; class V8InspectorImpl;
class V8InspectorSessionImpl; class V8InspectorSessionImpl;
enum class WrapMode;
using protocol::Maybe; using protocol::Maybe;
using protocol::Response; using protocol::Response;
@ -65,40 +65,38 @@ class EvaluateCallback {
class InjectedScript final { class InjectedScript final {
public: public:
InjectedScript(InspectedContext*, int sessionId); static std::unique_ptr<InjectedScript> create(InspectedContext*,
int sessionId);
~InjectedScript(); ~InjectedScript();
static InjectedScript* fromInjectedScriptHost(v8::Isolate* isolate,
v8::Local<v8::Object>);
InspectedContext* context() const { return m_context; } InspectedContext* context() const { return m_context; }
Response getProperties( Response getProperties(
v8::Local<v8::Object>, const String16& groupName, bool ownProperties, 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>>* std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
result, result,
Maybe<protocol::Runtime::ExceptionDetails>*); 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); void releaseObject(const String16& objectId);
Response wrapObject(v8::Local<v8::Value>, const String16& groupName, Response wrapObject(
WrapMode wrapMode, v8::Local<v8::Value>, const String16& groupName, bool forceValueType,
std::unique_ptr<protocol::Runtime::RemoteObject>* result); bool generatePreview,
Response wrapObject(v8::Local<v8::Value>, const String16& groupName, std::unique_ptr<protocol::Runtime::RemoteObject>* result) const;
WrapMode wrapMode, Response wrapObject(
v8::MaybeLocal<v8::Value> customPreviewConfig, v8::Local<v8::Value>, const String16& groupName, bool forceValueType,
int maxCustomPreviewDepth, bool generatePreview, v8::MaybeLocal<v8::Value> customPreviewConfig,
std::unique_ptr<protocol::Runtime::RemoteObject>* result); int maxCustomPreviewDepth,
std::unique_ptr<protocol::Runtime::RemoteObject>* result) const;
std::unique_ptr<protocol::Runtime::RemoteObject> wrapTable( 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, void addPromiseCallback(V8InspectorSessionImpl* session,
v8::MaybeLocal<v8::Value> value, v8::MaybeLocal<v8::Value> value,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, bool returnByValue,
bool generatePreview,
std::unique_ptr<EvaluateCallback> callback); std::unique_ptr<EvaluateCallback> callback);
Response findObject(const RemoteObjectId&, v8::Local<v8::Value>*) const; Response findObject(const RemoteObjectId&, v8::Local<v8::Value>*) const;
@ -109,16 +107,18 @@ class InjectedScript final {
v8::Local<v8::Value>* result); v8::Local<v8::Value>* result);
Response createExceptionDetails( Response createExceptionDetails(
const v8::TryCatch&, const String16& groupName, WrapMode wrapMode, const v8::TryCatch&, const String16& groupName, bool generatePreview,
Maybe<protocol::Runtime::ExceptionDetails>* result); Maybe<protocol::Runtime::ExceptionDetails>* result);
Response wrapEvaluateResult( Response wrapEvaluateResult(
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&, 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, std::unique_ptr<protocol::Runtime::RemoteObject>* result,
Maybe<protocol::Runtime::ExceptionDetails>*); Maybe<protocol::Runtime::ExceptionDetails>*);
v8::Local<v8::Value> lastEvaluationResult() const; v8::Local<v8::Value> lastEvaluationResult() const;
void setLastEvaluationResult(v8::Local<v8::Value> result); void setLastEvaluationResult(v8::Local<v8::Value> result);
int bindObject(v8::Local<v8::Value>, const String16& groupName);
class Scope { class Scope {
public: public:
Response initialize(); Response initialize();
@ -196,21 +196,23 @@ class InjectedScript final {
DISALLOW_COPY_AND_ASSIGN(CallFrameScope); DISALLOW_COPY_AND_ASSIGN(CallFrameScope);
}; };
String16 bindObject(v8::Local<v8::Value>, const String16& groupName);
private: 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(); v8::Local<v8::Object> commandLineAPI();
void unbindObject(int id); void unbindObject(int id);
void bindRemoteObjectIfNeeded(v8::Local<v8::Value>, const String16& groupName,
protocol::Runtime::RemoteObject* remoteObject);
class ProtocolPromiseHandler; class ProtocolPromiseHandler;
void discardEvaluateCallbacks(); void discardEvaluateCallbacks();
std::unique_ptr<EvaluateCallback> takeEvaluateCallback( std::unique_ptr<EvaluateCallback> takeEvaluateCallback(
EvaluateCallback* callback); EvaluateCallback* callback);
InspectedContext* m_context; InspectedContext* m_context;
v8::Global<v8::Value> m_value;
int m_sessionId; int m_sessionId;
v8::Global<v8::Value> m_lastEvaluationResult; v8::Global<v8::Value> m_lastEvaluationResult;
v8::Global<v8::Object> m_commandLineAPI; v8::Global<v8::Object> m_commandLineAPI;

View 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;

View File

@ -109,12 +109,14 @@ InjectedScript* InspectedContext::getInjectedScript(int sessionId) {
return it == m_injectedScripts.end() ? nullptr : it->second.get(); return it == m_injectedScripts.end() ? nullptr : it->second.get();
} }
InjectedScript* InspectedContext::createInjectedScript(int sessionId) { bool InspectedContext::createInjectedScript(int sessionId) {
std::unique_ptr<InjectedScript> injectedScript = 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()); CHECK(m_injectedScripts.find(sessionId) == m_injectedScripts.end());
m_injectedScripts[sessionId] = std::move(injectedScript); m_injectedScripts[sessionId] = std::move(injectedScript);
return getInjectedScript(sessionId); return true;
} }
void InspectedContext::discardInjectedScript(int sessionId) { void InspectedContext::discardInjectedScript(int sessionId) {

View File

@ -40,7 +40,7 @@ class InspectedContext {
V8InspectorImpl* inspector() const { return m_inspector; } V8InspectorImpl* inspector() const { return m_inspector; }
InjectedScript* getInjectedScript(int sessionId); InjectedScript* getInjectedScript(int sessionId);
InjectedScript* createInjectedScript(int sessionId); bool createInjectedScript(int sessionId);
void discardInjectedScript(int sessionId); void discardInjectedScript(int sessionId);
private: private:

View File

@ -1890,9 +1890,7 @@
"error", "error",
"proxy", "proxy",
"promise", "promise",
"typedarray", "typedarray"
"arraybuffer",
"dataview"
] ]
}, },
{ {

View File

@ -887,8 +887,6 @@ domain Runtime
proxy proxy
promise promise
typedarray typedarray
arraybuffer
dataview
# Object class (constructor) name. Specified for `object` type values only. # Object class (constructor) name. Specified for `object` type values only.
optional string className optional string className
# Remote object value in case of primitive values or JSON values (if it was requested). # Remote object value in case of primitive values or JSON values (if it was requested).

View File

@ -259,33 +259,19 @@ V8ConsoleMessage::wrapArguments(V8InspectorSessionImpl* session,
std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>> args = std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>> args =
protocol::Array<protocol::Runtime::RemoteObject>::create(); protocol::Array<protocol::Runtime::RemoteObject>::create();
if (m_type == ConsoleAPIType::kTable && generatePreview) {
v8::Local<v8::Value> value = m_arguments[0]->Get(isolate); v8::Local<v8::Value> table = m_arguments[0]->Get(isolate);
if (value->IsObject() && m_type == ConsoleAPIType::kTable && v8::Local<v8::Value> columns = m_arguments.size() > 1
generatePreview) { ? m_arguments[1]->Get(isolate)
v8::MaybeLocal<v8::Array> columns; : v8::Local<v8::Value>();
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;
}
}
}
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped = std::unique_ptr<protocol::Runtime::RemoteObject> wrapped =
session->wrapTable(context, v8::Local<v8::Object>::Cast(value), session->wrapTable(context, table, columns);
columns);
inspectedContext = inspector->getContext(contextGroupId, contextId); inspectedContext = inspector->getContext(contextGroupId, contextId);
if (!inspectedContext) return nullptr; if (!inspectedContext) return nullptr;
if (wrapped) { if (wrapped)
args->addItem(std::move(wrapped)); args->addItem(std::move(wrapped));
} else { else
args = nullptr; args = nullptr;
}
} else { } else {
for (size_t i = 0; i < m_arguments.size(); ++i) { for (size_t i = 0; i < m_arguments.size(); ++i) {
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped = std::unique_ptr<protocol::Runtime::RemoteObject> wrapped =

View File

@ -600,8 +600,9 @@ static void inspectImpl(const v8::FunctionCallbackInfo<v8::Value>& info,
InjectedScript* injectedScript = helper.injectedScript(sessionId); InjectedScript* injectedScript = helper.injectedScript(sessionId);
if (!injectedScript) return; if (!injectedScript) return;
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedObject; std::unique_ptr<protocol::Runtime::RemoteObject> wrappedObject;
protocol::Response response = injectedScript->wrapObject( protocol::Response response =
value, "", WrapMode::kNoPreview, &wrappedObject); injectedScript->wrapObject(value, "", false /** forceValueType */,
false /** generatePreview */, &wrappedObject);
if (!response.isSuccess()) return; if (!response.isSuccess()) return;
std::unique_ptr<protocol::DictionaryValue> hints = std::unique_ptr<protocol::DictionaryValue> hints =

View File

@ -260,9 +260,8 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
for (; !iterator->Done(); iterator->Advance()) { for (; !iterator->Done(); iterator->Advance()) {
std::unique_ptr<RemoteObject> object; std::unique_ptr<RemoteObject> object;
Response result = Response result = injectedScript->wrapObject(
injectedScript->wrapObject(iterator->GetObject(), kBacktraceObjectGroup, iterator->GetObject(), kBacktraceObjectGroup, false, false, &object);
WrapMode::kNoPreview, &object);
if (!result.isSuccess()) return result; if (!result.isSuccess()) return result;
auto scope = Scope::create() auto scope = Scope::create()
@ -1086,12 +1085,10 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame(
// context or session. // context or session.
response = scope.initialize(); response = scope.initialize();
if (!response.isSuccess()) return response; 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( return scope.injectedScript()->wrapEvaluateResult(
maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode, maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""),
result, exceptionDetails); returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), result,
exceptionDetails);
} }
Response V8DebuggerAgentImpl::setVariableValue( Response V8DebuggerAgentImpl::setVariableValue(
@ -1271,9 +1268,8 @@ Response V8DebuggerAgentImpl::currentCallFrames(
if (injectedScript) { if (injectedScript) {
v8::Local<v8::Value> receiver; v8::Local<v8::Value> receiver;
if (iterator->GetReceiver().ToLocal(&receiver)) { if (iterator->GetReceiver().ToLocal(&receiver)) {
res = res = injectedScript->wrapObject(receiver, kBacktraceObjectGroup, false,
injectedScript->wrapObject(receiver, kBacktraceObjectGroup, false, &protocolReceiver);
WrapMode::kNoPreview, &protocolReceiver);
if (!res.isSuccess()) return res; if (!res.isSuccess()) return res;
} }
} }
@ -1324,7 +1320,7 @@ Response V8DebuggerAgentImpl::currentCallFrames(
if (!returnValue.IsEmpty() && injectedScript) { if (!returnValue.IsEmpty() && injectedScript) {
std::unique_ptr<RemoteObject> value; std::unique_ptr<RemoteObject> value;
res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup, res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup,
WrapMode::kNoPreview, &value); false, false, &value);
if (!res.isSuccess()) return res; if (!res.isSuccess()) return res;
frame->setReturnValue(std::move(value)); frame->setReturnValue(std::move(value));
} }
@ -1532,8 +1528,8 @@ void V8DebuggerAgentImpl::didPause(
? protocol::Debugger::Paused::ReasonEnum::PromiseRejection ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
: protocol::Debugger::Paused::ReasonEnum::Exception; : protocol::Debugger::Paused::ReasonEnum::Exception;
std::unique_ptr<protocol::Runtime::RemoteObject> obj; std::unique_ptr<protocol::Runtime::RemoteObject> obj;
injectedScript->wrapObject(exception, kBacktraceObjectGroup, injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false,
WrapMode::kNoPreview, &obj); &obj);
std::unique_ptr<protocol::DictionaryValue> breakAuxData; std::unique_ptr<protocol::DictionaryValue> breakAuxData;
if (obj) { if (obj) {
breakAuxData = obj->toValue(); breakAuxData = obj->toValue();

View File

@ -10,6 +10,7 @@
#include "src/inspector/v8-debugger-agent-impl.h" #include "src/inspector/v8-debugger-agent-impl.h"
#include "src/inspector/v8-inspector-impl.h" #include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/v8-inspector-session-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-runtime-agent-impl.h"
#include "src/inspector/v8-stack-trace-impl.h" #include "src/inspector/v8-stack-trace-impl.h"
#include "src/inspector/v8-value-utils.h" #include "src/inspector/v8-value-utils.h"
@ -23,6 +24,102 @@ namespace {
static const int kMaxAsyncTaskStacks = 128 * 1024; static const int kMaxAsyncTaskStacks = 128 * 1024;
static const int kNoBreakpointId = 0; 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> template <typename Map>
void cleanupExpiredWeakPointers(Map& map) { void cleanupExpiredWeakPointers(Map& map) {
for (auto it = map.begin(); it != map.end();) { for (auto it = map.begin(); it != map.end();) {
@ -617,52 +714,28 @@ v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
for (; !iterator->Done(); iterator->Advance()) { for (; !iterator->Done(); iterator->Advance()) {
v8::Local<v8::Object> scope = v8::Object::New(m_isolate); 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>(); return v8::MaybeLocal<v8::Value>();
} }
String16 nameSuffix = toProtocolStringWithTypeCheck( String16 type = v8_inspector::scopeType(iterator->GetType());
m_isolate, iterator->GetFunctionDebugName()); String16 name;
String16 description; v8::Local<v8::Value> maybe_name = iterator->GetFunctionDebugName();
if (nameSuffix.length()) nameSuffix = " (" + nameSuffix + ")"; if (!maybe_name->IsUndefined()) {
switch (iterator->GetType()) { name = toProtocolStringWithTypeCheck(m_isolate, maybe_name);
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;
} }
v8::Local<v8::Object> object = iterator->GetObject(); v8::Local<v8::Object> object = iterator->GetObject();
createDataProperty(context, scope, createDataProperty(context, scope,
toV8StringInternalized(m_isolate, "description"), toV8StringInternalized(m_isolate, "type"),
toV8String(m_isolate, description)); toV8String(m_isolate, type));
createDataProperty(context, scope,
toV8StringInternalized(m_isolate, "name"),
toV8String(m_isolate, name));
createDataProperty(context, scope, createDataProperty(context, scope,
toV8StringInternalized(m_isolate, "object"), object); toV8StringInternalized(m_isolate, "object"), object);
createDataProperty(context, result, result->Length(), scope); createDataProperty(context, result, result->Length(), scope);
} }
if (!addInternalObject(context, v8::Local<v8::Array>::Cast(result), if (!markAsInternal(context, v8::Local<v8::Array>::Cast(result),
V8InternalValueType::kScopeList)) V8InternalValueType::kScopeList))
return v8::MaybeLocal<v8::Value>(); return v8::MaybeLocal<v8::Value>();
return result; return result;
} }
@ -677,45 +750,6 @@ v8::MaybeLocal<v8::Value> V8Debugger::generatorScopes(
return getTargetScopes(context, generator, GENERATOR); 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::MaybeLocal<v8::Uint32> V8Debugger::stableObjectId(
v8::Local<v8::Context> context, v8::Local<v8::Value> value) { v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
DCHECK(value->IsObject()); DCHECK(value->IsObject());
@ -747,6 +781,25 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
createDataProperty(context, properties, properties->Length(), id); 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; v8::Local<v8::Array> entries;
if (collectionsEntries(context, value).ToLocal(&entries)) { if (collectionsEntries(context, value).ToLocal(&entries)) {
createDataProperty(context, properties, properties->Length(), createDataProperty(context, properties, properties->Length(),
@ -754,6 +807,13 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
createDataProperty(context, properties, properties->Length(), entries); createDataProperty(context, properties, properties->Length(), entries);
} }
if (value->IsGeneratorObject()) { 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; v8::Local<v8::Value> scopes;
if (generatorScopes(context, value).ToLocal(&scopes)) { if (generatorScopes(context, value).ToLocal(&scopes)) {
createDataProperty(context, properties, properties->Length(), createDataProperty(context, properties, properties->Length(),
@ -1136,31 +1196,6 @@ std::pair<int64_t, int64_t> V8Debugger::debuggerIdFor(
return std::make_pair(0, 0); 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() { void V8Debugger::dumpAsyncTaskStacksStateForTest() {
fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount); fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size()); fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());

View File

@ -30,9 +30,6 @@ class V8InspectorImpl;
class V8StackTraceImpl; class V8StackTraceImpl;
struct V8StackTraceId; struct V8StackTraceId;
enum class WrapMode { kForceValue, kNoPreview, kWithPreview };
enum class V8InternalValueType { kNone, kEntry, kScope, kScopeList };
using protocol::Response; using protocol::Response;
using ScheduleStepIntoAsyncCallback = using ScheduleStepIntoAsyncCallback =
protocol::Debugger::Backend::ScheduleStepIntoAsyncCallback; protocol::Debugger::Backend::ScheduleStepIntoAsyncCallback;
@ -137,12 +134,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId, std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId,
const V8StackTraceId& id); 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: private:
void clearContinueToLocation(); void clearContinueToLocation();
bool shouldContinueToCurrentLocation(); bool shouldContinueToCurrentLocation();
@ -169,8 +160,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
v8::Local<v8::Function>); v8::Local<v8::Function>);
v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>, v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>,
v8::Local<v8::Value>); 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, void asyncTaskScheduledForStack(const String16& taskName, void* task,
bool recurring); bool recurring);
@ -264,8 +253,6 @@ class V8Debugger : public v8::debug::DebugDelegate,
uint32_t m_lastStableObjectId = 0; uint32_t m_lastStableObjectId = 0;
v8::Global<v8::debug::WeakMap> m_stableObjectId; v8::Global<v8::debug::WeakMap> m_stableObjectId;
v8::Global<v8::debug::WeakMap> m_internalObjects;
WasmTranslation m_wasmTranslation; WasmTranslation m_wasmTranslation;
DISALLOW_COPY_AND_ASSIGN(V8Debugger); DISALLOW_COPY_AND_ASSIGN(V8Debugger);

View 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

View 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_

View 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

View 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_

View File

@ -203,7 +203,12 @@ Response V8InspectorSessionImpl::findInjectedScript(
if (!context) return Response::Error("Cannot find context with specified id"); if (!context) return Response::Error("Cannot find context with specified id");
injectedScript = context->getInjectedScript(m_sessionId); injectedScript = context->getInjectedScript(m_sessionId);
if (!injectedScript) { 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) if (m_customObjectFormatterEnabled)
injectedScript->setCustomObjectFormatterEnabled(true); injectedScript->setCustomObjectFormatterEnabled(true);
} }
@ -280,16 +285,14 @@ V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
findInjectedScript(InspectedContext::contextId(context), injectedScript); findInjectedScript(InspectedContext::contextId(context), injectedScript);
if (!injectedScript) return nullptr; if (!injectedScript) return nullptr;
std::unique_ptr<protocol::Runtime::RemoteObject> result; std::unique_ptr<protocol::Runtime::RemoteObject> result;
injectedScript->wrapObject( injectedScript->wrapObject(value, groupName, false, generatePreview, &result);
value, groupName,
generatePreview ? WrapMode::kWithPreview : WrapMode::kNoPreview, &result);
return result; return result;
} }
std::unique_ptr<protocol::Runtime::RemoteObject> std::unique_ptr<protocol::Runtime::RemoteObject>
V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context, V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context,
v8::Local<v8::Object> table, v8::Local<v8::Value> table,
v8::MaybeLocal<v8::Array> columns) { v8::Local<v8::Value> columns) {
InjectedScript* injectedScript = nullptr; InjectedScript* injectedScript = nullptr;
findInjectedScript(InspectedContext::contextId(context), injectedScript); findInjectedScript(InspectedContext::contextId(context), injectedScript);
if (!injectedScript) return nullptr; if (!injectedScript) return nullptr;

View File

@ -55,8 +55,8 @@ class V8InspectorSessionImpl : public V8InspectorSession,
v8::Local<v8::Context>, v8::Local<v8::Value>, const String16& groupName, v8::Local<v8::Context>, v8::Local<v8::Value>, const String16& groupName,
bool generatePreview); bool generatePreview);
std::unique_ptr<protocol::Runtime::RemoteObject> wrapTable( std::unique_ptr<protocol::Runtime::RemoteObject> wrapTable(
v8::Local<v8::Context>, v8::Local<v8::Object> table, v8::Local<v8::Context>, v8::Local<v8::Value> table,
v8::MaybeLocal<v8::Array> columns); v8::Local<v8::Value> columns);
std::vector<std::unique_ptr<protocol::Schema::Domain>> supportedDomainsImpl(); std::vector<std::unique_ptr<protocol::Schema::Domain>> supportedDomainsImpl();
Response unwrapObject(const String16& objectId, v8::Local<v8::Value>*, Response unwrapObject(const String16& objectId, v8::Local<v8::Value>*,
v8::Local<v8::Context>*, String16* objectGroup); v8::Local<v8::Context>*, String16* objectGroup);

View 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

View 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_

View File

@ -90,14 +90,14 @@ template <typename ProtocolCallback>
bool wrapEvaluateResultAsync(InjectedScript* injectedScript, bool wrapEvaluateResultAsync(InjectedScript* injectedScript,
v8::MaybeLocal<v8::Value> maybeResultValue, v8::MaybeLocal<v8::Value> maybeResultValue,
const v8::TryCatch& tryCatch, const v8::TryCatch& tryCatch,
const String16& objectGroup, WrapMode wrapMode, const String16& objectGroup, bool returnByValue,
ProtocolCallback* callback) { bool generatePreview, ProtocolCallback* callback) {
std::unique_ptr<RemoteObject> result; std::unique_ptr<RemoteObject> result;
Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails; Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
Response response = injectedScript->wrapEvaluateResult( Response response = injectedScript->wrapEvaluateResult(
maybeResultValue, tryCatch, objectGroup, wrapMode, &result, maybeResultValue, tryCatch, objectGroup, returnByValue, generatePreview,
&exceptionDetails); &result, &exceptionDetails);
if (response.isSuccess()) { if (response.isSuccess()) {
callback->sendSuccess(std::move(result), std::move(exceptionDetails)); callback->sendSuccess(std::move(result), std::move(exceptionDetails));
return true; return true;
@ -110,8 +110,8 @@ void innerCallFunctionOn(
V8InspectorSessionImpl* session, InjectedScript::Scope& scope, V8InspectorSessionImpl* session, InjectedScript::Scope& scope,
v8::Local<v8::Value> recv, const String16& expression, v8::Local<v8::Value> recv, const String16& expression,
Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments, Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments,
bool silent, WrapMode wrapMode, bool userGesture, bool awaitPromise, bool silent, bool returnByValue, bool generatePreview, bool userGesture,
const String16& objectGroup, bool awaitPromise, const String16& objectGroup,
std::unique_ptr<V8RuntimeAgentImpl::CallFunctionOnCallback> callback) { std::unique_ptr<V8RuntimeAgentImpl::CallFunctionOnCallback> callback) {
V8InspectorImpl* inspector = session->inspector(); V8InspectorImpl* inspector = session->inspector();
@ -159,7 +159,7 @@ void innerCallFunctionOn(
if (scope.tryCatch().HasCaught()) { if (scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue,
scope.tryCatch(), objectGroup, WrapMode::kNoPreview, scope.tryCatch(), objectGroup, false, false,
callback.get()); callback.get());
return; return;
} }
@ -189,13 +189,13 @@ void innerCallFunctionOn(
if (!awaitPromise || scope.tryCatch().HasCaught()) { if (!awaitPromise || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup, wrapMode, scope.tryCatch(), objectGroup, returnByValue,
callback.get()); generatePreview, callback.get());
return; return;
} }
scope.injectedScript()->addPromiseCallback( scope.injectedScript()->addPromiseCallback(
session, maybeResultValue, objectGroup, wrapMode, session, maybeResultValue, objectGroup, returnByValue, generatePreview,
EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap( EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap(
std::move(callback))); std::move(callback)));
} }
@ -284,17 +284,16 @@ void V8RuntimeAgentImpl::evaluate(
return; return;
} }
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview;
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup.fromMaybe(""), mode, scope.tryCatch(), objectGroup.fromMaybe(""),
callback.get()); returnByValue.fromMaybe(false),
generatePreview.fromMaybe(false), callback.get());
return; return;
} }
scope.injectedScript()->addPromiseCallback( 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))); EvaluateCallbackWrapper<EvaluateCallback>::wrap(std::move(callback)));
} }
@ -313,11 +312,9 @@ void V8RuntimeAgentImpl::awaitPromise(
Response::Error("Could not find promise with given id")); Response::Error("Could not find promise with given id"));
return; return;
} }
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview;
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
scope.injectedScript()->addPromiseCallback( 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))); EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback)));
} }
@ -338,9 +335,6 @@ void V8RuntimeAgentImpl::callFunctionOn(
"Either ObjectId or executionContextId must be specified")); "Either ObjectId or executionContextId must be specified"));
return; return;
} }
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview;
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
if (objectId.isJust()) { if (objectId.isJust()) {
InjectedScript::ObjectScope scope(m_session, objectId.fromJust()); InjectedScript::ObjectScope scope(m_session, objectId.fromJust());
Response response = scope.initialize(); Response response = scope.initialize();
@ -348,13 +342,14 @@ void V8RuntimeAgentImpl::callFunctionOn(
callback->sendFailure(response); callback->sendFailure(response);
return; return;
} }
innerCallFunctionOn(m_session, scope, scope.object(), expression, innerCallFunctionOn(
std::move(optionalArguments), silent.fromMaybe(false), m_session, scope, scope.object(), expression,
mode, userGesture.fromMaybe(false), std::move(optionalArguments), silent.fromMaybe(false),
awaitPromise.fromMaybe(false), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
objectGroup.isJust() ? objectGroup.fromMaybe(String16()) userGesture.fromMaybe(false), awaitPromise.fromMaybe(false),
: scope.objectGroupName(), objectGroup.isJust() ? objectGroup.fromMaybe(String16())
std::move(callback)); : scope.objectGroupName(),
std::move(callback));
} else { } else {
int contextId = 0; int contextId = 0;
Response response = Response response =
@ -370,11 +365,12 @@ void V8RuntimeAgentImpl::callFunctionOn(
callback->sendFailure(response); callback->sendFailure(response);
return; return;
} }
innerCallFunctionOn(m_session, scope, scope.context()->Global(), expression, innerCallFunctionOn(
std::move(optionalArguments), silent.fromMaybe(false), m_session, scope, scope.context()->Global(), expression,
mode, userGesture.fromMaybe(false), std::move(optionalArguments), silent.fromMaybe(false),
awaitPromise.fromMaybe(false), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
objectGroup.fromMaybe(""), std::move(callback)); 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>(); v8::Local<v8::Object> object = scope.object().As<v8::Object>();
response = scope.injectedScript()->getProperties( response = scope.injectedScript()->getProperties(
object, scope.objectGroupName(), ownProperties.fromMaybe(false), object, scope.objectGroupName(), ownProperties.fromMaybe(false),
accessorPropertiesOnly.fromMaybe(false), accessorPropertiesOnly.fromMaybe(false), generatePreview.fromMaybe(false),
generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview,
result, exceptionDetails); result, exceptionDetails);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false)) if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false))
return Response::OK(); 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>> std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>
propertiesProtocolArray; propertiesProtocolArray =
response = scope.injectedScript()->getInternalProperties( protocol::Array<InternalPropertyDescriptor>::create();
object, scope.objectGroupName(), &propertiesProtocolArray); for (uint32_t i = 0; i < propertiesArray->Length(); i += 2) {
if (!response.isSuccess()) return response; 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()) if (propertiesProtocolArray->length())
*internalProperties = std::move(propertiesProtocolArray); *internalProperties = std::move(propertiesProtocolArray);
return Response::OK(); return Response::OK();
@ -481,7 +499,7 @@ Response V8RuntimeAgentImpl::compileScript(
if (!isOk) { if (!isOk) {
if (scope.tryCatch().HasCaught()) { if (scope.tryCatch().HasCaught()) {
response = scope.injectedScript()->createExceptionDetails( response = scope.injectedScript()->createExceptionDetails(
scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails); scope.tryCatch(), String16(), false, exceptionDetails);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
return Response::OK(); return Response::OK();
} else { } else {
@ -559,18 +577,17 @@ void V8RuntimeAgentImpl::runScript(
return; return;
} }
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview;
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
scope.tryCatch(), objectGroup.fromMaybe(""), mode, scope.tryCatch(), objectGroup.fromMaybe(""),
callback.get()); returnByValue.fromMaybe(false),
generatePreview.fromMaybe(false), callback.get());
return; return;
} }
scope.injectedScript()->addPromiseCallback( scope.injectedScript()->addPromiseCallback(
m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""), m_session, maybeResultValue.ToLocalChecked(),
mode, objectGroup.fromMaybe(""), returnByValue.fromMaybe(false),
generatePreview.fromMaybe(false),
EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback))); EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback)));
} }
@ -586,8 +603,8 @@ Response V8RuntimeAgentImpl::queryObjects(
v8::Local<v8::Array> resultArray = m_inspector->debugger()->queryObjects( v8::Local<v8::Array> resultArray = m_inspector->debugger()->queryObjects(
scope.context(), v8::Local<v8::Object>::Cast(scope.object())); scope.context(), v8::Local<v8::Object>::Cast(scope.object()));
return scope.injectedScript()->wrapObject( return scope.injectedScript()->wrapObject(
resultArray, objectGroup.fromMaybe(scope.objectGroupName()), resultArray, objectGroup.fromMaybe(scope.objectGroupName()), false, false,
WrapMode::kNoPreview, objects); objects);
} }
Response V8RuntimeAgentImpl::globalLexicalScopeNames( Response V8RuntimeAgentImpl::globalLexicalScopeNames(

View File

@ -6,6 +6,102 @@
namespace v8_inspector { 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::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
v8::Local<v8::Object> object, v8::Local<v8::Object> object,
v8::Local<v8::Name> key, v8::Local<v8::Name> key,
@ -26,4 +122,11 @@ v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
return array->CreateDataProperty(context, index, value); 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 } // namespace v8_inspector

View File

@ -18,6 +18,9 @@ v8::Maybe<bool> createDataProperty(v8::Local<v8::Context>,
v8::Maybe<bool> createDataProperty(v8::Local<v8::Context>, v8::Local<v8::Array>, v8::Maybe<bool> createDataProperty(v8::Local<v8::Context>, v8::Local<v8::Array>,
int index, v8::Local<v8::Value>); 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 } // namespace v8_inspector
#endif // V8_INSPECTOR_V8_VALUE_UTILS_H_ #endif // V8_INSPECTOR_V8_VALUE_UTILS_H_

File diff suppressed because it is too large Load Diff

View File

@ -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_

View File

@ -44,6 +44,7 @@ v8_executable("inspector-test") {
"sessions/", "sessions/",
"testcfg.py", "testcfg.py",
"type-profiler/", "type-profiler/",
"../../src/inspector/injected-script-source.js",
] ]
cflags = [] cflags = []

View File

@ -26,7 +26,18 @@ expression: Object(Symbol(42))
{ {
name : [[PrimitiveValue]] name : [[PrimitiveValue]]
type : symbol type : symbol
value : Symbol(42) valuePreview : {
description : Symbol
overflow : false
properties : [
[0] : {
name : description
type : string
value : 42
}
]
type : object
}
} }
expression: Object(BigInt(2)) expression: Object(BigInt(2))

View File

@ -0,0 +1,2 @@
Tests that stepping ignores injected script
InjectedSciptSource was not reached

View 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);

View File

@ -0,0 +1,2 @@
Tests that stepping does not ignore injected script when passed a flag
InjectedSciptSource on stack.

View File

@ -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);

View File

@ -17,6 +17,8 @@
############################################################################## ##############################################################################
['system == android', { ['system == android', {
# https://crbug.com/v8/8160
'debugger/stepping-with-exposed-injected-script': [FAIL],
# https://crbug.com/v8/8197 # https://crbug.com/v8/8197
'debugger/get-possible-breakpoints-class-fields': [SKIP], 'debugger/get-possible-breakpoints-class-fields': [SKIP],
}], # 'system == android' }], # 'system == android'

View File

@ -176,6 +176,8 @@ InspectorTest.ContextGroup = class {
if (session) { if (session) {
InspectorTest.log('WARNING: setupInjectedScriptEnvironment with debug flag for debugging only and should not be landed.'); 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.setupScriptMap();
session.Protocol.Debugger.enable(); session.Protocol.Debugger.enable();
session.Protocol.Debugger.onPaused(message => { session.Protocol.Debugger.onPaused(message => {

View File

@ -239,7 +239,6 @@ Checks console methods
name : 0 name : 0
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(2)
overflow : false overflow : false
@ -263,7 +262,6 @@ Checks console methods
name : 1 name : 1
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(2)
overflow : false overflow : false
@ -330,7 +328,6 @@ Checks console methods
name : 0 name : 0
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(2)
overflow : false overflow : false
@ -349,7 +346,6 @@ Checks console methods
name : 1 name : 1
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(2)
overflow : false overflow : false

View File

@ -47,9 +47,8 @@ console.table
name : 0 name : 0
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -71,9 +70,8 @@ console.table
name : 1 name : 1
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -95,9 +93,8 @@ console.table
name : 2 name : 2
subtype : array subtype : array
type : object type : object
value : Array(2)
valuePreview : { valuePreview : {
description : Array(2) description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -126,9 +123,8 @@ console.table
[0] : { [0] : {
name : 0 name : 0
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -142,15 +138,15 @@ console.table
value : Smith value : Smith
} }
] ]
subtype : array
type : object type : object
} }
} }
[1] : { [1] : {
name : 1 name : 1
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -164,15 +160,15 @@ console.table
value : Doe value : Doe
} }
] ]
subtype : array
type : object type : object
} }
} }
[2] : { [2] : {
name : 2 name : 2
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -186,6 +182,7 @@ console.table
value : Jones value : Jones
} }
] ]
subtype : array
type : object type : object
} }
} }
@ -200,9 +197,8 @@ console.table
[0] : { [0] : {
name : mother name : mother
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Object
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -222,9 +218,8 @@ console.table
[1] : { [1] : {
name : father name : father
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Object
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -244,9 +239,8 @@ console.table
[2] : { [2] : {
name : daughter name : daughter
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Object
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -273,9 +267,8 @@ console.table
[0] : { [0] : {
name : 0 name : 0
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -284,15 +277,15 @@ console.table
value : John value : John
} }
] ]
subtype : array
type : object type : object
} }
} }
[1] : { [1] : {
name : 1 name : 1
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -301,15 +294,15 @@ console.table
value : Jane value : Jane
} }
] ]
subtype : array
type : object type : object
} }
} }
[2] : { [2] : {
name : 2 name : 2
type : object type : object
value : Person
valuePreview : { valuePreview : {
description : Person description : Array(3)
overflow : false overflow : false
properties : [ properties : [
[0] : { [0] : {
@ -318,6 +311,7 @@ console.table
value : Emily value : Emily
} }
] ]
subtype : array
type : object type : object
} }
} }

View File

@ -7,6 +7,10 @@ expression: (function* foo() { yield 1 })
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [0] : {
name : [[StableObjectId]]
value : <StablectObjectId>
}
[1] : {
name : [[FunctionLocation]] name : [[FunctionLocation]]
value : { value : {
description : Object description : Object
@ -19,17 +23,13 @@ expression: (function* foo() { yield 1 })
} }
} }
} }
[1] : { [2] : {
name : [[IsGenerator]] name : [[IsGenerator]]
value : { value : {
type : boolean type : boolean
value : true value : true
} }
} }
[2] : {
name : [[StableObjectId]]
value : <StablectObjectId>
}
[3] : { [3] : {
name : [[Scopes]] name : [[Scopes]]
value : { value : {
@ -51,6 +51,10 @@ expression: (function foo() {})
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [0] : {
name : [[StableObjectId]]
value : <StablectObjectId>
}
[1] : {
name : [[FunctionLocation]] name : [[FunctionLocation]]
value : { value : {
description : Object description : Object
@ -63,10 +67,6 @@ expression: (function foo() {})
} }
} }
} }
[1] : {
name : [[StableObjectId]]
value : <StablectObjectId>
}
[2] : { [2] : {
name : [[Scopes]] name : [[Scopes]]
value : { value : {
@ -242,6 +242,35 @@ expression: gen1
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [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]] name : [[GeneratorLocation]]
value : { value : {
description : Object 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] : { [5] : {
name : [[Scopes]] name : [[Scopes]]
value : { value : {
@ -302,6 +302,35 @@ expression: gen1.next();gen1
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [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]] name : [[GeneratorLocation]]
value : { value : {
description : Object 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] : { [5] : {
name : [[Scopes]] name : [[Scopes]]
value : { value : {
@ -362,6 +362,35 @@ expression: gen1.next();gen1
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [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]] name : [[GeneratorLocation]]
value : { value : {
description : Object 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 : { result : {
internalProperties : [ internalProperties : [
[0] : { [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]] name : [[GeneratorLocation]]
value : { value : {
description : Object 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] : { [5] : {
name : [[Scopes]] name : [[Scopes]]
value : { value : {
@ -474,6 +474,35 @@ expression: gen2.next();gen2
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [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]] name : [[GeneratorLocation]]
value : { value : {
description : Object 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] : { [5] : {
name : [[Scopes]] name : [[Scopes]]
value : { value : {
@ -534,6 +534,35 @@ expression: gen2.next();gen2
result : { result : {
internalProperties : [ internalProperties : [
[0] : { [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]] name : [[GeneratorLocation]]
value : { value : {
description : Object 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>
}
] ]
} }
} }

View File

@ -589,6 +589,8 @@ Running test: testMap
objectId : <objectId> objectId : <objectId>
preview : { preview : {
description : Map(0) description : Map(0)
entries : [
]
overflow : false overflow : false
properties : [ properties : [
] ]
@ -816,6 +818,8 @@ Running test: testMap
objectId : <objectId> objectId : <objectId>
preview : { preview : {
description : MapIterator description : MapIterator
entries : [
]
overflow : false overflow : false
properties : [ properties : [
] ]
@ -893,6 +897,8 @@ Running test: testMap
objectId : <objectId> objectId : <objectId>
preview : { preview : {
description : MapIterator description : MapIterator
entries : [
]
overflow : false overflow : false
properties : [ properties : [
] ]
@ -1110,6 +1116,8 @@ Running test: testWeakMap
objectId : <objectId> objectId : <objectId>
preview : { preview : {
description : WeakMap description : WeakMap
entries : [
]
overflow : false overflow : false
properties : [ properties : [
] ]
@ -1194,6 +1202,8 @@ Running test: testWeakSet
objectId : <objectId> objectId : <objectId>
preview : { preview : {
description : WeakSet description : WeakSet
entries : [
]
overflow : false overflow : false
properties : [ properties : [
] ]

View File

@ -1,11 +1,11 @@
Runtime.getProperties for objects with accessor Runtime.getProperties for objects with accessor
title property with getter and setter: title property with getter and setter:
{ {
configurable : true configurable : false
enumerable : true enumerable : false
get : { get : {
className : Function className : Function
description : function () { [native code] } description : function nativeGetter() { [native code] }
objectId : <objectId> objectId : <objectId>
type : function type : function
} }
@ -13,18 +13,18 @@ title property with getter and setter:
name : title name : title
set : { set : {
className : Function className : Function
description : function () { [native code] } description : function nativeSetter() { [native code] }
objectId : <objectId> objectId : <objectId>
type : function type : function
} }
} }
title property with getter only: title property with getter only:
{ {
configurable : true configurable : false
enumerable : true enumerable : false
get : { get : {
className : Function className : Function
description : function () { [native code] } description : function nativeGetter() { [native code] }
objectId : <objectId> objectId : <objectId>
type : function type : function
} }

View File

@ -8,7 +8,7 @@ Terminate first evaluation (it forces injected-script-source compilation)
{ {
error : { error : {
code : -32000 code : -32000
message : Execution was terminated message : Cannot access specified execution context
} }
id : <messageId> id : <messageId>
} }

View File

@ -60,6 +60,7 @@ class TestCase(testcase.TestCase):
def _get_resources(self): def _get_resources(self):
return [ return [
os.path.join('src', 'inspector', 'injected-script-source.js'),
os.path.join( os.path.join(
'test', 'inspector', 'debugger', 'resources', 'break-locations.js'), 'test', 'inspector', 'debugger', 'resources', 'break-locations.js'),
] ]

View File

@ -412,15 +412,21 @@ class SourceProcessor(SourceFileProcessor):
IGNORE_COPYRIGHTS = ['box2d.js', IGNORE_COPYRIGHTS = ['box2d.js',
'cpplint.py', 'cpplint.py',
'check_injected_script_source.py',
'copy.js', 'copy.js',
'corrections.js', 'corrections.js',
'crypto.js', 'crypto.js',
'daemon.py', 'daemon.py',
'debugger-script.js',
'earley-boyer.js', 'earley-boyer.js',
'fannkuch.js', 'fannkuch.js',
'fasta.js', 'fasta.js',
'generate_protocol_externs.py',
'injected-script.cc', 'injected-script.cc',
'injected-script.h', 'injected-script.h',
'injected-script-source.js',
'java-script-call-frame.cc',
'java-script-call-frame.h',
'jsmin.py', 'jsmin.py',
'libraries.cc', 'libraries.cc',
'libraries-empty.cc', 'libraries-empty.cc',
@ -432,11 +438,14 @@ class SourceProcessor(SourceFileProcessor):
'raytrace.js', 'raytrace.js',
'regexp-pcre.js', 'regexp-pcre.js',
'resources-123.js', 'resources-123.js',
'rjsmin.py',
'sqlite.js', 'sqlite.js',
'sqlite-change-heap.js', 'sqlite-change-heap.js',
'sqlite-pointer-masking.js', 'sqlite-pointer-masking.js',
'sqlite-safe-heap.js', 'sqlite-safe-heap.js',
'v8-debugger-script.h', 'v8-debugger-script.h',
'v8-function-call.cc',
'v8-function-call.h',
'v8-inspector-impl.cc', 'v8-inspector-impl.cc',
'v8-inspector-impl.h', 'v8-inspector-impl.h',
'v8-runtime-agent-impl.cc', 'v8-runtime-agent-impl.cc',