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