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 14 var ArrayJoin; 15 var Bool16x8ToString; 16 var Bool32x4ToString; 17 var Bool8x16ToString; 18 var callSiteReceiverSymbol = 19 utils.ImportNow("call_site_receiver_symbol"); 20 var callSiteFunctionSymbol = 21 utils.ImportNow("call_site_function_symbol"); 22 var callSitePositionSymbol = 23 utils.ImportNow("call_site_position_symbol"); 24 var callSiteStrictSymbol = 25 utils.ImportNow("call_site_strict_symbol"); 26 var FLAG_harmony_tostring; 27 var Float32x4ToString; 28 var formattedStackTraceSymbol = 29 utils.ImportNow("formatted_stack_trace_symbol"); 30 var GlobalObject = global.Object; 31 var Int16x8ToString; 32 var Int32x4ToString; 33 var Int8x16ToString; 34 var InternalArray = utils.InternalArray; 35 var internalErrorSymbol = utils.ImportNow("internal_error_symbol"); 36 var ObjectDefineProperty; 37 var ObjectToString = utils.ImportNow("object_to_string"); 38 var Script = utils.ImportNow("Script"); 39 var stackTraceSymbol = utils.ImportNow("stack_trace_symbol"); 40 var StringCharAt; 41 var StringIndexOf; 42 var StringSubstring; 43 var SymbolToString; 44 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 45 var Uint16x8ToString; 46 var Uint32x4ToString; 47 var Uint8x16ToString; 48 49 utils.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 68 utils.ImportFromExperimental(function(from) { 69 FLAG_harmony_tostring = from.FLAG_harmony_tostring; 70 }); 71 72 // ------------------------------------------------------------------- 73 74 var GlobalError; 75 var GlobalTypeError; 76 var GlobalRangeError; 77 var GlobalURIError; 78 var GlobalSyntaxError; 79 var GlobalReferenceError; 80 var GlobalEvalError; 81 82 83 function 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 100 function IsErrorObject(obj) { 101 return HAS_PRIVATE(obj, stackTraceSymbol); 102 } 103 104 function 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 114 function 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 166 function 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. 186 function 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 198 function 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. 209 function 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. 220 function 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 */ 235 function 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 */ 274 function 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 */ 315 function 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 */ 358 function 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 389 function 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 */ 415 function 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 */ 426 function 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 */ 441 function ScriptNameOrSourceURL() { 442 if (this.source_url) return this.source_url; 443 return this.name; 444 } 445 446 447 utils.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 */ 489 function 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 */ 504 function SourceLocationSourceText() { 505 return %_Call(StringSubstring, this.script.source, this.start, this.end); 506 } 507 508 509 utils.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 */ 533 function 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 */ 546 function SourceSliceSourceText() { 547 return %_Call(StringSubstring, 548 this.script.source, 549 this.from_position, 550 this.to_position); 551 } 552 553 utils.SetUpLockedPrototype(SourceSlice, 554 ["script", "from_line", "to_line", "from_position", "to_position"], 555 ["sourceText", SourceSliceSourceText] 556 ); 557 558 559 function GetStackTraceLine(recv, fun, pos, isGlobal) { 560 return new CallSite(recv, fun, pos, false).toString(); 561 } 562 563 // ---------------------------------------------------------------------------- 564 // Error implementation 565 566 function 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 581 function CallSiteGetThis() { 582 return GET_PRIVATE(this, callSiteStrictSymbol) 583 ? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol); 584 } 585 586 function CallSiteGetFunction() { 587 return GET_PRIVATE(this, callSiteStrictSymbol) 588 ? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol); 589 } 590 591 function CallSiteGetPosition() { 592 return GET_PRIVATE(this, callSitePositionSymbol); 593 } 594 595 function CallSiteGetTypeName() { 596 return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false); 597 } 598 599 function CallSiteIsToplevel() { 600 return %CallSiteIsToplevelRT(this); 601 } 602 603 function CallSiteIsEval() { 604 return %CallSiteIsEvalRT(this); 605 } 606 607 function CallSiteGetEvalOrigin() { 608 var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol)); 609 return FormatEvalOrigin(script); 610 } 611 612 function CallSiteGetScriptNameOrSourceURL() { 613 return %CallSiteGetScriptNameOrSourceUrlRT(this); 614 } 615 616 function CallSiteGetFunctionName() { 617 // See if the function knows its own name 618 return %CallSiteGetFunctionNameRT(this); 619 } 620 621 function CallSiteGetMethodName() { 622 // See if we can find a unique property on the receiver that holds 623 // this function. 624 return %CallSiteGetMethodNameRT(this); 625 } 626 627 function CallSiteGetFileName() { 628 return %CallSiteGetFileNameRT(this); 629 } 630 631 function CallSiteGetLineNumber() { 632 return %CallSiteGetLineNumberRT(this); 633 } 634 635 function CallSiteGetColumnNumber() { 636 return %CallSiteGetColumnNumberRT(this); 637 } 638 639 function CallSiteIsNative() { 640 return %CallSiteIsNativeRT(this); 641 } 642 643 function CallSiteIsConstructor() { 644 return %CallSiteIsConstructorRT(this); 645 } 646 647 function 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 712 utils.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 732 function 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 771 function 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 784 function 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. 801 var formatting_custom_stack_trace = false; 802 803 804 function 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 843 function 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. 857 var 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. 884 var 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. 894 var captureStackTrace = function() {}; 895 896 897 // Set up special error type constructors. 898 function 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 929 GlobalError = SetUpError(global.Error); 930 GlobalEvalError = SetUpError(global.EvalError); 931 GlobalRangeError = SetUpError(global.RangeError); 932 GlobalReferenceError = SetUpError(global.ReferenceError); 933 GlobalSyntaxError = SetUpError(global.SyntaxError); 934 GlobalTypeError = SetUpError(global.TypeError); 935 GlobalURIError = SetUpError(global.URIError); 936 937 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM, 938 ['toString', ErrorToString]); 939 940 function 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 956 function MakeError(type, arg0, arg1, arg2) { 957 return MakeGenericError(GlobalError, type, arg0, arg1, arg2); 958 } 959 960 function MakeRangeError(type, arg0, arg1, arg2) { 961 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2); 962 } 963 964 function MakeSyntaxError(type, arg0, arg1, arg2) { 965 return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2); 966 } 967 968 function MakeTypeError(type, arg0, arg1, arg2) { 969 return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2); 970 } 971 972 function MakeURIError() { 973 return MakeGenericError(GlobalURIError, kURIMalformed); 974 } 975 976 // Boilerplate for exceptions for stack overflows. Used from 977 // Isolate::StackOverflow(). 978 var StackOverflowBoilerplate = MakeRangeError(kStackOverflow); 979 utils.InstallGetterSetter(StackOverflowBoilerplate, 'stack', 980 StackTraceGetter, StackTraceSetter) 981 982 // Define actual captureStackTrace function after everything has been set up. 983 captureStackTrace = 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 991 GlobalError.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 1005 utils.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