Commit 2943ded4 authored by Erik Luo's avatar Erik Luo Committed by Commit Bot

DevTools: add frontend support for BigInt

Prepares support for BigInts in
- JSAutocomplete
- objectValue, heap snapshot, console styles
- 'copy' command line API value

Screenshot: https://imgur.com/a/KqyBg

Bug: v8:7486
Change-Id: I12bab5a06dc940ebdb096c3b944fb71646f5b62c
Reviewed-on: https://chromium-review.googlesource.com/940774
Commit-Queue: Erik Luo <luoe@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542032}
parent 7c4c36f7
......@@ -1431,6 +1431,10 @@ crbug.com/546215 [ Android ] fast/inline-block/overflow-clip.html [ Failure ]
crbug.com/548765 http/tests/devtools/console-fetch-logging.js [ Failure Pass ]
# When BigInts are on by default, these should pass and be removed along with their FlagExpectations.
crbug.com/v8/7486 http/tests/devtools/startup/console/console-format-startup-bigint.js [ Skip ]
crbug.com/v8/7486 http/tests/devtools/console/console-format-bigint.js [ Skip ]
crbug.com/564109 [ Win ] http/tests/webfont/font-display-intervention.html [ Pass Failure Timeout ]
crbug.com/399951 http/tests/mime/javascript-mimetype-usecounters.html [ Pass Failure ]
......
Tests that console properly displays BigInts.
console-format-bigint.js:15 1n
console-format-bigint.js:16 BigInt {2n}
console-format-bigint.js:17 [1n]
console-format-bigint.js:18 [BigInt]
console-format-bigint.js:19 null 1n BigInt {2n}
Expanded all messages
console-format-bigint.js:15 1n
console-format-bigint.js:16 BigInt {2n}
__proto__: BigInt
[[PrimitiveValue]]: 2n
console-format-bigint.js:17 [1n]
0: 1n
length: 1
__proto__: Array(0)
console-format-bigint.js:18 [BigInt]
0: BigInt {2n}
length: 1
__proto__: Array(0)
console-format-bigint.js:19 null 1n BigInt {2n}
__proto__: BigInt
[[PrimitiveValue]]: 2n
Tests console logging for messages with BigInts that happen before DevTools is open.
console-format-startup-bigint.html:5 1n
console-format-startup-bigint.html:6 BigInt
__proto__: BigInt
[[PrimitiveValue]]: 2n
console-format-startup-bigint.html:7 Array(1)
0: 1n
length: 1
__proto__: Array(0)
console-format-startup-bigint.html:8 Array(1)
0: BigInt {2n}
length: 1
__proto__: Array(0)
console-format-startup-bigint.html:9 null 1n BigInt
__proto__: BigInt
[[PrimitiveValue]]: 2n
Tests that console properly displays BigInts.
console-format-bigint.js:15 1n
console-format-bigint.js:16 BigInt {2n}
console-format-bigint.js:17 [1n]
console-format-bigint.js:18 [BigInt]
console-format-bigint.js:19 null 1n BigInt {2n}
Expanded all messages
console-format-bigint.js:15 1n
console-format-bigint.js:16 BigInt {2n}
__proto__: BigInt
[[PrimitiveValue]]: 2n
console-format-bigint.js:17 [1n]
0: 1n
length: 1
__proto__: Array(0)
console-format-bigint.js:18 [BigInt]
0: BigInt {2n}
length: 1
__proto__: Array(0)
console-format-bigint.js:19 null 1n BigInt {2n}
__proto__: BigInt
[[PrimitiveValue]]: 2n
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(luoe): once BigInts are on by default, merge this test into
// http/tests/devtools/console/console-format.js
(async function() {
TestRunner.addResult('Tests that console properly displays BigInts.\n');
await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('console');
await TestRunner.evaluateInPagePromise(`
var wrappedBigInt = Object(BigInt(2));
console.log(1n);
console.log(wrappedBigInt);
console.log([1n]);
console.log([wrappedBigInt]);
console.log(null, 1n, wrappedBigInt);
`);
ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks);
TestRunner.addResult('Expanded all messages');
ConsoleTestRunner.expandConsoleMessages(dumpConsoleMessages);
function dumpConsoleMessages() {
ConsoleTestRunner.dumpConsoleMessages(false, false, TestRunner.textContentWithLineBreaks);
TestRunner.completeTest();
}
})();
......@@ -12,7 +12,8 @@ code node size: 50000
closure node size: 600000
regexp node size: 7000000
native node size: 80000000
{"total":987654341,"v8heap":907654341,"native":80000000,"code":50000,"jsArrays":20,"strings":300,"system":900000000}
bigint node size: 900000000
{"total":1887654341,"v8heap":1807654341,"native":80000000,"code":50000,"jsArrays":20,"strings":300,"system":900000000}
Profiler was disabled.
Tests console logging for messages with BigInts that happen before DevTools is open.
console-format-startup-bigint.html:5 1n
console-format-startup-bigint.html:6 BigInt
__proto__: BigInt
[[PrimitiveValue]]: 2n
console-format-startup-bigint.html:7 Array(1)
0: 1n
length: 1
__proto__: Array(0)
console-format-startup-bigint.html:8 Array(1)
0: BigInt {2n}
length: 1
__proto__: Array(0)
console-format-startup-bigint.html:9 null 1n BigInt
__proto__: BigInt
[[PrimitiveValue]]: 2n
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(luoe): once BigInts are on by default, merge this test into
// http/tests/devtools/startup/console/console-format-startup.js
(async function() {
await TestRunner.setupStartupTest('resources/console-format-startup-bigint.html');
TestRunner.addResult('Tests console logging for messages with BigInts that happen before DevTools is open.\n');
await TestRunner.loadModule('console_test_runner');
await TestRunner.showPanel('console');
TestRunner.hideInspectorView();
ConsoleTestRunner.expandConsoleMessages(finish);
function finish() {
ConsoleTestRunner.dumpConsoleMessagesIgnoreErrorStackFrames();
TestRunner.completeTest();
}
})();
<script type="text/javascript">
function onload()
{
var wrappedBigInt = Object(BigInt(2));
console.log(1n);
console.log(wrappedBigInt);
console.log([1n]);
console.log([wrappedBigInt]);
console.log(null, 1n, wrappedBigInt);
testRunner.inspectSecondaryWindow();
}
</script>
<body onload="onload()">
</body>
\ No newline at end of file
......@@ -547,6 +547,7 @@ Console.ConsoleViewMessage = class {
case 'regexp':
case 'symbol':
case 'undefined':
case 'bigint':
element = this._formatParameterAsValue(output);
break;
default:
......
......@@ -195,6 +195,15 @@ Array.prototype.mergeOrdered = function(array, comparator) {};
*/
Int32Array.prototype.lowerBound = function(object, comparator, left, right) {};
// TODO(luoe): remove these BigInt types once closure supports them.
/**
* @param {number|string} value
*/
const BigInt = function(value) {};
/** @typedef {*} */
const bigint = null;
// File System API
/**
* @constructor
......
......@@ -117,7 +117,8 @@ HeapProfilerTestRunner.createHeapSnapshotMockFactories = function() {
'regexp': 'regexp',
'number': 'number',
'native': 'native',
'synthetic': 'synthetic'
'synthetic': 'synthetic',
'bigint': 'bigint'
};
HeapProfilerTestRunner.HeapNode.prototype = {
......
......@@ -236,7 +236,9 @@ ObjectUI.JavaScriptAutocomplete = class {
completions =
await object.callFunctionJSONPromise(getCompletions, [SDK.RemoteObject.toCallArgument(object.subtype)]) ||
[];
} else if (object.type === 'string' || object.type === 'number' || object.type === 'boolean') {
} else if (
object.type === 'string' || object.type === 'number' || object.type === 'boolean' ||
object.type === 'bigint') {
const evaluateResult = await executionContext.evaluate(
{
expression: '(' + getCompletions + ')("' + object.type + '")',
......@@ -283,6 +285,9 @@ ObjectUI.JavaScriptAutocomplete = class {
object = new String('');
else if (type === 'number')
object = new Number(0);
// Object-wrapped BigInts cannot be constructed via `new BigInt`.
else if (type === 'bigint')
object = Object(BigInt(0));
else if (type === 'boolean')
object = new Boolean(false);
else
......
......@@ -41,6 +41,10 @@
color: rgb(28, 0, 207);
}
.object-value-bigint {
color: rgb(0, 93, 0);
}
.object-value-string,
.object-value-regexp,
.object-value-symbol {
......
......@@ -536,6 +536,9 @@ Profiler.HeapSnapshotGenericObjectNode = class extends Profiler.HeapSnapshotGrid
value = value + '()';
valueStyle = 'function';
break;
case 'bigint':
valueStyle = 'bigint';
break;
case 'number':
valueStyle = 'number';
break;
......
......@@ -84,7 +84,7 @@ SDK.RemoteObject = class {
}
/**
* @param {!Protocol.Runtime.RemoteObject|!SDK.RemoteObject|number|string|boolean|undefined|null} object
* @param {!Protocol.Runtime.RemoteObject|!SDK.RemoteObject|number|string|boolean|undefined|null|bigint} object
* @return {!Protocol.Runtime.CallArgument}
*/
static toCallArgument(object) {
......@@ -94,24 +94,27 @@ SDK.RemoteObject = class {
if (type === 'number') {
const description = String(object);
if (object === 0 && 1 / object < 0)
return {unserializableValue: Protocol.Runtime.UnserializableValue.Negative0};
if (description === 'NaN')
return {unserializableValue: Protocol.Runtime.UnserializableValue.NaN};
if (description === 'Infinity')
return {unserializableValue: Protocol.Runtime.UnserializableValue.Infinity};
if (description === '-Infinity')
return {unserializableValue: Protocol.Runtime.UnserializableValue.NegativeInfinity};
return {unserializableValue: SDK.RemoteObject.UnserializableNumber.Negative0};
if (description === SDK.RemoteObject.UnserializableNumber.NaN ||
description === SDK.RemoteObject.UnserializableNumber.Infinity ||
description === SDK.RemoteObject.UnserializableNumber.NegativeInfinity)
return {unserializableValue: description};
return {value: object};
}
if (type === 'bigint') {
const value = String(object) + 'n';
return {unserializableValue: /** @type {!Protocol.Runtime.UnserializableValue} */ (value)};
}
if (type === 'string' || type === 'boolean')
return {value: object};
if (!object)
return {value: null};
if (typeof object.unserializableValue !== 'undefined')
const isSDKRemoteObject = object instanceof SDK.RemoteObjectImpl;
if (!isSDKRemoteObject && typeof object.unserializableValue !== 'undefined')
return {unserializableValue: object.unserializableValue};
if (object instanceof SDK.RemoteObjectImpl && typeof object._unserializableValue !== 'undefined')
if (isSDKRemoteObject && typeof object._unserializableValue !== 'undefined')
return {unserializableValue: object._unserializableValue};
if (typeof object.objectId !== 'undefined')
......@@ -212,6 +215,11 @@ SDK.RemoteObject = class {
throw 'Not implemented';
}
/** @return {string|undefined} */
unserializableValue() {
throw 'Not implemented';
}
/** @return {string|undefined} */
get description() {
throw 'Not implemented';
......@@ -443,13 +451,15 @@ SDK.RemoteObjectImpl = class extends SDK.RemoteObject {
if (!this._description && (typeof value !== 'object' || value === null))
this._description = value + '';
this._hasChildren = false;
if (typeof unserializableValue !== 'undefined') {
if (typeof unserializableValue === 'string') {
this._unserializableValue = unserializableValue;
if (unserializableValue === Protocol.Runtime.UnserializableValue.Infinity ||
unserializableValue === Protocol.Runtime.UnserializableValue.NegativeInfinity ||
unserializableValue === Protocol.Runtime.UnserializableValue.Negative0 ||
unserializableValue === Protocol.Runtime.UnserializableValue.NaN)
if (unserializableValue === SDK.RemoteObject.UnserializableNumber.Infinity ||
unserializableValue === SDK.RemoteObject.UnserializableNumber.NegativeInfinity ||
unserializableValue === SDK.RemoteObject.UnserializableNumber.Negative0 ||
unserializableValue === SDK.RemoteObject.UnserializableNumber.NaN)
this._value = Number(unserializableValue);
else if (type === 'bigint' && unserializableValue.endsWith('n'))
this._value = BigInt(unserializableValue.substring(0, unserializableValue.length - 1));
else
this._value = unserializableValue;
......@@ -500,6 +510,14 @@ SDK.RemoteObjectImpl = class extends SDK.RemoteObject {
return this._value;
}
/**
* @override
* @return {string|undefined}
*/
unserializableValue() {
return this._unserializableValue;
}
/**
* @override
* @return {string|undefined}
......@@ -1389,3 +1407,14 @@ SDK.RemoteObject._descriptionLengthParenRegex = /\(([0-9]+)\)/;
* @type {!RegExp}
*/
SDK.RemoteObject._descriptionLengthSquareRegex = /\[([0-9]+)\]/;
/**
* @const
* @enum {!Protocol.Runtime.UnserializableValue}
*/
SDK.RemoteObject.UnserializableNumber = {
Negative0: /** @type {!Protocol.Runtime.UnserializableValue} */ ('-0'),
NaN: /** @type {!Protocol.Runtime.UnserializableValue} */ ('NaN'),
Infinity: /** @type {!Protocol.Runtime.UnserializableValue} */ ('Infinity'),
NegativeInfinity: /** @type {!Protocol.Runtime.UnserializableValue} */ ('-Infinity')
};
......@@ -187,25 +187,26 @@ SDK.RuntimeModel = class extends SDK.SDKModel {
}
/**
* @param {number|string|boolean|undefined} value
* @param {number|string|boolean|undefined|bigint} value
* @return {!SDK.RemoteObject}
*/
createRemoteObjectFromPrimitiveValue(value) {
const type = typeof value;
let unserializableValue = undefined;
if (typeof value === 'number') {
if (type === 'number') {
const description = String(value);
if (value === 0 && 1 / value < 0)
unserializableValue = Protocol.Runtime.UnserializableValue.Negative0;
if (description === 'NaN')
unserializableValue = Protocol.Runtime.UnserializableValue.NaN;
if (description === 'Infinity')
unserializableValue = Protocol.Runtime.UnserializableValue.Infinity;
if (description === '-Infinity')
unserializableValue = Protocol.Runtime.UnserializableValue.NegativeInfinity;
if (typeof unserializableValue !== 'undefined')
value = undefined;
unserializableValue = SDK.RemoteObject.UnserializableNumber.Negative0;
else if (
description === SDK.RemoteObject.UnserializableNumber.NaN ||
description === SDK.RemoteObject.UnserializableNumber.Infinity ||
description === SDK.RemoteObject.UnserializableNumber.NegativeInfinity)
unserializableValue = description;
}
if (type === 'bigint')
unserializableValue = /** @type {!Protocol.Runtime.UnserializableValue} */ (String(value) + 'n');
if (typeof unserializableValue !== 'undefined')
value = undefined;
return new SDK.RemoteObjectImpl(this, undefined, type, undefined, value, unserializableValue);
}
......@@ -357,7 +358,7 @@ SDK.RuntimeModel = class extends SDK.SDKModel {
*/
_copyRequested(object) {
if (!object.objectId) {
InspectorFrontendHost.copyText(object.value);
InspectorFrontendHost.copyText(object.unserializableValue() || object.value);
return;
}
object.callFunctionJSON(
......
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