blob: b5c4b564881e322fe5252a3e8c40bde22924bf95 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// -------------------------------------------------------------------
6
7(function(global, utils) {
8
9%CheckIsBootstrapping();
10
11// -------------------------------------------------------------------
12// Imports
13
14var ArrayJoin;
15var Bool16x8ToString;
16var Bool32x4ToString;
17var Bool8x16ToString;
18var callSiteReceiverSymbol =
19 utils.ImportNow("call_site_receiver_symbol");
20var callSiteFunctionSymbol =
21 utils.ImportNow("call_site_function_symbol");
22var callSitePositionSymbol =
23 utils.ImportNow("call_site_position_symbol");
24var callSiteStrictSymbol =
25 utils.ImportNow("call_site_strict_symbol");
Ben Murdochc5610432016-08-08 18:44:38 +010026var callSiteWasmObjectSymbol =
27 utils.ImportNow("call_site_wasm_obj_symbol");
28var callSiteWasmFunctionIndexSymbol =
29 utils.ImportNow("call_site_wasm_func_index_symbol");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030var Float32x4ToString;
31var formattedStackTraceSymbol =
32 utils.ImportNow("formatted_stack_trace_symbol");
33var GlobalObject = global.Object;
34var Int16x8ToString;
35var Int32x4ToString;
36var Int8x16ToString;
37var InternalArray = utils.InternalArray;
38var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
Ben Murdochda12d292016-06-02 14:46:10 +010039var ObjectHasOwnProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000040var ObjectToString = utils.ImportNow("object_to_string");
41var Script = utils.ImportNow("Script");
42var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043var StringIndexOf;
44var StringSubstring;
45var SymbolToString;
46var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
47var Uint16x8ToString;
48var Uint32x4ToString;
49var Uint8x16ToString;
50
51utils.Import(function(from) {
52 ArrayJoin = from.ArrayJoin;
53 Bool16x8ToString = from.Bool16x8ToString;
54 Bool32x4ToString = from.Bool32x4ToString;
55 Bool8x16ToString = from.Bool8x16ToString;
56 Float32x4ToString = from.Float32x4ToString;
57 Int16x8ToString = from.Int16x8ToString;
58 Int32x4ToString = from.Int32x4ToString;
59 Int8x16ToString = from.Int8x16ToString;
Ben Murdochda12d292016-06-02 14:46:10 +010060 ObjectHasOwnProperty = from.ObjectHasOwnProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 StringIndexOf = from.StringIndexOf;
62 StringSubstring = from.StringSubstring;
63 SymbolToString = from.SymbolToString;
64 Uint16x8ToString = from.Uint16x8ToString;
65 Uint32x4ToString = from.Uint32x4ToString;
66 Uint8x16ToString = from.Uint8x16ToString;
67});
68
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069// -------------------------------------------------------------------
70
71var GlobalError;
72var GlobalTypeError;
73var GlobalRangeError;
74var GlobalURIError;
75var GlobalSyntaxError;
76var GlobalReferenceError;
77var GlobalEvalError;
78
79
80function NoSideEffectsObjectToString() {
81 if (IS_UNDEFINED(this)) return "[object Undefined]";
82 if (IS_NULL(this)) return "[object Null]";
83 var O = TO_OBJECT(this);
84 var builtinTag = %_ClassOf(O);
Ben Murdochda12d292016-06-02 14:46:10 +010085 var tag = %GetDataProperty(O, toStringTagSymbol);
86 if (!IS_STRING(tag)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 tag = builtinTag;
88 }
89 return `[object ${tag}]`;
90}
91
92function IsErrorObject(obj) {
93 return HAS_PRIVATE(obj, stackTraceSymbol);
94}
95
96function NoSideEffectsErrorToString() {
97 var name = %GetDataProperty(this, "name");
98 var message = %GetDataProperty(this, "message");
99 name = IS_UNDEFINED(name) ? "Error" : NoSideEffectsToString(name);
100 message = IS_UNDEFINED(message) ? "" : NoSideEffectsToString(message);
101 if (name == "") return message;
102 if (message == "") return name;
103 return `${name}: ${message}`;
104}
105
106function NoSideEffectsToString(obj) {
107 if (IS_STRING(obj)) return obj;
108 if (IS_NUMBER(obj)) return %_NumberToString(obj);
109 if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false';
110 if (IS_UNDEFINED(obj)) return 'undefined';
111 if (IS_NULL(obj)) return 'null';
112 if (IS_FUNCTION(obj)) {
113 var str = %FunctionToString(obj);
114 if (str.length > 128) {
115 str = %_SubString(str, 0, 111) + "...<omitted>..." +
116 %_SubString(str, str.length - 2, str.length);
117 }
118 return str;
119 }
120 if (IS_SYMBOL(obj)) return %_Call(SymbolToString, obj);
121 if (IS_SIMD_VALUE(obj)) {
122 switch (typeof(obj)) {
123 case 'float32x4': return %_Call(Float32x4ToString, obj);
124 case 'int32x4': return %_Call(Int32x4ToString, obj);
125 case 'int16x8': return %_Call(Int16x8ToString, obj);
126 case 'int8x16': return %_Call(Int8x16ToString, obj);
127 case 'uint32x4': return %_Call(Uint32x4ToString, obj);
128 case 'uint16x8': return %_Call(Uint16x8ToString, obj);
129 case 'uint8x16': return %_Call(Uint8x16ToString, obj);
130 case 'bool32x4': return %_Call(Bool32x4ToString, obj);
131 case 'bool16x8': return %_Call(Bool16x8ToString, obj);
132 case 'bool8x16': return %_Call(Bool8x16ToString, obj);
133 }
134 }
135
136 if (IS_RECEIVER(obj)) {
137 // When internally formatting error objects, use a side-effects-free version
138 // of Error.prototype.toString independent of the actually installed
139 // toString method.
140 if (IsErrorObject(obj) ||
141 %GetDataProperty(obj, "toString") === ErrorToString) {
142 return %_Call(NoSideEffectsErrorToString, obj);
143 }
144
145 if (%GetDataProperty(obj, "toString") === ObjectToString) {
146 var constructor = %GetDataProperty(obj, "constructor");
147 if (IS_FUNCTION(constructor)) {
148 var constructor_name = %FunctionGetName(constructor);
149 if (constructor_name != "") return `#<${constructor_name}>`;
150 }
151 }
152 }
153
154 return %_Call(NoSideEffectsObjectToString, obj);
155}
156
157
158function MakeGenericError(constructor, type, arg0, arg1, arg2) {
159 var error = new constructor(FormatMessage(type, arg0, arg1, arg2));
160 error[internalErrorSymbol] = true;
161 return error;
162}
163
164
165/**
166 * Set up the Script function and constructor.
167 */
168%FunctionSetInstanceClassName(Script, 'Script');
169%AddNamedProperty(Script.prototype, 'constructor', Script,
170 DONT_ENUM | DONT_DELETE | READ_ONLY);
171%SetCode(Script, function(x) {
172 // Script objects can only be created by the VM.
173 throw MakeError(kUnsupported);
174});
175
176
177// Helper functions; called from the runtime system.
178function FormatMessage(type, arg0, arg1, arg2) {
179 var arg0 = NoSideEffectsToString(arg0);
180 var arg1 = NoSideEffectsToString(arg1);
181 var arg2 = NoSideEffectsToString(arg2);
182 try {
183 return %FormatMessageString(type, arg0, arg1, arg2);
184 } catch (e) {
185 return "<error>";
186 }
187}
188
189
190function GetLineNumber(message) {
191 var start_position = %MessageGetStartPosition(message);
192 if (start_position == -1) return kNoLineNumberInfo;
193 var script = %MessageGetScript(message);
194 var location = script.locationFromPosition(start_position, true);
195 if (location == null) return kNoLineNumberInfo;
196 return location.line + 1;
197}
198
199
200//Returns the offset of the given position within the containing line.
201function GetColumnNumber(message) {
202 var script = %MessageGetScript(message);
203 var start_position = %MessageGetStartPosition(message);
204 var location = script.locationFromPosition(start_position, true);
205 if (location == null) return -1;
206 return location.column;
207}
208
209
210// Returns the source code line containing the given source
211// position, or the empty string if the position is invalid.
212function GetSourceLine(message) {
213 var script = %MessageGetScript(message);
214 var start_position = %MessageGetStartPosition(message);
215 var location = script.locationFromPosition(start_position, true);
216 if (location == null) return "";
217 return location.sourceText();
218}
219
220
221/**
222 * Find a line number given a specific source position.
223 * @param {number} position The source position.
224 * @return {number} 0 if input too small, -1 if input too large,
225 else the line number.
226 */
227function ScriptLineFromPosition(position) {
228 var lower = 0;
229 var upper = this.lineCount() - 1;
230 var line_ends = this.line_ends;
231
232 // We'll never find invalid positions so bail right away.
233 if (position > line_ends[upper]) {
234 return -1;
235 }
236
237 // This means we don't have to safe-guard indexing line_ends[i - 1].
238 if (position <= line_ends[0]) {
239 return 0;
240 }
241
242 // Binary search to find line # from position range.
243 while (upper >= 1) {
244 var i = (lower + upper) >> 1;
245
246 if (position > line_ends[i]) {
247 lower = i + 1;
248 } else if (position <= line_ends[i - 1]) {
249 upper = i - 1;
250 } else {
251 return i;
252 }
253 }
254
255 return -1;
256}
257
Ben Murdochc5610432016-08-08 18:44:38 +0100258
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259/**
260 * Get information on a specific source position.
261 * @param {number} position The source position
262 * @param {boolean} include_resource_offset Set to true to have the resource
263 * offset added to the location
264 * @return {SourceLocation}
265 * If line is negative or not in the source null is returned.
266 */
267function ScriptLocationFromPosition(position,
268 include_resource_offset) {
269 var line = this.lineFromPosition(position);
270 if (line == -1) return null;
271
272 // Determine start, end and column.
273 var line_ends = this.line_ends;
274 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
275 var end = line_ends[line];
Ben Murdochc5610432016-08-08 18:44:38 +0100276 if (end > 0 && %_StringCharAt(this.source, end - 1) === '\r') {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 end--;
278 }
279 var column = position - start;
280
281 // Adjust according to the offset within the resource.
282 if (include_resource_offset) {
283 line += this.line_offset;
284 if (line == this.line_offset) {
285 column += this.column_offset;
286 }
287 }
288
289 return new SourceLocation(this, position, line, column, start, end);
290}
291
292
293/**
294 * Get information on a specific source line and column possibly offset by a
295 * fixed source position. This function is used to find a source position from
296 * a line and column position. The fixed source position offset is typically
297 * used to find a source position in a function based on a line and column in
298 * the source for the function alone. The offset passed will then be the
299 * start position of the source for the function within the full script source.
300 * @param {number} opt_line The line within the source. Default value is 0
301 * @param {number} opt_column The column in within the line. Default value is 0
302 * @param {number} opt_offset_position The offset from the begining of the
303 * source from where the line and column calculation starts.
304 * Default value is 0
305 * @return {SourceLocation}
306 * If line is negative or not in the source null is returned.
307 */
308function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
309 // Default is the first line in the script. Lines in the script is relative
310 // to the offset within the resource.
311 var line = 0;
312 if (!IS_UNDEFINED(opt_line)) {
313 line = opt_line - this.line_offset;
314 }
315
316 // Default is first column. If on the first line add the offset within the
317 // resource.
318 var column = opt_column || 0;
319 if (line == 0) {
320 column -= this.column_offset;
321 }
322
323 var offset_position = opt_offset_position || 0;
324 if (line < 0 || column < 0 || offset_position < 0) return null;
325 if (line == 0) {
326 return this.locationFromPosition(offset_position + column, false);
327 } else {
328 // Find the line where the offset position is located.
329 var offset_line = this.lineFromPosition(offset_position);
330
331 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
332 return null;
333 }
334
335 return this.locationFromPosition(
336 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
337 }
338}
339
340
341/**
342 * Get a slice of source code from the script. The boundaries for the slice is
343 * specified in lines.
344 * @param {number} opt_from_line The first line (zero bound) in the slice.
345 * Default is 0
346 * @param {number} opt_to_column The last line (zero bound) in the slice (non
347 * inclusive). Default is the number of lines in the script
348 * @return {SourceSlice} The source slice or null of the parameters where
349 * invalid
350 */
351function ScriptSourceSlice(opt_from_line, opt_to_line) {
352 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
353 : opt_from_line;
354 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
355 : opt_to_line;
356
357 // Adjust according to the offset within the resource.
358 from_line -= this.line_offset;
359 to_line -= this.line_offset;
360 if (from_line < 0) from_line = 0;
361 if (to_line > this.lineCount()) to_line = this.lineCount();
362
363 // Check parameters.
364 if (from_line >= this.lineCount() ||
365 to_line < 0 ||
366 from_line > to_line) {
367 return null;
368 }
369
370 var line_ends = this.line_ends;
371 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
372 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
373
374 // Return a source slice with line numbers re-adjusted to the resource.
375 return new SourceSlice(this,
376 from_line + this.line_offset,
377 to_line + this.line_offset,
378 from_position, to_position);
379}
380
381
382function ScriptSourceLine(opt_line) {
383 // Default is the first line in the script. Lines in the script are relative
384 // to the offset within the resource.
385 var line = 0;
386 if (!IS_UNDEFINED(opt_line)) {
387 line = opt_line - this.line_offset;
388 }
389
390 // Check parameter.
391 if (line < 0 || this.lineCount() <= line) {
392 return null;
393 }
394
395 // Return the source line.
396 var line_ends = this.line_ends;
397 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
398 var end = line_ends[line];
399 return %_Call(StringSubstring, this.source, start, end);
400}
401
402
403/**
404 * Returns the number of source lines.
405 * @return {number}
406 * Number of source lines.
407 */
408function ScriptLineCount() {
409 // Return number of source lines.
410 return this.line_ends.length;
411}
412
413
414/**
415 * Returns the position of the nth line end.
416 * @return {number}
417 * Zero-based position of the nth line end in the script.
418 */
419function ScriptLineEnd(n) {
420 return this.line_ends[n];
421}
422
423
424/**
425 * If sourceURL comment is available returns sourceURL comment contents.
426 * Otherwise, script name is returned. See
427 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
428 * and Source Map Revision 3 proposal for details on using //# sourceURL and
429 * deprecated //@ sourceURL comment to identify scripts that don't have name.
430 *
431 * @return {?string} script name if present, value for //# sourceURL comment or
432 * deprecated //@ sourceURL comment otherwise.
433 */
434function ScriptNameOrSourceURL() {
435 if (this.source_url) return this.source_url;
436 return this.name;
437}
438
439
440utils.SetUpLockedPrototype(Script, [
441 "source",
442 "name",
443 "source_url",
444 "source_mapping_url",
445 "line_ends",
446 "line_offset",
447 "column_offset"
448 ], [
449 "lineFromPosition", ScriptLineFromPosition,
450 "locationFromPosition", ScriptLocationFromPosition,
451 "locationFromLine", ScriptLocationFromLine,
452 "sourceSlice", ScriptSourceSlice,
453 "sourceLine", ScriptSourceLine,
454 "lineCount", ScriptLineCount,
455 "nameOrSourceURL", ScriptNameOrSourceURL,
456 "lineEnd", ScriptLineEnd
457 ]
458);
459
460
461/**
462 * Class for source location. A source location is a position within some
463 * source with the following properties:
464 * script : script object for the source
465 * line : source line number
466 * column : source column within the line
467 * position : position within the source
468 * start : position of start of source context (inclusive)
469 * end : position of end of source context (not inclusive)
470 * Source text for the source context is the character interval
471 * [start, end[. In most cases end will point to a newline character.
472 * It might point just past the final position of the source if the last
473 * source line does not end with a newline character.
474 * @param {Script} script The Script object for which this is a location
475 * @param {number} position Source position for the location
476 * @param {number} line The line number for the location
477 * @param {number} column The column within the line for the location
478 * @param {number} start Source position for start of source context
479 * @param {number} end Source position for end of source context
480 * @constructor
481 */
482function SourceLocation(script, position, line, column, start, end) {
483 this.script = script;
484 this.position = position;
485 this.line = line;
486 this.column = column;
487 this.start = start;
488 this.end = end;
489}
490
491
492/**
493 * Get the source text for a SourceLocation
494 * @return {String}
495 * Source text for this location.
496 */
497function SourceLocationSourceText() {
498 return %_Call(StringSubstring, this.script.source, this.start, this.end);
499}
500
501
502utils.SetUpLockedPrototype(SourceLocation,
503 ["script", "position", "line", "column", "start", "end"],
504 ["sourceText", SourceLocationSourceText]
505);
506
507
508/**
509 * Class for a source slice. A source slice is a part of a script source with
510 * the following properties:
511 * script : script object for the source
512 * from_line : line number for the first line in the slice
513 * to_line : source line number for the last line in the slice
514 * from_position : position of the first character in the slice
515 * to_position : position of the last character in the slice
516 * The to_line and to_position are not included in the slice, that is the lines
517 * in the slice are [from_line, to_line[. Likewise the characters in the slice
518 * are [from_position, to_position[.
519 * @param {Script} script The Script object for the source slice
520 * @param {number} from_line
521 * @param {number} to_line
522 * @param {number} from_position
523 * @param {number} to_position
524 * @constructor
525 */
526function SourceSlice(script, from_line, to_line, from_position, to_position) {
527 this.script = script;
528 this.from_line = from_line;
529 this.to_line = to_line;
530 this.from_position = from_position;
531 this.to_position = to_position;
532}
533
534/**
535 * Get the source text for a SourceSlice
536 * @return {String} Source text for this slice. The last line will include
537 * the line terminating characters (if any)
538 */
539function SourceSliceSourceText() {
540 return %_Call(StringSubstring,
541 this.script.source,
542 this.from_position,
543 this.to_position);
544}
545
546utils.SetUpLockedPrototype(SourceSlice,
547 ["script", "from_line", "to_line", "from_position", "to_position"],
548 ["sourceText", SourceSliceSourceText]
549);
550
551
552function GetStackTraceLine(recv, fun, pos, isGlobal) {
553 return new CallSite(recv, fun, pos, false).toString();
554}
555
556// ----------------------------------------------------------------------------
557// Error implementation
558
559function CallSite(receiver, fun, pos, strict_mode) {
Ben Murdochc5610432016-08-08 18:44:38 +0100560 // For wasm frames, receiver is the wasm object and fun is the function index
561 // instead of an actual function.
562 if (!IS_FUNCTION(fun) && !IS_NUMBER(fun)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000563 throw MakeTypeError(kCallSiteExpectsFunction, typeof fun);
564 }
565
566 if (IS_UNDEFINED(new.target)) {
567 return new CallSite(receiver, fun, pos, strict_mode);
568 }
569
Ben Murdochc5610432016-08-08 18:44:38 +0100570 if (IS_FUNCTION(fun)) {
571 SET_PRIVATE(this, callSiteReceiverSymbol, receiver);
572 SET_PRIVATE(this, callSiteFunctionSymbol, fun);
573 } else {
574 SET_PRIVATE(this, callSiteWasmObjectSymbol, receiver);
575 SET_PRIVATE(this, callSiteWasmFunctionIndexSymbol, TO_UINT32(fun));
576 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 SET_PRIVATE(this, callSitePositionSymbol, TO_INT32(pos));
578 SET_PRIVATE(this, callSiteStrictSymbol, TO_BOOLEAN(strict_mode));
579}
580
Ben Murdochda12d292016-06-02 14:46:10 +0100581function CheckCallSite(obj, name) {
Ben Murdochc5610432016-08-08 18:44:38 +0100582 if (!IS_RECEIVER(obj) || !HAS_PRIVATE(obj, callSitePositionSymbol)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100583 throw MakeTypeError(kCallSiteMethod, name);
584 }
585}
586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587function CallSiteGetThis() {
Ben Murdochda12d292016-06-02 14:46:10 +0100588 CheckCallSite(this, "getThis");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000589 return GET_PRIVATE(this, callSiteStrictSymbol)
590 ? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol);
591}
592
593function CallSiteGetFunction() {
Ben Murdochda12d292016-06-02 14:46:10 +0100594 CheckCallSite(this, "getFunction");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000595 return GET_PRIVATE(this, callSiteStrictSymbol)
596 ? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol);
597}
598
599function CallSiteGetPosition() {
Ben Murdochda12d292016-06-02 14:46:10 +0100600 CheckCallSite(this, "getPosition");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601 return GET_PRIVATE(this, callSitePositionSymbol);
602}
603
604function CallSiteGetTypeName() {
Ben Murdochda12d292016-06-02 14:46:10 +0100605 CheckCallSite(this, "getTypeName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000606 return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false);
607}
608
609function CallSiteIsToplevel() {
Ben Murdochda12d292016-06-02 14:46:10 +0100610 CheckCallSite(this, "isTopLevel");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 return %CallSiteIsToplevelRT(this);
612}
613
614function CallSiteIsEval() {
Ben Murdochda12d292016-06-02 14:46:10 +0100615 CheckCallSite(this, "isEval");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616 return %CallSiteIsEvalRT(this);
617}
618
619function CallSiteGetEvalOrigin() {
Ben Murdochda12d292016-06-02 14:46:10 +0100620 CheckCallSite(this, "getEvalOrigin");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000621 var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol));
622 return FormatEvalOrigin(script);
623}
624
625function CallSiteGetScriptNameOrSourceURL() {
Ben Murdochda12d292016-06-02 14:46:10 +0100626 CheckCallSite(this, "getScriptNameOrSourceURL");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627 return %CallSiteGetScriptNameOrSourceUrlRT(this);
628}
629
630function CallSiteGetFunctionName() {
631 // See if the function knows its own name
Ben Murdochda12d292016-06-02 14:46:10 +0100632 CheckCallSite(this, "getFunctionName");
Ben Murdochc5610432016-08-08 18:44:38 +0100633 if (HAS_PRIVATE(this, callSiteWasmObjectSymbol)) {
634 var wasm = GET_PRIVATE(this, callSiteWasmObjectSymbol);
635 var func_index = GET_PRIVATE(this, callSiteWasmFunctionIndexSymbol);
636 if (IS_UNDEFINED(wasm)) return "<WASM>";
637 return %WasmGetFunctionName(wasm, func_index);
638 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 return %CallSiteGetFunctionNameRT(this);
640}
641
642function CallSiteGetMethodName() {
643 // See if we can find a unique property on the receiver that holds
644 // this function.
Ben Murdochda12d292016-06-02 14:46:10 +0100645 CheckCallSite(this, "getMethodName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000646 return %CallSiteGetMethodNameRT(this);
647}
648
649function CallSiteGetFileName() {
Ben Murdochda12d292016-06-02 14:46:10 +0100650 CheckCallSite(this, "getFileName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000651 return %CallSiteGetFileNameRT(this);
652}
653
654function CallSiteGetLineNumber() {
Ben Murdochc5610432016-08-08 18:44:38 +0100655 if (HAS_PRIVATE(this, callSiteWasmObjectSymbol)) {
656 return GET_PRIVATE(this, callSiteWasmFunctionIndexSymbol);
657 }
Ben Murdochda12d292016-06-02 14:46:10 +0100658 CheckCallSite(this, "getLineNumber");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659 return %CallSiteGetLineNumberRT(this);
660}
661
662function CallSiteGetColumnNumber() {
Ben Murdochda12d292016-06-02 14:46:10 +0100663 CheckCallSite(this, "getColumnNumber");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 return %CallSiteGetColumnNumberRT(this);
665}
666
667function CallSiteIsNative() {
Ben Murdochda12d292016-06-02 14:46:10 +0100668 CheckCallSite(this, "isNative");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 return %CallSiteIsNativeRT(this);
670}
671
672function CallSiteIsConstructor() {
Ben Murdochda12d292016-06-02 14:46:10 +0100673 CheckCallSite(this, "isConstructor");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000674 return %CallSiteIsConstructorRT(this);
675}
676
677function CallSiteToString() {
Ben Murdochc5610432016-08-08 18:44:38 +0100678 if (HAS_PRIVATE(this, callSiteWasmObjectSymbol)) {
679 var funName = this.getFunctionName();
680 var funcIndex = GET_PRIVATE(this, callSiteWasmFunctionIndexSymbol);
681 var pos = this.getPosition();
682 return funName + " (<WASM>:" + funcIndex + ":" + pos + ")";
683 }
684
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 var fileName;
686 var fileLocation = "";
687 if (this.isNative()) {
688 fileLocation = "native";
689 } else {
690 fileName = this.getScriptNameOrSourceURL();
691 if (!fileName && this.isEval()) {
692 fileLocation = this.getEvalOrigin();
693 fileLocation += ", "; // Expecting source position to follow.
694 }
695
696 if (fileName) {
697 fileLocation += fileName;
698 } else {
699 // Source code does not originate from a file and is not native, but we
700 // can still get the source position inside the source string, e.g. in
701 // an eval string.
702 fileLocation += "<anonymous>";
703 }
704 var lineNumber = this.getLineNumber();
705 if (lineNumber != null) {
706 fileLocation += ":" + lineNumber;
707 var columnNumber = this.getColumnNumber();
708 if (columnNumber) {
709 fileLocation += ":" + columnNumber;
710 }
711 }
712 }
713
714 var line = "";
715 var functionName = this.getFunctionName();
716 var addSuffix = true;
717 var isConstructor = this.isConstructor();
718 var isMethodCall = !(this.isToplevel() || isConstructor);
719 if (isMethodCall) {
720 var typeName = GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), true);
721 var methodName = this.getMethodName();
722 if (functionName) {
723 if (typeName && %_Call(StringIndexOf, functionName, typeName) != 0) {
724 line += typeName + ".";
725 }
726 line += functionName;
727 if (methodName &&
728 (%_Call(StringIndexOf, functionName, "." + methodName) !=
729 functionName.length - methodName.length - 1)) {
730 line += " [as " + methodName + "]";
731 }
732 } else {
733 line += typeName + "." + (methodName || "<anonymous>");
734 }
735 } else if (isConstructor) {
736 line += "new " + (functionName || "<anonymous>");
737 } else if (functionName) {
738 line += functionName;
739 } else {
740 line += fileLocation;
741 addSuffix = false;
742 }
743 if (addSuffix) {
744 line += " (" + fileLocation + ")";
745 }
746 return line;
747}
748
749utils.SetUpLockedPrototype(CallSite, ["receiver", "fun", "pos"], [
750 "getThis", CallSiteGetThis,
751 "getTypeName", CallSiteGetTypeName,
752 "isToplevel", CallSiteIsToplevel,
753 "isEval", CallSiteIsEval,
754 "getEvalOrigin", CallSiteGetEvalOrigin,
755 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
756 "getFunction", CallSiteGetFunction,
757 "getFunctionName", CallSiteGetFunctionName,
758 "getMethodName", CallSiteGetMethodName,
759 "getFileName", CallSiteGetFileName,
760 "getLineNumber", CallSiteGetLineNumber,
761 "getColumnNumber", CallSiteGetColumnNumber,
762 "isNative", CallSiteIsNative,
763 "getPosition", CallSiteGetPosition,
764 "isConstructor", CallSiteIsConstructor,
765 "toString", CallSiteToString
766]);
767
768
769function FormatEvalOrigin(script) {
770 var sourceURL = script.nameOrSourceURL();
771 if (sourceURL) {
772 return sourceURL;
773 }
774
775 var eval_origin = "eval at ";
776 if (script.eval_from_function_name) {
777 eval_origin += script.eval_from_function_name;
778 } else {
779 eval_origin += "<anonymous>";
780 }
781
782 var eval_from_script = script.eval_from_script;
783 if (eval_from_script) {
784 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
785 // eval script originated from another eval.
786 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
787 } else {
788 // eval script originated from "real" source.
789 if (eval_from_script.name) {
790 eval_origin += " (" + eval_from_script.name;
791 var location = eval_from_script.locationFromPosition(
792 script.eval_from_script_position, true);
793 if (location) {
794 eval_origin += ":" + (location.line + 1);
795 eval_origin += ":" + (location.column + 1);
796 }
797 eval_origin += ")";
798 } else {
799 eval_origin += " (unknown source)";
800 }
801 }
802 }
803
804 return eval_origin;
805}
806
807
808function FormatErrorString(error) {
809 try {
810 return %_Call(ErrorToString, error);
811 } catch (e) {
812 try {
813 return "<error: " + e + ">";
814 } catch (ee) {
815 return "<error>";
816 }
817 }
818}
819
820
821function GetStackFrames(raw_stack) {
Ben Murdochc5610432016-08-08 18:44:38 +0100822 var internal_raw_stack = new InternalArray();
823 %MoveArrayContents(raw_stack, internal_raw_stack);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824 var frames = new InternalArray();
Ben Murdochc5610432016-08-08 18:44:38 +0100825 var sloppy_frames = internal_raw_stack[0];
826 for (var i = 1; i < internal_raw_stack.length; i += 4) {
827 var recv = internal_raw_stack[i];
828 var fun = internal_raw_stack[i + 1];
829 var code = internal_raw_stack[i + 2];
830 var pc = internal_raw_stack[i + 3];
831 // For traps in wasm, the bytecode offset is passed as (-1 - offset).
832 // Otherwise, lookup the position from the pc.
833 var pos = IS_NUMBER(fun) && pc < 0 ? (-1 - pc) :
834 %FunctionGetPositionForOffset(code, pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 sloppy_frames--;
836 frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
837 }
838 return frames;
839}
840
841
842// Flag to prevent recursive call of Error.prepareStackTrace.
843var formatting_custom_stack_trace = false;
844
845
846function FormatStackTrace(obj, raw_stack) {
847 var frames = GetStackFrames(raw_stack);
848 if (IS_FUNCTION(GlobalError.prepareStackTrace) &&
849 !formatting_custom_stack_trace) {
850 var array = [];
851 %MoveArrayContents(frames, array);
852 formatting_custom_stack_trace = true;
853 var stack_trace = UNDEFINED;
854 try {
855 stack_trace = GlobalError.prepareStackTrace(obj, array);
856 } catch (e) {
857 throw e; // The custom formatting function threw. Rethrow.
858 } finally {
859 formatting_custom_stack_trace = false;
860 }
861 return stack_trace;
862 }
863
864 var lines = new InternalArray();
865 lines.push(FormatErrorString(obj));
866 for (var i = 0; i < frames.length; i++) {
867 var frame = frames[i];
868 var line;
869 try {
870 line = frame.toString();
871 } catch (e) {
872 try {
873 line = "<error: " + e + ">";
874 } catch (ee) {
875 // Any code that reaches this point is seriously nasty!
876 line = "<error>";
877 }
878 }
879 lines.push(" at " + line);
880 }
881 return %_Call(ArrayJoin, lines, "\n");
882}
883
884
885function GetTypeName(receiver, requireConstructor) {
886 if (IS_NULL_OR_UNDEFINED(receiver)) return null;
887 if (IS_PROXY(receiver)) return "Proxy";
888
889 var constructor = %GetDataProperty(TO_OBJECT(receiver), "constructor");
890 if (!IS_FUNCTION(constructor)) {
891 return requireConstructor ? null : %_Call(NoSideEffectsToString, receiver);
892 }
893 return %FunctionGetName(constructor);
894}
895
896
897// Format the stack trace if not yet done, and return it.
898// Cache the formatted stack trace on the holder.
899var StackTraceGetter = function() {
900 var formatted_stack_trace = UNDEFINED;
901 var holder = this;
902 while (holder) {
903 var formatted_stack_trace =
904 GET_PRIVATE(holder, formattedStackTraceSymbol);
905 if (IS_UNDEFINED(formatted_stack_trace)) {
906 // No formatted stack trace available.
907 var stack_trace = GET_PRIVATE(holder, stackTraceSymbol);
908 if (IS_UNDEFINED(stack_trace)) {
909 // Neither formatted nor structured stack trace available.
910 // Look further up the prototype chain.
Ben Murdochc5610432016-08-08 18:44:38 +0100911 holder = %object_get_prototype_of(holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 continue;
913 }
914 formatted_stack_trace = FormatStackTrace(holder, stack_trace);
915 SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED);
916 SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace);
917 }
918 return formatted_stack_trace;
919 }
920 return UNDEFINED;
921};
922
923
924// If the receiver equals the holder, set the formatted stack trace that the
925// getter returns.
926var StackTraceSetter = function(v) {
927 if (IsErrorObject(this)) {
928 SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
929 SET_PRIVATE(this, formattedStackTraceSymbol, v);
930 }
931};
932
933
934// Use a dummy function since we do not actually want to capture a stack trace
935// when constructing the initial Error prototytpes.
936var captureStackTrace = function() {};
937
938
939// Set up special error type constructors.
940function SetUpError(error_function) {
941 %FunctionSetInstanceClassName(error_function, 'Error');
942 var name = error_function.name;
943 var prototype = new GlobalObject();
944 if (name !== 'Error') {
945 %InternalSetPrototype(error_function, GlobalError);
946 %InternalSetPrototype(prototype, GlobalError.prototype);
947 }
948 %FunctionSetPrototype(error_function, prototype);
949
950 %AddNamedProperty(error_function.prototype, 'name', name, DONT_ENUM);
951 %AddNamedProperty(error_function.prototype, 'message', '', DONT_ENUM);
952 %AddNamedProperty(
953 error_function.prototype, 'constructor', error_function, DONT_ENUM);
954
955 %SetCode(error_function, function(m) {
956 if (IS_UNDEFINED(new.target)) return new error_function(m);
957
958 try { captureStackTrace(this, error_function); } catch (e) { }
959 // Define all the expected properties directly on the error
960 // object. This avoids going through getters and setters defined
961 // on prototype objects.
962 if (!IS_UNDEFINED(m)) {
963 %AddNamedProperty(this, 'message', TO_STRING(m), DONT_ENUM);
964 }
965 });
966
967 %SetNativeFlag(error_function);
968 return error_function;
969};
970
971GlobalError = SetUpError(global.Error);
972GlobalEvalError = SetUpError(global.EvalError);
973GlobalRangeError = SetUpError(global.RangeError);
974GlobalReferenceError = SetUpError(global.ReferenceError);
975GlobalSyntaxError = SetUpError(global.SyntaxError);
976GlobalTypeError = SetUpError(global.TypeError);
977GlobalURIError = SetUpError(global.URIError);
978
979utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
980 ['toString', ErrorToString]);
981
982function ErrorToString() {
983 if (!IS_RECEIVER(this)) {
984 throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
985 }
986
987 var name = this.name;
988 name = IS_UNDEFINED(name) ? "Error" : TO_STRING(name);
989
990 var message = this.message;
991 message = IS_UNDEFINED(message) ? "" : TO_STRING(message);
992
993 if (name == "") return message;
994 if (message == "") return name;
995 return `${name}: ${message}`
996}
997
998function MakeError(type, arg0, arg1, arg2) {
999 return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
1000}
1001
1002function MakeRangeError(type, arg0, arg1, arg2) {
1003 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
1004}
1005
1006function MakeSyntaxError(type, arg0, arg1, arg2) {
1007 return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2);
1008}
1009
1010function MakeTypeError(type, arg0, arg1, arg2) {
1011 return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2);
1012}
1013
1014function MakeURIError() {
1015 return MakeGenericError(GlobalURIError, kURIMalformed);
1016}
1017
1018// Boilerplate for exceptions for stack overflows. Used from
1019// Isolate::StackOverflow().
1020var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
1021utils.InstallGetterSetter(StackOverflowBoilerplate, 'stack',
1022 StackTraceGetter, StackTraceSetter)
1023
1024// Define actual captureStackTrace function after everything has been set up.
1025captureStackTrace = function captureStackTrace(obj, cons_opt) {
1026 // Define accessors first, as this may fail and throw.
Ben Murdochc5610432016-08-08 18:44:38 +01001027 %object_define_property(obj, 'stack', { get: StackTraceGetter,
1028 set: StackTraceSetter,
1029 configurable: true });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030 %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
1031};
1032
1033GlobalError.captureStackTrace = captureStackTrace;
1034
1035%InstallToContext([
1036 "get_stack_trace_line_fun", GetStackTraceLine,
1037 "make_error_function", MakeGenericError,
1038 "make_range_error", MakeRangeError,
1039 "make_type_error", MakeTypeError,
1040 "message_get_column_number", GetColumnNumber,
1041 "message_get_line_number", GetLineNumber,
1042 "message_get_source_line", GetSourceLine,
1043 "no_side_effects_to_string_fun", NoSideEffectsToString,
1044 "stack_overflow_boilerplate", StackOverflowBoilerplate,
1045]);
1046
1047utils.Export(function(to) {
1048 to.ErrorToString = ErrorToString;
1049 to.MakeError = MakeError;
1050 to.MakeRangeError = MakeRangeError;
1051 to.MakeSyntaxError = MakeSyntaxError;
1052 to.MakeTypeError = MakeTypeError;
1053 to.MakeURIError = MakeURIError;
1054});
1055
1056});