1// 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}); 1015