Reland "Use BigInts in processor.mjs and related code to avoid unsafe ints in calculations"
This is a reland of commit efc1a98c53
Changes since revert:
- Handle "shared-library", "code-{deopt,move,delete}", "feedback-vector", "sfi-move" events
Original change's description:
> Use BigInts in processor.mjs and related code to avoid unsafe ints in
calculations
>
> Bug: v8:13440
> Change-Id: Ie03b831b511a49fb475b9f303ef8662189bdaf3d
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4017455
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Commit-Queue: Camillo Bruni <cbruni@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#84698}
Change-Id: If45d38526cab887a59f60e3becfbcb084c3d41d0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4086641
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Vasili Skurydzin <vasili.skurydzin@ibm.com>
Cr-Commit-Position: refs/heads/main@{#84939}
This commit is contained in:
parent
0b9fa062f0
commit
aee5fb0990
59
test/mjsunit/tools/processor-bigint.mjs
Normal file
59
test/mjsunit/tools/processor-bigint.mjs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2020 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: --logfile='+' --log --log-maps --log-ic --log-code
|
||||||
|
// Flags: --log-function-events --no-predictable
|
||||||
|
|
||||||
|
import { Processor } from "../../../tools/system-analyzer/processor.mjs";
|
||||||
|
|
||||||
|
// log code start
|
||||||
|
function doWork() {
|
||||||
|
let array = [];
|
||||||
|
for (let i = 0; i < 500; i++) {
|
||||||
|
doWorkStep(i, array);
|
||||||
|
}
|
||||||
|
let sum = 0;
|
||||||
|
for (let i = 0; i < 500; i++) {
|
||||||
|
sum += array[i]["property" + i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doWorkStep(i, array) {
|
||||||
|
const obj = {
|
||||||
|
["property" + i]: i,
|
||||||
|
};
|
||||||
|
array.push(obj);
|
||||||
|
obj.custom1 = 1;
|
||||||
|
obj.custom2 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = doWork();
|
||||||
|
// log code end
|
||||||
|
|
||||||
|
const logString = d8.log.getAndStop();
|
||||||
|
assertTrue(logString.length > 0);
|
||||||
|
const useBigInts = true;
|
||||||
|
const processor = new Processor(useBigInts);
|
||||||
|
await processor.processChunk(logString);
|
||||||
|
await processor.finalize();
|
||||||
|
|
||||||
|
const maps = processor.mapTimeline;
|
||||||
|
const ics = processor.icTimeline;
|
||||||
|
const scripts = processor.scripts;
|
||||||
|
|
||||||
|
(function testResults() {
|
||||||
|
assertEquals(result, 124750);
|
||||||
|
assertTrue(maps.length > 0);
|
||||||
|
assertTrue(ics.length > 0);
|
||||||
|
assertTrue(scripts.length > 0);
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testIcKeys() {
|
||||||
|
const keys = new Set();
|
||||||
|
ics.forEach(ic => keys.add(ic.key));
|
||||||
|
assertTrue(keys.has("custom1"));
|
||||||
|
assertTrue(keys.has("custom2"));
|
||||||
|
assertTrue(keys.has("push"));
|
||||||
|
})();
|
@ -65,6 +65,12 @@ export class CodeMap {
|
|||||||
*/
|
*/
|
||||||
pages_ = new Set();
|
pages_ = new Set();
|
||||||
|
|
||||||
|
constructor(useBigInt=false) {
|
||||||
|
this.useBigInt = useBigInt;
|
||||||
|
this.kPageSize = useBigInt ? BigInt(kPageSize) : kPageSize;
|
||||||
|
this.kOne = useBigInt ? 1n : 1;
|
||||||
|
this.kZero = useBigInt ? 0n : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a code entry that might overlap with static code (e.g. for builtins).
|
* Adds a code entry that might overlap with static code (e.g. for builtins).
|
||||||
@ -73,7 +79,7 @@ export class CodeMap {
|
|||||||
* @param {CodeEntry} codeEntry Code entry object.
|
* @param {CodeEntry} codeEntry Code entry object.
|
||||||
*/
|
*/
|
||||||
addAnyCode(start, codeEntry) {
|
addAnyCode(start, codeEntry) {
|
||||||
const pageAddr = (start / kPageSize) | 0;
|
const pageAddr = (start / this.kPageSize) | this.kZero;
|
||||||
if (!this.pages_.has(pageAddr)) return this.addCode(start, codeEntry);
|
if (!this.pages_.has(pageAddr)) return this.addCode(start, codeEntry);
|
||||||
// We might have loaded static code (builtins, bytecode handlers)
|
// We might have loaded static code (builtins, bytecode handlers)
|
||||||
// and we get more information later in v8.log with code-creation events.
|
// and we get more information later in v8.log with code-creation events.
|
||||||
@ -147,8 +153,8 @@ export class CodeMap {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
markPages_(start, end) {
|
markPages_(start, end) {
|
||||||
for (let addr = start; addr <= end; addr += kPageSize) {
|
for (let addr = start; addr <= end; addr += this.kPageSize) {
|
||||||
this.pages_.add((addr / kPageSize) | 0);
|
this.pages_.add((addr / this.kPageSize) | this.kZero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,13 +163,13 @@ export class CodeMap {
|
|||||||
*/
|
*/
|
||||||
deleteAllCoveredNodes_(tree, start, end) {
|
deleteAllCoveredNodes_(tree, start, end) {
|
||||||
const to_delete = [];
|
const to_delete = [];
|
||||||
let addr = end - 1;
|
let addr = end - this.kOne;
|
||||||
while (addr >= start) {
|
while (addr >= start) {
|
||||||
const node = tree.findGreatestLessThan(addr);
|
const node = tree.findGreatestLessThan(addr);
|
||||||
if (node === null) break;
|
if (node === null) break;
|
||||||
const start2 = node.key, end2 = start2 + node.value.size;
|
const start2 = node.key, end2 = start2 + node.value.size;
|
||||||
if (start2 < end && start < end2) to_delete.push(start2);
|
if (start2 < end && start < end2) to_delete.push(start2);
|
||||||
addr = start2 - 1;
|
addr = start2 - this.kOne;
|
||||||
}
|
}
|
||||||
for (let i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
|
for (let i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
|
||||||
}
|
}
|
||||||
@ -191,7 +197,7 @@ export class CodeMap {
|
|||||||
* @param {number} addr Address.
|
* @param {number} addr Address.
|
||||||
*/
|
*/
|
||||||
findAddress(addr) {
|
findAddress(addr) {
|
||||||
const pageAddr = (addr / kPageSize) | 0;
|
const pageAddr = (addr / this.kPageSize) | this.kZero;
|
||||||
if (this.pages_.has(pageAddr)) {
|
if (this.pages_.has(pageAddr)) {
|
||||||
// Static code entries can contain "holes" of unnamed code.
|
// Static code entries can contain "holes" of unnamed code.
|
||||||
// In this case, the whole library is assigned to this address.
|
// In this case, the whole library is assigned to this address.
|
||||||
|
@ -35,6 +35,16 @@
|
|||||||
export function parseString(field) { return field };
|
export function parseString(field) { return field };
|
||||||
export const parseVarArgs = 'parse-var-args';
|
export const parseVarArgs = 'parse-var-args';
|
||||||
|
|
||||||
|
// Checks fields for numbers that are not safe integers. Returns true if any are
|
||||||
|
// found.
|
||||||
|
function containsUnsafeInts(fields) {
|
||||||
|
for (let i = 0; i < fields.length; i++) {
|
||||||
|
let field = fields[i];
|
||||||
|
if ('number' == typeof(field) && !Number.isSafeInteger(field)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for processing log files.
|
* Base class for processing log files.
|
||||||
*
|
*
|
||||||
@ -44,7 +54,7 @@ export const parseVarArgs = 'parse-var-args';
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export class LogReader {
|
export class LogReader {
|
||||||
constructor(timedRange=false, pairwiseTimedRange=false) {
|
constructor(timedRange=false, pairwiseTimedRange=false, useBigInt=false) {
|
||||||
this.dispatchTable_ = new Map();
|
this.dispatchTable_ = new Map();
|
||||||
this.timedRange_ = timedRange;
|
this.timedRange_ = timedRange;
|
||||||
this.pairwiseTimedRange_ = pairwiseTimedRange;
|
this.pairwiseTimedRange_ = pairwiseTimedRange;
|
||||||
@ -54,6 +64,11 @@ export class LogReader {
|
|||||||
// Variables for tracking of 'current-time' log entries:
|
// Variables for tracking of 'current-time' log entries:
|
||||||
this.hasSeenTimerMarker_ = false;
|
this.hasSeenTimerMarker_ = false;
|
||||||
this.logLinesSinceLastTimerMarker_ = [];
|
this.logLinesSinceLastTimerMarker_ = [];
|
||||||
|
// Flag to parse all numeric fields as BigInt to avoid arithmetic errors
|
||||||
|
// caused by memory addresses being greater than MAX_SAFE_INTEGER
|
||||||
|
this.useBigInt = useBigInt;
|
||||||
|
this.parseFrame = useBigInt ? BigInt : parseInt;
|
||||||
|
this.hasSeenUnsafeIntegers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,11 +195,11 @@ export class LogReader {
|
|||||||
const firstChar = frame[0];
|
const firstChar = frame[0];
|
||||||
if (firstChar === '+' || firstChar === '-') {
|
if (firstChar === '+' || firstChar === '-') {
|
||||||
// An offset from the previous frame.
|
// An offset from the previous frame.
|
||||||
prevFrame += parseInt(frame, 16);
|
prevFrame += this.parseFrame(frame);
|
||||||
fullStack.push(prevFrame);
|
fullStack.push(prevFrame);
|
||||||
// Filter out possible 'overflow' string.
|
// Filter out possible 'overflow' string.
|
||||||
} else if (firstChar !== 'o') {
|
} else if (firstChar !== 'o') {
|
||||||
fullStack.push(parseInt(frame, 16));
|
fullStack.push(this.parseFrame(frame));
|
||||||
} else {
|
} else {
|
||||||
console.error(`Dropping unknown tick frame: ${frame}`);
|
console.error(`Dropping unknown tick frame: ${frame}`);
|
||||||
}
|
}
|
||||||
@ -216,6 +231,12 @@ export class LogReader {
|
|||||||
parsedFields[i] = parser(fields[1 + i]);
|
parsedFields[i] = parser(fields[1 + i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.useBigInt) {
|
||||||
|
if (!this.hasSeenUnsafeIntegers && containsUnsafeInts(parsedFields)) {
|
||||||
|
console.warn(`Log line containts unsafe integers: ${fields}`);
|
||||||
|
this.hasSeenUnsafeIntegers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Run the processor.
|
// Run the processor.
|
||||||
await dispatch.processor(...parsedFields);
|
await dispatch.processor(...parsedFields);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,6 @@ const kProfileOperationTick = 2;
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export class Profile {
|
export class Profile {
|
||||||
codeMap_ = new CodeMap();
|
|
||||||
topDownTree_ = new CallTree();
|
topDownTree_ = new CallTree();
|
||||||
bottomUpTree_ = new CallTree();
|
bottomUpTree_ = new CallTree();
|
||||||
c_entries_ = {__proto__:null};
|
c_entries_ = {__proto__:null};
|
||||||
@ -313,6 +312,11 @@ export class Profile {
|
|||||||
urlToScript_ = new Map();
|
urlToScript_ = new Map();
|
||||||
warnings = new Set();
|
warnings = new Set();
|
||||||
|
|
||||||
|
constructor(useBigInt=false) {
|
||||||
|
this.useBigInt = useBigInt;
|
||||||
|
this.codeMap_ = new CodeMap(useBigInt);
|
||||||
|
}
|
||||||
|
|
||||||
serializeVMSymbols() {
|
serializeVMSymbols() {
|
||||||
let result = this.codeMap_.getAllStaticEntriesWithAddresses();
|
let result = this.codeMap_.getAllStaticEntriesWithAddresses();
|
||||||
result.concat(this.codeMap_.getAllLibraryEntriesWithAddresses())
|
result.concat(this.codeMap_.getAllLibraryEntriesWithAddresses())
|
||||||
@ -513,7 +517,7 @@ export class Profile {
|
|||||||
// it is safe to put them in a single code map.
|
// it is safe to put them in a single code map.
|
||||||
let func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
|
let func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
|
||||||
if (func === null) {
|
if (func === null) {
|
||||||
func = new FunctionEntry(name);
|
func = new FunctionEntry(name, this.useBigInt);
|
||||||
this.codeMap_.addCode(funcAddr, func);
|
this.codeMap_.addCode(funcAddr, func);
|
||||||
} else if (func.name !== name) {
|
} else if (func.name !== name) {
|
||||||
// Function object has been overwritten with a new one.
|
// Function object has been overwritten with a new one.
|
||||||
@ -961,8 +965,8 @@ class FunctionEntry extends CodeEntry {
|
|||||||
/** @type {Set<DynamicCodeEntry>} */
|
/** @type {Set<DynamicCodeEntry>} */
|
||||||
_codeEntries = new Set();
|
_codeEntries = new Set();
|
||||||
|
|
||||||
constructor(name) {
|
constructor(name, useBigInt=false) {
|
||||||
super(0, name);
|
super(useBigInt ? 0n : 0, name);
|
||||||
const index = name.lastIndexOf(' ');
|
const index = name.lastIndexOf(' ');
|
||||||
this.functionName = 1 <= index ? name.substring(0, index) : '<anonymous>';
|
this.functionName = 1 <= index ? name.substring(0, index) : '<anonymous>';
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ export class TickLogEntry extends LogEntry {
|
|||||||
return 'Idle';
|
return 'Idle';
|
||||||
}
|
}
|
||||||
const topOfStack = processedStack[0];
|
const topOfStack = processedStack[0];
|
||||||
if (typeof topOfStack === 'number') {
|
if (typeof topOfStack === 'number' || typeof topOfStack === 'bigint') {
|
||||||
// TODO(cbruni): Handle VmStack and native ticks better.
|
// TODO(cbruni): Handle VmStack and native ticks better.
|
||||||
return 'Other';
|
return 'Other';
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ class AsyncConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Processor extends LogReader {
|
export class Processor extends LogReader {
|
||||||
_profile = new Profile();
|
|
||||||
_codeTimeline = new Timeline();
|
_codeTimeline = new Timeline();
|
||||||
_deoptTimeline = new Timeline();
|
_deoptTimeline = new Timeline();
|
||||||
_icTimeline = new Timeline();
|
_icTimeline = new Timeline();
|
||||||
@ -70,12 +69,16 @@ export class Processor extends LogReader {
|
|||||||
|
|
||||||
MAJOR_VERSION = 7;
|
MAJOR_VERSION = 7;
|
||||||
MINOR_VERSION = 6;
|
MINOR_VERSION = 6;
|
||||||
constructor() {
|
constructor(useBigInt = false) {
|
||||||
super();
|
super(false, false, useBigInt);
|
||||||
|
this.useBigInt = useBigInt;
|
||||||
|
this.kZero = useBigInt ? 0n : 0;
|
||||||
|
this.parseAddress = useBigInt ? BigInt : parseInt;
|
||||||
this._chunkConsumer =
|
this._chunkConsumer =
|
||||||
new AsyncConsumer((chunk) => this._processChunk(chunk));
|
new AsyncConsumer((chunk) => this._processChunk(chunk));
|
||||||
|
this._profile = new Profile(useBigInt);
|
||||||
const propertyICParser = [
|
const propertyICParser = [
|
||||||
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
|
this.parseAddress, parseInt, parseInt, parseInt, parseString, parseString,
|
||||||
parseString, parseString, parseString, parseString
|
parseString, parseString, parseString, parseString
|
||||||
];
|
];
|
||||||
this.setDispatchTable({
|
this.setDispatchTable({
|
||||||
@ -88,46 +91,47 @@ export class Processor extends LogReader {
|
|||||||
processor: this.processV8Version,
|
processor: this.processV8Version,
|
||||||
},
|
},
|
||||||
'shared-library': {
|
'shared-library': {
|
||||||
parsers: [parseString, parseInt, parseInt, parseInt],
|
parsers: [
|
||||||
|
parseString, this.parseAddress, this.parseAddress, this.parseAddress
|
||||||
|
],
|
||||||
processor: this.processSharedLibrary.bind(this),
|
processor: this.processSharedLibrary.bind(this),
|
||||||
isAsync: true,
|
isAsync: true,
|
||||||
},
|
},
|
||||||
'code-creation': {
|
'code-creation': {
|
||||||
parsers: [
|
parsers: [
|
||||||
parseString, parseInt, parseInt, parseInt, parseInt, parseString,
|
parseString, parseInt, parseInt, this.parseAddress, this.parseAddress,
|
||||||
parseVarArgs
|
parseString, parseVarArgs
|
||||||
],
|
],
|
||||||
processor: this.processCodeCreation
|
processor: this.processCodeCreation
|
||||||
},
|
},
|
||||||
'code-deopt': {
|
'code-deopt': {
|
||||||
parsers: [
|
parsers: [
|
||||||
parseInt, parseInt, parseInt, parseInt, parseInt, parseString,
|
parseInt, parseInt, this.parseAddress, parseInt, parseInt,
|
||||||
parseString, parseString
|
parseString, parseString, parseString
|
||||||
],
|
],
|
||||||
processor: this.processCodeDeopt
|
processor: this.processCodeDeopt
|
||||||
},
|
},
|
||||||
'code-move':
|
'code-move': {
|
||||||
{parsers: [parseInt, parseInt], processor: this.processCodeMove},
|
parsers: [this.parseAddress, this.parseAddress],
|
||||||
'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
|
processor: this.processCodeMove
|
||||||
|
},
|
||||||
|
'code-delete':
|
||||||
|
{parsers: [this.parseAddress], processor: this.processCodeDelete},
|
||||||
'code-source-info': {
|
'code-source-info': {
|
||||||
parsers: [
|
parsers: [
|
||||||
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
|
this.parseAddress, parseInt, parseInt, parseInt, parseString,
|
||||||
parseString
|
parseString, parseString
|
||||||
],
|
],
|
||||||
processor: this.processCodeSourceInfo
|
processor: this.processCodeSourceInfo
|
||||||
},
|
},
|
||||||
'code-disassemble': {
|
'code-disassemble': {
|
||||||
parsers: [
|
parsers: [this.parseAddress, parseString, parseString],
|
||||||
parseInt,
|
|
||||||
parseString,
|
|
||||||
parseString,
|
|
||||||
],
|
|
||||||
processor: this.processCodeDisassemble
|
processor: this.processCodeDisassemble
|
||||||
},
|
},
|
||||||
'feedback-vector': {
|
'feedback-vector': {
|
||||||
parsers: [
|
parsers: [
|
||||||
parseInt, parseString, parseInt, parseInt, parseString, parseString,
|
parseInt, parseString, parseInt, this.parseAddress, parseString,
|
||||||
parseInt, parseInt, parseString
|
parseString, parseInt, parseInt, parseString
|
||||||
],
|
],
|
||||||
processor: this.processFeedbackVector
|
processor: this.processFeedbackVector
|
||||||
},
|
},
|
||||||
@ -135,11 +139,15 @@ export class Processor extends LogReader {
|
|||||||
parsers: [parseInt, parseString, parseString],
|
parsers: [parseInt, parseString, parseString],
|
||||||
processor: this.processScriptSource
|
processor: this.processScriptSource
|
||||||
},
|
},
|
||||||
'sfi-move':
|
'sfi-move': {
|
||||||
{parsers: [parseInt, parseInt], processor: this.processFunctionMove},
|
parsers: [this.parseAddress, this.parseAddress],
|
||||||
|
processor: this.processFunctionMove
|
||||||
|
},
|
||||||
'tick': {
|
'tick': {
|
||||||
parsers:
|
parsers: [
|
||||||
[parseInt, parseInt, parseInt, parseInt, parseInt, parseVarArgs],
|
this.parseAddress, parseInt, parseInt, this.parseAddress, parseInt,
|
||||||
|
parseVarArgs
|
||||||
|
],
|
||||||
processor: this.processTick
|
processor: this.processTick
|
||||||
},
|
},
|
||||||
'active-runtime-timer': undefined,
|
'active-runtime-timer': undefined,
|
||||||
@ -157,8 +165,8 @@ export class Processor extends LogReader {
|
|||||||
{parsers: [parseInt, parseString], processor: this.processMapCreate},
|
{parsers: [parseInt, parseString], processor: this.processMapCreate},
|
||||||
'map': {
|
'map': {
|
||||||
parsers: [
|
parsers: [
|
||||||
parseString, parseInt, parseString, parseString, parseInt, parseInt,
|
parseString, parseInt, parseString, parseString, this.parseAddress,
|
||||||
parseInt, parseString, parseString
|
parseInt, parseInt, parseString, parseString
|
||||||
],
|
],
|
||||||
processor: this.processMap
|
processor: this.processMap
|
||||||
},
|
},
|
||||||
@ -352,7 +360,7 @@ export class Processor extends LogReader {
|
|||||||
let profilerEntry;
|
let profilerEntry;
|
||||||
let stateName = '';
|
let stateName = '';
|
||||||
if (maybe_func.length) {
|
if (maybe_func.length) {
|
||||||
const funcAddr = parseInt(maybe_func[0]);
|
const funcAddr = this.parseAddress(maybe_func[0]);
|
||||||
stateName = maybe_func[1] ?? '';
|
stateName = maybe_func[1] ?? '';
|
||||||
const state = Profile.parseState(maybe_func[1]);
|
const state = Profile.parseState(maybe_func[1]);
|
||||||
profilerEntry = this._profile.addFuncCode(
|
profilerEntry = this._profile.addFuncCode(
|
||||||
@ -404,7 +412,7 @@ export class Processor extends LogReader {
|
|||||||
optimization_tier, invocation_count, profiler_ticks, fbv_string) {
|
optimization_tier, invocation_count, profiler_ticks, fbv_string) {
|
||||||
const profCodeEntry = this._profile.findEntry(instructionStart);
|
const profCodeEntry = this._profile.findEntry(instructionStart);
|
||||||
if (!profCodeEntry) {
|
if (!profCodeEntry) {
|
||||||
console.warn('Didn\'t find code for FBV', {fbv, instructionStart});
|
console.warn('Didn\'t find code for FBV', {fbv_string, instructionStart});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const fbv = new FeedbackVectorEntry(
|
const fbv = new FeedbackVectorEntry(
|
||||||
@ -439,13 +447,13 @@ export class Processor extends LogReader {
|
|||||||
// that a callback calls itself. Instead we use tos_or_external_callback,
|
// that a callback calls itself. Instead we use tos_or_external_callback,
|
||||||
// as simply resetting PC will produce unaccounted ticks.
|
// as simply resetting PC will produce unaccounted ticks.
|
||||||
pc = tos_or_external_callback;
|
pc = tos_or_external_callback;
|
||||||
tos_or_external_callback = 0;
|
tos_or_external_callback = this.kZero;
|
||||||
} else if (tos_or_external_callback) {
|
} else if (tos_or_external_callback) {
|
||||||
// Find out, if top of stack was pointing inside a JS function
|
// Find out, if top of stack was pointing inside a JS function
|
||||||
// meaning that we have encountered a frameless invocation.
|
// meaning that we have encountered a frameless invocation.
|
||||||
const funcEntry = this._profile.findEntry(tos_or_external_callback);
|
const funcEntry = this._profile.findEntry(tos_or_external_callback);
|
||||||
if (!funcEntry?.isJSFunction?.()) {
|
if (!funcEntry?.isJSFunction?.()) {
|
||||||
tos_or_external_callback = 0;
|
tos_or_external_callback = this.kZero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const entryStack = this._profile.recordTick(
|
const entryStack = this._profile.recordTick(
|
||||||
|
Loading…
Reference in New Issue
Block a user