Commit 6e17719e authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] introduced v8::debug::EntriesPreview for inspector

- entries preview available even if debugger agent is disabled,
- less deprecated mirrors usage in debugger-script.js
- no usage of debugger context - zero probability of leaking it.
- better test coverage.

BUG=v8:5510
R=yangguo@chromium.org,jgruber@chromium.org,alph@chromium.org,luoe@chromium.org

Review-Url: https://codereview.chromium.org/2672213002
Cr-Commit-Position: refs/heads/master@{#42978}
parent a5298c6f
......@@ -7140,15 +7140,14 @@ Maybe<bool> Map::Delete(Local<Context> context, Local<Value> key) {
return Just(result->IsTrue(isolate));
}
Local<Array> Map::AsArray() const {
i::Handle<i::JSMap> obj = Utils::OpenHandle(this);
i::Isolate* isolate = obj->GetIsolate();
namespace {
i::Handle<i::JSArray> MapAsArray(i::Isolate* isolate, i::Object* table_obj,
int offset, int kind) {
i::Factory* factory = isolate->factory();
LOG_API(isolate, Map, AsArray);
ENTER_V8(isolate);
i::Handle<i::OrderedHashMap> table(i::OrderedHashMap::cast(obj->table()));
int length = table->NumberOfElements() * 2;
i::Handle<i::OrderedHashMap> table(i::OrderedHashMap::cast(table_obj));
if (offset >= table->NumberOfElements()) return factory->NewJSArray(0);
int length = (table->NumberOfElements() - offset) *
(kind == i::JSMapIterator::kKindEntries ? 2 : 1);
i::Handle<i::FixedArray> result = factory->NewFixedArray(length);
int result_index = 0;
{
......@@ -7158,15 +7157,30 @@ Local<Array> Map::AsArray() const {
for (int i = 0; i < capacity; ++i) {
i::Object* key = table->KeyAt(i);
if (key == the_hole) continue;
result->set(result_index++, key);
result->set(result_index++, table->ValueAt(i));
if (offset-- > 0) continue;
if (kind == i::JSMapIterator::kKindEntries ||
kind == i::JSMapIterator::kKindKeys) {
result->set(result_index++, key);
}
if (kind == i::JSMapIterator::kKindEntries ||
kind == i::JSMapIterator::kKindValues) {
result->set(result_index++, table->ValueAt(i));
}
}
}
DCHECK_EQ(result_index, result->length());
DCHECK_EQ(result_index, length);
i::Handle<i::JSArray> result_array =
factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length);
return Utils::ToLocal(result_array);
return factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length);
}
} // namespace
Local<Array> Map::AsArray() const {
i::Handle<i::JSMap> obj = Utils::OpenHandle(this);
i::Isolate* isolate = obj->GetIsolate();
LOG_API(isolate, Map, AsArray);
ENTER_V8(isolate);
return Utils::ToLocal(
MapAsArray(isolate, obj->table(), 0, i::JSMapIterator::kKindEntries));
}
......@@ -7232,15 +7246,13 @@ Maybe<bool> Set::Delete(Local<Context> context, Local<Value> key) {
return Just(result->IsTrue(isolate));
}
Local<Array> Set::AsArray() const {
i::Handle<i::JSSet> obj = Utils::OpenHandle(this);
i::Isolate* isolate = obj->GetIsolate();
namespace {
i::Handle<i::JSArray> SetAsArray(i::Isolate* isolate, i::Object* table_obj,
int offset) {
i::Factory* factory = isolate->factory();
LOG_API(isolate, Set, AsArray);
ENTER_V8(isolate);
i::Handle<i::OrderedHashSet> table(i::OrderedHashSet::cast(obj->table()));
int length = table->NumberOfElements();
i::Handle<i::OrderedHashSet> table(i::OrderedHashSet::cast(table_obj));
int length = table->NumberOfElements() - offset;
if (length <= 0) return factory->NewJSArray(0);
i::Handle<i::FixedArray> result = factory->NewFixedArray(length);
int result_index = 0;
{
......@@ -7250,14 +7262,22 @@ Local<Array> Set::AsArray() const {
for (int i = 0; i < capacity; ++i) {
i::Object* key = table->KeyAt(i);
if (key == the_hole) continue;
if (offset-- > 0) continue;
result->set(result_index++, key);
}
}
DCHECK_EQ(result_index, result->length());
DCHECK_EQ(result_index, length);
i::Handle<i::JSArray> result_array =
factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length);
return Utils::ToLocal(result_array);
return factory->NewJSArrayWithElements(result, i::FAST_ELEMENTS, length);
}
} // namespace
Local<Array> Set::AsArray() const {
i::Handle<i::JSSet> obj = Utils::OpenHandle(this);
i::Isolate* isolate = obj->GetIsolate();
LOG_API(isolate, Set, AsArray);
ENTER_V8(isolate);
return Utils::ToLocal(SetAsArray(isolate, obj->table(), 0));
}
......@@ -9354,6 +9374,46 @@ int debug::EstimatedValueSize(Isolate* v8_isolate, v8::Local<v8::Value> value) {
return i::Handle<i::HeapObject>::cast(object)->Size();
}
v8::MaybeLocal<v8::Array> debug::EntriesPreview(Isolate* v8_isolate,
v8::Local<v8::Value> value,
bool* is_key_value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8(isolate);
if (value->IsMap()) {
*is_key_value = true;
return value.As<Map>()->AsArray();
}
if (value->IsSet()) {
*is_key_value = false;
return value.As<Set>()->AsArray();
}
i::Handle<i::Object> object = Utils::OpenHandle(*value);
if (object->IsJSWeakCollection()) {
*is_key_value = object->IsJSWeakMap();
return Utils::ToLocal(i::JSWeakCollection::GetEntries(
i::Handle<i::JSWeakCollection>::cast(object), 0));
}
if (object->IsJSMapIterator()) {
i::Handle<i::JSMapIterator> iterator =
i::Handle<i::JSMapIterator>::cast(object);
int iterator_kind = i::Smi::cast(iterator->kind())->value();
*is_key_value = iterator_kind == i::JSMapIterator::kKindEntries;
if (!iterator->HasMore()) return v8::Array::New(v8_isolate);
return Utils::ToLocal(MapAsArray(isolate, iterator->table(),
i::Smi::cast(iterator->index())->value(),
iterator_kind));
}
if (object->IsJSSetIterator()) {
i::Handle<i::JSSetIterator> it = i::Handle<i::JSSetIterator>::cast(object);
*is_key_value = false;
if (!it->HasMore()) return v8::Array::New(v8_isolate);
return Utils::ToLocal(
SetAsArray(isolate, it->table(), i::Smi::cast(it->index())->value()));
}
return v8::MaybeLocal<v8::Array>();
}
Local<String> CpuProfileNode::GetFunctionName() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
i::Isolate* isolate = node->isolate();
......
......@@ -178,6 +178,10 @@ void ResetBlackboxedStateCache(Isolate* isolate,
int EstimatedValueSize(Isolate* isolate, v8::Local<v8::Value> value);
v8::MaybeLocal<v8::Array> EntriesPreview(Isolate* isolate,
v8::Local<v8::Value> value,
bool* is_key_value);
} // namespace debug
} // namespace v8
......
......@@ -126,24 +126,6 @@ DebuggerScript.getGeneratorObjectLocation = function(object)
return null;
}
/**
* @param {Object} object
* @return {!Array<!{value: *}>|undefined}
*/
DebuggerScript.getCollectionEntries = function(object)
{
var mirror = MakeMirror(object);
if (mirror.isMap())
return /** @type {!MapMirror} */(mirror).entries();
if (mirror.isSet() || mirror.isIterator()) {
var result = [];
var values = mirror.isSet() ? /** @type {!SetMirror} */(mirror).values() : /** @type {!IteratorMirror} */(mirror).preview();
for (var i = 0; i < values.length; ++i)
result.push({ value: values[i] });
return result;
}
}
/**
* @param {!ExecutionState} execState
* @param {!BreakpointInfo} info
......
......@@ -251,16 +251,6 @@ Mirror.prototype.isFunction = function() {}
/** @return {boolean} */
Mirror.prototype.isGenerator = function() {}
/** @return {boolean} */
Mirror.prototype.isMap = function() {}
/** @return {boolean} */
Mirror.prototype.isSet = function() {}
/** @return {boolean} */
Mirror.prototype.isIterator = function() {}
/**
* @interface
* @extends {Mirror}
......@@ -310,46 +300,6 @@ FunctionMirror.prototype.context = function() {}
*/
function UnresolvedFunctionMirror(value) {}
/**
* @interface
* @extends {ObjectMirror}
*/
function MapMirror () {}
/**
* @param {number=} limit
* @return {!Array<!{key: *, value: *}>}
*/
MapMirror.prototype.entries = function(limit) {}
/**
* @interface
* @extends {ObjectMirror}
*/
function SetMirror () {}
/**
* @param {number=} limit
* @return {!Array<*>}
*/
SetMirror.prototype.values = function(limit) {}
/**
* @interface
* @extends {ObjectMirror}
*/
function IteratorMirror () {}
/**
* @param {number=} limit
* @return {!Array<*>}
*/
IteratorMirror.prototype.preview = function(limit) {}
/**
* @interface
* @extends {ObjectMirror}
......
......@@ -42,6 +42,44 @@ V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector,
return inspector->enabledDebuggerAgentForGroup(contextGroupId);
}
v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context,
v8::Local<v8::Value> value) {
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Array> entries;
bool isKeyValue = false;
if (!v8::debug::EntriesPreview(isolate, value, &isKeyValue).ToLocal(&entries))
return v8::MaybeLocal<v8::Array>();
v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate);
CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0);
if (!wrappedEntries->SetPrototype(context, v8::Null(isolate))
.FromMaybe(false))
return v8::MaybeLocal<v8::Array>();
for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
v8::Local<v8::Value> item;
if (!entries->Get(context, i).ToLocal(&item)) continue;
v8::Local<v8::Value> value;
if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue;
v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
if (!wrapper->SetPrototype(context, v8::Null(isolate)).FromMaybe(false))
continue;
createDataProperty(
context, wrapper,
toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item);
if (isKeyValue) {
createDataProperty(context, wrapper,
toV8StringInternalized(isolate, "value"), value);
}
createDataProperty(context, wrappedEntries, wrappedEntries->Length(),
wrapper);
}
if (!markArrayEntriesAsInternal(context, wrappedEntries,
V8InternalValueType::kEntry)) {
return v8::MaybeLocal<v8::Array>();
}
return wrappedEntries;
}
} // namespace
static bool inLiveEditScope = false;
......@@ -266,15 +304,8 @@ bool V8Debugger::canBreakProgram() {
}
void V8Debugger::breakProgram() {
if (isPaused()) {
DCHECK(!m_runningNestedMessageLoop);
v8::Local<v8::Value> exception;
v8::Local<v8::Array> hitBreakpoints;
handleProgramBreak(m_pausedContext, m_executionState, exception,
hitBreakpoints);
return;
}
// Don't allow nested breaks.
if (isPaused()) return;
if (!canBreakProgram()) return;
v8::HandleScope scope(m_isolate);
......@@ -413,27 +444,14 @@ Response V8Debugger::setScriptSource(
}
JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) {
if (!m_isolate->InContext()) return JavaScriptCallFrames();
if (!isPaused()) return JavaScriptCallFrames();
v8::Local<v8::Value> currentCallFramesV8;
if (m_executionState.IsEmpty()) {
v8::Local<v8::Function> currentCallFramesFunction =
v8::Local<v8::Function>::Cast(
m_debuggerScript.Get(m_isolate)
->Get(debuggerContext(),
toV8StringInternalized(m_isolate, "currentCallFrames"))
.ToLocalChecked());
if (!v8::debug::Call(debuggerContext(), currentCallFramesFunction,
v8::Integer::New(m_isolate, limit))
.ToLocal(&currentCallFramesV8))
return JavaScriptCallFrames();
} else {
v8::Local<v8::Value> argv[] = {m_executionState,
v8::Integer::New(m_isolate, limit)};
if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true)
.ToLocal(&currentCallFramesV8))
return JavaScriptCallFrames();
v8::Local<v8::Value> argv[] = {m_executionState,
v8::Integer::New(m_isolate, limit)};
if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true)
.ToLocal(&currentCallFramesV8)) {
return JavaScriptCallFrames();
}
DCHECK(!currentCallFramesV8.IsEmpty());
if (!currentCallFramesV8->IsArray()) return JavaScriptCallFrames();
v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>();
JavaScriptCallFrames callFrames;
......@@ -703,17 +721,13 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
v8::True(m_isolate));
}
}
if (!enabled()) return properties;
if (value->IsMap() || value->IsWeakMap() || value->IsSet() ||
value->IsWeakSet() || value->IsSetIterator() || value->IsMapIterator()) {
v8::Local<v8::Value> entries =
collectionEntries(context, v8::Local<v8::Object>::Cast(value));
if (entries->IsArray()) {
createDataProperty(context, properties, properties->Length(),
toV8StringInternalized(m_isolate, "[[Entries]]"));
createDataProperty(context, properties, properties->Length(), entries);
}
v8::Local<v8::Array> entries;
if (collectionsEntries(context, value).ToLocal(&entries)) {
createDataProperty(context, properties, properties->Length(),
toV8StringInternalized(m_isolate, "[[Entries]]"));
createDataProperty(context, properties, properties->Length(), entries);
}
if (!enabled()) return properties;
if (value->IsGeneratorObject()) {
v8::Local<v8::Value> location =
generatorObjectLocation(context, v8::Local<v8::Object>::Cast(value));
......@@ -744,43 +758,6 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
return properties;
}
v8::Local<v8::Value> V8Debugger::collectionEntries(
v8::Local<v8::Context> context, v8::Local<v8::Object> object) {
if (!enabled()) {
UNREACHABLE();
return v8::Undefined(m_isolate);
}
v8::Local<v8::Value> argv[] = {object};
v8::Local<v8::Value> entriesValue;
if (!callDebuggerMethod("getCollectionEntries", 1, argv, true)
.ToLocal(&entriesValue) ||
!entriesValue->IsArray())
return v8::Undefined(m_isolate);
v8::Local<v8::Array> entries = entriesValue.As<v8::Array>();
v8::Local<v8::Array> copiedArray =
v8::Array::New(m_isolate, entries->Length());
if (!copiedArray->SetPrototype(context, v8::Null(m_isolate)).FromMaybe(false))
return v8::Undefined(m_isolate);
for (uint32_t i = 0; i < entries->Length(); ++i) {
v8::Local<v8::Value> item;
if (!entries->Get(debuggerContext(), i).ToLocal(&item))
return v8::Undefined(m_isolate);
v8::Local<v8::Value> copied;
if (!copyValueFromDebuggerContext(m_isolate, debuggerContext(), context,
item)
.ToLocal(&copied))
return v8::Undefined(m_isolate);
if (!createDataProperty(context, copiedArray, i, copied).FromMaybe(false))
return v8::Undefined(m_isolate);
}
if (!markArrayEntriesAsInternal(context,
v8::Local<v8::Array>::Cast(copiedArray),
V8InternalValueType::kEntry))
return v8::Undefined(m_isolate);
return copiedArray;
}
v8::Local<v8::Value> V8Debugger::generatorObjectLocation(
v8::Local<v8::Context> context, v8::Local<v8::Object> object) {
if (!enabled()) {
......
......@@ -113,8 +113,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
bool isPromiseRejection = false,
bool isUncaught = false);
v8::Local<v8::Value> collectionEntries(v8::Local<v8::Context>,
v8::Local<v8::Object>);
v8::Local<v8::Value> generatorObjectLocation(v8::Local<v8::Context>,
v8::Local<v8::Object>);
v8::Local<v8::Value> functionLocation(v8::Local<v8::Context>,
......
......@@ -18770,6 +18770,40 @@ bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
return was_present;
}
Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
int max_entries) {
Isolate* isolate = holder->GetIsolate();
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
if (max_entries == 0 || max_entries > table->NumberOfElements()) {
max_entries = table->NumberOfElements();
}
int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
Handle<FixedArray> entries =
isolate->factory()->NewFixedArray(max_entries * values_per_entry);
// Recompute max_values because GC could have removed elements from the table.
if (max_entries > table->NumberOfElements()) {
max_entries = table->NumberOfElements();
}
{
DisallowHeapAllocation no_gc;
int count = 0;
for (int i = 0;
count / values_per_entry < max_entries && i < table->Capacity(); i++) {
Handle<Object> key(table->KeyAt(i), isolate);
if (table->IsKey(isolate, *key)) {
entries->set(count++, *key);
if (values_per_entry > 1) {
Object* value = table->Lookup(key);
entries->set(count++, value);
}
}
}
DCHECK_EQ(max_entries * values_per_entry, count);
}
return isolate->factory()->NewJSArrayWithElements(entries);
}
// Check if there is a break point at this source position.
bool DebugInfo::HasBreakPoint(int source_position) {
// Get the break point info object for this code offset.
......
......@@ -10675,6 +10675,8 @@ class JSWeakCollection: public JSObject {
Handle<Object> value, int32_t hash);
static bool Delete(Handle<JSWeakCollection> collection, Handle<Object> key,
int32_t hash);
static Handle<JSArray> GetEntries(Handle<JSWeakCollection> holder,
int max_entries);
static const int kTableOffset = JSObject::kHeaderSize;
static const int kNextOffset = kTableOffset + kPointerSize;
......
......@@ -233,32 +233,7 @@ RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
CONVERT_NUMBER_CHECKED(int, max_entries, Int32, args[1]);
CHECK(max_entries >= 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
if (max_entries == 0 || max_entries > table->NumberOfElements()) {
max_entries = table->NumberOfElements();
}
Handle<FixedArray> entries =
isolate->factory()->NewFixedArray(max_entries * 2);
// Allocation can cause GC can delete weak elements. Reload.
if (max_entries > table->NumberOfElements()) {
max_entries = table->NumberOfElements();
}
{
DisallowHeapAllocation no_gc;
int count = 0;
for (int i = 0; count / 2 < max_entries && i < table->Capacity(); i++) {
Handle<Object> key(table->KeyAt(i), isolate);
if (table->IsKey(isolate, *key)) {
entries->set(count++, *key);
Object* value = table->Lookup(key);
entries->set(count++, value);
}
}
DCHECK_EQ(max_entries * 2, count);
}
return *isolate->factory()->NewJSArrayWithElements(entries);
return *JSWeakCollection::GetEntries(holder, max_entries);
}
......@@ -348,26 +323,7 @@ RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
CONVERT_NUMBER_CHECKED(int, max_values, Int32, args[1]);
CHECK(max_values >= 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
if (max_values == 0 || max_values > table->NumberOfElements()) {
max_values = table->NumberOfElements();
}
Handle<FixedArray> values = isolate->factory()->NewFixedArray(max_values);
// Recompute max_values because GC could have removed elements from the table.
if (max_values > table->NumberOfElements()) {
max_values = table->NumberOfElements();
}
{
DisallowHeapAllocation no_gc;
int count = 0;
for (int i = 0; count < max_values && i < table->Capacity(); i++) {
Object* key = table->KeyAt(i);
if (table->IsKey(isolate, key)) values->set(count++, key);
}
DCHECK_EQ(max_values, count);
}
return *isolate->factory()->NewJSArrayWithElements(values);
return *JSWeakCollection::GetEntries(holder, max_values);
}
} // namespace internal
} // namespace v8
......@@ -163,23 +163,19 @@ expression: (new Map([[1,2]])).entries()
[[Entries]]:
[
[0] : {
key : {
description : 1
overflow : false
properties : [
]
type : number
}
value : {
description : Array(2)
description : 2
overflow : false
properties : [
[0] : {
name : 0
type : number
value : 1
}
[1] : {
name : 1
type : number
value : 2
}
]
subtype : array
type : object
type : number
}
}
]
......@@ -209,15 +205,13 @@ expression: (new Set([[1,2]])).entries()
properties : [
[0] : {
name : 0
subtype : array
type : object
value : Array(2)
type : number
value : 1
}
[1] : {
name : 1
subtype : array
type : object
value : Array(2)
type : number
value : 2
}
]
subtype : array
......
// 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.
print('Checks internal [[Entries]] in Runtime.getProperties output');
Protocol.Runtime.enable();
InspectorTest.runTestSuite([
function maps(next) {
checkExpression('new Map([[1,2],[3,4]])')
.then(() => checkExpression('new Map()'))
.then(next);
},
function mapIterators(next) {
checkExpression('new Map([[1,2],[3,4]]).entries()')
.then(() => checkExpression('it = new Map([[1,2],[3,4]]).entries(); it.next(); it'))
.then(() => checkExpression('it = new Map([[1,2],[3,4]]).keys(); it.next(); it'))
.then(() => checkExpression('it = new Map([[1,2],[3,4]]).values(); it.next(); it'))
.then(() => checkExpression('it = new Map([[1,2],[3,4]]).entries(); it.next(); it.next(); it'))
.then(next);
},
function sets(next) {
checkExpression('new Set([1,2])')
.then(() => checkExpression('new Set()'))
.then(next);
},
function setIterators(next) {
checkExpression('new Set([1,2]).values()')
.then(() => checkExpression('it = new Set([1,2]).values(); it.next(); it'))
.then(() => checkExpression('it = new Set([1,2]).keys(); it.next(); it'))
.then(() => checkExpression('it = new Set([1,2]).entries(); it.next(); it'))
.then(() => checkExpression('it = new Set([1,2]).values(); it.next(); it.next(); it'))
.then(next);
},
function weakMaps(next) {
checkExpression('new WeakMap()')
.then(() => checkExpression('new WeakMap([[{ a: 2 }, 42]])'))
.then(next);
},
function weakSets(next) {
checkExpression('new WeakSet()')
.then(() => checkExpression('new WeakSet([{a:2}])'))
.then(next);
}
]);
function checkExpression(expression)
{
InspectorTest.log(`expression: ${expression}`);
var entriesObjectId;
return Protocol.Runtime.evaluate({ expression: expression })
.then(message => Protocol.Runtime.getProperties({ objectId: message.result.result.objectId }))
.then(message => message.result.internalProperties.filter(p => p.name === '[[Entries]]')[0])
.then(entries => entriesObjectId = entries.value.objectId)
.then(() => Protocol.Runtime.callFunctionOn({ objectId: entriesObjectId, functionDeclaration: 'function f() { return this; }', returnByValue: true }))
.then(message => InspectorTest.logMessage(message.result.result.value))
.then(() => Protocol.Runtime.getProperties({ objectId: entriesObjectId, ownProperties: true }))
.then(message => InspectorTest.logMessage(message));
}
Checks internal properties in Runtime.getProperties output
Running test: generatorFunction
expression: (function* foo() { yield 1 })
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[FunctionLocation]]
value : {
description : Object
subtype : internal#location
type : object
value : {
columnNumber : 14
lineNumber : 0
scriptId : <scriptId>
}
}
}
[1] : {
name : [[IsGenerator]]
value : {
type : boolean
value : true
}
}
[2] : {
name : [[Scopes]]
value : {
className : Array
description : Scopes[1]
objectId : <objectId>
subtype : internal#scopeList
type : object
}
}
]
}
}
Running test: regularFunction
expression: (function foo() {})
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[FunctionLocation]]
value : {
description : Object
subtype : internal#location
type : object
value : {
columnNumber : 13
lineNumber : 0
scriptId : <scriptId>
}
}
}
[1] : {
name : [[Scopes]]
value : {
className : Array
description : Scopes[1]
objectId : <objectId>
subtype : internal#scopeList
type : object
}
}
]
}
}
Running test: boxedObjects
expression: new Number(239)
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[PrimitiveValue]]
value : {
description : 239
type : number
value : 239
}
}
]
}
}
expression: new Boolean(false)
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[PrimitiveValue]]
value : {
type : boolean
value : false
}
}
]
}
}
expression: new String('abc')
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[PrimitiveValue]]
value : {
type : string
value : abc
}
}
]
}
}
expression: Object(Symbol(42))
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[PrimitiveValue]]
value : {
description : Symbol(42)
objectId : <objectId>
type : symbol
}
}
]
}
}
Running test: promise
expression: Promise.resolve(42)
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[PromiseStatus]]
value : {
type : string
value : resolved
}
}
[1] : {
name : [[PromiseValue]]
value : {
description : 42
type : number
value : 42
}
}
]
}
}
expression: new Promise(() => undefined)
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[PromiseStatus]]
value : {
type : string
value : pending
}
}
[1] : {
name : [[PromiseValue]]
value : {
type : undefined
}
}
]
}
}
Running test: generatorObject
expression: (function* foo() { yield 1 })()
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[GeneratorStatus]]
value : {
type : string
value : suspended
}
}
[1] : {
name : [[GeneratorFunction]]
value : {
className : GeneratorFunction
description : function* foo() { yield 1 }
objectId : <objectId>
type : function
}
}
[2] : {
name : [[GeneratorReceiver]]
value : {
className : global
description : global
objectId : <objectId>
type : object
}
}
[3] : {
name : [[GeneratorLocation]]
value : {
description : Object
subtype : internal#location
type : object
value : {
columnNumber : 14
lineNumber : 0
scriptId : <scriptId>
}
}
}
[4] : {
name : [[Scopes]]
value : {
className : Array
description : Scopes[2]
objectId : <objectId>
subtype : internal#scopeList
type : object
}
}
]
}
}
Running test: iteratorObject
expression: (new Map([[1,2]])).entries()
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[IteratorHasMore]]
value : {
type : boolean
value : true
}
}
[1] : {
name : [[IteratorIndex]]
value : {
description : 0
type : number
value : 0
}
}
[2] : {
name : [[IteratorKind]]
value : {
type : string
value : entries
}
}
[3] : {
name : [[Entries]]
value : {
className : Array
description : Array(1)
objectId : <objectId>
subtype : array
type : object
}
}
]
}
}
expression: (new Set([[1,2]])).entries()
{
id : <messageId>
result : {
internalProperties : [
[0] : {
name : [[IteratorHasMore]]
value : {
type : boolean
value : true
}
}
[1] : {
name : [[IteratorIndex]]
value : {
description : 0
type : number
value : 0
}
}
[2] : {
name : [[IteratorKind]]
value : {
type : string
value : entries
}
}
[3] : {
name : [[Entries]]
value : {
className : Array
description : Array(1)
objectId : <objectId>
subtype : array
type : object
}
}
]
}
}
// 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.
print('Checks internal properties in Runtime.getProperties output');
Protocol.Runtime.enable();
Protocol.Debugger.enable();
InspectorTest.runTestSuite([
function generatorFunction(next) {
checkExpression('(function* foo() { yield 1 })').then(next);
},
function regularFunction(next) {
checkExpression('(function foo() {})').then(next);
},
function boxedObjects(next) {
checkExpression('new Number(239)')
.then(() => checkExpression('new Boolean(false)'))
.then(() => checkExpression('new String(\'abc\')'))
.then(() => checkExpression('Object(Symbol(42))'))
.then(next);
},
function promise(next) {
checkExpression('Promise.resolve(42)')
.then(() => checkExpression('new Promise(() => undefined)'))
.then(next);
},
function generatorObject(next) {
checkExpression('(function* foo() { yield 1 })()')
.then(next);
},
function iteratorObject(next) {
checkExpression('(new Map([[1,2]])).entries()')
.then(() => checkExpression('(new Set([[1,2]])).entries()'))
.then(next);
}
]);
function checkExpression(expression)
{
InspectorTest.log(`expression: ${expression}`);
return Protocol.Runtime.evaluate({ expression: expression })
.then(message => Protocol.Runtime.getProperties({ objectId: message.result.result.objectId }))
.then(message => { delete message.result.result; return message; })
.then(InspectorTest.logMessage);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment