Skip to content

Commit 32b85f9

Browse files
committed
chakrashim: bug fixes for Error APIs
1. We parse error stack in chakra_shim to make it simliar to that of v8. However we were missing the case if stack messages has `\n`. Fixed it. Fixes: nodejs#78 2. Fixed Error.captureStackTrace Since `chakra_shim.js` that patches `Error.captureStackTrace` runs under strict mode, it was not able to get caller information. Having caller information is much reliable in captureStackTrace than matching using `function.name`. Removed `use strict` and disabled eslint rule for `use strict`. This helped in matching caller exactly regardless of name of form `o.p.q` in `Error.captureStackTrace`. Fixes: nodejs#75 3. Added missing functions on StackFrame Added following missing methods on StackFrame: * getFunction * getMethodName * getTypeName * isConstructor * isToplevel * isNative Implemented `getFunction`. `getFunction` currently works if `.stack` is called from same callsite where `new Error()` or `Error.captureStackTrace()` was called. However currently we don't record and store the callstack when these functions were called and so we lose the information of `.caller` when called later while populating `e.stack`. If we save the callstack, we would be holding references to all the functions in the callstack which doesn't seem right. I have added a TODO to solve this, but wanted to send this out so we get better coverage on node compatibility. Fixes : nodejs#70 PR-URL: nodejs/node-chakracore#85 Reviewed-By: Jianchun Xu <[email protected]>
1 parent fa65467 commit 32b85f9

File tree

1 file changed

+69
-26
lines changed

1 file changed

+69
-26
lines changed

deps/chakrashim/lib/chakra_shim.js

+69-26
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1818
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
1919
// IN THE SOFTWARE.
20-
'use strict';
2120

21+
/* eslint-disable strict */
2222
(function(keepAlive) {
2323
// Save original builtIns
2424
var
@@ -42,13 +42,29 @@
4242
var global = this;
4343

4444
// Simulate V8 JavaScript stack trace API
45-
function StackFrame(funcName, fileName, lineNumber, columnNumber) {
45+
function StackFrame(func, funcName, fileName, lineNumber, columnNumber) {
4646
this.column = columnNumber;
4747
this.lineNumber = lineNumber;
4848
this.scriptName = fileName;
4949
this.functionName = funcName;
50+
this.function = func;
5051
}
5152

53+
StackFrame.prototype.getFunction = function() {
54+
// TODO: Fix if .stack is called from different callsite
55+
// from where Error() or Error.captureStackTrace was called
56+
return this.function;
57+
};
58+
59+
StackFrame.prototype.getTypeName = function() {
60+
//TODO : Fix this
61+
return this.functionName;
62+
};
63+
64+
StackFrame.prototype.getMethodName = function() {
65+
return this.functionName;
66+
};
67+
5268
StackFrame.prototype.getFunctionName = function() {
5369
return this.functionName;
5470
};
@@ -70,6 +86,21 @@
7086
return false;
7187
};
7288

89+
StackFrame.prototype.isToplevel = function() {
90+
// TODO
91+
return false;
92+
};
93+
94+
StackFrame.prototype.isNative = function() {
95+
// TODO
96+
return false;
97+
};
98+
99+
StackFrame.prototype.isConstructor = function() {
100+
// TODO
101+
return false;
102+
};
103+
73104
StackFrame.prototype.toString = function() {
74105
return (this.functionName || 'Anonymous function') + ' (' +
75106
this.scriptName + ':' + this.lineNumber + ':' + this.column + ')';
@@ -89,13 +120,32 @@
89120
// Parse 'stack' string into StackTrace frames. Skip top 'skipDepth' frames,
90121
// and optionally skip top to 'startName' function frames.
91122
function parseStack(stack, skipDepth, startName) {
92-
var splittedStack = stack.split('\n');
93-
splittedStack.splice(0, skipDepth + 1); // also skip top name/message line
123+
var stackSplitter = /\)\s*at/;
124+
var reStackDetails = /\s(?:at\s)?(.*)\s\((.*)/;
125+
var fileDetailsSplitter = /:(\d+)/;
126+
127+
var curr = parseStack;
128+
var splittedStack = stack.split(stackSplitter);
94129
var errstack = [];
95130

96131
for (var i = 0; i < splittedStack.length; i++) {
97-
var parens = /\(/.exec(splittedStack[i]);
98-
var funcName = splittedStack[i].substr(6, parens.index - 7);
132+
// parseStack has 1 frame lesser than skipDepth. So skip calling .caller
133+
// once. After that, continue calling .caller
134+
if (skipDepth != 1 && curr) {
135+
try {
136+
curr = curr.caller;
137+
} catch (e) {
138+
curr = undefined; // .caller might not be allowed in curr's context
139+
}
140+
}
141+
142+
if (skipDepth-- > 0) {
143+
continue;
144+
}
145+
146+
var func = curr;
147+
var stackDetails = reStackDetails.exec(splittedStack[i]);
148+
var funcName = stackDetails[1];
99149

100150
if (startName) {
101151
if (funcName === startName) {
@@ -107,28 +157,14 @@
107157
funcName = null;
108158
}
109159

110-
var location = splittedStack[i].substr(parens.index + 1,
111-
splittedStack[i].length - parens.index - 2);
160+
var fileDetails = stackDetails[2].split(fileDetailsSplitter);
112161

113-
var fileName = location;
114-
var lineNumber = 0;
115-
var columnNumber = 0;
162+
var fileName = fileDetails[0];
163+
var lineNumber = fileDetails[1] ? fileDetails[1] : 0;
164+
var columnNumber = fileDetails[3] ? fileDetails[3] : 0;
116165

117-
var colonPattern = /:[0-9]+/g;
118-
var firstColon = colonPattern.exec(location);
119-
if (firstColon) {
120-
fileName = location.substr(0, firstColon.index);
121-
122-
var secondColon = colonPattern.exec(location);
123-
if (secondColon) {
124-
lineNumber = parseInt(location.substr(firstColon.index + 1,
125-
secondColon.index - firstColon.index - 1), 10);
126-
columnNumber = parseInt(location.substr(secondColon.index + 1,
127-
location.length - secondColon.index), 10);
128-
}
129-
}
130166
errstack.push(
131-
new StackFrame(funcName, fileName, lineNumber, columnNumber));
167+
new StackFrame(func, funcName, fileName, lineNumber, columnNumber));
132168
}
133169
return errstack;
134170
}
@@ -190,7 +226,7 @@
190226

191227
var funcSkipDepth = findFuncDepth(func);
192228
var startFuncName = (func && funcSkipDepth < 0) ? func.name : undefined;
193-
skipDepth += Math.max(funcSkipDepth, 0);
229+
skipDepth += Math.max(funcSkipDepth - 1, 0);
194230

195231
var currentStackTrace;
196232
function ensureStackTrace() {
@@ -216,6 +252,13 @@
216252
// this Chakra runtime would reset stack at throw time.
217253
Reflect_apply(oldStackDesc.set, e, [value]);
218254
}
255+
256+
// To retain overriden stackAccessors below,notify Chakra runtime to not
257+
// reset stack for this error object.
258+
if (e !== err) {
259+
Reflect_apply(oldStackDesc.set, err, ['']);
260+
}
261+
219262
Object_defineProperty(err, 'stack', {
220263
get: stackGetter, set: stackSetter, configurable: true, enumerable: false
221264
});

0 commit comments

Comments
 (0)