blob: f8cb967cdd064238ebbe75bf50edc2be168271f6 [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 Murdoch4a90d5f2016-03-22 12:00:34 +000026var Float32x4ToString;
27var formattedStackTraceSymbol =
28 utils.ImportNow("formatted_stack_trace_symbol");
29var GlobalObject = global.Object;
30var Int16x8ToString;
31var Int32x4ToString;
32var Int8x16ToString;
33var InternalArray = utils.InternalArray;
34var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
35var ObjectDefineProperty;
Ben Murdochda12d292016-06-02 14:46:10 +010036var ObjectHasOwnProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037var ObjectToString = utils.ImportNow("object_to_string");
38var Script = utils.ImportNow("Script");
39var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
40var StringCharAt;
41var StringIndexOf;
42var StringSubstring;
43var SymbolToString;
44var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
45var Uint16x8ToString;
46var Uint32x4ToString;
47var Uint8x16ToString;
48
49utils.Import(function(from) {
50 ArrayJoin = from.ArrayJoin;
51 Bool16x8ToString = from.Bool16x8ToString;
52 Bool32x4ToString = from.Bool32x4ToString;
53 Bool8x16ToString = from.Bool8x16ToString;
54 Float32x4ToString = from.Float32x4ToString;
55 Int16x8ToString = from.Int16x8ToString;
56 Int32x4ToString = from.Int32x4ToString;
57 Int8x16ToString = from.Int8x16ToString;
58 ObjectDefineProperty = from.ObjectDefineProperty;
Ben Murdochda12d292016-06-02 14:46:10 +010059 ObjectHasOwnProperty = from.ObjectHasOwnProperty;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 StringCharAt = from.StringCharAt;
61 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
258/**
259 * Get information on a specific source position.
260 * @param {number} position The source position
261 * @param {boolean} include_resource_offset Set to true to have the resource
262 * offset added to the location
263 * @return {SourceLocation}
264 * If line is negative or not in the source null is returned.
265 */
266function ScriptLocationFromPosition(position,
267 include_resource_offset) {
268 var line = this.lineFromPosition(position);
269 if (line == -1) return null;
270
271 // Determine start, end and column.
272 var line_ends = this.line_ends;
273 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
274 var end = line_ends[line];
275 if (end > 0 && %_Call(StringCharAt, this.source, end - 1) == '\r') {
276 end--;
277 }
278 var column = position - start;
279
280 // Adjust according to the offset within the resource.
281 if (include_resource_offset) {
282 line += this.line_offset;
283 if (line == this.line_offset) {
284 column += this.column_offset;
285 }
286 }
287
288 return new SourceLocation(this, position, line, column, start, end);
289}
290
291
292/**
293 * Get information on a specific source line and column possibly offset by a
294 * fixed source position. This function is used to find a source position from
295 * a line and column position. The fixed source position offset is typically
296 * used to find a source position in a function based on a line and column in
297 * the source for the function alone. The offset passed will then be the
298 * start position of the source for the function within the full script source.
299 * @param {number} opt_line The line within the source. Default value is 0
300 * @param {number} opt_column The column in within the line. Default value is 0
301 * @param {number} opt_offset_position The offset from the begining of the
302 * source from where the line and column calculation starts.
303 * Default value is 0
304 * @return {SourceLocation}
305 * If line is negative or not in the source null is returned.
306 */
307function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
308 // Default is the first line in the script. Lines in the script is relative
309 // to the offset within the resource.
310 var line = 0;
311 if (!IS_UNDEFINED(opt_line)) {
312 line = opt_line - this.line_offset;
313 }
314
315 // Default is first column. If on the first line add the offset within the
316 // resource.
317 var column = opt_column || 0;
318 if (line == 0) {
319 column -= this.column_offset;
320 }
321
322 var offset_position = opt_offset_position || 0;
323 if (line < 0 || column < 0 || offset_position < 0) return null;
324 if (line == 0) {
325 return this.locationFromPosition(offset_position + column, false);
326 } else {
327 // Find the line where the offset position is located.
328 var offset_line = this.lineFromPosition(offset_position);
329
330 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
331 return null;
332 }
333
334 return this.locationFromPosition(
335 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
336 }
337}
338
339
340/**
341 * Get a slice of source code from the script. The boundaries for the slice is
342 * specified in lines.
343 * @param {number} opt_from_line The first line (zero bound) in the slice.
344 * Default is 0
345 * @param {number} opt_to_column The last line (zero bound) in the slice (non
346 * inclusive). Default is the number of lines in the script
347 * @return {SourceSlice} The source slice or null of the parameters where
348 * invalid
349 */
350function ScriptSourceSlice(opt_from_line, opt_to_line) {
351 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
352 : opt_from_line;
353 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
354 : opt_to_line;
355
356 // Adjust according to the offset within the resource.
357 from_line -= this.line_offset;
358 to_line -= this.line_offset;
359 if (from_line < 0) from_line = 0;
360 if (to_line > this.lineCount()) to_line = this.lineCount();
361
362 // Check parameters.
363 if (from_line >= this.lineCount() ||
364 to_line < 0 ||
365 from_line > to_line) {
366 return null;
367 }
368
369 var line_ends = this.line_ends;
370 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
371 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
372
373 // Return a source slice with line numbers re-adjusted to the resource.
374 return new SourceSlice(this,
375 from_line + this.line_offset,
376 to_line + this.line_offset,
377 from_position, to_position);
378}
379
380
381function ScriptSourceLine(opt_line) {
382 // Default is the first line in the script. Lines in the script are relative
383 // to the offset within the resource.
384 var line = 0;
385 if (!IS_UNDEFINED(opt_line)) {
386 line = opt_line - this.line_offset;
387 }
388
389 // Check parameter.
390 if (line < 0 || this.lineCount() <= line) {
391 return null;
392 }
393
394 // Return the source line.
395 var line_ends = this.line_ends;
396 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
397 var end = line_ends[line];
398 return %_Call(StringSubstring, this.source, start, end);
399}
400
401
402/**
403 * Returns the number of source lines.
404 * @return {number}
405 * Number of source lines.
406 */
407function ScriptLineCount() {
408 // Return number of source lines.
409 return this.line_ends.length;
410}
411
412
413/**
414 * Returns the position of the nth line end.
415 * @return {number}
416 * Zero-based position of the nth line end in the script.
417 */
418function ScriptLineEnd(n) {
419 return this.line_ends[n];
420}
421
422
423/**
424 * If sourceURL comment is available returns sourceURL comment contents.
425 * Otherwise, script name is returned. See
426 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
427 * and Source Map Revision 3 proposal for details on using //# sourceURL and
428 * deprecated //@ sourceURL comment to identify scripts that don't have name.
429 *
430 * @return {?string} script name if present, value for //# sourceURL comment or
431 * deprecated //@ sourceURL comment otherwise.
432 */
433function ScriptNameOrSourceURL() {
434 if (this.source_url) return this.source_url;
435 return this.name;
436}
437
438
439utils.SetUpLockedPrototype(Script, [
440 "source",
441 "name",
442 "source_url",
443 "source_mapping_url",
444 "line_ends",
445 "line_offset",
446 "column_offset"
447 ], [
448 "lineFromPosition", ScriptLineFromPosition,
449 "locationFromPosition", ScriptLocationFromPosition,
450 "locationFromLine", ScriptLocationFromLine,
451 "sourceSlice", ScriptSourceSlice,
452 "sourceLine", ScriptSourceLine,
453 "lineCount", ScriptLineCount,
454 "nameOrSourceURL", ScriptNameOrSourceURL,
455 "lineEnd", ScriptLineEnd
456 ]
457);
458
459
460/**
461 * Class for source location. A source location is a position within some
462 * source with the following properties:
463 * script : script object for the source
464 * line : source line number
465 * column : source column within the line
466 * position : position within the source
467 * start : position of start of source context (inclusive)
468 * end : position of end of source context (not inclusive)
469 * Source text for the source context is the character interval
470 * [start, end[. In most cases end will point to a newline character.
471 * It might point just past the final position of the source if the last
472 * source line does not end with a newline character.
473 * @param {Script} script The Script object for which this is a location
474 * @param {number} position Source position for the location
475 * @param {number} line The line number for the location
476 * @param {number} column The column within the line for the location
477 * @param {number} start Source position for start of source context
478 * @param {number} end Source position for end of source context
479 * @constructor
480 */
481function SourceLocation(script, position, line, column, start, end) {
482 this.script = script;
483 this.position = position;
484 this.line = line;
485 this.column = column;
486 this.start = start;
487 this.end = end;
488}
489
490
491/**
492 * Get the source text for a SourceLocation
493 * @return {String}
494 * Source text for this location.
495 */
496function SourceLocationSourceText() {
497 return %_Call(StringSubstring, this.script.source, this.start, this.end);
498}
499
500
501utils.SetUpLockedPrototype(SourceLocation,
502 ["script", "position", "line", "column", "start", "end"],
503 ["sourceText", SourceLocationSourceText]
504);
505
506
507/**
508 * Class for a source slice. A source slice is a part of a script source with
509 * the following properties:
510 * script : script object for the source
511 * from_line : line number for the first line in the slice
512 * to_line : source line number for the last line in the slice
513 * from_position : position of the first character in the slice
514 * to_position : position of the last character in the slice
515 * The to_line and to_position are not included in the slice, that is the lines
516 * in the slice are [from_line, to_line[. Likewise the characters in the slice
517 * are [from_position, to_position[.
518 * @param {Script} script The Script object for the source slice
519 * @param {number} from_line
520 * @param {number} to_line
521 * @param {number} from_position
522 * @param {number} to_position
523 * @constructor
524 */
525function SourceSlice(script, from_line, to_line, from_position, to_position) {
526 this.script = script;
527 this.from_line = from_line;
528 this.to_line = to_line;
529 this.from_position = from_position;
530 this.to_position = to_position;
531}
532
533/**
534 * Get the source text for a SourceSlice
535 * @return {String} Source text for this slice. The last line will include
536 * the line terminating characters (if any)
537 */
538function SourceSliceSourceText() {
539 return %_Call(StringSubstring,
540 this.script.source,
541 this.from_position,
542 this.to_position);
543}
544
545utils.SetUpLockedPrototype(SourceSlice,
546 ["script", "from_line", "to_line", "from_position", "to_position"],
547 ["sourceText", SourceSliceSourceText]
548);
549
550
551function GetStackTraceLine(recv, fun, pos, isGlobal) {
552 return new CallSite(recv, fun, pos, false).toString();
553}
554
555// ----------------------------------------------------------------------------
556// Error implementation
557
558function CallSite(receiver, fun, pos, strict_mode) {
559 if (!IS_FUNCTION(fun)) {
560 throw MakeTypeError(kCallSiteExpectsFunction, typeof fun);
561 }
562
563 if (IS_UNDEFINED(new.target)) {
564 return new CallSite(receiver, fun, pos, strict_mode);
565 }
566
567 SET_PRIVATE(this, callSiteReceiverSymbol, receiver);
568 SET_PRIVATE(this, callSiteFunctionSymbol, fun);
569 SET_PRIVATE(this, callSitePositionSymbol, TO_INT32(pos));
570 SET_PRIVATE(this, callSiteStrictSymbol, TO_BOOLEAN(strict_mode));
571}
572
Ben Murdochda12d292016-06-02 14:46:10 +0100573function CheckCallSite(obj, name) {
574 if (!IS_RECEIVER(obj) || !HAS_PRIVATE(obj, callSiteFunctionSymbol)) {
575 throw MakeTypeError(kCallSiteMethod, name);
576 }
577}
578
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579function CallSiteGetThis() {
Ben Murdochda12d292016-06-02 14:46:10 +0100580 CheckCallSite(this, "getThis");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 return GET_PRIVATE(this, callSiteStrictSymbol)
582 ? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol);
583}
584
585function CallSiteGetFunction() {
Ben Murdochda12d292016-06-02 14:46:10 +0100586 CheckCallSite(this, "getFunction");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 return GET_PRIVATE(this, callSiteStrictSymbol)
588 ? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol);
589}
590
591function CallSiteGetPosition() {
Ben Murdochda12d292016-06-02 14:46:10 +0100592 CheckCallSite(this, "getPosition");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000593 return GET_PRIVATE(this, callSitePositionSymbol);
594}
595
596function CallSiteGetTypeName() {
Ben Murdochda12d292016-06-02 14:46:10 +0100597 CheckCallSite(this, "getTypeName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false);
599}
600
601function CallSiteIsToplevel() {
Ben Murdochda12d292016-06-02 14:46:10 +0100602 CheckCallSite(this, "isTopLevel");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000603 return %CallSiteIsToplevelRT(this);
604}
605
606function CallSiteIsEval() {
Ben Murdochda12d292016-06-02 14:46:10 +0100607 CheckCallSite(this, "isEval");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 return %CallSiteIsEvalRT(this);
609}
610
611function CallSiteGetEvalOrigin() {
Ben Murdochda12d292016-06-02 14:46:10 +0100612 CheckCallSite(this, "getEvalOrigin");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613 var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol));
614 return FormatEvalOrigin(script);
615}
616
617function CallSiteGetScriptNameOrSourceURL() {
Ben Murdochda12d292016-06-02 14:46:10 +0100618 CheckCallSite(this, "getScriptNameOrSourceURL");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 return %CallSiteGetScriptNameOrSourceUrlRT(this);
620}
621
622function CallSiteGetFunctionName() {
623 // See if the function knows its own name
Ben Murdochda12d292016-06-02 14:46:10 +0100624 CheckCallSite(this, "getFunctionName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625 return %CallSiteGetFunctionNameRT(this);
626}
627
628function CallSiteGetMethodName() {
629 // See if we can find a unique property on the receiver that holds
630 // this function.
Ben Murdochda12d292016-06-02 14:46:10 +0100631 CheckCallSite(this, "getMethodName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 return %CallSiteGetMethodNameRT(this);
633}
634
635function CallSiteGetFileName() {
Ben Murdochda12d292016-06-02 14:46:10 +0100636 CheckCallSite(this, "getFileName");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000637 return %CallSiteGetFileNameRT(this);
638}
639
640function CallSiteGetLineNumber() {
Ben Murdochda12d292016-06-02 14:46:10 +0100641 CheckCallSite(this, "getLineNumber");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642 return %CallSiteGetLineNumberRT(this);
643}
644
645function CallSiteGetColumnNumber() {
Ben Murdochda12d292016-06-02 14:46:10 +0100646 CheckCallSite(this, "getColumnNumber");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000647 return %CallSiteGetColumnNumberRT(this);
648}
649
650function CallSiteIsNative() {
Ben Murdochda12d292016-06-02 14:46:10 +0100651 CheckCallSite(this, "isNative");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000652 return %CallSiteIsNativeRT(this);
653}
654
655function CallSiteIsConstructor() {
Ben Murdochda12d292016-06-02 14:46:10 +0100656 CheckCallSite(this, "isConstructor");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 return %CallSiteIsConstructorRT(this);
658}
659
660function CallSiteToString() {
661 var fileName;
662 var fileLocation = "";
663 if (this.isNative()) {
664 fileLocation = "native";
665 } else {
666 fileName = this.getScriptNameOrSourceURL();
667 if (!fileName && this.isEval()) {
668 fileLocation = this.getEvalOrigin();
669 fileLocation += ", "; // Expecting source position to follow.
670 }
671
672 if (fileName) {
673 fileLocation += fileName;
674 } else {
675 // Source code does not originate from a file and is not native, but we
676 // can still get the source position inside the source string, e.g. in
677 // an eval string.
678 fileLocation += "<anonymous>";
679 }
680 var lineNumber = this.getLineNumber();
681 if (lineNumber != null) {
682 fileLocation += ":" + lineNumber;
683 var columnNumber = this.getColumnNumber();
684 if (columnNumber) {
685 fileLocation += ":" + columnNumber;
686 }
687 }
688 }
689
690 var line = "";
691 var functionName = this.getFunctionName();
692 var addSuffix = true;
693 var isConstructor = this.isConstructor();
694 var isMethodCall = !(this.isToplevel() || isConstructor);
695 if (isMethodCall) {
696 var typeName = GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), true);
697 var methodName = this.getMethodName();
698 if (functionName) {
699 if (typeName && %_Call(StringIndexOf, functionName, typeName) != 0) {
700 line += typeName + ".";
701 }
702 line += functionName;
703 if (methodName &&
704 (%_Call(StringIndexOf, functionName, "." + methodName) !=
705 functionName.length - methodName.length - 1)) {
706 line += " [as " + methodName + "]";
707 }
708 } else {
709 line += typeName + "." + (methodName || "<anonymous>");
710 }
711 } else if (isConstructor) {
712 line += "new " + (functionName || "<anonymous>");
713 } else if (functionName) {
714 line += functionName;
715 } else {
716 line += fileLocation;
717 addSuffix = false;
718 }
719 if (addSuffix) {
720 line += " (" + fileLocation + ")";
721 }
722 return line;
723}
724
725utils.SetUpLockedPrototype(CallSite, ["receiver", "fun", "pos"], [
726 "getThis", CallSiteGetThis,
727 "getTypeName", CallSiteGetTypeName,
728 "isToplevel", CallSiteIsToplevel,
729 "isEval", CallSiteIsEval,
730 "getEvalOrigin", CallSiteGetEvalOrigin,
731 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
732 "getFunction", CallSiteGetFunction,
733 "getFunctionName", CallSiteGetFunctionName,
734 "getMethodName", CallSiteGetMethodName,
735 "getFileName", CallSiteGetFileName,
736 "getLineNumber", CallSiteGetLineNumber,
737 "getColumnNumber", CallSiteGetColumnNumber,
738 "isNative", CallSiteIsNative,
739 "getPosition", CallSiteGetPosition,
740 "isConstructor", CallSiteIsConstructor,
741 "toString", CallSiteToString
742]);
743
744
745function FormatEvalOrigin(script) {
746 var sourceURL = script.nameOrSourceURL();
747 if (sourceURL) {
748 return sourceURL;
749 }
750
751 var eval_origin = "eval at ";
752 if (script.eval_from_function_name) {
753 eval_origin += script.eval_from_function_name;
754 } else {
755 eval_origin += "<anonymous>";
756 }
757
758 var eval_from_script = script.eval_from_script;
759 if (eval_from_script) {
760 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
761 // eval script originated from another eval.
762 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
763 } else {
764 // eval script originated from "real" source.
765 if (eval_from_script.name) {
766 eval_origin += " (" + eval_from_script.name;
767 var location = eval_from_script.locationFromPosition(
768 script.eval_from_script_position, true);
769 if (location) {
770 eval_origin += ":" + (location.line + 1);
771 eval_origin += ":" + (location.column + 1);
772 }
773 eval_origin += ")";
774 } else {
775 eval_origin += " (unknown source)";
776 }
777 }
778 }
779
780 return eval_origin;
781}
782
783
784function FormatErrorString(error) {
785 try {
786 return %_Call(ErrorToString, error);
787 } catch (e) {
788 try {
789 return "<error: " + e + ">";
790 } catch (ee) {
791 return "<error>";
792 }
793 }
794}
795
796
797function GetStackFrames(raw_stack) {
798 var frames = new InternalArray();
799 var sloppy_frames = raw_stack[0];
800 for (var i = 1; i < raw_stack.length; i += 4) {
801 var recv = raw_stack[i];
802 var fun = raw_stack[i + 1];
803 var code = raw_stack[i + 2];
804 var pc = raw_stack[i + 3];
805 var pos = %_IsSmi(code) ? code : %FunctionGetPositionForOffset(code, pc);
806 sloppy_frames--;
807 frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
808 }
809 return frames;
810}
811
812
813// Flag to prevent recursive call of Error.prepareStackTrace.
814var formatting_custom_stack_trace = false;
815
816
817function FormatStackTrace(obj, raw_stack) {
818 var frames = GetStackFrames(raw_stack);
819 if (IS_FUNCTION(GlobalError.prepareStackTrace) &&
820 !formatting_custom_stack_trace) {
821 var array = [];
822 %MoveArrayContents(frames, array);
823 formatting_custom_stack_trace = true;
824 var stack_trace = UNDEFINED;
825 try {
826 stack_trace = GlobalError.prepareStackTrace(obj, array);
827 } catch (e) {
828 throw e; // The custom formatting function threw. Rethrow.
829 } finally {
830 formatting_custom_stack_trace = false;
831 }
832 return stack_trace;
833 }
834
835 var lines = new InternalArray();
836 lines.push(FormatErrorString(obj));
837 for (var i = 0; i < frames.length; i++) {
838 var frame = frames[i];
839 var line;
840 try {
841 line = frame.toString();
842 } catch (e) {
843 try {
844 line = "<error: " + e + ">";
845 } catch (ee) {
846 // Any code that reaches this point is seriously nasty!
847 line = "<error>";
848 }
849 }
850 lines.push(" at " + line);
851 }
852 return %_Call(ArrayJoin, lines, "\n");
853}
854
855
856function GetTypeName(receiver, requireConstructor) {
857 if (IS_NULL_OR_UNDEFINED(receiver)) return null;
858 if (IS_PROXY(receiver)) return "Proxy";
859
860 var constructor = %GetDataProperty(TO_OBJECT(receiver), "constructor");
861 if (!IS_FUNCTION(constructor)) {
862 return requireConstructor ? null : %_Call(NoSideEffectsToString, receiver);
863 }
864 return %FunctionGetName(constructor);
865}
866
867
868// Format the stack trace if not yet done, and return it.
869// Cache the formatted stack trace on the holder.
870var StackTraceGetter = function() {
871 var formatted_stack_trace = UNDEFINED;
872 var holder = this;
873 while (holder) {
874 var formatted_stack_trace =
875 GET_PRIVATE(holder, formattedStackTraceSymbol);
876 if (IS_UNDEFINED(formatted_stack_trace)) {
877 // No formatted stack trace available.
878 var stack_trace = GET_PRIVATE(holder, stackTraceSymbol);
879 if (IS_UNDEFINED(stack_trace)) {
880 // Neither formatted nor structured stack trace available.
881 // Look further up the prototype chain.
882 holder = %_GetPrototype(holder);
883 continue;
884 }
885 formatted_stack_trace = FormatStackTrace(holder, stack_trace);
886 SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED);
887 SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace);
888 }
889 return formatted_stack_trace;
890 }
891 return UNDEFINED;
892};
893
894
895// If the receiver equals the holder, set the formatted stack trace that the
896// getter returns.
897var StackTraceSetter = function(v) {
898 if (IsErrorObject(this)) {
899 SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
900 SET_PRIVATE(this, formattedStackTraceSymbol, v);
901 }
902};
903
904
905// Use a dummy function since we do not actually want to capture a stack trace
906// when constructing the initial Error prototytpes.
907var captureStackTrace = function() {};
908
909
910// Set up special error type constructors.
911function SetUpError(error_function) {
912 %FunctionSetInstanceClassName(error_function, 'Error');
913 var name = error_function.name;
914 var prototype = new GlobalObject();
915 if (name !== 'Error') {
916 %InternalSetPrototype(error_function, GlobalError);
917 %InternalSetPrototype(prototype, GlobalError.prototype);
918 }
919 %FunctionSetPrototype(error_function, prototype);
920
921 %AddNamedProperty(error_function.prototype, 'name', name, DONT_ENUM);
922 %AddNamedProperty(error_function.prototype, 'message', '', DONT_ENUM);
923 %AddNamedProperty(
924 error_function.prototype, 'constructor', error_function, DONT_ENUM);
925
926 %SetCode(error_function, function(m) {
927 if (IS_UNDEFINED(new.target)) return new error_function(m);
928
929 try { captureStackTrace(this, error_function); } catch (e) { }
930 // Define all the expected properties directly on the error
931 // object. This avoids going through getters and setters defined
932 // on prototype objects.
933 if (!IS_UNDEFINED(m)) {
934 %AddNamedProperty(this, 'message', TO_STRING(m), DONT_ENUM);
935 }
936 });
937
938 %SetNativeFlag(error_function);
939 return error_function;
940};
941
942GlobalError = SetUpError(global.Error);
943GlobalEvalError = SetUpError(global.EvalError);
944GlobalRangeError = SetUpError(global.RangeError);
945GlobalReferenceError = SetUpError(global.ReferenceError);
946GlobalSyntaxError = SetUpError(global.SyntaxError);
947GlobalTypeError = SetUpError(global.TypeError);
948GlobalURIError = SetUpError(global.URIError);
949
950utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
951 ['toString', ErrorToString]);
952
953function ErrorToString() {
954 if (!IS_RECEIVER(this)) {
955 throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
956 }
957
958 var name = this.name;
959 name = IS_UNDEFINED(name) ? "Error" : TO_STRING(name);
960
961 var message = this.message;
962 message = IS_UNDEFINED(message) ? "" : TO_STRING(message);
963
964 if (name == "") return message;
965 if (message == "") return name;
966 return `${name}: ${message}`
967}
968
969function MakeError(type, arg0, arg1, arg2) {
970 return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
971}
972
973function MakeRangeError(type, arg0, arg1, arg2) {
974 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
975}
976
977function MakeSyntaxError(type, arg0, arg1, arg2) {
978 return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2);
979}
980
981function MakeTypeError(type, arg0, arg1, arg2) {
982 return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2);
983}
984
985function MakeURIError() {
986 return MakeGenericError(GlobalURIError, kURIMalformed);
987}
988
989// Boilerplate for exceptions for stack overflows. Used from
990// Isolate::StackOverflow().
991var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
992utils.InstallGetterSetter(StackOverflowBoilerplate, 'stack',
993 StackTraceGetter, StackTraceSetter)
994
995// Define actual captureStackTrace function after everything has been set up.
996captureStackTrace = function captureStackTrace(obj, cons_opt) {
997 // Define accessors first, as this may fail and throw.
998 ObjectDefineProperty(obj, 'stack', { get: StackTraceGetter,
999 set: StackTraceSetter,
1000 configurable: true });
1001 %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
1002};
1003
1004GlobalError.captureStackTrace = captureStackTrace;
1005
1006%InstallToContext([
1007 "get_stack_trace_line_fun", GetStackTraceLine,
1008 "make_error_function", MakeGenericError,
1009 "make_range_error", MakeRangeError,
1010 "make_type_error", MakeTypeError,
1011 "message_get_column_number", GetColumnNumber,
1012 "message_get_line_number", GetLineNumber,
1013 "message_get_source_line", GetSourceLine,
1014 "no_side_effects_to_string_fun", NoSideEffectsToString,
1015 "stack_overflow_boilerplate", StackOverflowBoilerplate,
1016]);
1017
1018utils.Export(function(to) {
1019 to.ErrorToString = ErrorToString;
1020 to.MakeError = MakeError;
1021 to.MakeRangeError = MakeRangeError;
1022 to.MakeSyntaxError = MakeSyntaxError;
1023 to.MakeTypeError = MakeTypeError;
1024 to.MakeURIError = MakeURIError;
1025});
1026
1027});