diff --git a/BUILD.gn b/BUILD.gn index 75d80e686e..d5772b06e0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1937,6 +1937,8 @@ v8_source_set("v8_base") { "src/debug/debug-frames.cc", "src/debug/debug-frames.h", "src/debug/debug-interface.h", + "src/debug/debug-property-iterator.cc", + "src/debug/debug-property-iterator.h", "src/debug/debug-scope-iterator.cc", "src/debug/debug-scope-iterator.h", "src/debug/debug-scopes.cc", diff --git a/DEPS b/DEPS index 4c09e71808..b3f9734450 100644 --- a/DEPS +++ b/DEPS @@ -245,17 +245,6 @@ hooks = [ '-s', 'v8/test/wasm-spec-tests/tests.tar.gz.sha1', ], }, - { - 'name': 'closure_compiler', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--no_auth', - '-u', - '--bucket', 'chromium-v8-closure-compiler', - '-s', 'v8/src/inspector/build/closure-compiler.tar.gz.sha1', - ], - }, { 'name': 'sysroot_arm', 'pattern': '.', diff --git a/src/api.cc b/src/api.cc index 407b7a4835..93a3f81597 100644 --- a/src/api.cc +++ b/src/api.cc @@ -9548,20 +9548,8 @@ Local debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) { i::HandleScope handle_scope(isolate); i::Builtins::Name builtin_id; switch (builtin) { - case kObjectKeys: - builtin_id = i::Builtins::kObjectKeys; - break; - case kObjectGetPrototypeOf: - builtin_id = i::Builtins::kObjectGetPrototypeOf; - break; - case kObjectGetOwnPropertyDescriptor: - builtin_id = i::Builtins::kObjectGetOwnPropertyDescriptor; - break; - case kObjectGetOwnPropertyNames: - builtin_id = i::Builtins::kObjectGetOwnPropertyNames; - break; - case kObjectGetOwnPropertySymbols: - builtin_id = i::Builtins::kObjectGetOwnPropertySymbols; + case kStringToLowerCase: + builtin_id = i::Builtins::kStringPrototypeToLocaleLowerCase; break; default: UNREACHABLE(); @@ -9569,10 +9557,11 @@ Local debug::GetBuiltin(Isolate* v8_isolate, Builtin builtin) { i::Handle name = isolate->factory()->empty_string(); i::NewFunctionArgs args = i::NewFunctionArgs::ForBuiltinWithoutPrototype( - name, builtin_id, i::LanguageMode::kSloppy); + name, builtin_id, i::LanguageMode::kStrict); i::Handle fun = isolate->factory()->NewFunction(args); - fun->shared()->DontAdaptArguments(); + fun->shared()->set_internal_formal_parameter_count(0); + fun->shared()->set_length(0); return Utils::ToLocal(handle_scope.CloseAndEscape(fun)); } @@ -9697,41 +9686,6 @@ void debug::SetReturnValue(v8::Isolate* v8_isolate, isolate->debug()->set_return_value(*Utils::OpenHandle(*value)); } -int debug::GetNativeAccessorDescriptor(v8::Local context, - v8::Local v8_object, - v8::Local v8_name) { - i::Handle object = Utils::OpenHandle(*v8_object); - i::Handle name = Utils::OpenHandle(*v8_name); - uint32_t index; - if (name->AsArrayIndex(&index)) { - return static_cast(debug::NativeAccessorType::None); - } - i::LookupIterator it = i::LookupIterator(object->GetIsolate(), object, name, - i::LookupIterator::OWN); - if (!it.IsFound()) return static_cast(debug::NativeAccessorType::None); - if (it.state() != i::LookupIterator::ACCESSOR) { - return static_cast(debug::NativeAccessorType::None); - } - i::Handle structure = it.GetAccessors(); - if (!structure->IsAccessorInfo()) { - return static_cast(debug::NativeAccessorType::None); - } - auto isolate = reinterpret_cast(context->GetIsolate()); - int result = 0; -#define IS_BUILTIN_ACESSOR(_, name, ...) \ - if (*structure == *isolate->factory()->name##_accessor()) \ - result |= static_cast(debug::NativeAccessorType::IsBuiltin); - ACCESSOR_INFO_LIST_GENERATOR(IS_BUILTIN_ACESSOR, /* not used */) -#undef IS_BUILTIN_ACESSOR - i::Handle accessor_info = - i::Handle::cast(structure); - if (accessor_info->getter()) - result |= static_cast(debug::NativeAccessorType::HasGetter); - if (accessor_info->setter()) - result |= static_cast(debug::NativeAccessorType::HasSetter); - return result; -} - int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) { return reinterpret_cast(v8_isolate) ->random_number_generator() diff --git a/src/debug/debug-interface.h b/src/debug/debug-interface.h index 14ccf2c20a..402130bb63 100644 --- a/src/debug/debug-interface.h +++ b/src/debug/debug-interface.h @@ -193,13 +193,7 @@ void ResetBlackboxedStateCache(Isolate* isolate, int EstimatedValueSize(Isolate* isolate, v8::Local value); -enum Builtin { - kObjectKeys, - kObjectGetPrototypeOf, - kObjectGetOwnPropertyDescriptor, - kObjectGetOwnPropertyNames, - kObjectGetOwnPropertySymbols, -}; +enum Builtin { kStringToLowerCase }; Local GetBuiltin(Isolate* isolate, Builtin builtin); @@ -474,14 +468,9 @@ void SetReturnValue(v8::Isolate* isolate, v8::Local value); enum class NativeAccessorType { None = 0, HasGetter = 1 << 0, - HasSetter = 1 << 1, - IsBuiltin = 1 << 2 + HasSetter = 1 << 1 }; -int GetNativeAccessorDescriptor(v8::Local context, - v8::Local object, - v8::Local name); - int64_t GetNextRandomInt64(v8::Isolate* isolate); v8::MaybeLocal EvaluateGlobal(v8::Isolate* isolate, @@ -518,6 +507,39 @@ class WeakMap : public v8::Object { private: WeakMap(); }; + +struct PropertyDescriptor { + bool enumerable : 1; + bool has_enumerable : 1; + bool configurable : 1; + bool has_configurable : 1; + bool writable : 1; + bool has_writable : 1; + v8::Local value; + v8::Local get; + v8::Local set; +}; + +class PropertyIterator { + public: + static std::unique_ptr Create(v8::Local object); + + virtual ~PropertyIterator() = default; + + virtual bool Done() const = 0; + virtual void Advance() = 0; + + virtual v8::Local name() const = 0; + + virtual bool is_native_accessor() = 0; + virtual bool has_native_getter() = 0; + virtual bool has_native_setter() = 0; + virtual Maybe attributes() = 0; + virtual Maybe descriptor() = 0; + + virtual bool is_own() = 0; + virtual bool is_array_index() = 0; +}; } // namespace debug } // namespace v8 diff --git a/src/debug/debug-property-iterator.cc b/src/debug/debug-property-iterator.cc new file mode 100644 index 0000000000..b23800e587 --- /dev/null +++ b/src/debug/debug-property-iterator.cc @@ -0,0 +1,213 @@ +// 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::Create( + v8::Local v8_object) { + internal::Isolate* isolate = + reinterpret_cast(v8_object->GetIsolate()); + return std::unique_ptr( + new internal::DebugPropertyIterator(isolate, + Utils::OpenHandle(*v8_object))); +} + +namespace internal { + +DebugPropertyIterator::DebugPropertyIterator(Isolate* isolate, + Handle 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(debug::NativeAccessorType::HasGetter); +} + +bool DebugPropertyIterator::has_native_setter() { + if (stage_ == kExoticIndices) return false; + CalculateNativeAccessorFlags(); + return native_accessor_flags_ & + static_cast(debug::NativeAccessorType::HasSetter); +} + +Handle DebugPropertyIterator::raw_name() const { + DCHECK(!Done()); + if (stage_ == kExoticIndices) { + return isolate_->factory()->Uint32ToString(current_key_index_); + } else { + return Handle::cast( + FixedArray::get(*keys_, current_key_index_, isolate_)); + } +} + +v8::Local DebugPropertyIterator::name() const { + return Utils::ToLocal(raw_name()); +} + +v8::Maybe DebugPropertyIterator::attributes() { + Handle receiver = + PrototypeIterator::GetCurrent(prototype_iterator_); + auto result = JSReceiver::GetPropertyAttributes(receiver, raw_name()); + if (result.IsNothing()) return Nothing(); + DCHECK(result.FromJust() != ABSENT); + return Just(static_cast(result.FromJust())); +} + +v8::Maybe DebugPropertyIterator::descriptor() { + Handle receiver = + PrototypeIterator::GetCurrent(prototype_iterator_); + + PropertyDescriptor descriptor; + Maybe did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( + isolate_, receiver, raw_name(), &descriptor); + if (did_get_descriptor.IsNothing()) { + return Nothing(); + } + 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(), + descriptor.has_get() ? Utils::ToLocal(descriptor.get()) + : v8::Local(), + descriptor.has_set() ? Utils::ToLocal(descriptor.set()) + : v8::Local(), + }); +} + +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::null(); + if (prototype_iterator_.IsAtEnd()) return; + Handle receiver = + PrototypeIterator::GetCurrent(prototype_iterator_); + bool has_exotic_indices = receiver->IsJSTypedArray(); + if (stage_ == kExoticIndices) { + if (!has_exotic_indices) return; + exotic_length_ = static_cast( + Handle::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::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(keys_->length()); +} + +namespace { +base::Flags GetNativeAccessorDescriptorInternal( + Handle object, Handle 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 structure = it.GetAccessors(); + if (!structure->IsAccessorInfo()) return debug::NativeAccessorType::None; + auto isolate = object->GetIsolate(); + base::Flags 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 accessor_info = Handle::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 receiver = + PrototypeIterator::GetCurrent(prototype_iterator_); + native_accessor_flags_ = + GetNativeAccessorDescriptorInternal(receiver, raw_name()); + calculated_native_accessor_flags_ = true; +} +} // namespace internal +} // namespace v8 diff --git a/src/debug/debug-property-iterator.h b/src/debug/debug-property-iterator.h new file mode 100644 index 0000000000..6a527f5dc7 --- /dev/null +++ b/src/debug/debug-property-iterator.h @@ -0,0 +1,62 @@ +// 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 receiver); + ~DebugPropertyIterator() override = default; + + bool Done() const override; + void Advance() override; + + v8::Local name() const override; + bool is_native_accessor() override; + bool has_native_getter() override; + bool has_native_setter() override; + v8::Maybe attributes() override; + v8::Maybe descriptor() override; + + bool is_own() override; + bool is_array_index() override; + + private: + void FillKeysForCurrentPrototypeAndStage(); + bool should_move_to_next_stage() const; + void CalculateNativeAccessorFlags(); + Handle 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 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_ diff --git a/src/inspector/BUILD.gn b/src/inspector/BUILD.gn index 7f97c70e54..72dc26a365 100644 --- a/src/inspector/BUILD.gn +++ b/src/inspector/BUILD.gn @@ -61,22 +61,6 @@ inspector_protocol_generate("protocol_generated_sources") { outputs = _protocol_generated } -action("inspector_injected_script") { - visibility = [ ":*" ] # Only targets in this file can depend on this. - script = "build/xxd.py" - inputs = [ - "injected-script-source.js", - ] - outputs = [ - "$target_gen_dir/injected-script-source.h", - ] - args = [ - "InjectedScriptSource_js", - rebase_path("injected-script-source.js", root_build_dir), - rebase_path("$target_gen_dir/injected-script-source.h", root_build_dir), - ] -} - config("inspector_config") { visibility = [ ":*" ] # Only targets in this file can depend on this. if (is_component_build) { @@ -86,7 +70,6 @@ config("inspector_config") { v8_source_set("inspector") { deps = [ - ":inspector_injected_script", ":protocol_generated_sources", ] configs = [ ":inspector_config" ] @@ -101,7 +84,6 @@ v8_source_set("inspector") { "../../include/v8-inspector-protocol.h", "../../include/v8-inspector.h", ] - sources += get_target_outputs(":inspector_injected_script") sources += [ "custom-preview.cc", "custom-preview.h", @@ -131,18 +113,12 @@ v8_source_set("inspector") { "v8-debugger-script.h", "v8-debugger.cc", "v8-debugger.h", - "v8-function-call.cc", - "v8-function-call.h", "v8-heap-profiler-agent-impl.cc", "v8-heap-profiler-agent-impl.h", - "v8-injected-script-host.cc", - "v8-injected-script-host.h", "v8-inspector-impl.cc", "v8-inspector-impl.h", "v8-inspector-session-impl.cc", "v8-inspector-session-impl.h", - "v8-internal-value-type.cc", - "v8-internal-value-type.h", "v8-profiler-agent-impl.cc", "v8-profiler-agent-impl.h", "v8-regex.cc", @@ -155,6 +131,8 @@ v8_source_set("inspector") { "v8-stack-trace-impl.h", "v8-value-utils.cc", "v8-value-utils.h", + "value-mirror.cc", + "value-mirror.h", "wasm-translation.cc", "wasm-translation.h", ] diff --git a/src/inspector/PRESUBMIT.py b/src/inspector/PRESUBMIT.py deleted file mode 100644 index 197a369279..0000000000 --- a/src/inspector/PRESUBMIT.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/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 diff --git a/src/inspector/build/check_injected_script_source.py b/src/inspector/build/check_injected_script_source.py deleted file mode 100644 index 0f2509cd8c..0000000000 --- a/src/inspector/build/check_injected_script_source.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/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+\(|(?= 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 '' -errors_found |= has_errors(validate_injected_script_out) - -os.remove(protocol_externs_file) - -if errors_found: - print 'ERRORS DETECTED' - sys.exit(1) diff --git a/src/inspector/build/generate_protocol_externs.py b/src/inspector/build/generate_protocol_externs.py deleted file mode 100755 index c2ba2c5b84..0000000000 --- a/src/inspector/build/generate_protocol_externs.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/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.}\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.} */\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.} 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) diff --git a/src/inspector/build/rjsmin.py b/src/inspector/build/rjsmin.py deleted file mode 100755 index 8357a6dcc1..0000000000 --- a/src/inspector/build/rjsmin.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/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())) diff --git a/src/inspector/build/xxd.py b/src/inspector/build/xxd.py deleted file mode 100644 index 5a63a7cb8d..0000000000 --- a/src/inspector/build/xxd.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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()) diff --git a/src/inspector/custom-preview.cc b/src/inspector/custom-preview.cc index 03b9893cd5..63d1d74ab8 100644 --- a/src/inspector/custom-preview.cc +++ b/src/inspector/custom-preview.cc @@ -113,7 +113,7 @@ bool substituteObjectTags(int sessionId, const String16& groupName, } std::unique_ptr wrapper; protocol::Response response = - injectedScript->wrapObject(originValue, groupName, false, false, + injectedScript->wrapObject(originValue, groupName, WrapMode::kNoPreview, configValue, maxDepth - 1, &wrapper); if (!response.isSuccess() || !wrapper) { reportError(context, tryCatch, "cannot wrap value"); @@ -379,13 +379,8 @@ void generateCustomPreview(int sessionId, const String16& groupName, reportError(context, tryCatch, "cannot find context with specified id"); return; } - (*preview)->setBodyGetterId(String16::concat( - "{\"injectedScriptId\":", - String16::fromInteger(InspectedContext::contextId(context)), - ",\"id\":", - String16::fromInteger( - injectedScript->bindObject(bodyFunction, groupName)), - "}")); + (*preview)->setBodyGetterId( + injectedScript->bindObject(bodyFunction, groupName)); } return; } diff --git a/src/inspector/injected-script-source.js b/src/inspector/injected-script-source.js deleted file mode 100644 index 37cb854cc9..0000000000 --- a/src/inspector/injected-script-source.js +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * Copyright (C) 2013 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: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. - */ - -"use strict"; - -/** - * @param {!InjectedScriptHostClass} InjectedScriptHost - * @param {!Window|!WorkerGlobalScope} inspectedGlobalObject - * @param {number} injectedScriptId - * @suppress {uselessCode} - */ -(function (InjectedScriptHost, inspectedGlobalObject, injectedScriptId) { - -/** - * @param {!Array.} array - * @param {...} var_args - * @template T - */ -function push(array, var_args) -{ - for (var i = 1; i < arguments.length; ++i) - array[array.length] = arguments[i]; -} - -/** - * @param {*} obj - * @return {string} - * @suppress {uselessCode} - */ -function toString(obj) -{ - // We don't use String(obj) because String could be overridden. - // Also the ("" + obj) expression may throw. - try { - return "" + obj; - } catch (e) { - var name = InjectedScriptHost.internalConstructorName(obj) || InjectedScriptHost.subtype(obj) || (typeof obj); - return "#<" + name + ">"; - } -} - -/** - * TODO(luoe): remove type-check suppression once bigint is supported by closure. - * @suppress {checkTypes} - * @param {*} obj - * @return {string} - */ -function toStringDescription(obj) -{ - if (typeof obj === "number" && obj === 0 && 1 / obj < 0) - return "-0"; // Negative zero. - if (typeof obj === "bigint") - return toString(obj) + "n"; - return toString(obj); -} - -/** - * FireBug's array detection. - * @param {*} obj - * @return {boolean} - */ -function isArrayLike(obj) -{ - if (typeof obj !== "object") - return false; - var splice = InjectedScriptHost.getProperty(obj, "splice"); - if (typeof splice === "function") { - if (!InjectedScriptHost.objectHasOwnProperty(/** @type {!Object} */ (obj), "length")) - return false; - var len = InjectedScriptHost.getProperty(obj, "length"); - // is len uint32? - return typeof len === "number" && len >>> 0 === len && (len > 0 || 1 / len > 0); - } - return false; -} - -/** - * @param {number} a - * @param {number} b - * @return {number} - */ -function max(a, b) -{ - return a > b ? a : b; -} - -/** - * FIXME: Remove once ES6 is supported natively by JS compiler. - * @param {*} obj - * @return {boolean} - */ -function isSymbol(obj) -{ - var type = typeof obj; - return (type === "symbol"); -} - -/** - * DOM Attributes which have observable side effect on getter, in the form of - * {interfaceName1: {attributeName1: true, - * attributeName2: true, - * ...}, - * interfaceName2: {...}, - * ...} - * @type {!Object>} - * @const - */ -var domAttributesWithObservableSideEffectOnGet = { - Request: { body: true, __proto__: null }, - Response: { body: true, __proto__: null }, - __proto__: null -} - -/** - * @param {!Object} object - * @param {string} attribute - * @return {boolean} - */ -function doesAttributeHaveObservableSideEffectOnGet(object, attribute) -{ - for (var interfaceName in domAttributesWithObservableSideEffectOnGet) { - var interfaceFunction = inspectedGlobalObject[interfaceName]; - // Call to instanceOf looks safe after typeof check. - var isInstance = typeof interfaceFunction === "function" && /* suppressBlacklist */ object instanceof interfaceFunction; - if (isInstance) - return attribute in domAttributesWithObservableSideEffectOnGet[interfaceName]; - } - return false; -} - -/** - * @constructor - */ -var InjectedScript = function() -{ -} -InjectedScriptHost.nullifyPrototype(InjectedScript); - -/** - * @type {!Object} - * @const - */ -InjectedScript.primitiveTypes = { - "undefined": true, - "boolean": true, - "number": true, - "string": true, - "bigint": true, - __proto__: null -} - -/** - * @type {!Object} - * @const - */ -InjectedScript.closureTypes = { - "local": "Local", - "closure": "Closure", - "catch": "Catch", - "block": "Block", - "script": "Script", - "with": "With Block", - "global": "Global", - "eval": "Eval", - "module": "Module", - __proto__: null -}; - -InjectedScript.prototype = { - /** - * @param {*} object - * @return {boolean} - */ - isPrimitiveValue: function(object) - { - // FIXME(33716): typeof document.all is always 'undefined'. - return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllCollection(object); - }, - - /** - * @param {*} object - * @return {boolean} - */ - _shouldPassByValue: function(object) - { - return typeof object === "object" && InjectedScriptHost.subtype(object) === "internal#location"; - }, - - /** - * @param {*} object - * @param {string} groupName - * @param {boolean} forceValueType - * @param {boolean} generatePreview - * @return {!RuntimeAgent.RemoteObject} - */ - wrapObject: function(object, groupName, forceValueType, generatePreview) - { - return this._wrapObject(object, groupName, forceValueType, generatePreview); - }, - - /** - * @param {!Object} table - * @param {!Array.|string|boolean} columns - * @return {!RuntimeAgent.RemoteObject} - */ - wrapTable: function(table, columns) - { - var columnNames = null; - if (typeof columns === "string") - columns = [columns]; - if (InjectedScriptHost.subtype(columns) === "array") { - columnNames = []; - InjectedScriptHost.nullifyPrototype(columnNames); - for (var i = 0; i < columns.length; ++i) - columnNames[i] = toString(columns[i]); - } - return this._wrapObject(table, "console", false, true, columnNames, true); - }, - - /** - * This method cannot throw. - * @param {*} object - * @param {string=} objectGroupName - * @param {boolean=} forceValueType - * @param {boolean=} generatePreview - * @param {?Array.=} columnNames - * @param {boolean=} isTable - * @param {boolean=} doNotBind - * @return {!RuntimeAgent.RemoteObject} - * @suppress {checkTypes} - */ - _wrapObject: function(object, objectGroupName, forceValueType, generatePreview, columnNames, isTable, doNotBind) - { - try { - return new InjectedScript.RemoteObject(object, objectGroupName, doNotBind, forceValueType, generatePreview, columnNames, isTable, undefined); - } catch (e) { - try { - var description = injectedScript._describe(e); - } catch (ex) { - var description = ""; - } - return new InjectedScript.RemoteObject(description); - } - }, - - /** - * @param {!Object|symbol} object - * @param {string=} objectGroupName - * @return {string} - */ - _bind: function(object, objectGroupName) - { - var id = InjectedScriptHost.bind(object, objectGroupName || ""); - return "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + "}"; - }, - - /** - * @param {!Object} object - * @param {string} objectGroupName - * @param {boolean} ownProperties - * @param {boolean} accessorPropertiesOnly - * @param {boolean} generatePreview - * @return {!Array|boolean} - */ - getProperties: function(object, objectGroupName, ownProperties, accessorPropertiesOnly, generatePreview) - { - var subtype = this._subtype(object); - if (subtype === "internal#scope") { - // Internally, scope contains object with scope variables and additional information like type, - // we use additional information for preview and would like to report variables as scope - // properties. - object = object.object; - } - - // Go over properties, wrap object values. - var descriptors = this._propertyDescriptors(object, addPropertyIfNeeded, ownProperties, accessorPropertiesOnly); - for (var i = 0; i < descriptors.length; ++i) { - var descriptor = descriptors[i]; - if ("get" in descriptor) - descriptor.get = this._wrapObject(descriptor.get, objectGroupName); - if ("set" in descriptor) - descriptor.set = this._wrapObject(descriptor.set, objectGroupName); - if ("value" in descriptor) - descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview); - if (!("configurable" in descriptor)) - descriptor.configurable = false; - if (!("enumerable" in descriptor)) - descriptor.enumerable = false; - if ("symbol" in descriptor) - descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName); - } - return descriptors; - - /** - * @param {!Array} descriptors - * @param {!Object} descriptor - * @return {boolean} - */ - function addPropertyIfNeeded(descriptors, descriptor) { - push(descriptors, descriptor); - return true; - } - }, - - /** - * @param {!Object} object - * @return {?Object} - */ - _objectPrototype: function(object) - { - if (InjectedScriptHost.subtype(object) === "proxy") - return null; - try { - return InjectedScriptHost.getPrototypeOf(object); - } catch (e) { - return null; - } - }, - - /** - * @param {!Object} object - * @param {!function(!Array, !Object)} addPropertyIfNeeded - * @param {boolean=} ownProperties - * @param {boolean=} accessorPropertiesOnly - * @param {?Array=} propertyNamesOnly - * @return {!Array} - */ - _propertyDescriptors: function(object, addPropertyIfNeeded, ownProperties, accessorPropertiesOnly, propertyNamesOnly) - { - var descriptors = []; - InjectedScriptHost.nullifyPrototype(descriptors); - var propertyProcessed = { __proto__: null }; - var subtype = InjectedScriptHost.subtype(object); - - /** - * @param {!Object} o - * @param {!Array=} properties - * @param {number=} objectLength - * @return {boolean} - */ - function process(o, properties, objectLength) - { - // When properties is not provided, iterate over the object's indices. - var length = properties ? properties.length : objectLength; - for (var i = 0; i < length; ++i) { - var property = properties ? properties[i] : ("" + i); - if (propertyProcessed[property]) - continue; - propertyProcessed[property] = true; - var name; - if (isSymbol(property)) - name = /** @type {string} */ (injectedScript._describe(property)); - else - name = typeof property === "number" ? ("" + property) : /** @type {string} */(property); - - if (subtype === "internal#scopeList" && name === "length") - continue; - - var descriptor; - try { - var nativeAccessorDescriptor = InjectedScriptHost.nativeAccessorDescriptor(o, property); - if (nativeAccessorDescriptor && !nativeAccessorDescriptor.isBuiltin) { - descriptor = { __proto__: null }; - if (nativeAccessorDescriptor.hasGetter) - descriptor.get = function nativeGetter() { return o[property]; }; - if (nativeAccessorDescriptor.hasSetter) - descriptor.set = function nativeSetter(v) { o[property] = v; }; - } else { - descriptor = InjectedScriptHost.getOwnPropertyDescriptor(o, property); - if (descriptor) { - InjectedScriptHost.nullifyPrototype(descriptor); - } - } - var isAccessorProperty = descriptor && ("get" in descriptor || "set" in descriptor); - if (accessorPropertiesOnly && !isAccessorProperty) - continue; - // Special case for Symbol.prototype.description where the receiver of the getter is not an actual object. - // Should only occur for nested previews. - var isSymbolDescription = isSymbol(object) && name === 'description'; - if (isSymbolDescription || (descriptor && "get" in descriptor && "set" in descriptor && name !== "__proto__" && - InjectedScriptHost.formatAccessorsAsProperties(object, descriptor.get) && - !doesAttributeHaveObservableSideEffectOnGet(object, name))) { - descriptor.value = object[property]; - descriptor.isOwn = true; - delete descriptor.get; - delete descriptor.set; - } - } catch (e) { - if (accessorPropertiesOnly) - continue; - descriptor = { value: e, wasThrown: true, __proto__: null }; - } - - // Not all bindings provide proper descriptors. Fall back to the non-configurable, non-enumerable, - // non-writable property. - if (!descriptor) { - try { - descriptor = { value: o[property], writable: false, __proto__: null }; - } catch (e) { - // Silent catch. - continue; - } - } - - descriptor.name = name; - if (o === object) - descriptor.isOwn = true; - if (isSymbol(property)) - descriptor.symbol = property; - if (!addPropertyIfNeeded(descriptors, descriptor)) - return false; - } - return true; - } - - if (propertyNamesOnly) { - for (var i = 0; i < propertyNamesOnly.length; ++i) { - var name = propertyNamesOnly[i]; - for (var o = object; this._isDefined(o); o = this._objectPrototype(/** @type {!Object} */ (o))) { - o = /** @type {!Object} */ (o); - if (InjectedScriptHost.objectHasOwnProperty(o, name)) { - if (!process(o, [name])) - return descriptors; - break; - } - if (ownProperties) - break; - } - } - return descriptors; - } - - var skipGetOwnPropertyNames; - try { - skipGetOwnPropertyNames = subtype === "typedarray" && object.length > 500000; - } catch (e) { - } - - for (var o = object; this._isDefined(o); o = this._objectPrototype(/** @type {!Object} */ (o))) { - o = /** @type {!Object} */ (o); - if (InjectedScriptHost.subtype(o) === "proxy") - continue; - - var typedArrays = subtype === "arraybuffer" ? InjectedScriptHost.typedArrayProperties(o) || [] : []; - for (var i = 0; i < typedArrays.length; i += 2) - addPropertyIfNeeded(descriptors, { name: typedArrays[i], value: typedArrays[i + 1], isOwn: true, enumerable: false, configurable: false, __proto__: null }); - - try { - if (skipGetOwnPropertyNames && o === object) { - if (!process(o, undefined, o.length)) - return descriptors; - } else { - // First call Object.keys() to enforce ordering of the property descriptors. - if (!process(o, InjectedScriptHost.keys(o))) - return descriptors; - if (!process(o, InjectedScriptHost.getOwnPropertyNames(o))) - return descriptors; - } - if (!process(o, InjectedScriptHost.getOwnPropertySymbols(o))) - return descriptors; - - if (ownProperties) { - var proto = this._objectPrototype(o); - if (proto && !accessorPropertiesOnly) { - var descriptor = { name: "__proto__", value: proto, writable: true, configurable: true, enumerable: false, isOwn: true, __proto__: null }; - if (!addPropertyIfNeeded(descriptors, descriptor)) - return descriptors; - } - } - } catch (e) { - } - - if (ownProperties) - break; - } - return descriptors; - }, - - /** - * @param {*} object - * @return {boolean} - */ - _isDefined: function(object) - { - return !!object || this._isHTMLAllCollection(object); - }, - - /** - * @param {*} object - * @return {boolean} - */ - _isHTMLAllCollection: function(object) - { - // document.all is reported as undefined, but we still want to process it. - return (typeof object === "undefined") && !!InjectedScriptHost.subtype(object); - }, - - /** - * @param {*} obj - * @return {?string} - */ - _subtype: function(obj) - { - if (obj === null) - return "null"; - - if (this.isPrimitiveValue(obj)) - return null; - - var subtype = InjectedScriptHost.subtype(obj); - if (subtype) - return subtype; - - if (isArrayLike(obj)) - return "array"; - - // If owning frame has navigated to somewhere else window properties will be undefined. - return null; - }, - - /** - * @param {*} obj - * @return {?string} - */ - _describe: function(obj) - { - if (this.isPrimitiveValue(obj)) - return null; - - var subtype = this._subtype(obj); - - if (subtype === "regexp") - return toString(obj); - - if (subtype === "date") - return toString(obj); - - if (subtype === "node") { - // We should warmup blink dom binding before calling anything, - // see (crbug.com/827585) for details. - InjectedScriptHost.getOwnPropertyDescriptor(/** @type {!Object} */(obj), "nodeName"); - var description = ""; - var nodeName = InjectedScriptHost.getProperty(obj, "nodeName"); - if (nodeName) { - description = nodeName.toLowerCase(); - } else { - var constructor = InjectedScriptHost.getProperty(obj, "constructor"); - if (constructor) - description = (InjectedScriptHost.getProperty(constructor, "name") || "").toLowerCase(); - } - - var nodeType = InjectedScriptHost.getProperty(obj, "nodeType"); - switch (nodeType) { - case 1 /* Node.ELEMENT_NODE */: - var id = InjectedScriptHost.getProperty(obj, "id"); - description += id ? "#" + id : ""; - var className = InjectedScriptHost.getProperty(obj, "className"); - description += (className && typeof className === "string") ? "." + className.trim().replace(/\s+/g, ".") : ""; - break; - case 10 /*Node.DOCUMENT_TYPE_NODE */: - description = ""; - break; - } - return description; - } - - if (subtype === "proxy") - return "Proxy"; - - var className = InjectedScriptHost.internalConstructorName(obj); - if (subtype === "array" || subtype === "typedarray") { - if (typeof obj.length === "number") - return className + "(" + obj.length + ")"; - return className; - } - - if (subtype === "map" || subtype === "set" || subtype === "blob") { - if (typeof obj.size === "number") - return className + "(" + obj.size + ")"; - return className; - } - - if (subtype === "arraybuffer" || subtype === "dataview") { - if (typeof obj.byteLength === "number") - return className + "(" + obj.byteLength + ")"; - return className; - } - - if (typeof obj === "function") - return toString(obj); - - if (isSymbol(obj)) { - try { - // It isn't safe, because Symbol.prototype.toString can be overriden. - return /* suppressBlacklist */ obj.toString() || "Symbol"; - } catch (e) { - return "Symbol"; - } - } - - if (InjectedScriptHost.subtype(obj) === "error") { - try { - const stack = obj.stack; - if (stack.substr(0, className.length) === className) - return stack; - const message = obj.message; - const index = /* suppressBlacklist */ stack.indexOf(message); - const messageWithStack = index !== -1 ? stack.substr(index) : message; - return className + ': ' + messageWithStack; - } catch(e) { - return className; - } - } - - if (subtype === "internal#entry") { - if ("key" in obj) - return "{" + this._describeIncludingPrimitives(obj.key) + " => " + this._describeIncludingPrimitives(obj.value) + "}"; - return this._describeIncludingPrimitives(obj.value); - } - - if (subtype === "internal#scopeList") - return "Scopes[" + obj.length + "]"; - - if (subtype === "internal#scope") - return (InjectedScript.closureTypes[obj.type] || "Unknown") + (obj.name ? " (" + obj.name + ")" : ""); - - return className; - }, - - /** - * @param {*} value - * @return {string} - */ - _describeIncludingPrimitives: function(value) - { - if (typeof value === "string") - return "\"" + value.replace(/\n/g, "\u21B5") + "\""; - if (value === null) - return "" + value; - return this.isPrimitiveValue(value) ? toStringDescription(value) : (this._describe(value) || ""); - } -} - -/** - * @type {!InjectedScript} - * @const - */ -var injectedScript = new InjectedScript(); - -/** - * @constructor - * @param {*} object - * @param {string=} objectGroupName - * @param {boolean=} doNotBind - * @param {boolean=} forceValueType - * @param {boolean=} generatePreview - * @param {?Array.=} columnNames - * @param {boolean=} isTable - * @param {boolean=} skipEntriesPreview - */ -InjectedScript.RemoteObject = function(object, objectGroupName, doNotBind, forceValueType, generatePreview, columnNames, isTable, skipEntriesPreview) -{ - this.type = typeof object; - if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object)) - this.type = "object"; - - if (injectedScript.isPrimitiveValue(object) || object === null || forceValueType) { - // We don't send undefined values over JSON. - if (this.type !== "undefined") - this.value = object; - - // Null object is object with 'null' subtype. - if (object === null) - this.subtype = "null"; - - // Provide user-friendly number values. - if (this.type === "number") { - this.description = toStringDescription(object); - switch (this.description) { - case "NaN": - case "Infinity": - case "-Infinity": - case "-0": - delete this.value; - this.unserializableValue = this.description; - break; - } - } - - // The "n" suffix of bigint primitives are not JSON serializable. - if (this.type === "bigint") { - delete this.value; - this.description = toStringDescription(object); - this.unserializableValue = this.description; - } - - return; - } - - if (injectedScript._shouldPassByValue(object)) { - this.value = object; - this.subtype = injectedScript._subtype(object); - this.description = injectedScript._describeIncludingPrimitives(object); - return; - } - - object = /** @type {!Object} */ (object); - - if (!doNotBind) - this.objectId = injectedScript._bind(object, objectGroupName); - var subtype = injectedScript._subtype(object); - if (subtype) - this.subtype = subtype; - var className = InjectedScriptHost.internalConstructorName(object); - if (className) - this.className = className; - this.description = injectedScript._describe(object); - - if (generatePreview && this.type === "object") { - if (this.subtype === "proxy") - this.preview = this._generatePreview(InjectedScriptHost.proxyTargetValue(object), undefined, columnNames, isTable, skipEntriesPreview); - else - this.preview = this._generatePreview(object, undefined, columnNames, isTable, skipEntriesPreview); - } -} - -InjectedScript.RemoteObject.prototype = { - /** - * @return {!RuntimeAgent.ObjectPreview} preview - */ - _createEmptyPreview: function() - { - var preview = { - type: /** @type {!RuntimeAgent.ObjectPreviewType.} */ (this.type), - description: this.description || toStringDescription(this.value), - overflow: false, - properties: [], - __proto__: null - }; - InjectedScriptHost.nullifyPrototype(preview.properties); - if (this.subtype) - preview.subtype = /** @type {!RuntimeAgent.ObjectPreviewSubtype.} */ (this.subtype); - return preview; - }, - - /** - * @param {!Object} object - * @param {?Array.=} firstLevelKeys - * @param {?Array.=} secondLevelKeys - * @param {boolean=} isTable - * @param {boolean=} skipEntriesPreview - * @return {!RuntimeAgent.ObjectPreview} preview - */ - _generatePreview: function(object, firstLevelKeys, secondLevelKeys, isTable, skipEntriesPreview) - { - var preview = this._createEmptyPreview(); - var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0; - var propertiesThreshold = { - properties: isTable ? 1000 : max(5, firstLevelKeysCount), - indexes: isTable ? 1000 : max(100, firstLevelKeysCount), - __proto__: null - }; - var subtype = this.subtype; - var primitiveString; - - try { - var descriptors = []; - InjectedScriptHost.nullifyPrototype(descriptors); - - // Add internal properties to preview. - var rawInternalProperties = InjectedScriptHost.getInternalProperties(object) || []; - var internalProperties = []; - InjectedScriptHost.nullifyPrototype(rawInternalProperties); - InjectedScriptHost.nullifyPrototype(internalProperties); - var entries = null; - for (var i = 0; i < rawInternalProperties.length; i += 2) { - if (rawInternalProperties[i] === "[[Entries]]") { - entries = /** @type {!Array<*>} */(rawInternalProperties[i + 1]); - continue; - } - if (rawInternalProperties[i] === "[[PrimitiveValue]]" && typeof rawInternalProperties[i + 1] === 'string') - primitiveString = rawInternalProperties[i + 1]; - var internalPropertyDescriptor = { - name: rawInternalProperties[i], - value: rawInternalProperties[i + 1], - isOwn: true, - enumerable: true, - __proto__: null - }; - push(descriptors, internalPropertyDescriptor); - } - var naturalDescriptors = injectedScript._propertyDescriptors(object, addPropertyIfNeeded, false /* ownProperties */, undefined /* accessorPropertiesOnly */, firstLevelKeys); - for (var i = 0; i < naturalDescriptors.length; i++) - push(descriptors, naturalDescriptors[i]); - - this._appendPropertyPreviewDescriptors(preview, descriptors, secondLevelKeys, isTable); - - if (subtype === "map" || subtype === "set" || subtype === "weakmap" || subtype === "weakset" || subtype === "iterator") - this._appendEntriesPreview(entries, preview, skipEntriesPreview); - - } catch (e) {} - - return preview; - - /** - * @param {!Array} descriptors - * @param {!Object} descriptor - * @return {boolean} - */ - function addPropertyIfNeeded(descriptors, descriptor) { - if (descriptor.wasThrown) - return true; - - // Ignore __proto__ property. - if (descriptor.name === "__proto__") - return true; - - // Ignore length property of array. - if ((subtype === "array" || subtype === "typedarray") && descriptor.name === "length") - return true; - - // Ignore size property of map, set. - if ((subtype === "map" || subtype === "set") && descriptor.name === "size") - return true; - - // Ignore ArrayBuffer previews - if (subtype === 'arraybuffer' && (descriptor.name === "[[Int8Array]]" || descriptor.name === "[[Uint8Array]]" || descriptor.name === "[[Int16Array]]" || descriptor.name === "[[Int32Array]]")) - return true; - - // Never preview prototype properties. - if (!descriptor.isOwn) - return true; - - // Ignore computed properties unless they have getters. - if (!("value" in descriptor) && !descriptor.get) - return true; - - // Ignore index properties when there is a primitive string. - if (primitiveString && primitiveString[descriptor.name] === descriptor.value) - return true; - - if (toString(descriptor.name >>> 0) === descriptor.name) - propertiesThreshold.indexes--; - else - propertiesThreshold.properties--; - - var canContinue = propertiesThreshold.indexes >= 0 && propertiesThreshold.properties >= 0; - if (!canContinue) { - preview.overflow = true; - return false; - } - push(descriptors, descriptor); - return true; - } - }, - - /** - * @param {!RuntimeAgent.ObjectPreview} preview - * @param {!Array.<*>|!Iterable.<*>} descriptors - * @param {?Array.=} secondLevelKeys - * @param {boolean=} isTable - */ - _appendPropertyPreviewDescriptors: function(preview, descriptors, secondLevelKeys, isTable) - { - for (var i = 0; i < descriptors.length; ++i) { - var descriptor = descriptors[i]; - var name = descriptor.name; - var value = descriptor.value; - var type = typeof value; - - // Special-case HTMLAll. - if (type === "undefined" && injectedScript._isHTMLAllCollection(value)) - type = "object"; - - // Ignore computed properties unless they have getters. - if (descriptor.get && !("value" in descriptor)) { - push(preview.properties, { name: name, type: "accessor", __proto__: null }); - continue; - } - - // Render own properties. - if (value === null) { - push(preview.properties, { name: name, type: "object", subtype: "null", value: "null", __proto__: null }); - continue; - } - - var maxLength = 100; - if (InjectedScript.primitiveTypes[type]) { - var valueString = type === "string" ? value : toStringDescription(value); - if (valueString.length > maxLength) - valueString = this._abbreviateString(valueString, maxLength, true); - push(preview.properties, { name: name, type: type, value: valueString, __proto__: null }); - continue; - } - - var property = { name: name, type: type, __proto__: null }; - var subtype = injectedScript._subtype(value); - if (subtype) - property.subtype = subtype; - - if (secondLevelKeys === null || secondLevelKeys) { - var subPreview = this._generatePreview(value, secondLevelKeys || undefined, undefined, isTable); - property.valuePreview = subPreview; - if (subPreview.overflow) - preview.overflow = true; - } else { - var description = ""; - if (type !== "function") - description = this._abbreviateString(/** @type {string} */ (injectedScript._describe(value)), maxLength, subtype === "regexp"); - property.value = description; - } - push(preview.properties, property); - } - }, - - /** - * @param {?Array<*>} entries - * @param {!RuntimeAgent.ObjectPreview} preview - * @param {boolean=} skipEntriesPreview - */ - _appendEntriesPreview: function(entries, preview, skipEntriesPreview) - { - if (!entries) - return; - if (skipEntriesPreview) { - if (entries.length) - preview.overflow = true; - return; - } - preview.entries = []; - InjectedScriptHost.nullifyPrototype(preview.entries); - var entriesThreshold = 5; - for (var i = 0; i < entries.length; ++i) { - if (preview.entries.length >= entriesThreshold) { - preview.overflow = true; - break; - } - var entry = entries[i]; - InjectedScriptHost.nullifyPrototype(entry); - var previewEntry = { - value: generateValuePreview(entry.value), - __proto__: null - }; - if ("key" in entry) - previewEntry.key = generateValuePreview(entry.key); - push(preview.entries, previewEntry); - } - - /** - * @param {*} value - * @return {!RuntimeAgent.ObjectPreview} - */ - function generateValuePreview(value) - { - var remoteObject = new InjectedScript.RemoteObject(value, undefined, true, undefined, true, undefined, undefined, true); - var valuePreview = remoteObject.preview || remoteObject._createEmptyPreview(); - return valuePreview; - } - }, - - /** - * @param {string} string - * @param {number} maxLength - * @param {boolean=} middle - * @return {string} - */ - _abbreviateString: function(string, maxLength, middle) - { - if (string.length <= maxLength) - return string; - if (middle) { - var leftHalf = maxLength >> 1; - var rightHalf = maxLength - leftHalf - 1; - return string.substr(0, leftHalf) + "\u2026" + string.substr(string.length - rightHalf, rightHalf); - } - return string.substr(0, maxLength) + "\u2026"; - }, - - __proto__: null -} - -return injectedScript; -}) diff --git a/src/inspector/injected-script.cc b/src/inspector/injected-script.cc index f58c19d4d8..f8daf792c2 100644 --- a/src/inspector/injected-script.cc +++ b/src/inspector/injected-script.cc @@ -30,26 +30,26 @@ #include "src/inspector/injected-script.h" +#include +#include + #include "src/inspector/custom-preview.h" -#include "src/inspector/injected-script-source.h" #include "src/inspector/inspected-context.h" #include "src/inspector/protocol/Protocol.h" #include "src/inspector/remote-object-id.h" #include "src/inspector/string-util.h" #include "src/inspector/v8-console.h" -#include "src/inspector/v8-function-call.h" -#include "src/inspector/v8-injected-script-host.h" #include "src/inspector/v8-inspector-impl.h" #include "src/inspector/v8-inspector-session-impl.h" #include "src/inspector/v8-stack-trace-impl.h" #include "src/inspector/v8-value-utils.h" +#include "src/inspector/value-mirror.h" #include "include/v8-inspector.h" namespace v8_inspector { namespace { -static const char privateKeyName[] = "v8-inspector#injectedScript"; static const char kGlobalHandleLabel[] = "DevTools console"; static bool isResolvableNumberLike(String16 query) { return query == "Infinity" || query == "-Infinity" || query == "NaN"; @@ -67,8 +67,7 @@ class InjectedScript::ProtocolPromiseHandler { static bool add(V8InspectorSessionImpl* session, v8::Local context, v8::Local value, int executionContextId, const String16& objectGroup, - bool returnByValue, bool generatePreview, - EvaluateCallback* callback) { + WrapMode wrapMode, EvaluateCallback* callback) { v8::Local resolver; if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) { callback->sendFailure(Response::InternalError()); @@ -81,9 +80,8 @@ class InjectedScript::ProtocolPromiseHandler { v8::Local promise = resolver->GetPromise(); V8InspectorImpl* inspector = session->inspector(); - ProtocolPromiseHandler* handler = - new ProtocolPromiseHandler(session, executionContextId, objectGroup, - returnByValue, generatePreview, callback); + ProtocolPromiseHandler* handler = new ProtocolPromiseHandler( + session, executionContextId, objectGroup, wrapMode, callback); v8::Local wrapper = handler->m_wrapper.Get(inspector->isolate()); v8::Local thenCallbackFunction = v8::Function::New(context, thenCallback, wrapper, 0, @@ -131,15 +129,13 @@ class InjectedScript::ProtocolPromiseHandler { ProtocolPromiseHandler(V8InspectorSessionImpl* session, int executionContextId, const String16& objectGroup, - bool returnByValue, bool generatePreview, - EvaluateCallback* callback) + WrapMode wrapMode, EvaluateCallback* callback) : m_inspector(session->inspector()), m_sessionId(session->sessionId()), m_contextGroupId(session->contextGroupId()), m_executionContextId(executionContextId), m_objectGroup(objectGroup), - m_returnByValue(returnByValue), - m_generatePreview(generatePreview), + m_wrapMode(wrapMode), m_callback(std::move(callback)), m_wrapper(m_inspector->isolate(), v8::External::New(m_inspector->isolate(), this)) { @@ -171,9 +167,8 @@ class InjectedScript::ProtocolPromiseHandler { scope.injectedScript()->takeEvaluateCallback(m_callback); if (!callback) return; std::unique_ptr wrappedValue; - response = scope.injectedScript()->wrapObject( - result, m_objectGroup, m_returnByValue, m_generatePreview, - &wrappedValue); + response = scope.injectedScript()->wrapObject(result, m_objectGroup, + m_wrapMode, &wrappedValue); if (!response.isSuccess()) { callback->sendFailure(response); return; @@ -193,9 +188,8 @@ class InjectedScript::ProtocolPromiseHandler { scope.injectedScript()->takeEvaluateCallback(m_callback); if (!callback) return; std::unique_ptr wrappedValue; - response = scope.injectedScript()->wrapObject( - result, m_objectGroup, m_returnByValue, m_generatePreview, - &wrappedValue); + response = scope.injectedScript()->wrapObject(result, m_objectGroup, + m_wrapMode, &wrappedValue); if (!response.isSuccess()) { callback->sendFailure(response); return; @@ -253,116 +247,142 @@ class InjectedScript::ProtocolPromiseHandler { int m_contextGroupId; int m_executionContextId; String16 m_objectGroup; - bool m_returnByValue; - bool m_generatePreview; + WrapMode m_wrapMode; EvaluateCallback* m_callback; v8::Global m_wrapper; }; -std::unique_ptr InjectedScript::create( - InspectedContext* inspectedContext, int sessionId) { - v8::Isolate* isolate = inspectedContext->isolate(); - v8::HandleScope handles(isolate); - v8::TryCatch tryCatch(isolate); - v8::Local 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(InjectedScriptSource_js), - sizeof(InjectedScriptSource_js)); - v8::Local value; - if (!inspectedContext->inspector() - ->compileAndRunInternalScript( - context, toV8String(isolate, injectedScriptSource)) - .ToLocal(&value)) { - return nullptr; - } - DCHECK(value->IsFunction()); - v8::Local scriptHostWrapper = - V8InjectedScriptHost::create(context, inspectedContext->inspector()); - v8::Local function = v8::Local::Cast(value); - v8::Local windowGlobal = context->Global(); - v8::Local info[] = { - scriptHostWrapper, windowGlobal, - v8::Number::New(isolate, inspectedContext->contextId())}; - - int contextGroupId = inspectedContext->contextGroupId(); - int contextId = inspectedContext->contextId(); - V8InspectorImpl* inspector = inspectedContext->inspector(); - v8::Local 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(new InjectedScript( - inspectedContext, injectedScriptValue.As(), sessionId)); - v8::Local 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 object, int sessionId) - : m_context(context), - m_value(context->isolate(), object), - m_sessionId(sessionId) {} +InjectedScript::InjectedScript(InspectedContext* context, int sessionId) + : m_context(context), m_sessionId(sessionId) {} InjectedScript::~InjectedScript() { discardEvaluateCallbacks(); } +namespace { +class PropertyAccumulator : public ValueMirror::PropertyAccumulator { + public: + explicit PropertyAccumulator(std::vector* mirrors) + : m_mirrors(mirrors) {} + bool Add(PropertyMirror mirror) override { + m_mirrors->push_back(std::move(mirror)); + return true; + } + + private: + std::vector* m_mirrors; +}; +} // anonymous namespace + Response InjectedScript::getProperties( v8::Local object, const String16& groupName, bool ownProperties, - bool accessorPropertiesOnly, bool generatePreview, + bool accessorPropertiesOnly, WrapMode wrapMode, std::unique_ptr>* properties, Maybe* exceptionDetails) { v8::HandleScope handles(m_context->isolate()); v8::Local context = m_context->context(); - V8FunctionCall function(m_context->inspector(), m_context->context(), - v8Value(), "getProperties"); - function.appendArgument(object); - function.appendArgument(groupName); - function.appendArgument(ownProperties); - function.appendArgument(accessorPropertiesOnly); - function.appendArgument(generatePreview); + v8::Isolate* isolate = m_context->isolate(); + int sessionId = m_sessionId; + v8::TryCatch tryCatch(isolate); - v8::TryCatch tryCatch(m_context->isolate()); - v8::Local resultValue = function.callWithoutExceptionHandling(); - if (tryCatch.HasCaught()) { - Response response = createExceptionDetails( - tryCatch, groupName, generatePreview, exceptionDetails); - if (!response.isSuccess()) return response; - // FIXME: make properties optional - *properties = Array::create(); - return Response::OK(); + *properties = Array::create(); + std::vector mirrors; + PropertyAccumulator accumulator(&mirrors); + if (!ValueMirror::getProperties(context, object, ownProperties, + accessorPropertiesOnly, &accumulator)) { + return createExceptionDetails(tryCatch, groupName, wrapMode, + exceptionDetails); + } + for (const PropertyMirror& mirror : mirrors) { + std::unique_ptr descriptor = + PropertyDescriptor::create() + .setName(mirror.name) + .setConfigurable(mirror.configurable) + .setEnumerable(mirror.enumerable) + .setIsOwn(mirror.isOwn) + .build(); + Response response; + std::unique_ptr remoteObject; + if (mirror.value) { + response = + mirror.value->buildRemoteObject(context, wrapMode, &remoteObject); + if (!response.isSuccess()) return response; + response = + bindRemoteObjectIfNeeded(sessionId, context, mirror.value->v8Value(), + groupName, remoteObject.get()); + if (!response.isSuccess()) return response; + descriptor->setValue(std::move(remoteObject)); + descriptor->setWritable(mirror.writable); + } + if (mirror.getter) { + response = + mirror.getter->buildRemoteObject(context, wrapMode, &remoteObject); + if (!response.isSuccess()) return response; + response = + bindRemoteObjectIfNeeded(sessionId, context, mirror.getter->v8Value(), + groupName, remoteObject.get()); + if (!response.isSuccess()) return response; + descriptor->setGet(std::move(remoteObject)); + } + if (mirror.setter) { + response = + mirror.setter->buildRemoteObject(context, wrapMode, &remoteObject); + if (!response.isSuccess()) return response; + response = + bindRemoteObjectIfNeeded(sessionId, context, mirror.setter->v8Value(), + groupName, remoteObject.get()); + if (!response.isSuccess()) return response; + descriptor->setSet(std::move(remoteObject)); + } + if (mirror.symbol) { + response = + mirror.symbol->buildRemoteObject(context, wrapMode, &remoteObject); + if (!response.isSuccess()) return response; + response = + bindRemoteObjectIfNeeded(sessionId, context, mirror.symbol->v8Value(), + groupName, remoteObject.get()); + if (!response.isSuccess()) return response; + descriptor->setSymbol(std::move(remoteObject)); + } + if (mirror.exception) { + response = + mirror.exception->buildRemoteObject(context, wrapMode, &remoteObject); + if (!response.isSuccess()) return response; + response = bindRemoteObjectIfNeeded(sessionId, context, + mirror.exception->v8Value(), + groupName, remoteObject.get()); + if (!response.isSuccess()) return response; + descriptor->setValue(std::move(remoteObject)); + descriptor->setWasThrown(true); + } + (*properties)->addItem(std::move(descriptor)); + } + return Response::OK(); +} + +Response InjectedScript::getInternalProperties( + v8::Local value, const String16& groupName, + std::unique_ptr>* result) { + *result = protocol::Array::create(); + v8::Local context = m_context->context(); + int sessionId = m_sessionId; + std::vector wrappers; + if (value->IsObject()) { + ValueMirror::getInternalProperties(m_context->context(), + value.As(), &wrappers); + } + for (size_t i = 0; i < wrappers.size(); ++i) { + std::unique_ptr remoteObject; + Response response = wrappers[i].value->buildRemoteObject( + m_context->context(), WrapMode::kNoPreview, &remoteObject); + if (!response.isSuccess()) return response; + response = bindRemoteObjectIfNeeded(sessionId, context, + wrappers[i].value->v8Value(), groupName, + remoteObject.get()); + if (!response.isSuccess()) return response; + (*result)->addItem(InternalPropertyDescriptor::create() + .setName(wrappers[i].name) + .setValue(std::move(remoteObject)) + .build()); } - if (resultValue.IsEmpty()) return Response::InternalError(); - std::unique_ptr protocolValue; - Response response = toProtocolValue(context, resultValue, &protocolValue); - if (!response.isSuccess()) return response; - protocol::ErrorSupport errors; - std::unique_ptr> result = - Array::fromValue(protocolValue.get(), &errors); - if (errors.hasErrors()) return Response::Error(errors.errors()); - *properties = std::move(result); return Response::OK(); } @@ -379,37 +399,27 @@ void InjectedScript::releaseObject(const String16& objectId) { } Response InjectedScript::wrapObject( - v8::Local value, const String16& groupName, bool forceValueType, - bool generatePreview, - std::unique_ptr* result) const { - return wrapObject(value, groupName, forceValueType, generatePreview, - v8::MaybeLocal(), kMaxCustomPreviewDepth, - result); + v8::Local value, const String16& groupName, WrapMode wrapMode, + std::unique_ptr* result) { + return wrapObject(value, groupName, wrapMode, v8::MaybeLocal(), + kMaxCustomPreviewDepth, result); } Response InjectedScript::wrapObject( - v8::Local value, const String16& groupName, bool forceValueType, - bool generatePreview, v8::MaybeLocal customPreviewConfig, - int maxCustomPreviewDepth, - std::unique_ptr* result) const { - v8::HandleScope handles(m_context->isolate()); - v8::Local wrappedObject; + v8::Local value, const String16& groupName, WrapMode wrapMode, + v8::MaybeLocal customPreviewConfig, int maxCustomPreviewDepth, + std::unique_ptr* result) { v8::Local context = m_context->context(); - + v8::Context::Scope contextScope(context); int customPreviewEnabled = m_customPreviewEnabled; int sessionId = m_sessionId; - - Response response = wrapValue(value, groupName, forceValueType, - generatePreview, &wrappedObject); + auto obj = ValueMirror::create(m_context->context(), value); + if (!obj) return Response::InternalError(); + Response response = obj->buildRemoteObject(context, wrapMode, result); if (!response.isSuccess()) return response; - protocol::ErrorSupport errors; - std::unique_ptr protocolValue; - response = toProtocolValue(context, wrappedObject, &protocolValue); + response = bindRemoteObjectIfNeeded(sessionId, context, value, groupName, + result->get()); if (!response.isSuccess()) return response; - - *result = - protocol::Runtime::RemoteObject::fromValue(protocolValue.get(), &errors); - if (!result->get()) return Response::Error(errors.errors()); if (customPreviewEnabled && value->IsObject()) { std::unique_ptr customPreview; generateCustomPreview(sessionId, groupName, context, value.As(), @@ -420,47 +430,65 @@ Response InjectedScript::wrapObject( return Response::OK(); } -Response InjectedScript::wrapValue(v8::Local value, - const String16& groupName, - bool forceValueType, bool generatePreview, - v8::Local* 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 InjectedScript::wrapTable( - v8::Local table, v8::Local columns) const { - v8::HandleScope handles(m_context->isolate()); + v8::Local table, v8::MaybeLocal maybeColumns) { + using protocol::Runtime::RemoteObject; + using protocol::Runtime::ObjectPreview; + using protocol::Runtime::PropertyPreview; + using protocol::Array; + + v8::Isolate* isolate = m_context->isolate(); + v8::HandleScope handles(isolate); v8::Local context = m_context->context(); - V8FunctionCall function(m_context->inspector(), context, v8Value(), - "wrapTable"); - function.appendArgument(table); - if (columns.IsEmpty()) - function.appendArgument(false); - else - function.appendArgument(columns); - bool hadException = false; - v8::Local r = function.call(hadException); - if (hadException || r.IsEmpty()) return nullptr; - std::unique_ptr protocolValue; - Response response = toProtocolValue(context, r, &protocolValue); - if (!response.isSuccess()) return nullptr; - protocol::ErrorSupport errors; - return protocol::Runtime::RemoteObject::fromValue(protocolValue.get(), - &errors); + + std::unique_ptr remoteObject; + Response response = + wrapObject(table, "console", WrapMode::kNoPreview, &remoteObject); + if (!remoteObject || !response.isSuccess()) return nullptr; + + auto mirror = ValueMirror::create(context, table); + std::unique_ptr preview; + int limit = 100; + mirror->buildObjectPreview(context, true /* generatePreviewForProperties */, + &limit, &limit, &preview); + + Array* columns = preview->getProperties(); + std::unordered_set selectedColumns; + v8::Local v8Columns; + if (maybeColumns.ToLocal(&v8Columns)) { + for (uint32_t i = 0; i < v8Columns->Length(); ++i) { + v8::Local column; + if (v8Columns->Get(context, i).ToLocal(&column) && column->IsString()) { + selectedColumns.insert( + toProtocolString(isolate, column.As())); + } + } + } + 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> filtered = + Array::create(); + Array* 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( V8InspectorSessionImpl* session, v8::MaybeLocal value, - const String16& objectGroup, bool returnByValue, bool generatePreview, + const String16& objectGroup, WrapMode wrapMode, std::unique_ptr callback) { if (value.IsEmpty()) { callback->sendFailure(Response::InternalError()); @@ -470,8 +498,7 @@ void InjectedScript::addPromiseCallback( v8::MicrotasksScope::kRunMicrotasks); if (ProtocolPromiseHandler::add( session, m_context->context(), value.ToLocalChecked(), - m_context->contextId(), objectGroup, returnByValue, generatePreview, - callback.get())) { + m_context->contextId(), objectGroup, wrapMode, callback.get())) { m_evaluateCallbacks.insert(callback.release()); } } @@ -521,10 +548,6 @@ void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) { m_customPreviewEnabled = enabled; } -v8::Local InjectedScript::v8Value() const { - return m_value.Get(m_context->isolate()); -} - v8::Local InjectedScript::lastEvaluationResult() const { if (m_lastEvaluationResult.IsEmpty()) return v8::Undefined(m_context->isolate()); @@ -576,7 +599,7 @@ Response InjectedScript::resolveCallArgument( Response InjectedScript::createExceptionDetails( const v8::TryCatch& tryCatch, const String16& objectGroup, - bool generatePreview, Maybe* result) { + WrapMode wrapMode, Maybe* result) { if (!tryCatch.HasCaught()) return Response::InternalError(); v8::Local message = tryCatch.Message(); v8::Local exception = tryCatch.Exception(); @@ -612,8 +635,10 @@ Response InjectedScript::createExceptionDetails( if (!exception.IsEmpty()) { std::unique_ptr wrapped; Response response = - wrapObject(exception, objectGroup, false /* forceValueType */, - generatePreview && !exception->IsNativeError(), &wrapped); + wrapObject(exception, objectGroup, + exception->IsNativeError() ? WrapMode::kNoPreview + : WrapMode::kWithPreview, + &wrapped); if (!response.isSuccess()) return response; exceptionDetails->setException(std::move(wrapped)); } @@ -623,15 +648,14 @@ Response InjectedScript::createExceptionDetails( Response InjectedScript::wrapEvaluateResult( v8::MaybeLocal maybeResultValue, const v8::TryCatch& tryCatch, - const String16& objectGroup, bool returnByValue, bool generatePreview, + const String16& objectGroup, WrapMode wrapMode, std::unique_ptr* result, Maybe* exceptionDetails) { v8::Local resultValue; if (!tryCatch.HasCaught()) { if (!maybeResultValue.ToLocal(&resultValue)) return Response::InternalError(); - Response response = wrapObject(resultValue, objectGroup, returnByValue, - generatePreview, result); + Response response = wrapObject(resultValue, objectGroup, wrapMode, result); if (!response.isSuccess()) return response; if (objectGroup == "console") { m_lastEvaluationResult.Reset(m_context->isolate(), resultValue); @@ -643,12 +667,14 @@ Response InjectedScript::wrapEvaluateResult( } v8::Local exception = tryCatch.Exception(); Response response = - wrapObject(exception, objectGroup, false, - generatePreview && !exception->IsNativeError(), result); + wrapObject(exception, objectGroup, + exception->IsNativeError() ? WrapMode::kNoPreview + : WrapMode::kWithPreview, + result); if (!response.isSuccess()) return response; // We send exception in result for compatibility reasons, even though it's // accessible through exceptionDetails.exception. - response = createExceptionDetails(tryCatch, objectGroup, generatePreview, + response = createExceptionDetails(tryCatch, objectGroup, wrapMode, exceptionDetails); if (!response.isSuccess()) return response; } @@ -797,33 +823,44 @@ Response InjectedScript::CallFrameScope::findInjectedScript( return session->findInjectedScript(remoteId.get(), m_injectedScript); } -InjectedScript* InjectedScript::fromInjectedScriptHost( - v8::Isolate* isolate, v8::Local injectedScriptObject) { - v8::HandleScope handleScope(isolate); - v8::Local context = isolate->GetCurrentContext(); - v8::Local privateKey = v8::Private::ForApi( - isolate, v8::String::NewFromUtf8(isolate, privateKeyName, - v8::NewStringType::kInternalized) - .ToLocalChecked()); - v8::Local value = - injectedScriptObject->GetPrivate(context, privateKey).ToLocalChecked(); - DCHECK(value->IsExternal()); - v8::Local external = value.As(); - return static_cast(external->Value()); -} - -int InjectedScript::bindObject(v8::Local value, - const String16& groupName) { +String16 InjectedScript::bindObject(v8::Local value, + const String16& groupName) { if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1; int id = m_lastBoundObjectId++; m_idToWrappedObject[id].Reset(m_context->isolate(), value); m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel); - if (!groupName.isEmpty() && id > 0) { m_idToObjectGroupName[id] = groupName; m_nameToObjectGroup[groupName].push_back(id); } - return id; + // TODO(dgozman): get rid of "injectedScript" notion. + return String16::concat( + "{\"injectedScriptId\":", String16::fromInteger(m_context->contextId()), + ",\"id\":", String16::fromInteger(id), "}"); +} + +// static +Response InjectedScript::bindRemoteObjectIfNeeded( + int sessionId, v8::Local context, v8::Local value, + const String16& groupName, protocol::Runtime::RemoteObject* remoteObject) { + if (!remoteObject) return Response::OK(); + if (remoteObject->hasValue()) return Response::OK(); + if (remoteObject->hasUnserializableValue()) return Response::OK(); + if (remoteObject->getType() != RemoteObject::TypeEnum::Undefined) { + v8::Isolate* isolate = context->GetIsolate(); + V8InspectorImpl* inspector = + static_cast(v8::debug::GetInspector(isolate)); + InspectedContext* inspectedContext = + inspector->getContext(InspectedContext::contextId(context)); + InjectedScript* injectedScript = + inspectedContext ? inspectedContext->getInjectedScript(sessionId) + : nullptr; + if (!injectedScript) { + return Response::Error("Cannot find context with specified id"); + } + remoteObject->setObjectId(injectedScript->bindObject(value, groupName)); + } + return Response::OK(); } void InjectedScript::unbindObject(int id) { diff --git a/src/inspector/injected-script.h b/src/inspector/injected-script.h index f2780f982e..d20048497d 100644 --- a/src/inspector/injected-script.h +++ b/src/inspector/injected-script.h @@ -46,9 +46,9 @@ namespace v8_inspector { class RemoteObjectId; -class V8FunctionCall; class V8InspectorImpl; class V8InspectorSessionImpl; +enum class WrapMode; using protocol::Maybe; using protocol::Response; @@ -65,38 +65,40 @@ class EvaluateCallback { class InjectedScript final { public: - static std::unique_ptr create(InspectedContext*, - int sessionId); + InjectedScript(InspectedContext*, int sessionId); ~InjectedScript(); - static InjectedScript* fromInjectedScriptHost(v8::Isolate* isolate, - v8::Local); InspectedContext* context() const { return m_context; } Response getProperties( v8::Local, const String16& groupName, bool ownProperties, - bool accessorPropertiesOnly, bool generatePreview, + bool accessorPropertiesOnly, WrapMode wrapMode, std::unique_ptr>* result, Maybe*); + + Response getInternalProperties( + v8::Local, const String16& groupName, + std::unique_ptr< + protocol::Array>* + result); + void releaseObject(const String16& objectId); - Response wrapObject( - v8::Local, const String16& groupName, bool forceValueType, - bool generatePreview, - std::unique_ptr* result) const; - Response wrapObject( - v8::Local, const String16& groupName, bool forceValueType, - bool generatePreview, v8::MaybeLocal customPreviewConfig, - int maxCustomPreviewDepth, - std::unique_ptr* result) const; + Response wrapObject(v8::Local, const String16& groupName, + WrapMode wrapMode, + std::unique_ptr* result); + Response wrapObject(v8::Local, const String16& groupName, + WrapMode wrapMode, + v8::MaybeLocal customPreviewConfig, + int maxCustomPreviewDepth, + std::unique_ptr* result); std::unique_ptr wrapTable( - v8::Local table, v8::Local columns) const; + v8::Local table, v8::MaybeLocal columns); void addPromiseCallback(V8InspectorSessionImpl* session, v8::MaybeLocal value, - const String16& objectGroup, bool returnByValue, - bool generatePreview, + const String16& objectGroup, WrapMode wrapMode, std::unique_ptr callback); Response findObject(const RemoteObjectId&, v8::Local*) const; @@ -107,18 +109,16 @@ class InjectedScript final { v8::Local* result); Response createExceptionDetails( - const v8::TryCatch&, const String16& groupName, bool generatePreview, + const v8::TryCatch&, const String16& groupName, WrapMode wrapMode, Maybe* result); Response wrapEvaluateResult( v8::MaybeLocal maybeResultValue, const v8::TryCatch&, - const String16& objectGroup, bool returnByValue, bool generatePreview, + const String16& objectGroup, WrapMode wrapMode, std::unique_ptr* result, Maybe*); v8::Local lastEvaluationResult() const; void setLastEvaluationResult(v8::Local result); - int bindObject(v8::Local, const String16& groupName); - class Scope { public: Response initialize(); @@ -196,23 +196,22 @@ class InjectedScript final { DISALLOW_COPY_AND_ASSIGN(CallFrameScope); }; + String16 bindObject(v8::Local, const String16& groupName); private: - InjectedScript(InspectedContext*, v8::Local, int sessionId); - v8::Local v8Value() const; - Response wrapValue(v8::Local, const String16& groupName, - bool forceValueType, bool generatePreview, - v8::Local* result) const; v8::Local commandLineAPI(); void unbindObject(int id); + static Response bindRemoteObjectIfNeeded( + int sessionId, v8::Local context, v8::Local, + const String16& groupName, protocol::Runtime::RemoteObject* remoteObject); + class ProtocolPromiseHandler; void discardEvaluateCallbacks(); std::unique_ptr takeEvaluateCallback( EvaluateCallback* callback); InspectedContext* m_context; - v8::Global m_value; int m_sessionId; v8::Global m_lastEvaluationResult; v8::Global m_commandLineAPI; diff --git a/src/inspector/injected_script_externs.js b/src/inspector/injected_script_externs.js deleted file mode 100644 index d293b8547d..0000000000 --- a/src/inspector/injected_script_externs.js +++ /dev/null @@ -1,122 +0,0 @@ -// 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} - */ -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} - */ -InjectedScriptHostClass.prototype.getOwnPropertyNames = function(obj) {} - -/** - * @param {!Object} obj - * @return {!Array} - */ -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|undefined} - */ -InjectedScriptHostClass.prototype.typedArrayProperties = function(arrayBuffer) {} - -/** @type {!InjectedScriptHostClass} */ -var InjectedScriptHost; -/** @type {!Window} */ -var inspectedGlobalObject; -/** @type {number} */ -var injectedScriptId; diff --git a/src/inspector/inspected-context.cc b/src/inspector/inspected-context.cc index bb98c87158..06728f3860 100644 --- a/src/inspector/inspected-context.cc +++ b/src/inspector/inspected-context.cc @@ -109,14 +109,12 @@ InjectedScript* InspectedContext::getInjectedScript(int sessionId) { return it == m_injectedScripts.end() ? nullptr : it->second.get(); } -bool InspectedContext::createInjectedScript(int sessionId) { +InjectedScript* InspectedContext::createInjectedScript(int sessionId) { std::unique_ptr injectedScript = - InjectedScript::create(this, sessionId); - // InjectedScript::create can destroy |this|. - if (!injectedScript) return false; + v8::base::make_unique(this, sessionId); CHECK(m_injectedScripts.find(sessionId) == m_injectedScripts.end()); m_injectedScripts[sessionId] = std::move(injectedScript); - return true; + return getInjectedScript(sessionId); } void InspectedContext::discardInjectedScript(int sessionId) { diff --git a/src/inspector/inspected-context.h b/src/inspector/inspected-context.h index ef0a0ca52a..a79bc9e5f6 100644 --- a/src/inspector/inspected-context.h +++ b/src/inspector/inspected-context.h @@ -40,7 +40,7 @@ class InspectedContext { V8InspectorImpl* inspector() const { return m_inspector; } InjectedScript* getInjectedScript(int sessionId); - bool createInjectedScript(int sessionId); + InjectedScript* createInjectedScript(int sessionId); void discardInjectedScript(int sessionId); private: diff --git a/src/inspector/js_protocol.json b/src/inspector/js_protocol.json index daa17bc669..db6ea65af7 100644 --- a/src/inspector/js_protocol.json +++ b/src/inspector/js_protocol.json @@ -1890,7 +1890,9 @@ "error", "proxy", "promise", - "typedarray" + "typedarray", + "arraybuffer", + "dataview" ] }, { diff --git a/src/inspector/js_protocol.pdl b/src/inspector/js_protocol.pdl index 4e815d201d..1f75ef558e 100644 --- a/src/inspector/js_protocol.pdl +++ b/src/inspector/js_protocol.pdl @@ -887,6 +887,8 @@ domain Runtime proxy promise typedarray + arraybuffer + dataview # Object class (constructor) name. Specified for `object` type values only. optional string className # Remote object value in case of primitive values or JSON values (if it was requested). diff --git a/src/inspector/v8-console-message.cc b/src/inspector/v8-console-message.cc index 6d39deeb4c..687dfd2217 100644 --- a/src/inspector/v8-console-message.cc +++ b/src/inspector/v8-console-message.cc @@ -259,19 +259,33 @@ V8ConsoleMessage::wrapArguments(V8InspectorSessionImpl* session, std::unique_ptr> args = protocol::Array::create(); - if (m_type == ConsoleAPIType::kTable && generatePreview) { - v8::Local table = m_arguments[0]->Get(isolate); - v8::Local columns = m_arguments.size() > 1 - ? m_arguments[1]->Get(isolate) - : v8::Local(); + + v8::Local value = m_arguments[0]->Get(isolate); + if (value->IsObject() && m_type == ConsoleAPIType::kTable && + generatePreview) { + v8::MaybeLocal columns; + if (m_arguments.size() > 1) { + v8::Local secondArgument = m_arguments[1]->Get(isolate); + if (secondArgument->IsArray()) { + columns = v8::Local::Cast(secondArgument); + } else if (secondArgument->IsString()) { + v8::TryCatch tryCatch(isolate); + v8::Local array = v8::Array::New(isolate); + if (array->Set(context, 0, secondArgument).IsJust()) { + columns = array; + } + } + } std::unique_ptr wrapped = - session->wrapTable(context, table, columns); + session->wrapTable(context, v8::Local::Cast(value), + columns); inspectedContext = inspector->getContext(contextGroupId, contextId); if (!inspectedContext) return nullptr; - if (wrapped) + if (wrapped) { args->addItem(std::move(wrapped)); - else + } else { args = nullptr; + } } else { for (size_t i = 0; i < m_arguments.size(); ++i) { std::unique_ptr wrapped = diff --git a/src/inspector/v8-console.cc b/src/inspector/v8-console.cc index ef4c7ccd1d..ccf6e4aea2 100644 --- a/src/inspector/v8-console.cc +++ b/src/inspector/v8-console.cc @@ -600,9 +600,8 @@ static void inspectImpl(const v8::FunctionCallbackInfo& info, InjectedScript* injectedScript = helper.injectedScript(sessionId); if (!injectedScript) return; std::unique_ptr wrappedObject; - protocol::Response response = - injectedScript->wrapObject(value, "", false /** forceValueType */, - false /** generatePreview */, &wrappedObject); + protocol::Response response = injectedScript->wrapObject( + value, "", WrapMode::kNoPreview, &wrappedObject); if (!response.isSuccess()) return; std::unique_ptr hints = diff --git a/src/inspector/v8-debugger-agent-impl.cc b/src/inspector/v8-debugger-agent-impl.cc index 3a5dfe918a..f3d2fa699c 100644 --- a/src/inspector/v8-debugger-agent-impl.cc +++ b/src/inspector/v8-debugger-agent-impl.cc @@ -260,8 +260,9 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator, for (; !iterator->Done(); iterator->Advance()) { std::unique_ptr object; - Response result = injectedScript->wrapObject( - iterator->GetObject(), kBacktraceObjectGroup, false, false, &object); + Response result = + injectedScript->wrapObject(iterator->GetObject(), kBacktraceObjectGroup, + WrapMode::kNoPreview, &object); if (!result.isSuccess()) return result; auto scope = Scope::create() @@ -1085,10 +1086,12 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame( // context or session. response = scope.initialize(); if (!response.isSuccess()) return response; + WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview + : WrapMode::kNoPreview; + if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; return scope.injectedScript()->wrapEvaluateResult( - maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), - returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), result, - exceptionDetails); + maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode, + result, exceptionDetails); } Response V8DebuggerAgentImpl::setVariableValue( @@ -1268,8 +1271,9 @@ Response V8DebuggerAgentImpl::currentCallFrames( if (injectedScript) { v8::Local receiver; if (iterator->GetReceiver().ToLocal(&receiver)) { - res = injectedScript->wrapObject(receiver, kBacktraceObjectGroup, false, - false, &protocolReceiver); + res = + injectedScript->wrapObject(receiver, kBacktraceObjectGroup, + WrapMode::kNoPreview, &protocolReceiver); if (!res.isSuccess()) return res; } } @@ -1320,7 +1324,7 @@ Response V8DebuggerAgentImpl::currentCallFrames( if (!returnValue.IsEmpty() && injectedScript) { std::unique_ptr value; res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup, - false, false, &value); + WrapMode::kNoPreview, &value); if (!res.isSuccess()) return res; frame->setReturnValue(std::move(value)); } @@ -1528,8 +1532,8 @@ void V8DebuggerAgentImpl::didPause( ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection : protocol::Debugger::Paused::ReasonEnum::Exception; std::unique_ptr obj; - injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false, - &obj); + injectedScript->wrapObject(exception, kBacktraceObjectGroup, + WrapMode::kNoPreview, &obj); std::unique_ptr breakAuxData; if (obj) { breakAuxData = obj->toValue(); diff --git a/src/inspector/v8-debugger.cc b/src/inspector/v8-debugger.cc index 5f826b56a9..4b254bfd39 100644 --- a/src/inspector/v8-debugger.cc +++ b/src/inspector/v8-debugger.cc @@ -10,7 +10,6 @@ #include "src/inspector/v8-debugger-agent-impl.h" #include "src/inspector/v8-inspector-impl.h" #include "src/inspector/v8-inspector-session-impl.h" -#include "src/inspector/v8-internal-value-type.h" #include "src/inspector/v8-runtime-agent-impl.h" #include "src/inspector/v8-stack-trace-impl.h" #include "src/inspector/v8-value-utils.h" @@ -24,102 +23,6 @@ namespace { static const int kMaxAsyncTaskStacks = 128 * 1024; static const int kNoBreakpointId = 0; -v8::MaybeLocal collectionsEntries(v8::Local context, - v8::Local value) { - v8::Isolate* isolate = context->GetIsolate(); - v8::Local entries; - bool isKeyValue = false; - if (!value->IsObject() || - !value.As()->PreviewEntries(&isKeyValue).ToLocal(&entries)) { - return v8::MaybeLocal(); - } - - v8::Local wrappedEntries = v8::Array::New(isolate); - CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0); - if (!wrappedEntries->SetPrototype(context, v8::Null(isolate)) - .FromMaybe(false)) - return v8::MaybeLocal(); - for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) { - v8::Local item; - if (!entries->Get(context, i).ToLocal(&item)) continue; - v8::Local value; - if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue; - v8::Local 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(); - } - return wrappedEntries; -} - -v8::MaybeLocal buildLocation(v8::Local context, - int scriptId, int lineNumber, - int columnNumber) { - if (scriptId == v8::UnboundScript::kNoScriptId) - return v8::MaybeLocal(); - if (lineNumber == v8::Function::kLineOffsetNotFound || - columnNumber == v8::Function::kLineOffsetNotFound) { - return v8::MaybeLocal(); - } - v8::Isolate* isolate = context->GetIsolate(); - v8::Local location = v8::Object::New(isolate); - if (!location->SetPrototype(context, v8::Null(isolate)).FromMaybe(false)) { - return v8::MaybeLocal(); - } - if (!createDataProperty(context, location, - toV8StringInternalized(isolate, "scriptId"), - toV8String(isolate, String16::fromInteger(scriptId))) - .FromMaybe(false)) { - return v8::MaybeLocal(); - } - if (!createDataProperty(context, location, - toV8StringInternalized(isolate, "lineNumber"), - v8::Integer::New(isolate, lineNumber)) - .FromMaybe(false)) { - return v8::MaybeLocal(); - } - if (!createDataProperty(context, location, - toV8StringInternalized(isolate, "columnNumber"), - v8::Integer::New(isolate, columnNumber)) - .FromMaybe(false)) { - return v8::MaybeLocal(); - } - if (!markAsInternal(context, location, V8InternalValueType::kLocation)) { - return v8::MaybeLocal(); - } - return location; -} - -v8::MaybeLocal generatorObjectLocation( - v8::Local context, v8::Local value) { - if (!value->IsGeneratorObject()) return v8::MaybeLocal(); - v8::Local generatorObject = - v8::debug::GeneratorObject::Cast(value); - if (!generatorObject->IsSuspended()) { - v8::Local func = generatorObject->Function(); - return buildLocation(context, func->ScriptId(), func->GetScriptLineNumber(), - func->GetScriptColumnNumber()); - } - v8::Local script; - if (!generatorObject->Script().ToLocal(&script)) - return v8::MaybeLocal(); - v8::debug::Location suspendedLocation = generatorObject->SuspendedLocation(); - return buildLocation(context, script->Id(), suspendedLocation.GetLineNumber(), - suspendedLocation.GetColumnNumber()); -} - template void cleanupExpiredWeakPointers(Map& map) { for (auto it = map.begin(); it != map.end();) { @@ -714,28 +617,52 @@ v8::MaybeLocal V8Debugger::getTargetScopes( for (; !iterator->Done(); iterator->Advance()) { v8::Local scope = v8::Object::New(m_isolate); - if (!markAsInternal(context, scope, V8InternalValueType::kScope)) { + if (!addInternalObject(context, scope, V8InternalValueType::kScope)) { return v8::MaybeLocal(); } - String16 type = v8_inspector::scopeType(iterator->GetType()); - String16 name; - v8::Local maybe_name = iterator->GetFunctionDebugName(); - if (!maybe_name->IsUndefined()) { - name = toProtocolStringWithTypeCheck(m_isolate, maybe_name); + String16 nameSuffix = toProtocolStringWithTypeCheck( + m_isolate, iterator->GetFunctionDebugName()); + String16 description; + if (nameSuffix.length()) nameSuffix = " (" + nameSuffix + ")"; + switch (iterator->GetType()) { + case v8::debug::ScopeIterator::ScopeTypeGlobal: + description = "Global" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeLocal: + description = "Local" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeWith: + description = "With Block" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeClosure: + description = "Closure" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeCatch: + description = "Catch" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeBlock: + description = "Block" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeScript: + description = "Script" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeEval: + description = "Eval" + nameSuffix; + break; + case v8::debug::ScopeIterator::ScopeTypeModule: + description = "Module" + nameSuffix; + break; } v8::Local object = iterator->GetObject(); createDataProperty(context, scope, - toV8StringInternalized(m_isolate, "type"), - toV8String(m_isolate, type)); - createDataProperty(context, scope, - toV8StringInternalized(m_isolate, "name"), - toV8String(m_isolate, name)); + toV8StringInternalized(m_isolate, "description"), + toV8String(m_isolate, description)); createDataProperty(context, scope, toV8StringInternalized(m_isolate, "object"), object); createDataProperty(context, result, result->Length(), scope); } - if (!markAsInternal(context, v8::Local::Cast(result), - V8InternalValueType::kScopeList)) + if (!addInternalObject(context, v8::Local::Cast(result), + V8InternalValueType::kScopeList)) return v8::MaybeLocal(); return result; } @@ -750,6 +677,45 @@ v8::MaybeLocal V8Debugger::generatorScopes( return getTargetScopes(context, generator, GENERATOR); } +v8::MaybeLocal V8Debugger::collectionsEntries( + v8::Local context, v8::Local value) { + v8::Isolate* isolate = context->GetIsolate(); + v8::Local entries; + bool isKeyValue = false; + if (!value->IsObject() || + !value.As()->PreviewEntries(&isKeyValue).ToLocal(&entries)) { + return v8::MaybeLocal(); + } + + v8::Local wrappedEntries = v8::Array::New(isolate); + CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0); + if (!wrappedEntries->SetPrototype(context, v8::Null(isolate)) + .FromMaybe(false)) + return v8::MaybeLocal(); + for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) { + v8::Local item; + if (!entries->Get(context, i).ToLocal(&item)) continue; + v8::Local value; + if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue; + v8::Local 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 V8Debugger::stableObjectId( v8::Local context, v8::Local value) { DCHECK(value->IsObject()); @@ -781,25 +747,6 @@ v8::MaybeLocal V8Debugger::internalProperties( createDataProperty(context, properties, properties->Length(), id); } } - if (value->IsFunction()) { - v8::Local function = value.As(); - v8::Local 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 entries; if (collectionsEntries(context, value).ToLocal(&entries)) { createDataProperty(context, properties, properties->Length(), @@ -807,13 +754,6 @@ v8::MaybeLocal V8Debugger::internalProperties( createDataProperty(context, properties, properties->Length(), entries); } if (value->IsGeneratorObject()) { - v8::Local location; - if (generatorObjectLocation(context, value).ToLocal(&location)) { - createDataProperty( - context, properties, properties->Length(), - toV8StringInternalized(m_isolate, "[[GeneratorLocation]]")); - createDataProperty(context, properties, properties->Length(), location); - } v8::Local scopes; if (generatorScopes(context, value).ToLocal(&scopes)) { createDataProperty(context, properties, properties->Length(), @@ -1196,6 +1136,31 @@ std::pair V8Debugger::debuggerIdFor( return std::make_pair(0, 0); } +bool V8Debugger::addInternalObject(v8::Local context, + v8::Local 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(type))) + .IsEmpty(); +} + +V8InternalValueType V8Debugger::getInternalType(v8::Local context, + v8::Local object) { + if (m_internalObjects.IsEmpty()) return V8InternalValueType::kNone; + v8::Local typeValue; + if (!m_internalObjects.Get(m_isolate) + ->Get(context, object) + .ToLocal(&typeValue) || + !typeValue->IsUint32()) { + return V8InternalValueType::kNone; + } + return static_cast(typeValue.As()->Value()); +} + void V8Debugger::dumpAsyncTaskStacksStateForTest() { fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount); fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size()); diff --git a/src/inspector/v8-debugger.h b/src/inspector/v8-debugger.h index a99653add6..0c48bf11a7 100644 --- a/src/inspector/v8-debugger.h +++ b/src/inspector/v8-debugger.h @@ -30,6 +30,9 @@ class V8InspectorImpl; class V8StackTraceImpl; struct V8StackTraceId; +enum class WrapMode { kForceValue, kNoPreview, kWithPreview }; +enum class V8InternalValueType { kNone, kEntry, kScope, kScopeList }; + using protocol::Response; using ScheduleStepIntoAsyncCallback = protocol::Debugger::Backend::ScheduleStepIntoAsyncCallback; @@ -134,6 +137,12 @@ class V8Debugger : public v8::debug::DebugDelegate, std::shared_ptr stackTraceFor(int contextGroupId, const V8StackTraceId& id); + bool addInternalObject(v8::Local context, + v8::Local object, + V8InternalValueType type); + V8InternalValueType getInternalType(v8::Local context, + v8::Local object); + private: void clearContinueToLocation(); bool shouldContinueToCurrentLocation(); @@ -160,6 +169,8 @@ class V8Debugger : public v8::debug::DebugDelegate, v8::Local); v8::MaybeLocal generatorScopes(v8::Local, v8::Local); + v8::MaybeLocal collectionsEntries(v8::Local context, + v8::Local value); void asyncTaskScheduledForStack(const String16& taskName, void* task, bool recurring); @@ -253,6 +264,8 @@ class V8Debugger : public v8::debug::DebugDelegate, uint32_t m_lastStableObjectId = 0; v8::Global m_stableObjectId; + v8::Global m_internalObjects; + WasmTranslation m_wasmTranslation; DISALLOW_COPY_AND_ASSIGN(V8Debugger); diff --git a/src/inspector/v8-function-call.cc b/src/inspector/v8-function-call.cc deleted file mode 100644 index ebeb7a3d07..0000000000 --- a/src/inspector/v8-function-call.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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 context, - v8::Local value, const String16& name) - : m_inspector(inspector), - m_context(context), - m_name(toV8String(context->GetIsolate(), name)), - m_value(value) {} - -void V8FunctionCall::appendArgument(v8::Local 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 V8FunctionCall::call(bool& hadException, - bool reportExceptions) { - v8::TryCatch tryCatch(m_context->GetIsolate()); - tryCatch.SetVerbose(reportExceptions); - - v8::Local result = callWithoutExceptionHandling(); - hadException = tryCatch.HasCaught(); - return result; -} - -v8::Local V8FunctionCall::callWithoutExceptionHandling() { - v8::Context::Scope contextScope(m_context); - - v8::Local thisObject = v8::Local::Cast(m_value); - v8::Local value; - if (!thisObject->Get(m_context, m_name).ToLocal(&value)) - return v8::Local(); - - DCHECK(value->IsFunction()); - - v8::Local function = v8::Local::Cast(value); - std::unique_ptr[]> info( - new v8::Local[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 maybeResult = function->Call( - m_context, thisObject, static_cast(m_arguments.size()), info.get()); - if (contextGroupId) { - m_inspector->client()->unmuteMetrics(contextGroupId); - m_inspector->unmuteExceptions(contextGroupId); - } - - v8::Local result; - if (!maybeResult.ToLocal(&result)) return v8::Local(); - return result; -} - -} // namespace v8_inspector diff --git a/src/inspector/v8-function-call.h b/src/inspector/v8-function-call.h deleted file mode 100644 index 28a5886c91..0000000000 --- a/src/inspector/v8-function-call.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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::Local, - const String16& name); - - void appendArgument(v8::Local); - void appendArgument(const String16&); - void appendArgument(int); - void appendArgument(bool); - - v8::Local call(bool& hadException, bool reportExceptions = true); - v8::Local callWithoutExceptionHandling(); - - protected: - V8InspectorImpl* m_inspector; - v8::Local m_context; - std::vector> m_arguments; - v8::Local m_name; - v8::Local m_value; -}; - -} // namespace v8_inspector - -#endif // V8_INSPECTOR_V8_FUNCTION_CALL_H_ diff --git a/src/inspector/v8-injected-script-host.cc b/src/inspector/v8-injected-script-host.cc deleted file mode 100644 index d9c1d59aa8..0000000000 --- a/src/inspector/v8-injected-script-host.cc +++ /dev/null @@ -1,427 +0,0 @@ -// 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 context, - v8::Local obj, const char* name, - v8::FunctionCallback callback, - v8::Local external) { - v8::Local funcName = - toV8StringInternalized(context->GetIsolate(), name); - v8::Local 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& info) { - DCHECK(!info.Data().IsEmpty()); - DCHECK(info.Data()->IsExternal()); - V8InspectorImpl* inspector = - static_cast(info.Data().As()->Value()); - DCHECK(inspector); - return inspector; -} - -template -void addTypedArrayProperty(std::vector>* props, - v8::Isolate* isolate, - v8::Local arraybuffer, - String16 name, size_t length) { - props->push_back(toV8String(isolate, name)); - props->push_back(TypedArray::New(arraybuffer, 0, length)); -} - -} // namespace - -v8::Local V8InjectedScriptHost::create( - v8::Local context, V8InspectorImpl* inspector) { - v8::Isolate* isolate = inspector->isolate(); - v8::Local injectedScriptHost = v8::Object::New(isolate); - bool success = injectedScriptHost->SetPrototype(context, v8::Null(isolate)) - .FromMaybe(false); - DCHECK(success); - USE(success); - v8::Local 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& info) { - CHECK_EQ(1, info.Length()); - DCHECK(info[0]->IsObject()); - if (!info[0]->IsObject()) return; - v8::Isolate* isolate = info.GetIsolate(); - info[0] - .As() - ->SetPrototype(isolate->GetCurrentContext(), v8::Null(isolate)) - .ToChecked(); -} - -void V8InjectedScriptHost::getPropertyCallback( - const v8::FunctionCallbackInfo& info) { - CHECK(info.Length() == 2 && info[1]->IsString()); - if (!info[0]->IsObject()) return; - v8::Isolate* isolate = info.GetIsolate(); - v8::Local context = isolate->GetCurrentContext(); - v8::TryCatch tryCatch(isolate); - v8::Isolate::DisallowJavascriptExecutionScope throwJs( - isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); - v8::Local property; - if (info[0] - .As() - ->Get(context, v8::Local::Cast(info[1])) - .ToLocal(&property)) { - info.GetReturnValue().Set(property); - } -} - -void V8InjectedScriptHost::internalConstructorNameCallback( - const v8::FunctionCallbackInfo& info) { - if (info.Length() < 1 || !info[0]->IsObject()) return; - - v8::Local object = info[0].As(); - info.GetReturnValue().Set(object->GetConstructorName()); -} - -void V8InjectedScriptHost::formatAccessorsAsProperties( - const v8::FunctionCallbackInfo& 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()->ScriptId() != v8::UnboundScript::kNoScriptId) - return; - info.GetReturnValue().Set( - unwrapInspector(info)->client()->formatAccessorsAsProperties(info[0])); -} - -void V8InjectedScriptHost::subtypeCallback( - const v8::FunctionCallbackInfo& info) { - if (info.Length() < 1) return; - - v8::Isolate* isolate = info.GetIsolate(); - v8::Local value = info[0]; - if (value->IsObject()) { - v8::Local internalType = v8InternalValueTypeFrom( - isolate->GetCurrentContext(), v8::Local::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 subtype = - unwrapInspector(info)->client()->valueSubtype(value); - if (subtype) { - info.GetReturnValue().Set(toV8String(isolate, subtype->string())); - return; - } -} - -void V8InjectedScriptHost::getInternalPropertiesCallback( - const v8::FunctionCallbackInfo& info) { - if (info.Length() < 1) return; - - std::unordered_set 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 allProperties; - if (!unwrapInspector(info) - ->debugger() - ->internalProperties(isolate->GetCurrentContext(), info[0]) - .ToLocal(&allProperties) || - !allProperties->IsArray() || allProperties->Length() % 2 != 0) - return; - - { - v8::Local context = isolate->GetCurrentContext(); - v8::TryCatch tryCatch(isolate); - v8::Isolate::DisallowJavascriptExecutionScope throwJs( - isolate, - v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); - - v8::Local 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 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 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& info) { - if (info.Length() < 2 || !info[0]->IsObject() || !info[1]->IsString()) return; - bool result = info[0] - .As() - ->HasOwnProperty(info.GetIsolate()->GetCurrentContext(), - v8::Local::Cast(info[1])) - .FromMaybe(false); - info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), result)); -} - -void V8InjectedScriptHost::bindCallback( - const v8::FunctionCallbackInfo& info) { - if (info.Length() < 2 || !info[1]->IsString()) return; - InjectedScript* injectedScript = - InjectedScript::fromInjectedScriptHost(info.GetIsolate(), info.Holder()); - if (!injectedScript) return; - - v8::Local context = info.GetIsolate()->GetCurrentContext(); - v8::Local 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& info) { - if (info.Length() != 1 || !info[0]->IsProxy()) { - UNREACHABLE(); - return; - } - v8::Local target = info[0].As(); - while (target->IsProxy()) - target = v8::Local::Cast(target)->GetTarget(); - info.GetReturnValue().Set(target); -} - -void V8InjectedScriptHost::nativeAccessorDescriptorCallback( - const v8::FunctionCallbackInfo& 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 context = isolate->GetCurrentContext(); - int flags = v8::debug::GetNativeAccessorDescriptor( - context, v8::Local::Cast(info[0]), - v8::Local::Cast(info[1])); - if (flags == static_cast(v8::debug::NativeAccessorType::None)) { - info.GetReturnValue().Set(v8::Undefined(isolate)); - return; - } - - bool isBuiltin = - flags & static_cast(v8::debug::NativeAccessorType::IsBuiltin); - bool hasGetter = - flags & static_cast(v8::debug::NativeAccessorType::HasGetter); - bool hasSetter = - flags & static_cast(v8::debug::NativeAccessorType::HasSetter); - v8::Local 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& 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 arrayBuffer = info[0].As(); - size_t length = arrayBuffer->ByteLength(); - if (length == 0) return; - std::vector> arrays_vector; - addTypedArrayProperty(&arrays_vector, isolate, arrayBuffer, - "[[Int8Array]]", length); - addTypedArrayProperty(&arrays_vector, isolate, arrayBuffer, - "[[Uint8Array]]", length); - - if (length % 2 == 0) { - addTypedArrayProperty(&arrays_vector, isolate, arrayBuffer, - "[[Int16Array]]", length / 2); - } - if (length % 4 == 0) { - addTypedArrayProperty(&arrays_vector, isolate, arrayBuffer, - "[[Int32Array]]", length / 4); - } - - if (tryCatch.HasCaught()) return; - v8::Local context = isolate->GetCurrentContext(); - v8::Local arrays = - v8::Array::New(isolate, static_cast(arrays_vector.size())); - for (uint32_t i = 0; i < static_cast(arrays_vector.size()); i++) - createDataProperty(context, arrays, i, arrays_vector[i]); - if (tryCatch.HasCaught()) return; - info.GetReturnValue().Set(arrays); -} - -} // namespace v8_inspector diff --git a/src/inspector/v8-injected-script-host.h b/src/inspector/v8-injected-script-host.h deleted file mode 100644 index 6a3ee3d386..0000000000 --- a/src/inspector/v8-injected-script-host.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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 create(v8::Local, V8InspectorImpl*); - - private: - static void nullifyPrototypeCallback( - const v8::FunctionCallbackInfo&); - static void getPropertyCallback(const v8::FunctionCallbackInfo&); - static void internalConstructorNameCallback( - const v8::FunctionCallbackInfo&); - static void formatAccessorsAsProperties( - const v8::FunctionCallbackInfo&); - static void subtypeCallback(const v8::FunctionCallbackInfo&); - static void getInternalPropertiesCallback( - const v8::FunctionCallbackInfo&); - static void objectHasOwnPropertyCallback( - const v8::FunctionCallbackInfo&); - static void bindCallback(const v8::FunctionCallbackInfo&); - static void proxyTargetValueCallback( - const v8::FunctionCallbackInfo&); - static void nativeAccessorDescriptorCallback( - const v8::FunctionCallbackInfo&); - static void typedArrayPropertiesCallback( - const v8::FunctionCallbackInfo&); -}; - -} // namespace v8_inspector - -#endif // V8_INSPECTOR_V8_INJECTED_SCRIPT_HOST_H_ diff --git a/src/inspector/v8-inspector-session-impl.cc b/src/inspector/v8-inspector-session-impl.cc index d37f87a2a7..db05b24102 100644 --- a/src/inspector/v8-inspector-session-impl.cc +++ b/src/inspector/v8-inspector-session-impl.cc @@ -203,12 +203,7 @@ Response V8InspectorSessionImpl::findInjectedScript( if (!context) return Response::Error("Cannot find context with specified id"); injectedScript = context->getInjectedScript(m_sessionId); if (!injectedScript) { - 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); + injectedScript = context->createInjectedScript(m_sessionId); if (m_customObjectFormatterEnabled) injectedScript->setCustomObjectFormatterEnabled(true); } @@ -285,14 +280,16 @@ V8InspectorSessionImpl::wrapObject(v8::Local context, findInjectedScript(InspectedContext::contextId(context), injectedScript); if (!injectedScript) return nullptr; std::unique_ptr result; - injectedScript->wrapObject(value, groupName, false, generatePreview, &result); + injectedScript->wrapObject( + value, groupName, + generatePreview ? WrapMode::kWithPreview : WrapMode::kNoPreview, &result); return result; } std::unique_ptr V8InspectorSessionImpl::wrapTable(v8::Local context, - v8::Local table, - v8::Local columns) { + v8::Local table, + v8::MaybeLocal columns) { InjectedScript* injectedScript = nullptr; findInjectedScript(InspectedContext::contextId(context), injectedScript); if (!injectedScript) return nullptr; diff --git a/src/inspector/v8-inspector-session-impl.h b/src/inspector/v8-inspector-session-impl.h index 5053d4dd78..461cc0a2f0 100644 --- a/src/inspector/v8-inspector-session-impl.h +++ b/src/inspector/v8-inspector-session-impl.h @@ -55,8 +55,8 @@ class V8InspectorSessionImpl : public V8InspectorSession, v8::Local, v8::Local, const String16& groupName, bool generatePreview); std::unique_ptr wrapTable( - v8::Local, v8::Local table, - v8::Local columns); + v8::Local, v8::Local table, + v8::MaybeLocal columns); std::vector> supportedDomainsImpl(); Response unwrapObject(const String16& objectId, v8::Local*, v8::Local*, String16* objectGroup); diff --git a/src/inspector/v8-internal-value-type.cc b/src/inspector/v8-internal-value-type.cc deleted file mode 100644 index 54e839e64e..0000000000 --- a/src/inspector/v8-internal-value-type.cc +++ /dev/null @@ -1,75 +0,0 @@ -// 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 internalSubtypePrivate(v8::Isolate* isolate) { - return v8::Private::ForApi( - isolate, - toV8StringInternalized(isolate, "V8InternalType#internalSubtype")); -} - -v8::Local 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 context, - v8::Local object, V8InternalValueType type) { - v8::Isolate* isolate = context->GetIsolate(); - v8::Local privateValue = internalSubtypePrivate(isolate); - v8::Local subtype = subtypeForInternalType(isolate, type); - return object->SetPrivate(context, privateValue, subtype).FromMaybe(false); -} - -bool markArrayEntriesAsInternal(v8::Local context, - v8::Local array, - V8InternalValueType type) { - v8::Isolate* isolate = context->GetIsolate(); - v8::Local privateValue = internalSubtypePrivate(isolate); - v8::Local subtype = subtypeForInternalType(isolate, type); - for (uint32_t i = 0; i < array->Length(); ++i) { - v8::Local entry; - if (!array->Get(context, i).ToLocal(&entry) || !entry->IsObject()) - return false; - if (!entry.As() - ->SetPrivate(context, privateValue, subtype) - .FromMaybe(false)) - return false; - } - return true; -} - -v8::Local v8InternalValueTypeFrom(v8::Local context, - v8::Local object) { - v8::Isolate* isolate = context->GetIsolate(); - v8::Local privateValue = internalSubtypePrivate(isolate); - if (!object->HasPrivate(context, privateValue).FromMaybe(false)) - return v8::Null(isolate); - v8::Local subtypeValue; - if (!object->GetPrivate(context, privateValue).ToLocal(&subtypeValue) || - !subtypeValue->IsString()) - return v8::Null(isolate); - return subtypeValue; -} - -} // namespace v8_inspector diff --git a/src/inspector/v8-internal-value-type.h b/src/inspector/v8-internal-value-type.h deleted file mode 100644 index 991919a82e..0000000000 --- a/src/inspector/v8-internal-value-type.h +++ /dev/null @@ -1,23 +0,0 @@ -// 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::Local, - V8InternalValueType); -bool markArrayEntriesAsInternal(v8::Local, v8::Local, - V8InternalValueType); -v8::Local v8InternalValueTypeFrom(v8::Local, - v8::Local); - -} // namespace v8_inspector - -#endif // V8_INSPECTOR_V8_INTERNAL_VALUE_TYPE_H_ diff --git a/src/inspector/v8-runtime-agent-impl.cc b/src/inspector/v8-runtime-agent-impl.cc index 9e3697cf9e..d34965dcb4 100644 --- a/src/inspector/v8-runtime-agent-impl.cc +++ b/src/inspector/v8-runtime-agent-impl.cc @@ -90,14 +90,14 @@ template bool wrapEvaluateResultAsync(InjectedScript* injectedScript, v8::MaybeLocal maybeResultValue, const v8::TryCatch& tryCatch, - const String16& objectGroup, bool returnByValue, - bool generatePreview, ProtocolCallback* callback) { + const String16& objectGroup, WrapMode wrapMode, + ProtocolCallback* callback) { std::unique_ptr result; Maybe exceptionDetails; Response response = injectedScript->wrapEvaluateResult( - maybeResultValue, tryCatch, objectGroup, returnByValue, generatePreview, - &result, &exceptionDetails); + maybeResultValue, tryCatch, objectGroup, wrapMode, &result, + &exceptionDetails); if (response.isSuccess()) { callback->sendSuccess(std::move(result), std::move(exceptionDetails)); return true; @@ -110,8 +110,8 @@ void innerCallFunctionOn( V8InspectorSessionImpl* session, InjectedScript::Scope& scope, v8::Local recv, const String16& expression, Maybe> optionalArguments, - bool silent, bool returnByValue, bool generatePreview, bool userGesture, - bool awaitPromise, const String16& objectGroup, + bool silent, WrapMode wrapMode, bool userGesture, bool awaitPromise, + const String16& objectGroup, std::unique_ptr callback) { V8InspectorImpl* inspector = session->inspector(); @@ -159,7 +159,7 @@ void innerCallFunctionOn( if (scope.tryCatch().HasCaught()) { wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue, - scope.tryCatch(), objectGroup, false, false, + scope.tryCatch(), objectGroup, WrapMode::kNoPreview, callback.get()); return; } @@ -189,13 +189,13 @@ void innerCallFunctionOn( if (!awaitPromise || scope.tryCatch().HasCaught()) { wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, - scope.tryCatch(), objectGroup, returnByValue, - generatePreview, callback.get()); + scope.tryCatch(), objectGroup, wrapMode, + callback.get()); return; } scope.injectedScript()->addPromiseCallback( - session, maybeResultValue, objectGroup, returnByValue, generatePreview, + session, maybeResultValue, objectGroup, wrapMode, EvaluateCallbackWrapper::wrap( std::move(callback))); } @@ -284,16 +284,17 @@ void V8RuntimeAgentImpl::evaluate( return; } + WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview + : WrapMode::kNoPreview; + if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, - scope.tryCatch(), objectGroup.fromMaybe(""), - returnByValue.fromMaybe(false), - generatePreview.fromMaybe(false), callback.get()); + scope.tryCatch(), objectGroup.fromMaybe(""), mode, + callback.get()); return; } scope.injectedScript()->addPromiseCallback( - m_session, maybeResultValue, objectGroup.fromMaybe(""), - returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), + m_session, maybeResultValue, objectGroup.fromMaybe(""), mode, EvaluateCallbackWrapper::wrap(std::move(callback))); } @@ -312,9 +313,11 @@ void V8RuntimeAgentImpl::awaitPromise( Response::Error("Could not find promise with given id")); return; } + WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview + : WrapMode::kNoPreview; + if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; scope.injectedScript()->addPromiseCallback( - m_session, scope.object(), scope.objectGroupName(), - returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), + m_session, scope.object(), scope.objectGroupName(), mode, EvaluateCallbackWrapper::wrap(std::move(callback))); } @@ -335,6 +338,9 @@ void V8RuntimeAgentImpl::callFunctionOn( "Either ObjectId or executionContextId must be specified")); return; } + WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview + : WrapMode::kNoPreview; + if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; if (objectId.isJust()) { InjectedScript::ObjectScope scope(m_session, objectId.fromJust()); Response response = scope.initialize(); @@ -342,14 +348,13 @@ void V8RuntimeAgentImpl::callFunctionOn( callback->sendFailure(response); return; } - innerCallFunctionOn( - m_session, scope, scope.object(), expression, - std::move(optionalArguments), silent.fromMaybe(false), - returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), - userGesture.fromMaybe(false), awaitPromise.fromMaybe(false), - objectGroup.isJust() ? objectGroup.fromMaybe(String16()) - : scope.objectGroupName(), - std::move(callback)); + innerCallFunctionOn(m_session, scope, scope.object(), expression, + std::move(optionalArguments), silent.fromMaybe(false), + mode, userGesture.fromMaybe(false), + awaitPromise.fromMaybe(false), + objectGroup.isJust() ? objectGroup.fromMaybe(String16()) + : scope.objectGroupName(), + std::move(callback)); } else { int contextId = 0; Response response = @@ -365,12 +370,11 @@ void V8RuntimeAgentImpl::callFunctionOn( callback->sendFailure(response); return; } - innerCallFunctionOn( - m_session, scope, scope.context()->Global(), expression, - std::move(optionalArguments), silent.fromMaybe(false), - returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), - userGesture.fromMaybe(false), awaitPromise.fromMaybe(false), - objectGroup.fromMaybe(""), std::move(callback)); + innerCallFunctionOn(m_session, scope, scope.context()->Global(), expression, + std::move(optionalArguments), silent.fromMaybe(false), + mode, userGesture.fromMaybe(false), + awaitPromise.fromMaybe(false), + objectGroup.fromMaybe(""), std::move(callback)); } } @@ -397,40 +401,18 @@ Response V8RuntimeAgentImpl::getProperties( v8::Local object = scope.object().As(); response = scope.injectedScript()->getProperties( object, scope.objectGroupName(), ownProperties.fromMaybe(false), - accessorPropertiesOnly.fromMaybe(false), generatePreview.fromMaybe(false), + accessorPropertiesOnly.fromMaybe(false), + generatePreview.fromMaybe(false) ? WrapMode::kWithPreview + : WrapMode::kNoPreview, result, exceptionDetails); if (!response.isSuccess()) return response; if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false)) return Response::OK(); - v8::Local propertiesArray; - if (!m_inspector->debugger() - ->internalProperties(scope.context(), scope.object()) - .ToLocal(&propertiesArray)) { - return Response::InternalError(); - } std::unique_ptr> - propertiesProtocolArray = - protocol::Array::create(); - for (uint32_t i = 0; i < propertiesArray->Length(); i += 2) { - v8::Local name; - if (!propertiesArray->Get(scope.context(), i).ToLocal(&name) || - !name->IsString()) { - return Response::InternalError(); - } - v8::Local value; - if (!propertiesArray->Get(scope.context(), i + 1).ToLocal(&value)) - return Response::InternalError(); - std::unique_ptr 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())) - .setValue(std::move(wrappedValue)) - .build()); - } + propertiesProtocolArray; + response = scope.injectedScript()->getInternalProperties( + object, scope.objectGroupName(), &propertiesProtocolArray); + if (!response.isSuccess()) return response; if (propertiesProtocolArray->length()) *internalProperties = std::move(propertiesProtocolArray); return Response::OK(); @@ -499,7 +481,7 @@ Response V8RuntimeAgentImpl::compileScript( if (!isOk) { if (scope.tryCatch().HasCaught()) { response = scope.injectedScript()->createExceptionDetails( - scope.tryCatch(), String16(), false, exceptionDetails); + scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails); if (!response.isSuccess()) return response; return Response::OK(); } else { @@ -577,17 +559,18 @@ void V8RuntimeAgentImpl::runScript( return; } + WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview + : WrapMode::kNoPreview; + if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue; if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, - scope.tryCatch(), objectGroup.fromMaybe(""), - returnByValue.fromMaybe(false), - generatePreview.fromMaybe(false), callback.get()); + scope.tryCatch(), objectGroup.fromMaybe(""), mode, + callback.get()); return; } scope.injectedScript()->addPromiseCallback( - m_session, maybeResultValue.ToLocalChecked(), - objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), - generatePreview.fromMaybe(false), + m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""), + mode, EvaluateCallbackWrapper::wrap(std::move(callback))); } @@ -603,8 +586,8 @@ Response V8RuntimeAgentImpl::queryObjects( v8::Local resultArray = m_inspector->debugger()->queryObjects( scope.context(), v8::Local::Cast(scope.object())); return scope.injectedScript()->wrapObject( - resultArray, objectGroup.fromMaybe(scope.objectGroupName()), false, false, - objects); + resultArray, objectGroup.fromMaybe(scope.objectGroupName()), + WrapMode::kNoPreview, objects); } Response V8RuntimeAgentImpl::globalLexicalScopeNames( diff --git a/src/inspector/v8-value-utils.cc b/src/inspector/v8-value-utils.cc index feaffd36d0..dd73c2919d 100644 --- a/src/inspector/v8-value-utils.cc +++ b/src/inspector/v8-value-utils.cc @@ -6,102 +6,6 @@ namespace v8_inspector { -namespace { - -protocol::Response toProtocolValue(v8::Local context, - v8::Local value, int maxDepth, - std::unique_ptr* 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()->Value()); - return Response::OK(); - } - if (value->IsNumber()) { - double doubleValue = value.As()->Value(); - int intValue = static_cast(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())); - return Response::OK(); - } - if (value->IsArray()) { - v8::Local array = value.As(); - std::unique_ptr inspectorArray = - protocol::ListValue::create(); - uint32_t length = array->Length(); - for (uint32_t i = 0; i < length; i++) { - v8::Local value; - if (!array->Get(context, i).ToLocal(&value)) - return Response::InternalError(); - std::unique_ptr 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 jsonObject = - protocol::DictionaryValue::create(); - v8::Local object = v8::Local::Cast(value); - v8::Local 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 name; - if (!propertyNames->Get(context, i).ToLocal(&name)) - return Response::InternalError(); - // FIXME(yurys): v8::Object should support GetOwnPropertyNames - if (name->IsString()) { - v8::Maybe hasRealNamedProperty = object->HasRealNamedProperty( - context, v8::Local::Cast(name)); - if (hasRealNamedProperty.IsNothing() || - !hasRealNamedProperty.FromJust()) - continue; - } - v8::Local propertyName; - if (!name->ToString(context).ToLocal(&propertyName)) continue; - v8::Local property; - if (!object->Get(context, name).ToLocal(&property)) - return Response::InternalError(); - if (property->IsUndefined()) continue; - std::unique_ptr 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 createDataProperty(v8::Local context, v8::Local object, v8::Local key, @@ -122,11 +26,4 @@ v8::Maybe createDataProperty(v8::Local context, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); return array->CreateDataProperty(context, index, value); } - -protocol::Response toProtocolValue(v8::Local context, - v8::Local value, - std::unique_ptr* result) { - return toProtocolValue(context, value, 1000, result); -} - } // namespace v8_inspector diff --git a/src/inspector/v8-value-utils.h b/src/inspector/v8-value-utils.h index 029fee224b..6817d9fbb6 100644 --- a/src/inspector/v8-value-utils.h +++ b/src/inspector/v8-value-utils.h @@ -18,9 +18,6 @@ v8::Maybe createDataProperty(v8::Local, v8::Maybe createDataProperty(v8::Local, v8::Local, int index, v8::Local); -protocol::Response toProtocolValue(v8::Local, v8::Local, - std::unique_ptr* result); - } // namespace v8_inspector #endif // V8_INSPECTOR_V8_VALUE_UTILS_H_ diff --git a/src/inspector/value-mirror.cc b/src/inspector/value-mirror.cc new file mode 100644 index 0000000000..879610320e --- /dev/null +++ b/src/inspector/value-mirror.cc @@ -0,0 +1,1611 @@ +// 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/inspector/value-mirror.h" + +#include +#include + +#include "src/debug/debug-interface.h" +#include "src/inspector/v8-debugger.h" +#include "src/inspector/v8-inspector-impl.h" +#include "src/inspector/v8-value-utils.h" + +namespace v8_inspector { + +using protocol::Response; +using protocol::Runtime::RemoteObject; +using protocol::Runtime::ObjectPreview; +using protocol::Runtime::PropertyPreview; +using protocol::Runtime::EntryPreview; +using protocol::Runtime::InternalPropertyDescriptor; + +namespace { +V8InspectorClient* clientFor(v8::Local context) { + return static_cast( + v8::debug::GetInspector(context->GetIsolate())) + ->client(); +} + +V8InternalValueType v8InternalValueTypeFrom(v8::Local context, + v8::Local value) { + if (!value->IsObject()) return V8InternalValueType::kNone; + V8Debugger* debugger = static_cast( + v8::debug::GetInspector(context->GetIsolate())) + ->debugger(); + return debugger->getInternalType(context, value.As()); +} + +Response toProtocolValue(v8::Local context, + v8::Local value, int maxDepth, + std::unique_ptr* result) { + 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()->Value()); + return Response::OK(); + } + if (value->IsNumber()) { + double doubleValue = value.As()->Value(); + int intValue = static_cast(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())); + return Response::OK(); + } + if (value->IsArray()) { + v8::Local array = value.As(); + std::unique_ptr inspectorArray = + protocol::ListValue::create(); + uint32_t length = array->Length(); + for (uint32_t i = 0; i < length; i++) { + v8::Local value; + if (!array->Get(context, i).ToLocal(&value)) + return Response::InternalError(); + std::unique_ptr 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 jsonObject = + protocol::DictionaryValue::create(); + v8::Local object = v8::Local::Cast(value); + v8::Local 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 name; + if (!propertyNames->Get(context, i).ToLocal(&name)) + return Response::InternalError(); + // FIXME(yurys): v8::Object should support GetOwnPropertyNames + if (name->IsString()) { + v8::Maybe hasRealNamedProperty = object->HasRealNamedProperty( + context, v8::Local::Cast(name)); + if (hasRealNamedProperty.IsNothing() || + !hasRealNamedProperty.FromJust()) + continue; + } + v8::Local propertyName; + if (!name->ToString(context).ToLocal(&propertyName)) continue; + v8::Local property; + if (!object->Get(context, name).ToLocal(&property)) + return Response::InternalError(); + if (property->IsUndefined()) continue; + std::unique_ptr 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"); +} + +Response toProtocolValue(v8::Local context, + v8::Local value, + std::unique_ptr* result) { + if (value->IsUndefined()) return Response::OK(); + return toProtocolValue(context, value, 1000, result); +} + +enum AbbreviateMode { kMiddle, kEnd }; + +String16 abbreviateString(const String16& value, AbbreviateMode mode) { + const size_t maxLength = 100; + if (value.length() <= maxLength) return value; + UChar ellipsis = static_cast(0x2026); + if (mode == kMiddle) { + return String16::concat( + value.substring(0, maxLength / 2), String16(&ellipsis, 1), + value.substring(value.length() - maxLength / 2 + 1)); + } + return String16::concat(value.substring(0, maxLength - 1), ellipsis); +} + +String16 descriptionForSymbol(v8::Local context, + v8::Local symbol) { + return String16::concat( + "Symbol(", + toProtocolStringWithTypeCheck(context->GetIsolate(), symbol->Name()), + ")"); +} + +String16 descriptionForBigInt(v8::Local context, + v8::Local value) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::Local description; + if (!value->ToString(context).ToLocal(&description)) return String16(); + return toProtocolString(isolate, description) + "n"; +} + +String16 descriptionForPrimitiveType(v8::Local context, + v8::Local value) { + if (value->IsUndefined()) return RemoteObject::TypeEnum::Undefined; + if (value->IsNull()) return RemoteObject::SubtypeEnum::Null; + if (value->IsBoolean()) { + return value.As()->Value() ? "true" : "false"; + } + if (value->IsString()) { + return toProtocolString(context->GetIsolate(), value.As()); + } + UNREACHABLE(); + return String16(); +} + +String16 descriptionForRegExp(v8::Isolate* isolate, + v8::Local value) { + String16Builder description; + description.append('/'); + description.append(toProtocolString(isolate, value->GetSource())); + description.append('/'); + v8::RegExp::Flags flags = value->GetFlags(); + if (flags & v8::RegExp::Flags::kGlobal) description.append('g'); + if (flags & v8::RegExp::Flags::kIgnoreCase) description.append('i'); + if (flags & v8::RegExp::Flags::kMultiline) description.append('m'); + if (flags & v8::RegExp::Flags::kDotAll) description.append('s'); + if (flags & v8::RegExp::Flags::kUnicode) description.append('u'); + if (flags & v8::RegExp::Flags::kSticky) description.append('y'); + return description.toString(); +} + +enum class ErrorType { kNative, kClient }; + +String16 descriptionForError(v8::Local context, + v8::Local object, ErrorType type) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + String16 className = toProtocolString(isolate, object->GetConstructorName()); + v8::Local stackValue; + if (!object->Get(context, toV8String(isolate, "stack")) + .ToLocal(&stackValue) || + !stackValue->IsString()) { + return String16(); + } + String16 stack = toProtocolString(isolate, stackValue.As()); + String16 description = stack; + if (type == ErrorType::kClient) { + if (stack.substring(0, className.length()) != className) { + v8::Local messageValue; + if (!object->Get(context, toV8String(isolate, "message")) + .ToLocal(&messageValue) || + !messageValue->IsString()) { + return stack; + } + String16 message = toProtocolStringWithTypeCheck(isolate, messageValue); + size_t index = stack.find(message); + String16 stackWithoutMessage = + index != String16::kNotFound + ? stack.substring(index + message.length()) + : String16(); + description = className + ": " + message + stackWithoutMessage; + } + } + return description; +} + +String16 descriptionForObject(v8::Isolate* isolate, + v8::Local object) { + return toProtocolString(isolate, object->GetConstructorName()); +} + +String16 descriptionForDate(v8::Local context, + v8::Local date) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::Local description; + if (!date->ToString(context).ToLocal(&description)) { + return descriptionForObject(isolate, date); + } + return toProtocolString(isolate, description); +} + +String16 descriptionForScopeList(v8::Local list) { + return String16::concat( + "Scopes[", String16::fromInteger(static_cast(list->Length())), + ']'); +} + +String16 descriptionForScope(v8::Local context, + v8::Local object) { + v8::Isolate* isolate = context->GetIsolate(); + v8::Local value; + if (!object->GetRealNamedProperty(context, toV8String(isolate, "description")) + .ToLocal(&value)) { + return String16(); + } + return toProtocolStringWithTypeCheck(isolate, value); +} + +String16 descriptionForCollection(v8::Isolate* isolate, + v8::Local object, size_t length) { + String16 className = toProtocolString(isolate, object->GetConstructorName()); + return String16::concat(className, '(', String16::fromInteger(length), ')'); +} + +String16 descriptionForEntry(v8::Local context, + v8::Local object) { + v8::Isolate* isolate = context->GetIsolate(); + String16 key; + v8::Local tmp; + if (object->GetRealNamedProperty(context, toV8String(isolate, "key")) + .ToLocal(&tmp)) { + auto wrapper = ValueMirror::create(context, tmp); + if (wrapper) { + std::unique_ptr preview; + int limit = 5; + wrapper->buildEntryPreview(context, false, &limit, &limit, &preview); + if (preview) { + key = preview->getDescription(String16()); + if (preview->getType() == RemoteObject::TypeEnum::String) { + key = String16::concat('\"', key, '\"'); + } + } + } + } + + String16 value; + if (object->GetRealNamedProperty(context, toV8String(isolate, "value")) + .ToLocal(&tmp)) { + auto wrapper = ValueMirror::create(context, tmp); + if (wrapper) { + std::unique_ptr preview; + int limit = 5; + wrapper->buildEntryPreview(context, false, &limit, &limit, &preview); + if (preview) { + value = preview->getDescription(String16()); + if (preview->getType() == RemoteObject::TypeEnum::String) { + value = String16::concat('\"', value, '\"'); + } + } + } + } + + return key.length() ? ("{" + key + " => " + value + "}") : value; +} + +String16 descriptionForFunction(v8::Local context, + v8::Local value) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::Local description; + if (!value->ToString(context).ToLocal(&description)) { + return descriptionForObject(isolate, value); + } + return toProtocolString(isolate, description); +} + +class PrimitiveValueMirror final : public ValueMirror { + public: + PrimitiveValueMirror(v8::Local value, const String16& type) + : m_value(value), m_type(type) {} + + v8::Local v8Value() override { return m_value; } + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + std::unique_ptr protocolValue; + toProtocolValue(context, m_value, &protocolValue); + *result = RemoteObject::create() + .setType(m_type) + .setValue(std::move(protocolValue)) + .build(); + if (m_value->IsNull()) + (*result)->setSubtype(RemoteObject::SubtypeEnum::Null); + return Response::OK(); + } + + void buildEntryPreview(v8::Local context, + bool generatePreviewForProperties, int* nameLimit, + int* indexLimit, + std::unique_ptr* preview) override { + *preview = + ObjectPreview::create() + .setType(m_type) + .setDescription(descriptionForPrimitiveType(context, m_value)) + .setOverflow(false) + .setProperties(protocol::Array::create()) + .build(); + if (m_value->IsNull()) + (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null); + } + + void buildPropertyPreview( + v8::Local context, const String16& name, + std::unique_ptr* preview) override { + *preview = PropertyPreview::create() + .setName(name) + .setValue(abbreviateString( + descriptionForPrimitiveType(context, m_value), kMiddle)) + .setType(m_type) + .build(); + if (m_value->IsNull()) + (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null); + } + + private: + v8::Local m_value; + String16 m_type; + String16 m_subtype; +}; + +class NumberMirror final : public ValueMirror { + public: + explicit NumberMirror(v8::Local value) : m_value(value) {} + v8::Local v8Value() override { return m_value; } + + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + bool unserializable = false; + String16 descriptionValue = description(&unserializable); + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Number) + .setDescription(descriptionValue) + .build(); + if (unserializable) { + (*result)->setUnserializableValue(descriptionValue); + } else { + (*result)->setValue(protocol::FundamentalValue::create(m_value->Value())); + } + return Response::OK(); + } + void buildPropertyPreview(v8::Local context, + const String16& name, + std::unique_ptr* result) override { + bool unserializable = false; + *result = PropertyPreview::create() + .setName(name) + .setType(RemoteObject::TypeEnum::Number) + .setValue(description(&unserializable)) + .build(); + } + void buildEntryPreview(v8::Local context, + bool generatePreviewForProperties, int* nameLimit, + int* indexLimit, + std::unique_ptr* preview) override { + bool unserializable = false; + *preview = ObjectPreview::create() + .setType(RemoteObject::TypeEnum::Number) + .setDescription(description(&unserializable)) + .setOverflow(false) + .setProperties(protocol::Array::create()) + .build(); + } + + private: + String16 description(bool* unserializable) { + *unserializable = true; + double rawValue = m_value->Value(); + if (std::isnan(rawValue)) return "NaN"; + if (rawValue == 0.0 && std::signbit(rawValue)) return "-0"; + if (std::isinf(rawValue)) { + return std::signbit(rawValue) ? "-Infinity" : "Infinity"; + } + *unserializable = false; + return String16::fromDouble(rawValue); + } + + v8::Local m_value; +}; + +class BigIntMirror final : public ValueMirror { + public: + explicit BigIntMirror(v8::Local value) : m_value(value) {} + + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + String16 description = descriptionForBigInt(context, m_value); + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Bigint) + .setUnserializableValue(description) + .setDescription(description) + .build(); + return Response::OK(); + } + + void buildPropertyPreview( + v8::Local context, const String16& name, + std::unique_ptr* preview) override { + *preview = PropertyPreview::create() + .setName(name) + .setType(RemoteObject::TypeEnum::Bigint) + .setValue(abbreviateString( + descriptionForBigInt(context, m_value), kMiddle)) + .build(); + } + + void buildEntryPreview( + v8::Local context, bool generatePreviewForProperties, + int* nameLimit, int* indexLimit, + std::unique_ptr* preview) override { + *preview = ObjectPreview::create() + .setType(RemoteObject::TypeEnum::Bigint) + .setDescription(descriptionForBigInt(context, m_value)) + .setOverflow(false) + .setProperties(protocol::Array::create()) + .build(); + } + + v8::Local v8Value() override { return m_value; } + + private: + v8::Local m_value; +}; + +class SymbolMirror final : public ValueMirror { + public: + explicit SymbolMirror(v8::Local value) + : m_symbol(value.As()) {} + + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + if (mode == WrapMode::kForceValue) { + return Response::Error("Object couldn't be returned by value"); + } + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Symbol) + .setDescription(descriptionForSymbol(context, m_symbol)) + .build(); + return Response::OK(); + } + + void buildPropertyPreview( + v8::Local context, const String16& name, + std::unique_ptr* preview) override { + *preview = PropertyPreview::create() + .setName(name) + .setType(RemoteObject::TypeEnum::Symbol) + .setValue(abbreviateString( + descriptionForSymbol(context, m_symbol), kEnd)) + .build(); + } + + v8::Local v8Value() override { return m_symbol; } + + private: + v8::Local m_symbol; +}; + +class LocationMirror final : public ValueMirror { + public: + static std::unique_ptr create( + v8::Local function) { + return create(function, function->ScriptId(), + function->GetScriptLineNumber(), + function->GetScriptColumnNumber()); + } + static std::unique_ptr createForGenerator( + v8::Local value) { + v8::Local generatorObject = + v8::debug::GeneratorObject::Cast(value); + if (!generatorObject->IsSuspended()) { + return create(generatorObject->Function()); + } + v8::Local script; + if (!generatorObject->Script().ToLocal(&script)) return nullptr; + v8::debug::Location suspendedLocation = + generatorObject->SuspendedLocation(); + return create(value, script->Id(), suspendedLocation.GetLineNumber(), + suspendedLocation.GetColumnNumber()); + } + + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + auto location = protocol::DictionaryValue::create(); + location->setString("scriptId", String16::fromInteger(m_scriptId)); + location->setInteger("lineNumber", m_lineNumber); + location->setInteger("columnNumber", m_columnNumber); + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Object) + .setSubtype("internal#location") + .setDescription("Object") + .setValue(std::move(location)) + .build(); + return Response::OK(); + } + v8::Local v8Value() override { return m_value; } + + private: + static std::unique_ptr create(v8::Local value, + int scriptId, int lineNumber, + int columnNumber) { + if (scriptId == v8::UnboundScript::kNoScriptId) return nullptr; + if (lineNumber == v8::Function::kLineOffsetNotFound || + columnNumber == v8::Function::kLineOffsetNotFound) { + return nullptr; + } + return std::unique_ptr( + new LocationMirror(value, scriptId, lineNumber, columnNumber)); + } + + LocationMirror(v8::Local value, int scriptId, int lineNumber, + int columnNumber) + : m_value(value), + m_scriptId(scriptId), + m_lineNumber(lineNumber), + m_columnNumber(columnNumber) {} + + v8::Local m_value; + int m_scriptId; + int m_lineNumber; + int m_columnNumber; +}; + +class FunctionMirror final : public ValueMirror { + public: + explicit FunctionMirror(v8::Local value) + : m_value(value.As()) {} + + v8::Local v8Value() override { return m_value; } + + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + // TODO(alph): drop this functionality. + if (mode == WrapMode::kForceValue) { + std::unique_ptr protocolValue; + Response response = toProtocolValue(context, m_value, &protocolValue); + if (!response.isSuccess()) return response; + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Function) + .setValue(std::move(protocolValue)) + .build(); + } else { + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Function) + .setClassName(toProtocolStringWithTypeCheck( + context->GetIsolate(), m_value->GetConstructorName())) + .setDescription(descriptionForFunction(context, m_value)) + .build(); + } + return Response::OK(); + } + + void buildPropertyPreview(v8::Local context, + const String16& name, + std::unique_ptr* result) override { + *result = PropertyPreview::create() + .setName(name) + .setType(RemoteObject::TypeEnum::Function) + .setValue(String16()) + .build(); + } + void buildEntryPreview(v8::Local context, + bool generatePreviewForProperties, int* nameLimit, + int* indexLimit, + std::unique_ptr* preview) override { + *preview = ObjectPreview::create() + .setType(RemoteObject::TypeEnum::Function) + .setDescription(descriptionForFunction(context, m_value)) + .setOverflow(false) + .setProperties(protocol::Array::create()) + .build(); + } + + private: + v8::Local m_value; +}; + +bool isArrayLike(v8::Local context, v8::Local value, + size_t* length) { + if (!value->IsObject()) return false; + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::MicrotasksScope microtasksScope(isolate, + v8::MicrotasksScope::kDoNotRunMicrotasks); + v8::Local object = value.As(); + v8::Local spliceValue; + if (!object->IsArgumentsObject() && + (!object->GetRealNamedProperty(context, toV8String(isolate, "splice")) + .ToLocal(&spliceValue) || + !spliceValue->IsFunction())) { + return false; + } + v8::Local lengthValue; + v8::Maybe result = + object->HasOwnProperty(context, toV8String(isolate, "length")); + if (result.IsNothing()) return false; + if (!result.FromJust() || + !object->Get(context, toV8String(isolate, "length")) + .ToLocal(&lengthValue) || + !lengthValue->IsUint32()) { + return false; + } + *length = v8::Local::Cast(lengthValue)->Value(); + return true; +} + +struct EntryMirror { + std::unique_ptr key; + std::unique_ptr value; + + static bool getEntries(v8::Local context, + v8::Local object, size_t limit, + bool* overflow, std::vector* mirrors) { + bool isKeyValue = false; + v8::Local entries; + if (!object->PreviewEntries(&isKeyValue).ToLocal(&entries)) return false; + for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) { + v8::Local tmp; + + std::unique_ptr keyMirror; + if (isKeyValue && entries->Get(context, i).ToLocal(&tmp)) { + keyMirror = ValueMirror::create(context, tmp); + } + std::unique_ptr valueMirror; + if (entries->Get(context, isKeyValue ? i + 1 : i).ToLocal(&tmp)) { + valueMirror = ValueMirror::create(context, tmp); + } else { + continue; + } + if (mirrors->size() == limit) { + *overflow = true; + return true; + } + mirrors->emplace_back( + EntryMirror{std::move(keyMirror), std::move(valueMirror)}); + } + return mirrors->size() > 0; + } +}; + +class PreviewPropertyAccumulator : public ValueMirror::PropertyAccumulator { + public: + PreviewPropertyAccumulator(const std::vector& blacklist, + int skipIndex, int* nameLimit, int* indexLimit, + bool* overflow, + std::vector* mirrors) + : m_blacklist(blacklist), + m_skipIndex(skipIndex), + m_nameLimit(nameLimit), + m_indexLimit(indexLimit), + m_overflow(overflow), + m_mirrors(mirrors) {} + + bool Add(PropertyMirror mirror) override { + if (mirror.exception) return true; + if ((!mirror.getter || !mirror.getter->v8Value()->IsFunction()) && + !mirror.value) { + return true; + } + if (!mirror.isOwn) return true; + if (std::find(m_blacklist.begin(), m_blacklist.end(), mirror.name) != + m_blacklist.end()) { + return true; + } + if (mirror.isIndex && m_skipIndex > 0) { + --m_skipIndex; + if (m_skipIndex > 0) return true; + } + int* limit = mirror.isIndex ? m_indexLimit : m_nameLimit; + if (!*limit) { + *m_overflow = true; + return false; + } + --*limit; + m_mirrors->push_back(std::move(mirror)); + return true; + } + + private: + std::vector m_blacklist; + int m_skipIndex; + int* m_nameLimit; + int* m_indexLimit; + bool* m_overflow; + std::vector* m_mirrors; +}; + +bool getPropertiesForPreview(v8::Local context, + v8::Local object, int* nameLimit, + int* indexLimit, bool* overflow, + std::vector* properties) { + std::vector blacklist; + size_t length = 0; + if (object->IsArray() || isArrayLike(context, object, &length) || + object->IsStringObject()) { + blacklist.push_back("length"); + } else { + auto clientSubtype = clientFor(context)->valueSubtype(object); + if (clientSubtype && toString16(clientSubtype->string()) == "array") { + blacklist.push_back("length"); + } + } + if (object->IsArrayBuffer() || object->IsSharedArrayBuffer()) { + blacklist.push_back("[[Int8Array]]"); + blacklist.push_back("[[Uint8Array]]"); + blacklist.push_back("[[Int16Array]]"); + blacklist.push_back("[[Int32Array]]"); + } + int skipIndex = object->IsStringObject() + ? object.As()->ValueOf()->Length() + 1 + : -1; + PreviewPropertyAccumulator accumulator(blacklist, skipIndex, nameLimit, + indexLimit, overflow, properties); + return ValueMirror::getProperties(context, object, false, false, + &accumulator); +} + +void getInternalPropertiesForPreview( + v8::Local context, v8::Local object, + int* nameLimit, bool* overflow, + std::vector* properties) { + std::vector mirrors; + ValueMirror::getInternalProperties(context, object, &mirrors); + std::vector whitelist; + if (object->IsBooleanObject() || object->IsNumberObject() || + object->IsStringObject() || object->IsSymbolObject() || + object->IsBigIntObject()) { + whitelist.emplace_back("[[PrimitiveValue]]"); + } else if (object->IsPromise()) { + whitelist.emplace_back("[[PromiseStatus]]"); + whitelist.emplace_back("[[PromiseValue]]"); + } else if (object->IsGeneratorObject()) { + whitelist.emplace_back("[[GeneratorStatus]]"); + } + for (auto& mirror : mirrors) { + if (std::find(whitelist.begin(), whitelist.end(), mirror.name) == + whitelist.end()) { + continue; + } + if (!*nameLimit) { + *overflow = true; + return; + } + --*nameLimit; + properties->push_back(std::move(mirror)); + } +} + +class ObjectMirror final : public ValueMirror { + public: + ObjectMirror(v8::Local value, const String16& description) + : m_value(value.As()), + m_description(description), + m_hasSubtype(false) {} + ObjectMirror(v8::Local value, const String16& subtype, + const String16& description) + : m_value(value.As()), + m_description(description), + m_hasSubtype(true), + m_subtype(subtype) {} + + v8::Local v8Value() override { return m_value; } + + Response buildRemoteObject(v8::Local context, WrapMode mode, + std::unique_ptr* result) override { + if (mode == WrapMode::kForceValue) { + std::unique_ptr protocolValue; + Response response = toProtocolValue(context, m_value, &protocolValue); + if (!response.isSuccess()) return response; + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Object) + .setValue(std::move(protocolValue)) + .build(); + } else { + v8::Isolate* isolate = context->GetIsolate(); + *result = RemoteObject::create() + .setType(RemoteObject::TypeEnum::Object) + .setClassName(toProtocolString( + isolate, m_value->GetConstructorName())) + .setDescription(m_description) + .build(); + if (m_hasSubtype) (*result)->setSubtype(m_subtype); + if (mode == WrapMode::kWithPreview) { + std::unique_ptr previewValue; + int nameLimit = 5; + int indexLimit = 100; + buildObjectPreview(context, false, &nameLimit, &indexLimit, + &previewValue); + (*result)->setPreview(std::move(previewValue)); + } + } + return Response::OK(); + } + + void buildObjectPreview(v8::Local context, + bool generatePreviewForProperties, int* nameLimit, + int* indexLimit, + std::unique_ptr* result) override { + buildObjectPreviewInternal(context, false /* forEntry */, + generatePreviewForProperties, nameLimit, + indexLimit, result); + } + + void buildEntryPreview(v8::Local context, + bool generatePreviewForProperties, int* nameLimit, + int* indexLimit, + std::unique_ptr* result) override { + buildObjectPreviewInternal(context, true /* forEntry */, + generatePreviewForProperties, nameLimit, + indexLimit, result); + } + + void buildPropertyPreview(v8::Local context, + const String16& name, + std::unique_ptr* result) override { + *result = PropertyPreview::create() + .setName(name) + .setType(RemoteObject::TypeEnum::Object) + .setValue(abbreviateString( + m_description, + m_subtype == RemoteObject::SubtypeEnum::Regexp ? kMiddle + : kEnd)) + .build(); + if (m_hasSubtype) (*result)->setSubtype(m_subtype); + } + + private: + void buildObjectPreviewInternal(v8::Local context, bool forEntry, + bool generatePreviewForProperties, + int* nameLimit, int* indexLimit, + std::unique_ptr* result) { + std::unique_ptr> properties = + protocol::Array::create(); + std::unique_ptr> entriesPreview; + bool overflow = false; + + v8::Local value = m_value; + while (value->IsProxy()) value = value.As()->GetTarget(); + if (value->IsObject() && !value->IsProxy()) { + v8::Local objectForPreview = value.As(); + std::vector internalProperties; + getInternalPropertiesForPreview(context, objectForPreview, nameLimit, + &overflow, &internalProperties); + for (size_t i = 0; i < internalProperties.size(); ++i) { + std::unique_ptr propertyPreview; + internalProperties[i].value->buildPropertyPreview( + context, internalProperties[i].name, &propertyPreview); + if (propertyPreview) { + properties->addItem(std::move(propertyPreview)); + } + } + + std::vector mirrors; + if (getPropertiesForPreview(context, objectForPreview, nameLimit, + indexLimit, &overflow, &mirrors)) { + for (size_t i = 0; i < mirrors.size(); ++i) { + std::unique_ptr preview; + std::unique_ptr valuePreview; + if (mirrors[i].value) { + mirrors[i].value->buildPropertyPreview(context, mirrors[i].name, + &preview); + if (generatePreviewForProperties) { + mirrors[i].value->buildObjectPreview(context, false, nameLimit, + indexLimit, &valuePreview); + } + } else { + preview = PropertyPreview::create() + .setName(mirrors[i].name) + .setType(PropertyPreview::TypeEnum::Accessor) + .build(); + } + if (valuePreview) { + preview->setValuePreview(std::move(valuePreview)); + } + properties->addItem(std::move(preview)); + } + } + + std::vector entries; + if (EntryMirror::getEntries(context, objectForPreview, 5, &overflow, + &entries)) { + if (forEntry) { + overflow = true; + } else { + entriesPreview = protocol::Array::create(); + for (const auto& entry : entries) { + std::unique_ptr valuePreview; + entry.value->buildEntryPreview( + context, generatePreviewForProperties, nameLimit, indexLimit, + &valuePreview); + if (!valuePreview) continue; + std::unique_ptr keyPreview; + if (entry.key) { + entry.key->buildEntryPreview(context, + generatePreviewForProperties, + nameLimit, indexLimit, &keyPreview); + if (!keyPreview) continue; + } + std::unique_ptr entryPreview = + EntryPreview::create() + .setValue(std::move(valuePreview)) + .build(); + if (keyPreview) entryPreview->setKey(std::move(keyPreview)); + entriesPreview->addItem(std::move(entryPreview)); + } + } + } + } + *result = ObjectPreview::create() + .setType(RemoteObject::TypeEnum::Object) + .setDescription(m_description) + .setOverflow(overflow) + .setProperties(std::move(properties)) + .build(); + if (m_hasSubtype) (*result)->setSubtype(m_subtype); + if (entriesPreview) (*result)->setEntries(std::move(entriesPreview)); + } + + v8::Local m_value; + String16 m_description; + bool m_hasSubtype; + String16 m_subtype; +}; + +void nativeGetterCallback(const v8::FunctionCallbackInfo& info) { + v8::Local data = info.Data().As(); + v8::Isolate* isolate = info.GetIsolate(); + v8::Local context = isolate->GetCurrentContext(); + v8::Local name; + if (!data->GetRealNamedProperty(context, toV8String(isolate, "name")) + .ToLocal(&name)) { + return; + } + v8::Local object; + if (!data->GetRealNamedProperty(context, toV8String(isolate, "object")) + .ToLocal(&object) || + !object->IsObject()) { + return; + } + v8::Local value; + if (!object.As()->Get(context, name).ToLocal(&value)) return; + info.GetReturnValue().Set(value); +} + +std::unique_ptr createNativeGetter(v8::Local context, + v8::Local object, + v8::Local name) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + + v8::Local data = v8::Object::New(isolate); + if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) { + return nullptr; + } + if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) { + return nullptr; + } + + v8::Local function; + if (!v8::Function::New(context, nativeGetterCallback, data, 0, + v8::ConstructorBehavior::kThrow) + .ToLocal(&function)) { + return nullptr; + } + return ValueMirror::create(context, function); +} + +void nativeSetterCallback(const v8::FunctionCallbackInfo& info) { + if (info.Length() < 1) return; + v8::Local data = info.Data().As(); + v8::Isolate* isolate = info.GetIsolate(); + v8::Local context = isolate->GetCurrentContext(); + v8::Local name; + if (!data->GetRealNamedProperty(context, toV8String(isolate, "name")) + .ToLocal(&name)) { + return; + } + v8::Local object; + if (!data->GetRealNamedProperty(context, toV8String(isolate, "object")) + .ToLocal(&object) || + !object->IsObject()) { + return; + } + v8::Local value; + if (!object.As()->Set(context, name, info[0]).IsNothing()) return; +} + +std::unique_ptr createNativeSetter(v8::Local context, + v8::Local object, + v8::Local name) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + + v8::Local data = v8::Object::New(isolate); + if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) { + return nullptr; + } + if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) { + return nullptr; + } + + v8::Local function; + if (!v8::Function::New(context, nativeSetterCallback, data, 1, + v8::ConstructorBehavior::kThrow) + .ToLocal(&function)) { + return nullptr; + } + return ValueMirror::create(context, function); +} + +bool doesAttributeHaveObservableSideEffectOnGet(v8::Local context, + v8::Local object, + v8::Local name) { + // TODO(dgozman): we should remove this, annotate more embedder properties as + // side-effect free, and call all getters which do not produce side effects. + if (!name->IsString()) return false; + v8::Isolate* isolate = context->GetIsolate(); + if (!name.As()->StringEquals(toV8String(isolate, "body"))) { + return false; + } + + v8::TryCatch tryCatch(isolate); + v8::Local request; + if (context->Global() + ->GetRealNamedProperty(context, toV8String(isolate, "Request")) + .ToLocal(&request)) { + if (request->IsObject() && + object->InstanceOf(context, request.As()) + .FromMaybe(false)) { + return true; + } + } + if (tryCatch.HasCaught()) tryCatch.Reset(); + + v8::Local response; + if (context->Global() + ->GetRealNamedProperty(context, toV8String(isolate, "Response")) + .ToLocal(&response)) { + if (response->IsObject() && + object->InstanceOf(context, response.As()) + .FromMaybe(false)) { + return true; + } + } + return false; +} +template +void addTypedArrayView(v8::Local context, + v8::Local buffer, size_t length, + const char* name, + ValueMirror::PropertyAccumulator* accumulator) { + accumulator->Add(PropertyMirror{ + String16(name), false, false, false, true, false, + ValueMirror::create(context, ArrayView::New(buffer, 0, length)), nullptr, + nullptr, nullptr, nullptr}); +} + +template +void addTypedArrayViews(v8::Local context, + v8::Local buffer, + ValueMirror::PropertyAccumulator* accumulator) { + // TODO(alph): these should be internal properties. + size_t length = buffer->ByteLength(); + addTypedArrayView(context, buffer, length, "[[Int8Array]]", + accumulator); + addTypedArrayView(context, buffer, length, "[[Uint8Array]]", + accumulator); + if (buffer->ByteLength() % 2 == 0) { + addTypedArrayView(context, buffer, length / 2, + "[[Int16Array]]", accumulator); + } + if (buffer->ByteLength() % 4 == 0) { + addTypedArrayView(context, buffer, length / 4, + "[[Int32Array]]", accumulator); + } +} +} // anonymous namespace + +ValueMirror::~ValueMirror() = default; + +// static +bool ValueMirror::getProperties(v8::Local context, + v8::Local object, + bool ownProperties, bool accessorPropertiesOnly, + PropertyAccumulator* accumulator) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::Local set = v8::Set::New(isolate); + + v8::MicrotasksScope microtasksScope(isolate, + v8::MicrotasksScope::kDoNotRunMicrotasks); + V8InternalValueType internalType = v8InternalValueTypeFrom(context, object); + if (internalType == V8InternalValueType::kScope) { + v8::Local value; + if (!object->Get(context, toV8String(isolate, "object")).ToLocal(&value) || + !value->IsObject()) { + return false; + } else { + object = value.As(); + } + } + if (internalType == V8InternalValueType::kScopeList) { + if (!set->Add(context, toV8String(isolate, "length")).ToLocal(&set)) { + return false; + } + } + bool shouldSkipProto = internalType == V8InternalValueType::kScopeList; + + bool formatAccessorsAsProperties = + clientFor(context)->formatAccessorsAsProperties(object); + + if (object->IsArrayBuffer()) { + addTypedArrayViews(context, object.As(), accumulator); + } + if (object->IsSharedArrayBuffer()) { + addTypedArrayViews(context, object.As(), + accumulator); + } + + for (auto iterator = v8::debug::PropertyIterator::Create(object); + !iterator->Done(); iterator->Advance()) { + bool isOwn = iterator->is_own(); + if (!isOwn && ownProperties) break; + v8::Local v8Name = iterator->name(); + v8::Maybe result = set->Has(context, v8Name); + if (result.IsNothing()) return false; + if (result.FromJust()) continue; + if (!set->Add(context, v8Name).ToLocal(&set)) return false; + + String16 name; + std::unique_ptr symbolMirror; + if (v8Name->IsString()) { + name = toProtocolString(isolate, v8Name.As()); + } else { + v8::Local symbol = v8Name.As(); + name = descriptionForSymbol(context, symbol); + symbolMirror = ValueMirror::create(context, symbol); + } + + v8::PropertyAttribute attributes; + std::unique_ptr valueMirror; + std::unique_ptr getterMirror; + std::unique_ptr setterMirror; + std::unique_ptr exceptionMirror; + bool writable = false; + bool enumerable = false; + bool configurable = false; + + bool isAccessorProperty = false; + v8::TryCatch tryCatch(isolate); + if (!iterator->attributes().To(&attributes)) { + exceptionMirror = ValueMirror::create(context, tryCatch.Exception()); + } else { + if (iterator->is_native_accessor()) { + if (iterator->has_native_getter()) { + getterMirror = createNativeGetter(context, object, v8Name); + } + if (iterator->has_native_setter()) { + setterMirror = createNativeSetter(context, object, v8Name); + } + writable = !(attributes & v8::PropertyAttribute::ReadOnly); + enumerable = !(attributes & v8::PropertyAttribute::DontEnum); + configurable = !(attributes & v8::PropertyAttribute::DontDelete); + isAccessorProperty = getterMirror || setterMirror; + } else { + v8::TryCatch tryCatch(isolate); + v8::debug::PropertyDescriptor descriptor; + if (!iterator->descriptor().To(&descriptor)) { + exceptionMirror = ValueMirror::create(context, tryCatch.Exception()); + } else { + writable = descriptor.has_writable ? descriptor.writable : false; + enumerable = + descriptor.has_enumerable ? descriptor.enumerable : false; + configurable = + descriptor.has_configurable ? descriptor.configurable : false; + if (!descriptor.value.IsEmpty()) { + valueMirror = ValueMirror::create(context, descriptor.value); + } + bool getterIsNativeFunction = false; + if (!descriptor.get.IsEmpty()) { + v8::Local get = descriptor.get; + getterMirror = ValueMirror::create(context, get); + getterIsNativeFunction = + get->IsFunction() && get.As()->ScriptId() == + v8::UnboundScript::kNoScriptId; + } + if (!descriptor.set.IsEmpty()) { + setterMirror = ValueMirror::create(context, descriptor.set); + } + isAccessorProperty = getterMirror || setterMirror; + bool isSymbolDescription = + object->IsSymbol() && name == "description"; + if (isSymbolDescription || + (name != "__proto__" && getterIsNativeFunction && + formatAccessorsAsProperties && + !doesAttributeHaveObservableSideEffectOnGet(context, object, + v8Name))) { + v8::TryCatch tryCatch(isolate); + v8::Local value; + if (object->Get(context, v8Name).ToLocal(&value)) { + valueMirror = ValueMirror::create(context, value); + isOwn = true; + setterMirror = nullptr; + getterMirror = nullptr; + } + } + } + } + } + if (accessorPropertiesOnly && !isAccessorProperty) continue; + auto mirror = PropertyMirror{name, + writable, + configurable, + enumerable, + isOwn, + iterator->is_array_index(), + std::move(valueMirror), + std::move(getterMirror), + std::move(setterMirror), + std::move(symbolMirror), + std::move(exceptionMirror)}; + if (!accumulator->Add(std::move(mirror))) return true; + } + if (!shouldSkipProto && ownProperties && !object->IsProxy() && + !accessorPropertiesOnly) { + v8::Local prototype = object->GetPrototype(); + if (prototype->IsObject()) { + accumulator->Add(PropertyMirror{String16("__proto__"), true, true, false, + true, false, + ValueMirror::create(context, prototype), + nullptr, nullptr, nullptr, nullptr}); + } + } + return true; +} + +// static +void ValueMirror::getInternalProperties( + v8::Local context, v8::Local object, + std::vector* mirrors) { + v8::Isolate* isolate = context->GetIsolate(); + v8::MicrotasksScope microtasksScope(isolate, + v8::MicrotasksScope::kDoNotRunMicrotasks); + v8::TryCatch tryCatch(isolate); + if (object->IsFunction()) { + v8::Local function = object.As(); + auto location = LocationMirror::create(function); + if (location) { + mirrors->emplace_back(InternalPropertyMirror{ + String16("[[FunctionLocation]]"), std::move(location)}); + } + if (function->IsGeneratorFunction()) { + mirrors->emplace_back(InternalPropertyMirror{ + String16("[[IsGenerator]]"), + ValueMirror::create(context, v8::True(context->GetIsolate()))}); + } + } + if (object->IsGeneratorObject()) { + auto location = LocationMirror::createForGenerator(object); + if (location) { + mirrors->emplace_back(InternalPropertyMirror{ + String16("[[GeneratorLocation]]"), std::move(location)}); + } + } + V8Debugger* debugger = + static_cast(v8::debug::GetInspector(isolate)) + ->debugger(); + v8::Local properties; + if (debugger->internalProperties(context, object).ToLocal(&properties)) { + for (uint32_t i = 0; i < properties->Length(); i += 2) { + v8::Local name; + if (!properties->Get(context, i).ToLocal(&name) || !name->IsString()) { + tryCatch.Reset(); + continue; + } + v8::Local value; + if (!properties->Get(context, i + 1).ToLocal(&value)) { + tryCatch.Reset(); + continue; + } + auto wrapper = ValueMirror::create(context, value); + if (wrapper) { + mirrors->emplace_back(InternalPropertyMirror{ + toProtocolStringWithTypeCheck(context->GetIsolate(), name), + std::move(wrapper)}); + } + } + } +} + +String16 descriptionForNode(v8::Local context, + v8::Local value) { + if (!value->IsObject()) return String16(); + v8::Local object = value.As(); + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::Local nodeName; + if (!object->Get(context, toV8String(isolate, "nodeName")) + .ToLocal(&nodeName)) { + return String16(); + } + String16 description; + v8::Local toLowerCase = + v8::debug::GetBuiltin(isolate, v8::debug::kStringToLowerCase); + if (nodeName->IsString()) { + if (!toLowerCase->Call(context, nodeName, 0, nullptr).ToLocal(&nodeName)) + return String16(); + if (nodeName->IsString()) { + description = toProtocolString(isolate, nodeName.As()); + } + } + if (!description.length()) { + v8::Local value; + if (!object->Get(context, toV8String(isolate, "constructor")) + .ToLocal(&value) || + !value->IsObject()) { + return String16(); + } + if (!value.As() + ->Get(context, toV8String(isolate, "name")) + .ToLocal(&value) || + !value->IsString()) { + return String16(); + } + description = toProtocolString(isolate, value.As()); + } + v8::Local nodeType; + if (!object->Get(context, toV8String(isolate, "nodeType")) + .ToLocal(&nodeType) || + !nodeType->IsInt32()) { + return description; + } + if (nodeType.As()->Value() == 1) { + v8::Local idValue; + if (!object->Get(context, toV8String(isolate, "id")).ToLocal(&idValue)) { + return description; + } + if (idValue->IsString()) { + String16 id = toProtocolString(isolate, idValue.As()); + if (id.length()) { + description = String16::concat(description, '#', id); + } + } + v8::Local classNameValue; + if (!object->Get(context, toV8String(isolate, "className")) + .ToLocal(&classNameValue)) { + return description; + } + if (classNameValue->IsString() && + classNameValue.As()->Length()) { + String16 classes = + toProtocolString(isolate, classNameValue.As()); + String16Builder output; + bool previousIsDot = false; + for (size_t i = 0; i < classes.length(); ++i) { + if (classes[i] == ' ') { + if (!previousIsDot) { + output.append('.'); + previousIsDot = true; + } + } else { + output.append(classes[i]); + previousIsDot = classes[i] == '.'; + } + } + description = String16::concat(description, '.', output.toString()); + } + } else if (nodeType.As()->Value() == 1) { + return String16::concat("'); + } + return description; +} + +std::unique_ptr clientMirror(v8::Local context, + v8::Local value, + const String16& subtype) { + // TODO(alph): description and length retrieval should move to embedder. + if (subtype == "node") { + return v8::base::make_unique( + value, subtype, descriptionForNode(context, value)); + } + if (subtype == "error") { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Error, + descriptionForError(context, value.As(), + ErrorType::kClient)); + } + if (subtype == "array" && value->IsObject()) { + v8::Isolate* isolate = context->GetIsolate(); + v8::TryCatch tryCatch(isolate); + v8::Local object = value.As(); + v8::Local lengthValue; + if (object->Get(context, toV8String(isolate, "length")) + .ToLocal(&lengthValue)) { + if (lengthValue->IsInt32()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Array, + descriptionForCollection(isolate, object, + lengthValue.As()->Value())); + } + } + } + return v8::base::make_unique( + value, + descriptionForObject(context->GetIsolate(), value.As())); +} + +std::unique_ptr ValueMirror::create(v8::Local context, + v8::Local value) { + if (value->IsNull()) { + return v8::base::make_unique( + value, RemoteObject::TypeEnum::Object); + } + if (value->IsBoolean()) { + return v8::base::make_unique( + value, RemoteObject::TypeEnum::Boolean); + } + if (value->IsNumber()) { + return v8::base::make_unique(value.As()); + } + v8::Isolate* isolate = context->GetIsolate(); + if (value->IsString()) { + return v8::base::make_unique( + value, RemoteObject::TypeEnum::String); + } + if (value->IsBigInt()) { + return v8::base::make_unique(value.As()); + } + if (value->IsSymbol()) { + return v8::base::make_unique(value.As()); + } + auto clientSubtype = (value->IsUndefined() || value->IsObject()) + ? clientFor(context)->valueSubtype(value) + : nullptr; + if (clientSubtype) { + String16 subtype = toString16(clientSubtype->string()); + return clientMirror(context, value, subtype); + } + if (value->IsUndefined()) { + return v8::base::make_unique( + value, RemoteObject::TypeEnum::Undefined); + } + if (value->IsRegExp()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Regexp, + descriptionForRegExp(isolate, value.As())); + } + if (value->IsFunction()) { + return v8::base::make_unique(value); + } + if (value->IsProxy()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Proxy, "Proxy"); + } + if (value->IsDate()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Date, + descriptionForDate(context, value.As())); + } + if (value->IsPromise()) { + v8::Local promise = value.As(); + return v8::base::make_unique( + promise, RemoteObject::SubtypeEnum::Promise, + descriptionForObject(isolate, promise)); + } + if (value->IsNativeError()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Error, + descriptionForError(context, value.As(), + ErrorType::kNative)); + } + if (value->IsMap()) { + v8::Local map = value.As(); + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Map, + descriptionForCollection(isolate, map, map->Size())); + } + if (value->IsSet()) { + v8::Local set = value.As(); + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Set, + descriptionForCollection(isolate, set, set->Size())); + } + if (value->IsWeakMap()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Weakmap, + descriptionForObject(isolate, value.As())); + } + if (value->IsWeakSet()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Weakset, + descriptionForObject(isolate, value.As())); + } + if (value->IsMapIterator() || value->IsSetIterator()) { + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Iterator, + descriptionForObject(isolate, value.As())); + } + if (value->IsGeneratorObject()) { + v8::Local object = value.As(); + return v8::base::make_unique( + object, RemoteObject::SubtypeEnum::Generator, + descriptionForObject(isolate, object)); + } + if (value->IsTypedArray()) { + v8::Local array = value.As(); + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Typedarray, + descriptionForCollection(isolate, array, array->Length())); + } + if (value->IsArrayBuffer()) { + v8::Local buffer = value.As(); + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Arraybuffer, + descriptionForCollection(isolate, buffer, buffer->ByteLength())); + } + if (value->IsSharedArrayBuffer()) { + v8::Local buffer = value.As(); + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Arraybuffer, + descriptionForCollection(isolate, buffer, buffer->ByteLength())); + } + if (value->IsDataView()) { + v8::Local view = value.As(); + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Dataview, + descriptionForCollection(isolate, view, view->ByteLength())); + } + V8InternalValueType internalType = + v8InternalValueTypeFrom(context, v8::Local::Cast(value)); + if (value->IsArray() && internalType == V8InternalValueType::kScopeList) { + return v8::base::make_unique( + value, "internal#scopeList", + descriptionForScopeList(value.As())); + } + if (value->IsObject() && internalType == V8InternalValueType::kEntry) { + return v8::base::make_unique( + value, "internal#entry", + descriptionForEntry(context, value.As())); + } + if (value->IsObject() && internalType == V8InternalValueType::kScope) { + return v8::base::make_unique( + value, "internal#scope", + descriptionForScope(context, value.As())); + } + size_t length = 0; + if (value->IsArray() || isArrayLike(context, value, &length)) { + length = value->IsArray() ? value.As()->Length() : length; + return v8::base::make_unique( + value, RemoteObject::SubtypeEnum::Array, + descriptionForCollection(isolate, value.As(), length)); + } + if (value->IsObject()) { + return v8::base::make_unique( + value, descriptionForObject(isolate, value.As())); + } + return nullptr; +} +} // namespace v8_inspector diff --git a/src/inspector/value-mirror.h b/src/inspector/value-mirror.h new file mode 100644 index 0000000000..4a7ee2e333 --- /dev/null +++ b/src/inspector/value-mirror.h @@ -0,0 +1,79 @@ +// 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 + +#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 value; +}; + +struct PropertyMirror { + String16 name; + bool writable; + bool configurable; + bool enumerable; + bool isOwn; + bool isIndex; + std::unique_ptr value; + std::unique_ptr getter; + std::unique_ptr setter; + std::unique_ptr symbol; + std::unique_ptr exception; +}; + +class ValueMirror { + public: + virtual ~ValueMirror(); + + static std::unique_ptr create(v8::Local context, + v8::Local value); + virtual protocol::Response buildRemoteObject( + v8::Local context, WrapMode mode, + std::unique_ptr* result) = 0; + virtual void buildPropertyPreview( + v8::Local context, const String16& name, + std::unique_ptr*) {} + virtual void buildObjectPreview( + v8::Local context, bool generatePreviewForProperties, + int* nameLimit, int* indexLimit, + std::unique_ptr*) {} + virtual void buildEntryPreview( + v8::Local context, bool generatePreviewForProperties, + int* nameLimit, int* indexLimit, + std::unique_ptr*) {} + virtual v8::Local v8Value() = 0; + + class PropertyAccumulator { + public: + virtual ~PropertyAccumulator() = default; + virtual bool Add(PropertyMirror mirror) = 0; + }; + static bool getProperties(v8::Local context, + v8::Local object, bool ownProperties, + bool accessorPropertiesOnly, + PropertyAccumulator* accumulator); + static void getInternalProperties( + v8::Local context, v8::Local object, + std::vector* mirrors); +}; +} // namespace v8_inspector + +#endif // V8_INSPECTOR_VALUE_MIRROR_H_ diff --git a/test/inspector/BUILD.gn b/test/inspector/BUILD.gn index fc3d51506f..f83c7d044d 100644 --- a/test/inspector/BUILD.gn +++ b/test/inspector/BUILD.gn @@ -44,7 +44,6 @@ v8_executable("inspector-test") { "sessions/", "testcfg.py", "type-profiler/", - "../../src/inspector/injected-script-source.js", ] cflags = [] diff --git a/test/inspector/debugger/object-preview-internal-properties-expected.txt b/test/inspector/debugger/object-preview-internal-properties-expected.txt index a24ba5c370..9f265261f8 100644 --- a/test/inspector/debugger/object-preview-internal-properties-expected.txt +++ b/test/inspector/debugger/object-preview-internal-properties-expected.txt @@ -26,18 +26,7 @@ expression: Object(Symbol(42)) { name : [[PrimitiveValue]] type : symbol - valuePreview : { - description : Symbol - overflow : false - properties : [ - [0] : { - name : description - type : string - value : 42 - } - ] - type : object - } + value : Symbol(42) } expression: Object(BigInt(2)) diff --git a/test/inspector/debugger/stepping-ignores-injected-script-expected.txt b/test/inspector/debugger/stepping-ignores-injected-script-expected.txt deleted file mode 100644 index 5a63493dc7..0000000000 --- a/test/inspector/debugger/stepping-ignores-injected-script-expected.txt +++ /dev/null @@ -1,2 +0,0 @@ -Tests that stepping ignores injected script -InjectedSciptSource was not reached diff --git a/test/inspector/debugger/stepping-ignores-injected-script.js b/test/inspector/debugger/stepping-ignores-injected-script.js deleted file mode 100644 index 9021664a96..0000000000 --- a/test/inspector/debugger/stepping-ignores-injected-script.js +++ /dev/null @@ -1,21 +0,0 @@ -// 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); diff --git a/test/inspector/debugger/stepping-with-exposed-injected-script-expected.txt b/test/inspector/debugger/stepping-with-exposed-injected-script-expected.txt deleted file mode 100644 index 65c32c3ec9..0000000000 --- a/test/inspector/debugger/stepping-with-exposed-injected-script-expected.txt +++ /dev/null @@ -1,2 +0,0 @@ -Tests that stepping does not ignore injected script when passed a flag -InjectedSciptSource on stack. diff --git a/test/inspector/debugger/stepping-with-exposed-injected-script.js b/test/inspector/debugger/stepping-with-exposed-injected-script.js deleted file mode 100644 index d608137c81..0000000000 --- a/test/inspector/debugger/stepping-with-exposed-injected-script.js +++ /dev/null @@ -1,22 +0,0 @@ -// 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); diff --git a/test/inspector/inspector.status b/test/inspector/inspector.status index af69fc1ca5..dfe0541b47 100644 --- a/test/inspector/inspector.status +++ b/test/inspector/inspector.status @@ -17,8 +17,6 @@ ############################################################################## ['system == android', { - # https://crbug.com/v8/8160 - 'debugger/stepping-with-exposed-injected-script': [FAIL], # https://crbug.com/v8/8197 'debugger/get-possible-breakpoints-class-fields': [SKIP], }], # 'system == android' diff --git a/test/inspector/protocol-test.js b/test/inspector/protocol-test.js index fcfff726da..9d3e5d7999 100644 --- a/test/inspector/protocol-test.js +++ b/test/inspector/protocol-test.js @@ -176,8 +176,6 @@ InspectorTest.ContextGroup = class { if (session) { InspectorTest.log('WARNING: setupInjectedScriptEnvironment with debug flag for debugging only and should not be landed.'); - InspectorTest.log('WARNING: run test with --expose-inspector-scripts flag to get more details.'); - InspectorTest.log('WARNING: you can additionally comment rjsmin in xxd.py to get unminified injected-script-source.js.'); session.setupScriptMap(); session.Protocol.Debugger.enable(); session.Protocol.Debugger.onPaused(message => { diff --git a/test/inspector/runtime/console-methods-expected.txt b/test/inspector/runtime/console-methods-expected.txt index 45373f9dc7..0d7e9d601b 100644 --- a/test/inspector/runtime/console-methods-expected.txt +++ b/test/inspector/runtime/console-methods-expected.txt @@ -239,6 +239,7 @@ Checks console methods name : 0 subtype : array type : object + value : Array(2) valuePreview : { description : Array(2) overflow : false @@ -262,6 +263,7 @@ Checks console methods name : 1 subtype : array type : object + value : Array(2) valuePreview : { description : Array(2) overflow : false @@ -328,6 +330,7 @@ Checks console methods name : 0 subtype : array type : object + value : Array(2) valuePreview : { description : Array(2) overflow : false @@ -346,6 +349,7 @@ Checks console methods name : 1 subtype : array type : object + value : Array(2) valuePreview : { description : Array(2) overflow : false diff --git a/test/inspector/runtime/console-table-expected.txt b/test/inspector/runtime/console-table-expected.txt index a4367c6563..3f4e0f13e0 100644 --- a/test/inspector/runtime/console-table-expected.txt +++ b/test/inspector/runtime/console-table-expected.txt @@ -47,8 +47,9 @@ console.table name : 0 subtype : array type : object + value : Array(2) valuePreview : { - description : Array(3) + description : Array(2) overflow : false properties : [ [0] : { @@ -70,8 +71,9 @@ console.table name : 1 subtype : array type : object + value : Array(2) valuePreview : { - description : Array(3) + description : Array(2) overflow : false properties : [ [0] : { @@ -93,8 +95,9 @@ console.table name : 2 subtype : array type : object + value : Array(2) valuePreview : { - description : Array(3) + description : Array(2) overflow : false properties : [ [0] : { @@ -123,8 +126,9 @@ console.table [0] : { name : 0 type : object + value : Person valuePreview : { - description : Array(3) + description : Person overflow : false properties : [ [0] : { @@ -138,15 +142,15 @@ console.table value : Smith } ] - subtype : array type : object } } [1] : { name : 1 type : object + value : Person valuePreview : { - description : Array(3) + description : Person overflow : false properties : [ [0] : { @@ -160,15 +164,15 @@ console.table value : Doe } ] - subtype : array type : object } } [2] : { name : 2 type : object + value : Person valuePreview : { - description : Array(3) + description : Person overflow : false properties : [ [0] : { @@ -182,7 +186,6 @@ console.table value : Jones } ] - subtype : array type : object } } @@ -197,8 +200,9 @@ console.table [0] : { name : mother type : object + value : Person valuePreview : { - description : Object + description : Person overflow : false properties : [ [0] : { @@ -218,8 +222,9 @@ console.table [1] : { name : father type : object + value : Person valuePreview : { - description : Object + description : Person overflow : false properties : [ [0] : { @@ -239,8 +244,9 @@ console.table [2] : { name : daughter type : object + value : Person valuePreview : { - description : Object + description : Person overflow : false properties : [ [0] : { @@ -267,8 +273,9 @@ console.table [0] : { name : 0 type : object + value : Person valuePreview : { - description : Array(3) + description : Person overflow : false properties : [ [0] : { @@ -277,15 +284,15 @@ console.table value : John } ] - subtype : array type : object } } [1] : { name : 1 type : object + value : Person valuePreview : { - description : Array(3) + description : Person overflow : false properties : [ [0] : { @@ -294,15 +301,15 @@ console.table value : Jane } ] - subtype : array type : object } } [2] : { name : 2 type : object + value : Person valuePreview : { - description : Array(3) + description : Person overflow : false properties : [ [0] : { @@ -311,7 +318,6 @@ console.table value : Emily } ] - subtype : array type : object } } diff --git a/test/inspector/runtime/internal-properties-expected.txt b/test/inspector/runtime/internal-properties-expected.txt index c114696eb8..d7c768ad55 100644 --- a/test/inspector/runtime/internal-properties-expected.txt +++ b/test/inspector/runtime/internal-properties-expected.txt @@ -7,10 +7,6 @@ expression: (function* foo() { yield 1 }) result : { internalProperties : [ [0] : { - name : [[StableObjectId]] - value : - } - [1] : { name : [[FunctionLocation]] value : { description : Object @@ -23,13 +19,17 @@ expression: (function* foo() { yield 1 }) } } } - [2] : { + [1] : { name : [[IsGenerator]] value : { type : boolean value : true } } + [2] : { + name : [[StableObjectId]] + value : + } [3] : { name : [[Scopes]] value : { @@ -51,10 +51,6 @@ expression: (function foo() {}) result : { internalProperties : [ [0] : { - name : [[StableObjectId]] - value : - } - [1] : { name : [[FunctionLocation]] value : { description : Object @@ -67,6 +63,10 @@ expression: (function foo() {}) } } } + [1] : { + name : [[StableObjectId]] + value : + } [2] : { name : [[Scopes]] value : { @@ -242,35 +242,6 @@ expression: gen1 result : { internalProperties : [ [0] : { - name : [[GeneratorStatus]] - value : { - type : string - value : suspended - } - } - [1] : { - name : [[GeneratorFunction]] - value : { - className : GeneratorFunction - description : function* foo() { yield 1; } - objectId : - type : function - } - } - [2] : { - name : [[GeneratorReceiver]] - value : { - className : global - description : global - objectId : - type : object - } - } - [3] : { - name : [[StableObjectId]] - value : - } - [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -283,6 +254,35 @@ expression: gen1 } } } + [1] : { + name : [[GeneratorStatus]] + value : { + type : string + value : suspended + } + } + [2] : { + name : [[GeneratorFunction]] + value : { + className : GeneratorFunction + description : function* foo() { yield 1; } + objectId : + type : function + } + } + [3] : { + name : [[GeneratorReceiver]] + value : { + className : global + description : global + objectId : + type : object + } + } + [4] : { + name : [[StableObjectId]] + value : + } [5] : { name : [[Scopes]] value : { @@ -302,35 +302,6 @@ expression: gen1.next();gen1 result : { internalProperties : [ [0] : { - name : [[GeneratorStatus]] - value : { - type : string - value : suspended - } - } - [1] : { - name : [[GeneratorFunction]] - value : { - className : GeneratorFunction - description : function* foo() { yield 1; } - objectId : - type : function - } - } - [2] : { - name : [[GeneratorReceiver]] - value : { - className : global - description : global - objectId : - type : object - } - } - [3] : { - name : [[StableObjectId]] - value : - } - [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -343,6 +314,35 @@ expression: gen1.next();gen1 } } } + [1] : { + name : [[GeneratorStatus]] + value : { + type : string + value : suspended + } + } + [2] : { + name : [[GeneratorFunction]] + value : { + className : GeneratorFunction + description : function* foo() { yield 1; } + objectId : + type : function + } + } + [3] : { + name : [[GeneratorReceiver]] + value : { + className : global + description : global + objectId : + type : object + } + } + [4] : { + name : [[StableObjectId]] + value : + } [5] : { name : [[Scopes]] value : { @@ -362,35 +362,6 @@ expression: gen1.next();gen1 result : { internalProperties : [ [0] : { - name : [[GeneratorStatus]] - value : { - type : string - value : closed - } - } - [1] : { - name : [[GeneratorFunction]] - value : { - className : GeneratorFunction - description : function* foo() { yield 1; } - objectId : - type : function - } - } - [2] : { - name : [[GeneratorReceiver]] - value : { - className : global - description : global - objectId : - type : object - } - } - [3] : { - name : [[StableObjectId]] - value : - } - [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -403,6 +374,35 @@ expression: gen1.next();gen1 } } } + [1] : { + name : [[GeneratorStatus]] + value : { + type : string + value : closed + } + } + [2] : { + name : [[GeneratorFunction]] + value : { + className : GeneratorFunction + description : function* foo() { yield 1; } + objectId : + type : function + } + } + [3] : { + name : [[GeneratorReceiver]] + value : { + className : global + description : global + objectId : + type : object + } + } + [4] : { + name : [[StableObjectId]] + value : + } ] } } @@ -414,35 +414,6 @@ expression: gen2 result : { internalProperties : [ [0] : { - name : [[GeneratorStatus]] - value : { - type : string - value : suspended - } - } - [1] : { - name : [[GeneratorFunction]] - value : { - className : GeneratorFunction - description : function* foo() { yield 1; } - objectId : - type : function - } - } - [2] : { - name : [[GeneratorReceiver]] - value : { - className : global - description : global - objectId : - type : object - } - } - [3] : { - name : [[StableObjectId]] - value : - } - [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -455,6 +426,35 @@ expression: gen2 } } } + [1] : { + name : [[GeneratorStatus]] + value : { + type : string + value : suspended + } + } + [2] : { + name : [[GeneratorFunction]] + value : { + className : GeneratorFunction + description : function* foo() { yield 1; } + objectId : + type : function + } + } + [3] : { + name : [[GeneratorReceiver]] + value : { + className : global + description : global + objectId : + type : object + } + } + [4] : { + name : [[StableObjectId]] + value : + } [5] : { name : [[Scopes]] value : { @@ -474,35 +474,6 @@ expression: gen2.next();gen2 result : { internalProperties : [ [0] : { - name : [[GeneratorStatus]] - value : { - type : string - value : suspended - } - } - [1] : { - name : [[GeneratorFunction]] - value : { - className : GeneratorFunction - description : function* foo() { yield 1; } - objectId : - type : function - } - } - [2] : { - name : [[GeneratorReceiver]] - value : { - className : global - description : global - objectId : - type : object - } - } - [3] : { - name : [[StableObjectId]] - value : - } - [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -515,6 +486,35 @@ expression: gen2.next();gen2 } } } + [1] : { + name : [[GeneratorStatus]] + value : { + type : string + value : suspended + } + } + [2] : { + name : [[GeneratorFunction]] + value : { + className : GeneratorFunction + description : function* foo() { yield 1; } + objectId : + type : function + } + } + [3] : { + name : [[GeneratorReceiver]] + value : { + className : global + description : global + objectId : + type : object + } + } + [4] : { + name : [[StableObjectId]] + value : + } [5] : { name : [[Scopes]] value : { @@ -534,35 +534,6 @@ expression: gen2.next();gen2 result : { internalProperties : [ [0] : { - name : [[GeneratorStatus]] - value : { - type : string - value : closed - } - } - [1] : { - name : [[GeneratorFunction]] - value : { - className : GeneratorFunction - description : function* foo() { yield 1; } - objectId : - type : function - } - } - [2] : { - name : [[GeneratorReceiver]] - value : { - className : global - description : global - objectId : - type : object - } - } - [3] : { - name : [[StableObjectId]] - value : - } - [4] : { name : [[GeneratorLocation]] value : { description : Object @@ -575,6 +546,35 @@ expression: gen2.next();gen2 } } } + [1] : { + name : [[GeneratorStatus]] + value : { + type : string + value : closed + } + } + [2] : { + name : [[GeneratorFunction]] + value : { + className : GeneratorFunction + description : function* foo() { yield 1; } + objectId : + type : function + } + } + [3] : { + name : [[GeneratorReceiver]] + value : { + className : global + description : global + objectId : + type : object + } + } + [4] : { + name : [[StableObjectId]] + value : + } ] } } diff --git a/test/inspector/runtime/remote-object-expected.txt b/test/inspector/runtime/remote-object-expected.txt index 3c2d796a4a..6f5f4e7761 100644 --- a/test/inspector/runtime/remote-object-expected.txt +++ b/test/inspector/runtime/remote-object-expected.txt @@ -589,8 +589,6 @@ Running test: testMap objectId : preview : { description : Map(0) - entries : [ - ] overflow : false properties : [ ] @@ -818,8 +816,6 @@ Running test: testMap objectId : preview : { description : MapIterator - entries : [ - ] overflow : false properties : [ ] @@ -897,8 +893,6 @@ Running test: testMap objectId : preview : { description : MapIterator - entries : [ - ] overflow : false properties : [ ] @@ -1116,8 +1110,6 @@ Running test: testWeakMap objectId : preview : { description : WeakMap - entries : [ - ] overflow : false properties : [ ] @@ -1202,8 +1194,6 @@ Running test: testWeakSet objectId : preview : { description : WeakSet - entries : [ - ] overflow : false properties : [ ] diff --git a/test/inspector/runtime/runtime-get-properties-and-accessor-expected.txt b/test/inspector/runtime/runtime-get-properties-and-accessor-expected.txt index 648187c2b4..8789f64ba6 100644 --- a/test/inspector/runtime/runtime-get-properties-and-accessor-expected.txt +++ b/test/inspector/runtime/runtime-get-properties-and-accessor-expected.txt @@ -1,11 +1,11 @@ Runtime.getProperties for objects with accessor title property with getter and setter: { - configurable : false - enumerable : false + configurable : true + enumerable : true get : { className : Function - description : function nativeGetter() { [native code] } + description : function () { [native code] } objectId : type : function } @@ -13,18 +13,18 @@ title property with getter and setter: name : title set : { className : Function - description : function nativeSetter() { [native code] } + description : function () { [native code] } objectId : type : function } } title property with getter only: { - configurable : false - enumerable : false + configurable : true + enumerable : true get : { className : Function - description : function nativeGetter() { [native code] } + description : function () { [native code] } objectId : type : function } diff --git a/test/inspector/runtime/terminate-execution-expected.txt b/test/inspector/runtime/terminate-execution-expected.txt index b64854cf80..24df70ebb6 100644 --- a/test/inspector/runtime/terminate-execution-expected.txt +++ b/test/inspector/runtime/terminate-execution-expected.txt @@ -8,7 +8,7 @@ Terminate first evaluation (it forces injected-script-source compilation) { error : { code : -32000 - message : Cannot access specified execution context + message : Execution was terminated } id : } diff --git a/test/inspector/testcfg.py b/test/inspector/testcfg.py index 50b7795dfc..9660147624 100644 --- a/test/inspector/testcfg.py +++ b/test/inspector/testcfg.py @@ -60,7 +60,6 @@ class TestCase(testcase.TestCase): def _get_resources(self): return [ - os.path.join('src', 'inspector', 'injected-script-source.js'), os.path.join( 'test', 'inspector', 'debugger', 'resources', 'break-locations.js'), ] diff --git a/tools/v8_presubmit.py b/tools/v8_presubmit.py index f35bd9a2ee..80d651bdf0 100755 --- a/tools/v8_presubmit.py +++ b/tools/v8_presubmit.py @@ -412,21 +412,15 @@ class SourceProcessor(SourceFileProcessor): IGNORE_COPYRIGHTS = ['box2d.js', 'cpplint.py', - 'check_injected_script_source.py', 'copy.js', 'corrections.js', 'crypto.js', 'daemon.py', - 'debugger-script.js', 'earley-boyer.js', 'fannkuch.js', 'fasta.js', - 'generate_protocol_externs.py', 'injected-script.cc', 'injected-script.h', - 'injected-script-source.js', - 'java-script-call-frame.cc', - 'java-script-call-frame.h', 'jsmin.py', 'libraries.cc', 'libraries-empty.cc', @@ -438,14 +432,11 @@ class SourceProcessor(SourceFileProcessor): 'raytrace.js', 'regexp-pcre.js', 'resources-123.js', - 'rjsmin.py', 'sqlite.js', 'sqlite-change-heap.js', 'sqlite-pointer-masking.js', 'sqlite-safe-heap.js', 'v8-debugger-script.h', - 'v8-function-call.cc', - 'v8-function-call.h', 'v8-inspector-impl.cc', 'v8-inspector-impl.h', 'v8-runtime-agent-impl.cc',