From 5edf74d96ad03fed375ecda64cfc80443a98f29f Mon Sep 17 00:00:00 2001 From: Kyle Farnung Date: Fri, 23 Feb 2018 11:30:05 -0800 Subject: [PATCH 1/3] lib: update TTD to use `let` and `const` PR-URL: https://github.com/nodejs/node-chakracore/pull/476 Reviewed-By: Jack Horton Reviewed-By: Taylor Woll Reviewed-By: Seth Brenith Reviewed-By: Jimmy Thomson --- lib/internal/process.js | 8 +-- lib/trace_mgr.js | 112 ++++++++++++++++++++-------------------- 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/lib/internal/process.js b/lib/internal/process.js index 9d0ecb49ead..319e1623f74 100644 --- a/lib/internal/process.js +++ b/lib/internal/process.js @@ -182,7 +182,7 @@ function setupKillAndExit() { }; } -var ttdSigIntHandler; +let ttdSigIntHandler; function setupSignalHandlers() { const signalWraps = Object.create(null); let Signal; @@ -231,12 +231,12 @@ function setupSignalHandlers() { if (global.enabledDiagnosticsTrace) { (function() { const type = 'SIGINT'; - var Signal = process.binding('signal_wrap').Signal; - var wrap = new Signal(); + const Signal = process.binding('signal_wrap').Signal; + const wrap = new Signal(); wrap.unref(); - var handler = require('trace_mgr').onSigIntHandler; + const handler = require('trace_mgr').onSigIntHandler; const userHandler = process.emit.bind(process, type, type); wrap.onsignal = function() { // If signalWraps[type] exists, then the user script diff --git a/lib/trace_mgr.js b/lib/trace_mgr.js index cb0bf8ea67e..74dc5e8bc16 100644 --- a/lib/trace_mgr.js +++ b/lib/trace_mgr.js @@ -2,13 +2,11 @@ //Disable trace handling inside trace handler to avoid recursion //Set to true to prevent action till loading is complete -- set to false at end -var reentrantDisable = true; +let reentrantDisable = true; -var process = require('process'); - -var lazyloadDone = false; -var path; -var fs; +let lazyloadDone = false; +let path; +let fs; /////////////////////////////// //Trace calls @@ -21,7 +19,7 @@ var fs; *@result 're-entrant' 'disabled', 'no-sample', 'fail', 'success' */ function emitTrace(emitKind, optInfo) { - var res = emitTrace_helper(emitKind, optInfo); + const res = emitTrace_helper(emitKind, optInfo); if (res.flag === 'success') { //This is an intentional programatic breakpoint // -- it is only triggerable in --replay-debug mode @@ -32,7 +30,7 @@ function emitTrace(emitKind, optInfo) { exports.emitTrace = emitTrace; function buildTraceResult(flagv, actionv) { - var realAction = actionv || function() { }; + const realAction = actionv || function() { }; return { flag: flagv, action: realAction }; } @@ -60,7 +58,7 @@ function emitTrace_helper(emitKind, optInfo) { //Process a synchronous write action for a unique trace bin // -- otherwise a async action on a multiple trace bin - var sampleRes = buildTraceResult('no-sample'); + let sampleRes = buildTraceResult('no-sample'); if (emitKind === 'emitOnExit' || emitKind === 'emitOnException' || emitKind === 'emitOnSigInt') { @@ -86,13 +84,13 @@ function emitTrace_helper(emitKind, optInfo) { //Helpers for trace calls function emitSyncTraceKind(emitKind, optInfo) { //build up trace name - var traceName = emitKind; + let traceName = emitKind; if (emitKind === 'emitOnExit') { traceName += ('_code-' + optInfo); } //invoke the trace writer and remote manager if needed - var resolvedPath = createTraceLogTarget(traceName); + const resolvedPath = createTraceLogTarget(traceName); if (!resolvedPath) { return buildTraceResult('fail'); } @@ -116,19 +114,19 @@ function emitSyncTraceKind(emitKind, optInfo) { function emitAsyncTraceKind(emitKind) { //get trace stack and check if we want to emit - var stk = generateFuzzyStack(emitKind); - var entry = checkBinShouldEmit(stk); + const stk = generateFuzzyStack(emitKind); + const entry = checkBinShouldEmit(stk); if (!entry) { return buildTraceResult('no-sample'); } //build up trace name - var traceBucketName = `${emitKind}_${stk.fbin}_bucket-${entry.bucketId}`; - var traceDirName = `trace-${entry.traceCtr}`; - var traceName = path.join(traceBucketName, traceDirName); + const traceBucketName = `${emitKind}_${stk.fbin}_bucket-${entry.bucketId}`; + const traceDirName = `trace-${entry.traceCtr}`; + const traceName = path.join(traceBucketName, traceDirName); //invoke the trace writer and remote manager if needed - var resolvedPath = createTraceLogTarget(traceName); + const resolvedPath = createTraceLogTarget(traceName); if (!resolvedPath) { return buildTraceResult('fail'); } @@ -154,17 +152,17 @@ function emitAsyncTraceKind(emitKind) { //create a directory for emitting the trace (if possible) and return it function createTraceLogTarget(tracename) { - var traceRootDir = emitOptions.localTraceDirectory || + const traceRootDir = emitOptions.localTraceDirectory || path.dirname(process.mainModule.filename); // Add the PID to the trace name tracename = `${tracename}_pid${process.pid}`; - var resolvedTracePath = + const resolvedTracePath = path.resolve(traceRootDir, '_diagnosticTraces', tracename); //ensure directory exists and is empty... - var ok = ensureTraceTarget(resolvedTracePath); + const ok = ensureTraceTarget(resolvedTracePath); if (!ok) { return undefined; } @@ -179,7 +177,7 @@ function ensureTraceTarget(pth) { return false; } - var okdir = createTargetDirectory(pth); + const okdir = createTargetDirectory(pth); if (!okdir) { return false; } @@ -189,7 +187,7 @@ function ensureTraceTarget(pth) { function createTargetDirectory(pth) { //see if it just exists and, if so, just return true - var accessok = fs.constants.R_OK | fs.constants.W_OK | fs.constants.X_OK; + const accessok = fs.constants.R_OK | fs.constants.W_OK | fs.constants.X_OK; try { fs.accessSync(pth, accessok); if (fs.statSync(pth).isDirectory()) { @@ -198,9 +196,9 @@ function createTargetDirectory(pth) { } catch (ei) { } //walk up the directory to see where the first valid part of the path is - var prefixPath = pth; - var suffixPaths = []; - var baseFound = false; + let prefixPath = pth; + const suffixPaths = []; + let baseFound = false; do { //check for bad prefix if (prefixPath === path.dirname(prefixPath)) { @@ -233,14 +231,14 @@ function createTargetDirectory(pth) { function deleteTargetDirectoryContents(pth) { try { - var items = fs.readdirSync(pth); + const items = fs.readdirSync(pth); for (var i = 0; i < items.length; i++) { - var fpath = path.resolve(pth, items[i]); - var stats = fs.lstatSync(fpath); + const fpath = path.resolve(pth, items[i]); + const stats = fs.lstatSync(fpath); if (stats.isFile()) { fs.unlinkSync(fpath); } else if (stats.isDirectory()) { - var recok = deleteTargetDirectoryContents(fpath); + const recok = deleteTargetDirectoryContents(fpath); if (!recok) { return false; } @@ -262,7 +260,7 @@ function deleteTargetDirectoryContents(pth) { function updateGlobalSampleStats(eventKind) { currentSampleRate[eventKind] *= emitOptions.backoffFactors[eventKind]; - var updateTime = new Date(); + const updateTime = new Date(); emitMinTimeValue.emitOnLogWarn = new Date(updateTime); emitMinTimeValue.emitOnLogError = new Date(updateTime); @@ -274,7 +272,7 @@ function updateGlobalSampleStats(eventKind) { /////////////////////////////// //Trace emit manager code -var emitOptions = { +const emitOptions = { emitOnExit: 'error', //emit a trace on exit -- off, error, all emitOnException: true, //emit a trace on uncaught execption emitOnSigInt: true, //emit a trace on sigint @@ -313,17 +311,17 @@ var emitOptions = { remoteTraceManagerObj: undefined //manager object for remote trace support }; -var callStackEmitInfoMap = new Map(); -var bucketCtr = 0; +const callStackEmitInfoMap = new Map(); +let bucketCtr = 0; -var emitMinTimeValue = { +const emitMinTimeValue = { emitOnLogWarn: new Date(0), emitOnLogError: new Date(0), emitOnAssert: new Date(0) }; -var currentSampleRate = {}; -for (var srp in emitOptions.initialRates) { +const currentSampleRate = {}; +for (const srp in emitOptions.initialRates) { currentSampleRate[srp] = emitOptions.initialRates[srp]; } @@ -331,12 +329,12 @@ for (var srp in emitOptions.initialRates) { *Update emitOptions from the given options object */ function setOptions(optionsObj) { - for (var opt in optionsObj) { + for (const opt in optionsObj) { //TODO: need more error checking on the validity of the option values emitOptions[opt] = optionsObj[opt]; } - for (var srp in emitOptions.initialRates) { + for (const srp in emitOptions.initialRates) { currentSampleRate[srp] = emitOptions.initialRates[srp]; } } @@ -363,7 +361,7 @@ function checkGlobalShouldEmit(emitKind, optInfo) { return false; } - var sampleInterval = new Date() - emitMinTimeValue[emitKind]; + const sampleInterval = new Date() - emitMinTimeValue[emitKind]; //Don't sample too often no matter what (or we can basically live lock) if (sampleInterval < emitOptions.globalMinInterval) { @@ -372,8 +370,8 @@ function checkGlobalShouldEmit(emitKind, optInfo) { //Relax our global rate if it has been a while if (sampleInterval >= emitOptions.globalBackoffCancelInterval) { - var currRate = currentSampleRate[emitKind]; - var blRate = emitOptions.baselineRates[emitKind]; + const currRate = currentSampleRate[emitKind]; + const blRate = emitOptions.baselineRates[emitKind]; currentSampleRate[emitKind] = Math.max(currRate, blRate); } @@ -388,7 +386,7 @@ function checkGlobalShouldEmit(emitKind, optInfo) { *@result if we want to sample return the entry otherwise undefined */ function checkBinShouldEmit(fuzzyStack) { - var entry = resolveStackEntry(fuzzyStack); + const entry = resolveStackEntry(fuzzyStack); //stop sampling after max sampled values -- e.g. we don't need 100 repros if (entry.traceCtr > emitOptions.binMaxSampled) { @@ -396,7 +394,7 @@ function checkBinShouldEmit(fuzzyStack) { } //check if we want to sample on this entry -- we don't need every hit on this - var sampleProb = Math.pow(emitOptions.binBackoffFactor, entry.traceCtr); + const sampleProb = Math.pow(emitOptions.binBackoffFactor, entry.traceCtr); return (Math.random() < sampleProb) ? entry : undefined; } @@ -416,7 +414,7 @@ function resolveStackEntry(fuzzyStack) { if (!callStackEmitInfoMap.has(fuzzyStack.hash)) { callStackEmitInfoMap.set(fuzzyStack.hash, []); } - var stackList = callStackEmitInfoMap.get(fuzzyStack.hash); + const stackList = callStackEmitInfoMap.get(fuzzyStack.hash); for (var i = 0; i < stackList.length; ++i) { if (eqFuzzyStacks(fuzzyStack, stackList[i].stack)) { @@ -450,7 +448,7 @@ function directIsAbsoluteW32(pth) { if (len === 0) return false; - var code = pth.charCodeAt(0); + let code = pth.charCodeAt(0); if (code === 47/*/*/ || code === 92/*\*/) { return true; } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || @@ -470,7 +468,7 @@ function directIsAbsolutePosix(pth) { return pth.length > 0 && pth.charCodeAt(0) === 47/*/*/; } -var directIsAbsolute = (process.platform === 'win32') ? +const directIsAbsolute = (process.platform === 'win32') ? directIsAbsoluteW32 : directIsAbsolutePosix; @@ -479,7 +477,7 @@ var directIsAbsolute = (process.platform === 'win32') ? */ function generateFuzzyStack(eventKind) { //Create an array of the file/lines for user space code in the call stack - var errstk = new Error() + let errstk = new Error() .stack .split('\n') .slice(1) @@ -490,14 +488,14 @@ function generateFuzzyStack(eventKind) { return directIsAbsolute(frame); }); - var lastframe = errstk[errstk.length - 1]; - var fname = lastframe.substr(lastframe.lastIndexOf(path.sep) + 1) + const lastframe = errstk[errstk.length - 1]; + const fname = lastframe.substr(lastframe.lastIndexOf(path.sep) + 1) .replace('.js:', '_line-') .replace(':', '_column-'); //Identify which frames are recursive (appear multiple times in the stack) - var recFrames = new Map(); - var hasRecFrames = false; + const recFrames = new Map(); + let hasRecFrames = false; for (var i = 0; i < errstk.length; ++i) { if (recFrames.has(errstk[i])) { hasRecFrames = true; @@ -509,13 +507,13 @@ function generateFuzzyStack(eventKind) { if (hasRecFrames) { //Compress any recursive frames - var cpos = 0; - var fpos = 0; + let cpos = 0; + let fpos = 0; while (fpos < errstk.length) { if (recFrames.get(errstk[fpos])) { - var recArray = []; - var spanpos = fpos; - var spanend = errstk.lastIndexOf(errstk[fpos]); + const recArray = []; + let spanpos = fpos; + let spanend = errstk.lastIndexOf(errstk[fpos]); while (spanpos <= spanend) { if (recArray.indexOf(errstk[spanpos]) === -1) { recArray.push(errstk[spanpos]); @@ -540,7 +538,7 @@ function generateFuzzyStack(eventKind) { errstk = errstk.slice(0, cpos); } - var chash = 5381; + let chash = 5381; for (i = 0; i < errstk.length; ++i) { if (Array.isArray(errstk[i])) { for (var j = 0; j < errstk[i].length; ++j) { From 2fb4e2892cc206f040e9f05364542898e5e62a89 Mon Sep 17 00:00:00 2001 From: Kyle Farnung Date: Thu, 22 Feb 2018 19:39:05 -0800 Subject: [PATCH 2/3] chakrashim: switch `var` to `let` and `const` PR-URL: https://github.com/nodejs/node-chakracore/pull/476 Reviewed-By: Jack Horton Reviewed-By: Taylor Woll Reviewed-By: Seth Brenith Reviewed-By: Jimmy Thomson --- deps/chakrashim/lib/chakra_shim.js | 162 +++++++++++++++++++---------- 1 file changed, 107 insertions(+), 55 deletions(-) diff --git a/deps/chakrashim/lib/chakra_shim.js b/deps/chakrashim/lib/chakra_shim.js index fb6aba1fc47..d636cbaed6b 100644 --- a/deps/chakrashim/lib/chakra_shim.js +++ b/deps/chakrashim/lib/chakra_shim.js @@ -110,7 +110,7 @@ // default StackTrace stringify function function prepareStackTrace(error, stack) { - var stackString = (error.name || 'Error') + ': ' + (error.message || ''); + let stackString = (error.name || 'Error') + ': ' + (error.message || ''); for (var i = 0; i < stack.length; i++) { stackString += '\n at ' + stack[i].toString(); @@ -122,13 +122,13 @@ // Parse 'stack' string into StackTrace frames. Skip top 'skipDepth' frames, // and optionally skip top to 'startName' function frames. function parseStack(stack, skipDepth, startName) { - var stackSplitter = /\)\s*at/; - var reStackDetails = /\s(?:at\s)?(.*)\s\((.*)/; - var fileDetailsSplitter = /:(\d+)/; + const stackSplitter = /\)\s*at/; + const reStackDetails = /\s(?:at\s)?(.*)\s\((.*)/; + const fileDetailsSplitter = /:(\d+)/; - var curr = parseStack; - var splittedStack = stack.split(stackSplitter); - var errstack = []; + let curr = parseStack; + const splittedStack = stack.split(stackSplitter); + const errstack = []; for (var i = 0; i < splittedStack.length; i++) { // parseStack has 1 frame lesser than skipDepth. So skip calling .caller @@ -145,9 +145,9 @@ continue; } - var func = curr; - var stackDetails = reStackDetails.exec(splittedStack[i]); - var funcName = stackDetails[1]; + const func = curr; + const stackDetails = reStackDetails.exec(splittedStack[i]); + let funcName = stackDetails[1]; if (startName) { if (funcName === startName) { @@ -159,15 +159,16 @@ funcName = null; } - var fileDetails = stackDetails[2].split(fileDetailsSplitter); + const fileDetails = stackDetails[2].split(fileDetailsSplitter); - var fileName = fileDetails[0]; - var lineNumber = fileDetails[1] ? fileDetails[1] : 0; - var columnNumber = fileDetails[3] ? fileDetails[3] : 0; + const fileName = fileDetails[0]; + const lineNumber = fileDetails[1] ? fileDetails[1] : 0; + const columnNumber = fileDetails[3] ? fileDetails[3] : 0; errstack.push(new StackFrame(func, funcName, fileName, lineNumber, columnNumber)); } + return errstack; } @@ -177,9 +178,9 @@ } try { - var curr = privateCaptureStackTrace.caller; - var limit = Error.stackTraceLimit; - var skipDepth = 0; + let curr = privateCaptureStackTrace.caller; + const limit = Error.stackTraceLimit; + let skipDepth = 0; while (curr) { skipDepth++; if (curr === func) { @@ -199,10 +200,11 @@ } function withStackTraceLimitOffset(offset, f) { - var oldLimit = BuiltInError.stackTraceLimit; + const oldLimit = BuiltInError.stackTraceLimit; if (typeof oldLimit === 'number') { BuiltInError.stackTraceLimit = oldLimit + offset; } + try { return f(); } finally { @@ -223,31 +225,34 @@ // e -- a new Error object which already captured stack // skipDepth -- known number of top frames to be skipped function privateCaptureStackTrace(err, func, e, skipDepth) { - var currentStack = e; - var isPrepared = false; - var oldStackDesc = Object_getOwnPropertyDescriptor(e, 'stack'); + let currentStack = e; + let isPrepared = false; + const oldStackDesc = Object_getOwnPropertyDescriptor(e, 'stack'); - var funcSkipDepth = findFuncDepth(func); - var startFuncName = (func && funcSkipDepth < 0) ? func.name : undefined; + const funcSkipDepth = findFuncDepth(func); + const startFuncName = (func && funcSkipDepth < 0) ? func.name : undefined; skipDepth += Math.max(funcSkipDepth - 1, 0); - var currentStackTrace; + let currentStackTrace; function ensureStackTrace() { if (!currentStackTrace) { currentStackTrace = parseStack( Reflect_apply(oldStackDesc.get, e, []) || '', // Call saved old getter skipDepth, startFuncName); } + return currentStackTrace; } function stackGetter() { if (!isPrepared) { - var prep = Error.prepareStackTrace || prepareStackTrace; + const prep = Error.prepareStackTrace || prepareStackTrace; stackSetter(prep(err, ensureStackTrace())); } + return currentStack; } + function stackSetter(value) { currentStack = value; isPrepared = true; @@ -272,7 +277,7 @@ // patch Error types to hook with Error.captureStackTrace/prepareStackTrace function patchErrorTypes() { // save a map from wrapper to builtin native types - var typeToNative = new Map(); + const typeToNative = new Map(); // patch all these builtin Error types [ @@ -280,7 +285,7 @@ URIError ].forEach(function(type) { function newType() { - var e = withStackTraceLimitOffset( + const e = withStackTraceLimitOffset( 3, () => Reflect_construct(type, arguments, new.target || newType)); // skip 3 frames: lambda, withStackTraceLimitOffset, this frame privateCaptureStackTrace(e, undefined, e, 3); @@ -319,16 +324,16 @@ Error.captureStackTrace = captureStackTrace; } - var mapIteratorProperty = 'MapIteratorIndicator'; + const mapIteratorProperty = 'MapIteratorIndicator'; function patchMapIterator() { - var originalMapMethods = []; + const originalMapMethods = []; originalMapMethods.push(['entries', Map_entries]); originalMapMethods.push(['values', Map_values]); originalMapMethods.push(['keys', Map_keys]); originalMapMethods.forEach(function(pair) { Map.prototype[pair[0]] = function() { - var result = pair[1].apply(this); + const result = pair[1].apply(this); Object_defineProperty( result, mapIteratorProperty, { value: true, enumerable: false, writable: false }); @@ -337,15 +342,15 @@ }); } - var setIteratorProperty = 'SetIteratorIndicator'; + const setIteratorProperty = 'SetIteratorIndicator'; function patchSetIterator() { - var originalSetMethods = []; + const originalSetMethods = []; originalSetMethods.push(['entries', Set_entries]); originalSetMethods.push(['values', Set_values]); originalSetMethods.forEach(function(pair) { Set.prototype[pair[0]] = function() { - var result = pair[1].apply(this); + const result = pair[1].apply(this); Object_defineProperty( result, setIteratorProperty, { value: true, enumerable: false, writable: false }); @@ -366,7 +371,7 @@ patchDebug(global.Debug); } - var otherProcess; + let otherProcess; function patchDebug(Debug) { if (!Debug || Debug.MakeMirror) { @@ -430,20 +435,21 @@ } // Simulate v8 micro tasks queue - var microTasks = []; + const microTasks = []; function patchUtils(utils) { - var isUintRegex = /^(0|[1-9]\d*)$/; + const isUintRegex = /^(0|[1-9]\d*)$/; function isUint(value) { - var result = isUintRegex.test(value); + const result = isUintRegex.test(value); isUintRegex.lastIndex = 0; return result; } + utils.cloneObject = function(source, target) { Object_getOwnPropertyNames(source).forEach(function(key) { try { - var desc = Object_getOwnPropertyDescriptor(source, key); + const desc = Object_getOwnPropertyDescriptor(source, key); if (desc.value === source) desc.value = target; Object_defineProperty(target, key, desc); } catch (e) { @@ -451,45 +457,52 @@ } }); }; + utils.getPropertyNames = function(a) { - var names = []; - for (var propertyName in a) { + const names = []; + for (const propertyName in a) { if (isUint(propertyName)) { names.push(Global_ParseInt(propertyName)); } else { names.push(propertyName); } } + return names; }; + utils.getEnumerableNamedProperties = function(obj) { - var props = []; - for (var key in obj) { + const props = []; + for (const key in obj) { if (!isUint(key)) props.push(key); } + return props; }; + utils.getEnumerableIndexedProperties = function(obj) { - var props = []; - for (var key in obj) { + const props = []; + for (const key in obj) { if (isUint(key)) props.push(key); } + return props; }; + utils.createEnumerationIterator = function(props) { - var i = 0; + let i = 0; return { next: function() { - if (i === props.length) - return { done: true }; + if (i === props.length) return { done: true }; return { value: props[i++] }; } }; }; + utils.createPropertyDescriptorsEnumerationIterator = function(props) { - var i = 0; + let i = 0; return { next: function() { if (i === props.length) return { done: true }; @@ -497,44 +510,56 @@ } }; }; + utils.getNamedOwnKeys = function(obj) { - var props = []; + const props = []; Object_keys(obj).forEach(function(item) { if (!isUint(item)) props.push(item); }); + return props; }; + utils.getIndexedOwnKeys = function(obj) { - var props = []; + const props = []; Object_keys(obj).forEach(function(item) { if (isUint(item)) props.push(item); }); + return props; }; + utils.getStackTrace = function() { return captureStackTrace({}, undefined)(); }; + utils.isMapIterator = function(value) { return value[mapIteratorProperty] === true; }; + utils.isSetIterator = function(value) { return value[setIteratorProperty] === true; }; + function compareType(o, expectedType) { return Object_prototype_toString.call(o) === '[object ' + expectedType + ']'; } + utils.isBooleanObject = function(obj) { return compareType(obj, 'Boolean'); }; + utils.isDate = function(obj) { return compareType(obj, 'Date'); }; + utils.isMap = function(obj) { return compareType(obj, 'Map'); }; + utils.isNativeError = function(obj) { return compareType(obj, 'Error') || obj instanceof Error || @@ -545,73 +570,94 @@ obj instanceof TypeError || obj instanceof URIError; }; + utils.isPromise = function(obj) { return compareType(obj, 'Promise') && obj instanceof Promise; }; + utils.isRegExp = function(obj) { return compareType(obj, 'RegExp'); }; + utils.isAsyncFunction = function(obj) { // CHAKRA-TODO return false; }; + utils.isSet = function(obj) { return compareType(obj, 'Set'); }; + utils.isStringObject = function(obj) { return compareType(obj, 'String'); }; + utils.isNumberObject = function(obj) { return compareType(obj, 'Number'); }; + utils.isArgumentsObject = function(obj) { return compareType(obj, 'Arguments'); }; + utils.isGeneratorObject = function(obj) { return compareType(obj, 'Generator'); }; + utils.isWeakMap = function(obj) { return compareType(obj, 'WeakMap'); }; + utils.isWeakSet = function(obj) { return compareType(obj, 'WeakSet'); }; + utils.isSymbolObject = function(obj) { return compareType(obj, 'Symbol'); }; + utils.isName = function(obj) { return compareType(obj, 'String') || compareType(obj, 'Symbol'); }; + utils.getSymbolKeyFor = function(symbol) { return Symbol_keyFor(symbol); }; + utils.getSymbolFor = function(key) { return Symbol_for(key); }; + utils.jsonParse = function(text, reviver) { return JSON_parse(text, reviver); }; + utils.jsonStringify = function(value, replacer, space) { return JSON_stringify(value, replacer, space); }; + utils.ensureDebug = ensureDebug; + utils.enqueueMicrotask = function(task) { microTasks.push(task); }; + utils.dequeueMicrotask = function(task) { return microTasks.shift(); }; + utils.isProxy = function(value) { // CHAKRA-TODO: Need to add JSRT API to detect this return false; }; + utils.getPropertyAttributes = function(object, value) { - var descriptor = Object_getOwnPropertyDescriptor(object, value); + const descriptor = Object_getOwnPropertyDescriptor(object, value); if (descriptor === undefined) { return -1; } - var attributes = 0; + let attributes = 0; // taken from v8.h. Update if this changes in future const ReadOnly = 1; const DontEnum = 2; @@ -620,28 +666,34 @@ if (!descriptor.writable) { attributes |= ReadOnly; } + if (!descriptor.enumerable) { attributes |= DontEnum; } + if (!descriptor.configurable) { attributes |= DontDelete; } + return attributes; }; + utils.getOwnPropertyNames = function(obj) { - var ownPropertyNames = Object_getOwnPropertyNames(obj); - var i = 0; + const ownPropertyNames = Object_getOwnPropertyNames(obj); + let i = 0; while (i < ownPropertyNames.length) { - var item = ownPropertyNames[i]; + const item = ownPropertyNames[i]; if (isUint(item)) { ownPropertyNames[i] = Global_ParseInt(item); i++; continue; } + // As per spec, getOwnPropertyNames() first include // numeric properties followed by non-numeric break; } + return ownPropertyNames; }; } From 2552d1c7a2ed2d5084520d00dd1bbc21df364d8e Mon Sep 17 00:00:00 2001 From: Kyle Farnung Date: Mon, 26 Feb 2018 11:20:58 -0800 Subject: [PATCH 3/3] doc: fix Markdown linter failures PR-URL: https://github.com/nodejs/node-chakracore/pull/476 Reviewed-By: Jack Horton Reviewed-By: Taylor Woll Reviewed-By: Seth Brenith Reviewed-By: Jimmy Thomson --- README.md | 23 ++++++---- TTD-README.md | 125 +++++++++++++++++++++++++++++--------------------- 2 files changed, 86 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 4dfadbb79fe..553370a84d1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # Node.js on ChakraCore -This project enables Node.js to optionally use the [ChakraCore](https://github.com/Microsoft/ChakraCore) -JavaScript engine. This project is still **work in progress** and not an officially -supported Node.js branch. For more context into this project, please refer to the +This project enables Node.js to optionally use the +[ChakraCore](https://github.com/Microsoft/ChakraCore) JavaScript engine. This +project is still **work in progress** and not an officially supported Node.js +branch. For more context into this project, please refer to the [original PR](https://github.com/nodejs/node/pull/4765). ### How it works @@ -19,18 +20,20 @@ to work. ### Time Travel Debugging Time-Travel debugging is an exciting new addition to Node.js debugging, first -introduced in Node-ChakraCore, and now supported by [VSCode](https://github.com/microsoft/vscode/). -We are developing in the open and want to share our progress to get feedback, -bug reports, functionality requests, and pull-requests from the community. +introduced in Node-ChakraCore, and now supported by +[VSCode](https://github.com/microsoft/vscode/). We are developing in the open +and want to share our progress to get feedback, bug reports, functionality +requests, and pull-requests from the community. Check out this [Time-Travel Debugging](TTD-README.md) page to learn how to get started with TTD on Node-ChakraCore with VSCode. ### Node.js API (NAPI) -Node-ChakraCore is an active participant in the [ABI-Stable-Node](https://github.com/nodejs/abi-stable-node) -project also called NAPI. The goal of this project is to ease the lives of native -add-ons developers, by providing a stable Node API which also guarantees stable -ABI across disparate Node versions. This allows native modules to just work across +Node-ChakraCore is an active participant in the +[ABI-Stable-Node](https://github.com/nodejs/abi-stable-node) project also called +NAPI. The goal of this project is to ease the lives of native add-ons +developers, by providing a stable Node API which also guarantees stable ABI +across disparate Node versions. This allows native modules to just work across different versions and flavors of Node.js without recompilations, reducing the maintenance cost for module developers and thus improving compatibility. diff --git a/TTD-README.md b/TTD-README.md index cce1cbe6f92..644289a7c66 100644 --- a/TTD-README.md +++ b/TTD-README.md @@ -1,63 +1,73 @@ # Diagnostic Tracing and Time Travel Debugging with Node-ChakraCore -In post-mortem debugging scenarios, developers frequently find themselves +In post-mortem debugging scenarios, developers frequently find themselves hunting for failure clues (e.g. error text) in the log files and then searching -for those clues in their code. Once the log statement is found in the source code, -the developer is often left to re-construct the context of the error. +for those clues in their code. Once the log statement is found in the source +code, the developer is often left to re-construct the context of the error. -The cutting edge diagnostic capabilities in Node-ChakraCore allows developers to -look at the faulting code within the full fidelity of the debugger with all the -runtime context preserved, enabling them to deeply inspect the code as it was during -the original execution. Node-Chakracore has been extended with a suite of such features -to support tracing and reproducing program executions and a range of updates to improve -the time-travel debugging experience. +The cutting edge diagnostic capabilities in Node-ChakraCore allows developers to +look at the faulting code within the full fidelity of the debugger with all the +runtime context preserved, enabling them to deeply inspect the code as it was +during the original execution. Node-Chakracore has been extended with a suite of +such features to support tracing and reproducing program executions and a range +of updates to improve the time-travel debugging experience. -This project is being developed in the open and we are always happy to get feedback, bug reports, -functionality requests, and pull-requests from the community. +This project is being developed in the open and we are always happy to get +feedback, bug reports, functionality requests, and pull-requests from the +community. ## Diagnostic Tracing -Reproducing issues that depend on a specific interleaving of callbacks, specifics of -a server configuration or users system, or transient network/file-system behavior can be -challenging. To help simplify the process we have updated Node-ChakraCore with a suite -of **diagnostic tracing** features. These features allow you to record an application -execution using the `--record` flag and, then when any of the conditions listed below -occur, a diagnostic trace is written out to disk (with the location printed to -`stderr`). +Reproducing issues that depend on a specific interleaving of callbacks, +specifics of a server configuration or users system, or transient +network/file-system behavior can be challenging. To help simplify the process we +have updated Node-ChakraCore with a suite of **diagnostic tracing** features. +These features allow you to record an application execution using the `--record` +flag and, then when any of the conditions listed below occur, a diagnostic trace +is written out to disk (with the location printed to `stderr`). Default trace emit events: - Unhandled exceptions *always* emit a trace. - Exit with a non-zero exit code *always* emits a trace. -- Failed `asserts` *probabilistically* emit a trace with a backoff to prevent overloading. -- Calls to `console.error` and `console.warn` *probabilistically* emit a trace with a backoff to prevent overloading. +- Failed `asserts` *probabilistically* emit a trace with a backoff to prevent + overloading. +- Calls to `console.error` and `console.warn` *probabilistically* emit a trace + with a backoff to prevent overloading. - A `SIGINT` signal will *always* emit a trace. -When we run with our remote-file server [demo](https://github.com/mrkmarron/RFSDemoJS) with the record flag and -hit a bug in the file I/O code (followed by crtl-c on the command line) we get the output shown below. +When we run with our remote-file server +[demo](https://github.com/mrkmarron/RFSDemoJS) with the record flag and hit a +bug in the file I/O code (followed by crtl-c on the command line) we get the +output shown below. ![Running node with --record flag and two trace output events.](doc/ttd_assets/TraceSnap.png) -Once written to disk these trace directories can be used locally or copied to another machine -for later analysis and debugging. +Once written to disk these trace directories can be used locally or copied to +another machine for later analysis and debugging. -The animation below shows us launching the `TraceDebug` configuration in the VSCode debugger with the trace -directory argument set to the `emitOnSigInt` trace (written after seeing the file not found error). -When the trace hits the point where it raised and triggered for the error message write it will break into the debugger -allowing us to inspect local variables, the call stack and, set a breakpoint where the callback that received -the I/O error was registered. Then we reverse-execute back-in-time to this callback registration and can -inspect local variables as well as the full call stack as they existed then. +The animation below shows us launching the `TraceDebug` configuration in the +VSCode debugger with the trace directory argument set to the `emitOnSigInt` +trace (written after seeing the file not found error). When the trace hits the +point where it raised and triggered for the error message write it will break +into the debugger allowing us to inspect local variables, the call stack and, +set a breakpoint where the callback that received the I/O error was registered. +Then we reverse-execute back-in-time to this callback registration and can +inspect local variables as well as the full call stack as they existed then. ![Replay debugging with the --replay-debug flag and TTD.](doc/ttd_assets/TTDTrace.gif) -If desired we can single step-back through other statements as well or execute forward again, seeing the -exact set of statements and variable values that existed during the original execution, until we have -all the information we need to understand the problem. +If desired we can single step-back through other statements as well or execute +forward again, seeing the exact set of statements and variable values that +existed during the original execution, until we have all the information we need +to understand the problem. -## Time-Travel Debugging +## Time-Travel Debugging -TTD functionality is available in Node-ChakraCore and is supported by -[VSCode](https://code.visualstudio.com/). You can use VSCode to debug diagnostic +TTD functionality is available in Node-ChakraCore and is supported by +[VSCode](https://code.visualstudio.com/). You can use VSCode to debug diagnostic traces even if you don't have the project sources available. This is done by: - Creating an empty `dummy.js` file in the trace directory. -- Adding the following configuration into your `.vscode\launch.json` configuration file. +- Adding the following configuration into your `.vscode\launch.json` + configuration file. + ```json { "name": "Trace Debug", @@ -71,7 +81,7 @@ traces even if you don't have the project sources available. This is done by: "runtimeArgs": [ "run", "chakracore-nightly", - "--nolazy", + "--nolazy", "--break-first", "--replay-debug=./" ], @@ -83,29 +93,40 @@ traces even if you don't have the project sources available. This is done by: To get started with diagnostic tracing and TTD you will need the following: - Install [Node-ChakraCore](https://github.com/nodejs/node-chakracore/releases) - - (Recommended) install [NVS](https://github.com/jasongin/nvs/blob/master/README.md) which is a cross-platform tool for switching between different versions and forks of Node.js and will allow you to easily switch between Node-ChakraCore and other Node.js versions. Once NVS is installed simply enter the following commands in the console: - + - (Recommended) install + [NVS](https://github.com/jasongin/nvs/blob/master/README.md) which is a + cross-platform tool for switching between different versions and forks of + Node.js and will allow you to easily switch between Node-ChakraCore and + other Node.js versions. Once NVS is installed simply enter the following + commands in the console: + ```console $ nvs remote chakracore-nightly https://nodejs.org/download/chakracore-nightly/ $ nvs add chakracore-nightly/latest $ nvs use chakracore-nightly ``` - - (Manual) Download the build for your platform/architecture and manually add the location of the binaries to your path. + + - (Manual) Download the build for your platform/architecture and manually + add the location of the binaries to your path. - Install [VSCode](https://code.visualstudio.com/) using the latest installer. ## Sample Program -The code for the Remote File System sample demo'ed at NodeInteractive is available -[here](https://github.com/mrkmarron/RFSDemoJS). +The code for the Remote File System sample demo'ed at NodeInteractive is +available [here](https://github.com/mrkmarron/RFSDemoJS). -You can clone the repo to a location of your choice and `npm install` the dependencies. Once -you launch the application it will serve up the contents of the folder `testdata` on port 3000. The -application is designed to intermittently rename the files `hello_world.js <-> helloWorld.js` -in the background. So, as shown in the screenshot above, a warn trace can be triggered by interacting -with the application and clicking on this file at various times. You can always trigger a sigint -trace via crtl-c at the command line. +You can clone the repo to a location of your choice and `npm install` the +dependencies. Once you launch the application it will serve up the contents of +the folder `testdata` on port 3000. The application is designed to +intermittently rename the files `hello_world.js <-> helloWorld.js` in the +background. So, as shown in the screenshot above, a warn trace can be triggered +by interacting with the application and clicking on this file at various times. +You can always trigger a sigint trace via crtl-c at the command line. -Once this SIGINT trace is written it can be replay debugged in VSCode using the `TraceDebug` launch configuration and you can change the path if you want to debug other trace files that are written. +Once this SIGINT trace is written it can be replay debugged in VSCode using the +`TraceDebug` launch configuration and you can change the path if you want to +debug other trace files that are written. ## Feedback -Please let us know on our [issues page](https://github.com/nodejs/node-chakracore/issues) if -you have any question or comment. +Please let us know on our +[issues page](https://github.com/nodejs/node-chakracore/issues) if you have any +question or comment.