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 7var kMessages = { 8 // Error 9 cyclic_proto: ["Cyclic __proto__ value"], 10 code_gen_from_strings: ["%0"], 11 generator_running: ["Generator is already running"], 12 generator_finished: ["Generator has already finished"], 13 // TypeError 14 unexpected_token: ["Unexpected token ", "%0"], 15 unexpected_token_number: ["Unexpected number"], 16 unexpected_token_string: ["Unexpected string"], 17 unexpected_token_identifier: ["Unexpected identifier"], 18 unexpected_reserved: ["Unexpected reserved word"], 19 unexpected_strict_reserved: ["Unexpected strict mode reserved word"], 20 unexpected_eos: ["Unexpected end of input"], 21 malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], 22 unterminated_regexp: ["Invalid regular expression: missing /"], 23 regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], 24 incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], 25 multiple_defaults_in_switch: ["More than one default clause in switch statement"], 26 newline_after_throw: ["Illegal newline after throw"], 27 label_redeclaration: ["Label '", "%0", "' has already been declared"], 28 var_redeclaration: ["Identifier '", "%0", "' has already been declared"], 29 no_catch_or_finally: ["Missing catch or finally after try"], 30 unknown_label: ["Undefined label '", "%0", "'"], 31 uncaught_exception: ["Uncaught ", "%0"], 32 stack_trace: ["Stack Trace:\n", "%0"], 33 called_non_callable: ["%0", " is not a function"], 34 undefined_method: ["Object ", "%1", " has no method '", "%0", "'"], 35 property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"], 36 cannot_convert_to_primitive: ["Cannot convert object to primitive value"], 37 not_constructor: ["%0", " is not a constructor"], 38 not_defined: ["%0", " is not defined"], 39 non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"], 40 non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"], 41 with_expression: ["%0", " has no properties"], 42 illegal_invocation: ["Illegal invocation"], 43 no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], 44 apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], 45 apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"], 46 invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], 47 instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"], 48 instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"], 49 undefined_or_null_to_object: ["Cannot convert undefined or null to object"], 50 reduce_no_initial: ["Reduce of empty array with no initial value"], 51 getter_must_be_callable: ["Getter must be a function: ", "%0"], 52 setter_must_be_callable: ["Setter must be a function: ", "%0"], 53 value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"], 54 proto_object_or_null: ["Object prototype may only be an Object or null: ", "%0"], 55 property_desc_object: ["Property description must be an object: ", "%0"], 56 redefine_disallowed: ["Cannot redefine property: ", "%0"], 57 define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."], 58 non_extensible_proto: ["%0", " is not extensible"], 59 handler_non_object: ["Proxy.", "%0", " called with non-object as handler"], 60 proto_non_object: ["Proxy.", "%0", " called with non-object as prototype"], 61 trap_function_expected: ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"], 62 handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"], 63 handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"], 64 handler_returned_false: ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"], 65 handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"], 66 proxy_prop_not_configurable: ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"], 67 proxy_non_object_prop_names: ["Trap '", "%1", "' returned non-object ", "%0"], 68 proxy_repeated_prop_name: ["Trap '", "%1", "' returned repeated property name '", "%2", "'"], 69 invalid_weakmap_key: ["Invalid value used as weak map key"], 70 invalid_weakset_value: ["Invalid value used in weak set"], 71 not_date_object: ["this is not a Date object."], 72 observe_non_object: ["Object.", "%0", " cannot ", "%0", " non-object"], 73 observe_non_function: ["Object.", "%0", " cannot deliver to non-function"], 74 observe_callback_frozen: ["Object.observe cannot deliver to a frozen function object"], 75 observe_invalid_accept: ["Object.observe accept must be an array of strings."], 76 observe_type_non_string: ["Invalid changeRecord with non-string 'type' property"], 77 observe_perform_non_string: ["Invalid non-string changeType"], 78 observe_perform_non_function: ["Cannot perform non-function"], 79 observe_notify_non_notifier: ["notify called on non-notifier object"], 80 observe_global_proxy: ["%0", " cannot be called on the global proxy object"], 81 not_typed_array: ["this is not a typed array."], 82 invalid_argument: ["invalid_argument"], 83 data_view_not_array_buffer: ["First argument to DataView constructor must be an ArrayBuffer"], 84 constructor_not_function: ["Constructor ", "%0", " requires 'new'"], 85 not_a_symbol: ["%0", " is not a symbol"], 86 not_a_promise: ["%0", " is not a promise"], 87 resolver_not_a_function: ["Promise resolver ", "%0", " is not a function"], 88 promise_cyclic: ["Chaining cycle detected for promise ", "%0"], 89 array_functions_on_frozen: ["Cannot modify frozen array elements"], 90 array_functions_change_sealed: ["Cannot add/remove sealed array elements"], 91 first_argument_not_regexp: ["First argument to ", "%0", " must not be a regular expression"], 92 // RangeError 93 invalid_array_length: ["Invalid array length"], 94 invalid_array_buffer_length: ["Invalid array buffer length"], 95 invalid_string_length: ["Invalid string length"], 96 invalid_typed_array_offset: ["Start offset is too large:"], 97 invalid_typed_array_length: ["Invalid typed array length"], 98 invalid_typed_array_alignment: ["%0", " of ", "%1", " should be a multiple of ", "%2"], 99 typed_array_set_source_too_large: 100 ["Source is too large"], 101 typed_array_set_negative_offset: 102 ["Start offset is negative"], 103 invalid_data_view_offset: ["Start offset is outside the bounds of the buffer"], 104 invalid_data_view_length: ["Invalid data view length"], 105 invalid_data_view_accessor_offset: 106 ["Offset is outside the bounds of the DataView"], 107 108 stack_overflow: ["Maximum call stack size exceeded"], 109 invalid_time_value: ["Invalid time value"], 110 invalid_count_value: ["Invalid count value"], 111 // ReferenceError 112 invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"], 113 invalid_lhs_in_for: ["Invalid left-hand side in for-loop"], 114 invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"], 115 invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"], 116 // SyntaxError 117 paren_in_arg_string: ["Function arg string contains parenthesis"], 118 not_isvar: ["builtin %IS_VAR: not a variable"], 119 single_function_literal: ["Single function literal required"], 120 invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"], 121 invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], 122 illegal_break: ["Illegal break statement"], 123 illegal_continue: ["Illegal continue statement"], 124 illegal_return: ["Illegal return statement"], 125 illegal_let: ["Illegal let declaration outside extended mode"], 126 error_loading_debugger: ["Error loading debugger"], 127 no_input_to_regexp: ["No input to ", "%0"], 128 invalid_json: ["String '", "%0", "' is not valid JSON"], 129 circular_structure: ["Converting circular structure to JSON"], 130 called_on_non_object: ["%0", " called on non-object"], 131 called_on_null_or_undefined: ["%0", " called on null or undefined"], 132 array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], 133 object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], 134 illegal_access: ["Illegal access"], 135 invalid_cached_data_function: ["Invalid cached data for function ", "%0"], 136 invalid_cached_data: ["Invalid cached data"], 137 strict_mode_with: ["Strict mode code may not include a with statement"], 138 strict_eval_arguments: ["Unexpected eval or arguments in strict mode"], 139 too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"], 140 too_many_parameters: ["Too many parameters in function definition (only 65535 allowed)"], 141 too_many_variables: ["Too many variables declared (only 4194303 allowed)"], 142 strict_param_dupe: ["Strict mode function may not have duplicate parameter names"], 143 strict_octal_literal: ["Octal literals are not allowed in strict mode."], 144 strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"], 145 accessor_data_property: ["Object literal may not have data and accessor property with the same name"], 146 accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"], 147 strict_delete: ["Delete of an unqualified identifier in strict mode."], 148 strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"], 149 strict_const: ["Use of const in strict mode."], 150 strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ], 151 strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"], 152 strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"], 153 strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"], 154 strict_caller: ["Illegal access to a strict mode caller function."], 155 generator_poison_pill: ["'caller' and 'arguments' properties may not be accessed on generator functions."], 156 unprotected_let: ["Illegal let declaration in unprotected statement context."], 157 unprotected_const: ["Illegal const declaration in unprotected statement context."], 158 cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"], 159 redef_external_array_element: ["Cannot redefine a property of an object with external array elements"], 160 harmony_const_assign: ["Assignment to constant variable."], 161 symbol_to_string: ["Cannot convert a Symbol value to a string"], 162 symbol_to_primitive: ["Cannot convert a Symbol wrapper object to a primitive value"], 163 invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"], 164 module_type_error: ["Module '", "%0", "' used improperly"], 165 module_export_undefined: ["Export '", "%0", "' is not defined in module"] 166}; 167 168 169function FormatString(format, args) { 170 var result = ""; 171 var arg_num = 0; 172 for (var i = 0; i < format.length; i++) { 173 var str = format[i]; 174 if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) { 175 // Two-char string starts with "%". 176 var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0; 177 if (arg_num < 4) { 178 // str is one of %0, %1, %2 or %3. 179 try { 180 str = NoSideEffectToString(args[arg_num]); 181 } catch (e) { 182 if (%IsJSModule(args[arg_num])) 183 str = "module"; 184 else if (IS_SPEC_OBJECT(args[arg_num])) 185 str = "object"; 186 else 187 str = "#<error>"; 188 } 189 } 190 } 191 result += str; 192 } 193 return result; 194} 195 196 197function NoSideEffectToString(obj) { 198 if (IS_STRING(obj)) return obj; 199 if (IS_NUMBER(obj)) return %_NumberToString(obj); 200 if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false'; 201 if (IS_UNDEFINED(obj)) return 'undefined'; 202 if (IS_NULL(obj)) return 'null'; 203 if (IS_FUNCTION(obj)) { 204 var str = %_CallFunction(obj, FunctionToString); 205 if (str.length > 128) { 206 str = %_SubString(str, 0, 111) + "...<omitted>..." + 207 %_SubString(str, str.length - 2, str.length); 208 } 209 return str; 210 } 211 if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) { 212 var constructor = %GetDataProperty(obj, "constructor"); 213 if (typeof constructor == "function") { 214 var constructorName = constructor.name; 215 if (IS_STRING(constructorName) && constructorName !== "") { 216 return "#<" + constructorName + ">"; 217 } 218 } 219 } 220 if (CanBeSafelyTreatedAsAnErrorObject(obj)) { 221 return %_CallFunction(obj, ErrorToString); 222 } 223 return %_CallFunction(obj, ObjectToString); 224} 225 226// To determine whether we can safely stringify an object using ErrorToString 227// without the risk of side-effects, we need to check whether the object is 228// either an instance of a native error type (via '%_ClassOf'), or has $Error 229// in its prototype chain and hasn't overwritten 'toString' with something 230// strange and unusual. 231function CanBeSafelyTreatedAsAnErrorObject(obj) { 232 switch (%_ClassOf(obj)) { 233 case 'Error': 234 case 'EvalError': 235 case 'RangeError': 236 case 'ReferenceError': 237 case 'SyntaxError': 238 case 'TypeError': 239 case 'URIError': 240 return true; 241 } 242 243 var objToString = %GetDataProperty(obj, "toString"); 244 return obj instanceof $Error && objToString === ErrorToString; 245} 246 247 248// When formatting internally created error messages, do not 249// invoke overwritten error toString methods but explicitly use 250// the error to string method. This is to avoid leaking error 251// objects between script tags in a browser setting. 252function ToStringCheckErrorObject(obj) { 253 if (CanBeSafelyTreatedAsAnErrorObject(obj)) { 254 return %_CallFunction(obj, ErrorToString); 255 } else { 256 return ToString(obj); 257 } 258} 259 260 261function ToDetailString(obj) { 262 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) { 263 var constructor = obj.constructor; 264 if (typeof constructor == "function") { 265 var constructorName = constructor.name; 266 if (IS_STRING(constructorName) && constructorName !== "") { 267 return "#<" + constructorName + ">"; 268 } 269 } 270 } 271 return ToStringCheckErrorObject(obj); 272} 273 274 275function MakeGenericError(constructor, type, args) { 276 if (IS_UNDEFINED(args)) args = []; 277 return new constructor(FormatMessage(type, args)); 278} 279 280 281/** 282 * Set up the Script function and constructor. 283 */ 284%FunctionSetInstanceClassName(Script, 'Script'); 285%SetProperty(Script.prototype, 'constructor', Script, 286 DONT_ENUM | DONT_DELETE | READ_ONLY); 287%SetCode(Script, function(x) { 288 // Script objects can only be created by the VM. 289 throw new $Error("Not supported"); 290}); 291 292 293// Helper functions; called from the runtime system. 294function FormatMessage(type, args) { 295 var format = kMessages[type]; 296 if (!format) return "<unknown message " + type + ">"; 297 return FormatString(format, args); 298} 299 300 301function GetLineNumber(message) { 302 var start_position = %MessageGetStartPosition(message); 303 if (start_position == -1) return kNoLineNumberInfo; 304 var script = %MessageGetScript(message); 305 var location = script.locationFromPosition(start_position, true); 306 if (location == null) return kNoLineNumberInfo; 307 return location.line + 1; 308} 309 310 311// Returns the source code line containing the given source 312// position, or the empty string if the position is invalid. 313function GetSourceLine(message) { 314 var script = %MessageGetScript(message); 315 var start_position = %MessageGetStartPosition(message); 316 var location = script.locationFromPosition(start_position, true); 317 if (location == null) return ""; 318 location.restrict(); 319 return location.sourceText(); 320} 321 322 323function MakeTypeError(type, args) { 324 return MakeGenericError($TypeError, type, args); 325} 326 327 328function MakeRangeError(type, args) { 329 return MakeGenericError($RangeError, type, args); 330} 331 332 333function MakeSyntaxError(type, args) { 334 return MakeGenericError($SyntaxError, type, args); 335} 336 337 338function MakeReferenceError(type, args) { 339 return MakeGenericError($ReferenceError, type, args); 340} 341 342 343function MakeEvalError(type, args) { 344 return MakeGenericError($EvalError, type, args); 345} 346 347 348function MakeError(type, args) { 349 return MakeGenericError($Error, type, args); 350} 351 352/** 353 * Find a line number given a specific source position. 354 * @param {number} position The source position. 355 * @return {number} 0 if input too small, -1 if input too large, 356 else the line number. 357 */ 358function ScriptLineFromPosition(position) { 359 var lower = 0; 360 var upper = this.lineCount() - 1; 361 var line_ends = this.line_ends; 362 363 // We'll never find invalid positions so bail right away. 364 if (position > line_ends[upper]) { 365 return -1; 366 } 367 368 // This means we don't have to safe-guard indexing line_ends[i - 1]. 369 if (position <= line_ends[0]) { 370 return 0; 371 } 372 373 // Binary search to find line # from position range. 374 while (upper >= 1) { 375 var i = (lower + upper) >> 1; 376 377 if (position > line_ends[i]) { 378 lower = i + 1; 379 } else if (position <= line_ends[i - 1]) { 380 upper = i - 1; 381 } else { 382 return i; 383 } 384 } 385 386 return -1; 387} 388 389/** 390 * Get information on a specific source position. 391 * @param {number} position The source position 392 * @param {boolean} include_resource_offset Set to true to have the resource 393 * offset added to the location 394 * @return {SourceLocation} 395 * If line is negative or not in the source null is returned. 396 */ 397function ScriptLocationFromPosition(position, 398 include_resource_offset) { 399 var line = this.lineFromPosition(position); 400 if (line == -1) return null; 401 402 // Determine start, end and column. 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 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') { 407 end--; 408 } 409 var column = position - start; 410 411 // Adjust according to the offset within the resource. 412 if (include_resource_offset) { 413 line += this.line_offset; 414 if (line == this.line_offset) { 415 column += this.column_offset; 416 } 417 } 418 419 return new SourceLocation(this, position, line, column, start, end); 420} 421 422 423/** 424 * Get information on a specific source line and column possibly offset by a 425 * fixed source position. This function is used to find a source position from 426 * a line and column position. The fixed source position offset is typically 427 * used to find a source position in a function based on a line and column in 428 * the source for the function alone. The offset passed will then be the 429 * start position of the source for the function within the full script source. 430 * @param {number} opt_line The line within the source. Default value is 0 431 * @param {number} opt_column The column in within the line. Default value is 0 432 * @param {number} opt_offset_position The offset from the begining of the 433 * source from where the line and column calculation starts. 434 * Default value is 0 435 * @return {SourceLocation} 436 * If line is negative or not in the source null is returned. 437 */ 438function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) { 439 // Default is the first line in the script. Lines in the script is relative 440 // to the offset within the resource. 441 var line = 0; 442 if (!IS_UNDEFINED(opt_line)) { 443 line = opt_line - this.line_offset; 444 } 445 446 // Default is first column. If on the first line add the offset within the 447 // resource. 448 var column = opt_column || 0; 449 if (line == 0) { 450 column -= this.column_offset; 451 } 452 453 var offset_position = opt_offset_position || 0; 454 if (line < 0 || column < 0 || offset_position < 0) return null; 455 if (line == 0) { 456 return this.locationFromPosition(offset_position + column, false); 457 } else { 458 // Find the line where the offset position is located. 459 var offset_line = this.lineFromPosition(offset_position); 460 461 if (offset_line == -1 || offset_line + line >= this.lineCount()) { 462 return null; 463 } 464 465 return this.locationFromPosition( 466 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here. 467 } 468} 469 470 471/** 472 * Get a slice of source code from the script. The boundaries for the slice is 473 * specified in lines. 474 * @param {number} opt_from_line The first line (zero bound) in the slice. 475 * Default is 0 476 * @param {number} opt_to_column The last line (zero bound) in the slice (non 477 * inclusive). Default is the number of lines in the script 478 * @return {SourceSlice} The source slice or null of the parameters where 479 * invalid 480 */ 481function ScriptSourceSlice(opt_from_line, opt_to_line) { 482 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset 483 : opt_from_line; 484 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() 485 : opt_to_line; 486 487 // Adjust according to the offset within the resource. 488 from_line -= this.line_offset; 489 to_line -= this.line_offset; 490 if (from_line < 0) from_line = 0; 491 if (to_line > this.lineCount()) to_line = this.lineCount(); 492 493 // Check parameters. 494 if (from_line >= this.lineCount() || 495 to_line < 0 || 496 from_line > to_line) { 497 return null; 498 } 499 500 var line_ends = this.line_ends; 501 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1; 502 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1; 503 504 // Return a source slice with line numbers re-adjusted to the resource. 505 return new SourceSlice(this, 506 from_line + this.line_offset, 507 to_line + this.line_offset, 508 from_position, to_position); 509} 510 511 512function ScriptSourceLine(opt_line) { 513 // Default is the first line in the script. Lines in the script are relative 514 // to the offset within the resource. 515 var line = 0; 516 if (!IS_UNDEFINED(opt_line)) { 517 line = opt_line - this.line_offset; 518 } 519 520 // Check parameter. 521 if (line < 0 || this.lineCount() <= line) { 522 return null; 523 } 524 525 // Return the source line. 526 var line_ends = this.line_ends; 527 var start = line == 0 ? 0 : line_ends[line - 1] + 1; 528 var end = line_ends[line]; 529 return %_CallFunction(this.source, start, end, StringSubstring); 530} 531 532 533/** 534 * Returns the number of source lines. 535 * @return {number} 536 * Number of source lines. 537 */ 538function ScriptLineCount() { 539 // Return number of source lines. 540 return this.line_ends.length; 541} 542 543 544/** 545 * If sourceURL comment is available and script starts at zero returns sourceURL 546 * comment contents. Otherwise, script name is returned. See 547 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt 548 * and Source Map Revision 3 proposal for details on using //# sourceURL and 549 * deprecated //@ sourceURL comment to identify scripts that don't have name. 550 * 551 * @return {?string} script name if present, value for //# sourceURL or 552 * deprecated //@ sourceURL comment otherwise. 553 */ 554function ScriptNameOrSourceURL() { 555 if (this.line_offset > 0 || this.column_offset > 0) { 556 return this.name; 557 } 558 559 // The result is cached as on long scripts it takes noticable time to search 560 // for the sourceURL. 561 if (this.hasCachedNameOrSourceURL) { 562 return this.cachedNameOrSourceURL; 563 } 564 this.hasCachedNameOrSourceURL = true; 565 566 // TODO(608): the spaces in a regexp below had to be escaped as \040 567 // because this file is being processed by js2c whose handling of spaces 568 // in regexps is broken. Also, ['"] are excluded from allowed URLs to 569 // avoid matches against sources that invoke evals with sourceURL. 570 // A better solution would be to detect these special comments in 571 // the scanner/parser. 572 var source = ToString(this.source); 573 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0); 574 this.cachedNameOrSourceURL = this.name; 575 if (sourceUrlPos > 4) { 576 var sourceUrlPattern = 577 /\/\/[#@][\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm; 578 // Don't reuse lastMatchInfo here, so we create a new array with room 579 // for four captures (array with length one longer than the index 580 // of the fourth capture, where the numbering is zero-based). 581 var matchInfo = new InternalArray(CAPTURE(3) + 1); 582 var match = 583 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo); 584 if (match) { 585 this.cachedNameOrSourceURL = 586 %_SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]); 587 } 588 } 589 return this.cachedNameOrSourceURL; 590} 591 592 593SetUpLockedPrototype(Script, 594 $Array("source", "name", "line_ends", "line_offset", "column_offset", 595 "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ), 596 $Array( 597 "lineFromPosition", ScriptLineFromPosition, 598 "locationFromPosition", ScriptLocationFromPosition, 599 "locationFromLine", ScriptLocationFromLine, 600 "sourceSlice", ScriptSourceSlice, 601 "sourceLine", ScriptSourceLine, 602 "lineCount", ScriptLineCount, 603 "nameOrSourceURL", ScriptNameOrSourceURL 604 ) 605); 606 607 608/** 609 * Class for source location. A source location is a position within some 610 * source with the following properties: 611 * script : script object for the source 612 * line : source line number 613 * column : source column within the line 614 * position : position within the source 615 * start : position of start of source context (inclusive) 616 * end : position of end of source context (not inclusive) 617 * Source text for the source context is the character interval 618 * [start, end[. In most cases end will point to a newline character. 619 * It might point just past the final position of the source if the last 620 * source line does not end with a newline character. 621 * @param {Script} script The Script object for which this is a location 622 * @param {number} position Source position for the location 623 * @param {number} line The line number for the location 624 * @param {number} column The column within the line for the location 625 * @param {number} start Source position for start of source context 626 * @param {number} end Source position for end of source context 627 * @constructor 628 */ 629function SourceLocation(script, position, line, column, start, end) { 630 this.script = script; 631 this.position = position; 632 this.line = line; 633 this.column = column; 634 this.start = start; 635 this.end = end; 636} 637 638var kLineLengthLimit = 78; 639 640/** 641 * Restrict source location start and end positions to make the source slice 642 * no more that a certain number of characters wide. 643 * @param {number} opt_limit The with limit of the source text with a default 644 * of 78 645 * @param {number} opt_before The number of characters to prefer before the 646 * position with a default value of 10 less that the limit 647 */ 648function SourceLocationRestrict(opt_limit, opt_before) { 649 // Find the actual limit to use. 650 var limit; 651 var before; 652 if (!IS_UNDEFINED(opt_limit)) { 653 limit = opt_limit; 654 } else { 655 limit = kLineLengthLimit; 656 } 657 if (!IS_UNDEFINED(opt_before)) { 658 before = opt_before; 659 } else { 660 // If no before is specified center for small limits and perfer more source 661 // before the the position that after for longer limits. 662 if (limit <= 20) { 663 before = $floor(limit / 2); 664 } else { 665 before = limit - 10; 666 } 667 } 668 if (before >= limit) { 669 before = limit - 1; 670 } 671 672 // If the [start, end[ interval is too big we restrict 673 // it in one or both ends. We make sure to always produce 674 // restricted intervals of maximum allowed size. 675 if (this.end - this.start > limit) { 676 var start_limit = this.position - before; 677 var end_limit = this.position + limit - before; 678 if (this.start < start_limit && end_limit < this.end) { 679 this.start = start_limit; 680 this.end = end_limit; 681 } else if (this.start < start_limit) { 682 this.start = this.end - limit; 683 } else { 684 this.end = this.start + limit; 685 } 686 } 687} 688 689 690/** 691 * Get the source text for a SourceLocation 692 * @return {String} 693 * Source text for this location. 694 */ 695function SourceLocationSourceText() { 696 return %_CallFunction(this.script.source, 697 this.start, 698 this.end, 699 StringSubstring); 700} 701 702 703SetUpLockedPrototype(SourceLocation, 704 $Array("script", "position", "line", "column", "start", "end"), 705 $Array( 706 "restrict", SourceLocationRestrict, 707 "sourceText", SourceLocationSourceText 708 ) 709); 710 711 712/** 713 * Class for a source slice. A source slice is a part of a script source with 714 * the following properties: 715 * script : script object for the source 716 * from_line : line number for the first line in the slice 717 * to_line : source line number for the last line in the slice 718 * from_position : position of the first character in the slice 719 * to_position : position of the last character in the slice 720 * The to_line and to_position are not included in the slice, that is the lines 721 * in the slice are [from_line, to_line[. Likewise the characters in the slice 722 * are [from_position, to_position[. 723 * @param {Script} script The Script object for the source slice 724 * @param {number} from_line 725 * @param {number} to_line 726 * @param {number} from_position 727 * @param {number} to_position 728 * @constructor 729 */ 730function SourceSlice(script, from_line, to_line, from_position, to_position) { 731 this.script = script; 732 this.from_line = from_line; 733 this.to_line = to_line; 734 this.from_position = from_position; 735 this.to_position = to_position; 736} 737 738/** 739 * Get the source text for a SourceSlice 740 * @return {String} Source text for this slice. The last line will include 741 * the line terminating characters (if any) 742 */ 743function SourceSliceSourceText() { 744 return %_CallFunction(this.script.source, 745 this.from_position, 746 this.to_position, 747 StringSubstring); 748} 749 750SetUpLockedPrototype(SourceSlice, 751 $Array("script", "from_line", "to_line", "from_position", "to_position"), 752 $Array("sourceText", SourceSliceSourceText) 753); 754 755 756// Returns the offset of the given position within the containing 757// line. 758function GetPositionInLine(message) { 759 var script = %MessageGetScript(message); 760 var start_position = %MessageGetStartPosition(message); 761 var location = script.locationFromPosition(start_position, false); 762 if (location == null) return -1; 763 location.restrict(); 764 return start_position - location.start; 765} 766 767 768function GetStackTraceLine(recv, fun, pos, isGlobal) { 769 return new CallSite(recv, fun, pos, false).toString(); 770} 771 772// ---------------------------------------------------------------------------- 773// Error implementation 774 775var CallSiteReceiverKey = NEW_PRIVATE("CallSite#receiver"); 776var CallSiteFunctionKey = NEW_PRIVATE("CallSite#function"); 777var CallSitePositionKey = NEW_PRIVATE("CallSite#position"); 778var CallSiteStrictModeKey = NEW_PRIVATE("CallSite#strict_mode"); 779 780function CallSite(receiver, fun, pos, strict_mode) { 781 SET_PRIVATE(this, CallSiteReceiverKey, receiver); 782 SET_PRIVATE(this, CallSiteFunctionKey, fun); 783 SET_PRIVATE(this, CallSitePositionKey, pos); 784 SET_PRIVATE(this, CallSiteStrictModeKey, strict_mode); 785} 786 787function CallSiteGetThis() { 788 return GET_PRIVATE(this, CallSiteStrictModeKey) 789 ? UNDEFINED : GET_PRIVATE(this, CallSiteReceiverKey); 790} 791 792function CallSiteGetTypeName() { 793 return GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), false); 794} 795 796function CallSiteIsToplevel() { 797 if (GET_PRIVATE(this, CallSiteReceiverKey) == null) { 798 return true; 799 } 800 return IS_GLOBAL(GET_PRIVATE(this, CallSiteReceiverKey)); 801} 802 803function CallSiteIsEval() { 804 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 805 return script && script.compilation_type == COMPILATION_TYPE_EVAL; 806} 807 808function CallSiteGetEvalOrigin() { 809 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 810 return FormatEvalOrigin(script); 811} 812 813function CallSiteGetScriptNameOrSourceURL() { 814 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 815 return script ? script.nameOrSourceURL() : null; 816} 817 818function CallSiteGetFunction() { 819 return GET_PRIVATE(this, CallSiteStrictModeKey) 820 ? UNDEFINED : GET_PRIVATE(this, CallSiteFunctionKey); 821} 822 823function CallSiteGetFunctionName() { 824 // See if the function knows its own name 825 var name = GET_PRIVATE(this, CallSiteFunctionKey).name; 826 if (name) { 827 return name; 828 } 829 name = %FunctionGetInferredName(GET_PRIVATE(this, CallSiteFunctionKey)); 830 if (name) { 831 return name; 832 } 833 // Maybe this is an evaluation? 834 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 835 if (script && script.compilation_type == COMPILATION_TYPE_EVAL) { 836 return "eval"; 837 } 838 return null; 839} 840 841function CallSiteGetMethodName() { 842 // See if we can find a unique property on the receiver that holds 843 // this function. 844 var receiver = GET_PRIVATE(this, CallSiteReceiverKey); 845 var fun = GET_PRIVATE(this, CallSiteFunctionKey); 846 var ownName = fun.name; 847 if (ownName && receiver && 848 (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun || 849 %_CallFunction(receiver, ownName, ObjectLookupSetter) === fun || 850 (IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) { 851 // To handle DontEnum properties we guess that the method has 852 // the same name as the function. 853 return ownName; 854 } 855 var name = null; 856 for (var prop in receiver) { 857 if (%_CallFunction(receiver, prop, ObjectLookupGetter) === fun || 858 %_CallFunction(receiver, prop, ObjectLookupSetter) === fun || 859 (IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) { 860 // If we find more than one match bail out to avoid confusion. 861 if (name) { 862 return null; 863 } 864 name = prop; 865 } 866 } 867 if (name) { 868 return name; 869 } 870 return null; 871} 872 873function CallSiteGetFileName() { 874 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 875 return script ? script.name : null; 876} 877 878function CallSiteGetLineNumber() { 879 if (GET_PRIVATE(this, CallSitePositionKey) == -1) { 880 return null; 881 } 882 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 883 var location = null; 884 if (script) { 885 location = script.locationFromPosition( 886 GET_PRIVATE(this, CallSitePositionKey), true); 887 } 888 return location ? location.line + 1 : null; 889} 890 891function CallSiteGetColumnNumber() { 892 if (GET_PRIVATE(this, CallSitePositionKey) == -1) { 893 return null; 894 } 895 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 896 var location = null; 897 if (script) { 898 location = script.locationFromPosition( 899 GET_PRIVATE(this, CallSitePositionKey), true); 900 } 901 return location ? location.column + 1: null; 902} 903 904function CallSiteIsNative() { 905 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey)); 906 return script ? (script.type == TYPE_NATIVE) : false; 907} 908 909function CallSiteGetPosition() { 910 return GET_PRIVATE(this, CallSitePositionKey); 911} 912 913function CallSiteIsConstructor() { 914 var receiver = GET_PRIVATE(this, CallSiteReceiverKey); 915 var constructor = (receiver != null && IS_OBJECT(receiver)) 916 ? %GetDataProperty(receiver, "constructor") : null; 917 if (!constructor) return false; 918 return GET_PRIVATE(this, CallSiteFunctionKey) === constructor; 919} 920 921function CallSiteToString() { 922 var fileName; 923 var fileLocation = ""; 924 if (this.isNative()) { 925 fileLocation = "native"; 926 } else { 927 fileName = this.getScriptNameOrSourceURL(); 928 if (!fileName && this.isEval()) { 929 fileLocation = this.getEvalOrigin(); 930 fileLocation += ", "; // Expecting source position to follow. 931 } 932 933 if (fileName) { 934 fileLocation += fileName; 935 } else { 936 // Source code does not originate from a file and is not native, but we 937 // can still get the source position inside the source string, e.g. in 938 // an eval string. 939 fileLocation += "<anonymous>"; 940 } 941 var lineNumber = this.getLineNumber(); 942 if (lineNumber != null) { 943 fileLocation += ":" + lineNumber; 944 var columnNumber = this.getColumnNumber(); 945 if (columnNumber) { 946 fileLocation += ":" + columnNumber; 947 } 948 } 949 } 950 951 var line = ""; 952 var functionName = this.getFunctionName(); 953 var addSuffix = true; 954 var isConstructor = this.isConstructor(); 955 var isMethodCall = !(this.isToplevel() || isConstructor); 956 if (isMethodCall) { 957 var typeName = GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), true); 958 var methodName = this.getMethodName(); 959 if (functionName) { 960 if (typeName && 961 %_CallFunction(functionName, typeName, StringIndexOfJS) != 0) { 962 line += typeName + "."; 963 } 964 line += functionName; 965 if (methodName && 966 (%_CallFunction(functionName, "." + methodName, StringIndexOfJS) != 967 functionName.length - methodName.length - 1)) { 968 line += " [as " + methodName + "]"; 969 } 970 } else { 971 line += typeName + "." + (methodName || "<anonymous>"); 972 } 973 } else if (isConstructor) { 974 line += "new " + (functionName || "<anonymous>"); 975 } else if (functionName) { 976 line += functionName; 977 } else { 978 line += fileLocation; 979 addSuffix = false; 980 } 981 if (addSuffix) { 982 line += " (" + fileLocation + ")"; 983 } 984 return line; 985} 986 987SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array( 988 "getThis", CallSiteGetThis, 989 "getTypeName", CallSiteGetTypeName, 990 "isToplevel", CallSiteIsToplevel, 991 "isEval", CallSiteIsEval, 992 "getEvalOrigin", CallSiteGetEvalOrigin, 993 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL, 994 "getFunction", CallSiteGetFunction, 995 "getFunctionName", CallSiteGetFunctionName, 996 "getMethodName", CallSiteGetMethodName, 997 "getFileName", CallSiteGetFileName, 998 "getLineNumber", CallSiteGetLineNumber, 999 "getColumnNumber", CallSiteGetColumnNumber, 1000 "isNative", CallSiteIsNative, 1001 "getPosition", CallSiteGetPosition, 1002 "isConstructor", CallSiteIsConstructor, 1003 "toString", CallSiteToString 1004)); 1005 1006 1007function FormatEvalOrigin(script) { 1008 var sourceURL = script.nameOrSourceURL(); 1009 if (sourceURL) { 1010 return sourceURL; 1011 } 1012 1013 var eval_origin = "eval at "; 1014 if (script.eval_from_function_name) { 1015 eval_origin += script.eval_from_function_name; 1016 } else { 1017 eval_origin += "<anonymous>"; 1018 } 1019 1020 var eval_from_script = script.eval_from_script; 1021 if (eval_from_script) { 1022 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) { 1023 // eval script originated from another eval. 1024 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")"; 1025 } else { 1026 // eval script originated from "real" source. 1027 if (eval_from_script.name) { 1028 eval_origin += " (" + eval_from_script.name; 1029 var location = eval_from_script.locationFromPosition( 1030 script.eval_from_script_position, true); 1031 if (location) { 1032 eval_origin += ":" + (location.line + 1); 1033 eval_origin += ":" + (location.column + 1); 1034 } 1035 eval_origin += ")"; 1036 } else { 1037 eval_origin += " (unknown source)"; 1038 } 1039 } 1040 } 1041 1042 return eval_origin; 1043} 1044 1045 1046function FormatErrorString(error) { 1047 try { 1048 return %_CallFunction(error, ErrorToString); 1049 } catch (e) { 1050 try { 1051 return "<error: " + e + ">"; 1052 } catch (ee) { 1053 return "<error>"; 1054 } 1055 } 1056} 1057 1058 1059function GetStackFrames(raw_stack) { 1060 var frames = new InternalArray(); 1061 var sloppy_frames = raw_stack[0]; 1062 for (var i = 1; i < raw_stack.length; i += 4) { 1063 var recv = raw_stack[i]; 1064 var fun = raw_stack[i + 1]; 1065 var code = raw_stack[i + 2]; 1066 var pc = raw_stack[i + 3]; 1067 var pos = %FunctionGetPositionForOffset(code, pc); 1068 sloppy_frames--; 1069 frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0))); 1070 } 1071 return frames; 1072} 1073 1074 1075// Flag to prevent recursive call of Error.prepareStackTrace. 1076var formatting_custom_stack_trace = false; 1077 1078 1079function FormatStackTrace(obj, error_string, frames) { 1080 if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) { 1081 var array = []; 1082 %MoveArrayContents(frames, array); 1083 formatting_custom_stack_trace = true; 1084 var stack_trace = UNDEFINED; 1085 try { 1086 stack_trace = $Error.prepareStackTrace(obj, array); 1087 } catch (e) { 1088 throw e; // The custom formatting function threw. Rethrow. 1089 } finally { 1090 formatting_custom_stack_trace = false; 1091 } 1092 return stack_trace; 1093 } 1094 1095 var lines = new InternalArray(); 1096 lines.push(error_string); 1097 for (var i = 0; i < frames.length; i++) { 1098 var frame = frames[i]; 1099 var line; 1100 try { 1101 line = frame.toString(); 1102 } catch (e) { 1103 try { 1104 line = "<error: " + e + ">"; 1105 } catch (ee) { 1106 // Any code that reaches this point is seriously nasty! 1107 line = "<error>"; 1108 } 1109 } 1110 lines.push(" at " + line); 1111 } 1112 return %_CallFunction(lines, "\n", ArrayJoin); 1113} 1114 1115 1116function GetTypeName(receiver, requireConstructor) { 1117 var constructor = receiver.constructor; 1118 if (!constructor) { 1119 return requireConstructor ? null : 1120 %_CallFunction(receiver, ObjectToString); 1121 } 1122 var constructorName = constructor.name; 1123 if (!constructorName) { 1124 return requireConstructor ? null : 1125 %_CallFunction(receiver, ObjectToString); 1126 } 1127 return constructorName; 1128} 1129 1130 1131function captureStackTrace(obj, cons_opt) { 1132 var stackTraceLimit = $Error.stackTraceLimit; 1133 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; 1134 if (stackTraceLimit < 0 || stackTraceLimit > 10000) { 1135 stackTraceLimit = 10000; 1136 } 1137 var stack = %CollectStackTrace(obj, 1138 cons_opt ? cons_opt : captureStackTrace, 1139 stackTraceLimit); 1140 1141 var error_string = FormatErrorString(obj); 1142 1143 // Set the 'stack' property on the receiver. If the receiver is the same as 1144 // holder of this setter, the accessor pair is turned into a data property. 1145 var setter = function(v) { 1146 // Set data property on the receiver (not necessarily holder). 1147 %DefineOrRedefineDataProperty(this, 'stack', v, NONE); 1148 if (this === obj) { 1149 // Release context values if holder is the same as the receiver. 1150 stack = error_string = UNDEFINED; 1151 } 1152 }; 1153 1154 // The holder of this getter ('obj') may not be the receiver ('this'). 1155 // When this getter is called the first time, we use the context values to 1156 // format a stack trace string and turn this accessor pair into a data 1157 // property (on the holder). 1158 var getter = function() { 1159 // Stack is still a raw array awaiting to be formatted. 1160 var result = FormatStackTrace(obj, error_string, GetStackFrames(stack)); 1161 // Replace this accessor to return result directly. 1162 %DefineOrRedefineAccessorProperty( 1163 obj, 'stack', function() { return result }, setter, DONT_ENUM); 1164 // Release context values. 1165 stack = error_string = UNDEFINED; 1166 return result; 1167 }; 1168 1169 %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM); 1170} 1171 1172 1173function SetUpError() { 1174 // Define special error type constructors. 1175 1176 var DefineError = function(f) { 1177 // Store the error function in both the global object 1178 // and the runtime object. The function is fetched 1179 // from the runtime object when throwing errors from 1180 // within the runtime system to avoid strange side 1181 // effects when overwriting the error functions from 1182 // user code. 1183 var name = f.name; 1184 %SetProperty(global, name, f, DONT_ENUM); 1185 %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY); 1186 // Configure the error function. 1187 if (name == 'Error') { 1188 // The prototype of the Error object must itself be an error. 1189 // However, it can't be an instance of the Error object because 1190 // it hasn't been properly configured yet. Instead we create a 1191 // special not-a-true-error-but-close-enough object. 1192 var ErrorPrototype = function() {}; 1193 %FunctionSetPrototype(ErrorPrototype, $Object.prototype); 1194 %FunctionSetInstanceClassName(ErrorPrototype, 'Error'); 1195 %FunctionSetPrototype(f, new ErrorPrototype()); 1196 } else { 1197 %FunctionSetPrototype(f, new $Error()); 1198 } 1199 %FunctionSetInstanceClassName(f, 'Error'); 1200 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM); 1201 %SetProperty(f.prototype, "name", name, DONT_ENUM); 1202 %SetCode(f, function(m) { 1203 if (%_IsConstructCall()) { 1204 // Define all the expected properties directly on the error 1205 // object. This avoids going through getters and setters defined 1206 // on prototype objects. 1207 %IgnoreAttributesAndSetProperty(this, 'stack', UNDEFINED, DONT_ENUM); 1208 if (!IS_UNDEFINED(m)) { 1209 %IgnoreAttributesAndSetProperty( 1210 this, 'message', ToString(m), DONT_ENUM); 1211 } 1212 captureStackTrace(this, f); 1213 } else { 1214 return new f(m); 1215 } 1216 }); 1217 %SetNativeFlag(f); 1218 }; 1219 1220 DefineError(function Error() { }); 1221 DefineError(function TypeError() { }); 1222 DefineError(function RangeError() { }); 1223 DefineError(function SyntaxError() { }); 1224 DefineError(function ReferenceError() { }); 1225 DefineError(function EvalError() { }); 1226 DefineError(function URIError() { }); 1227} 1228 1229SetUpError(); 1230 1231$Error.captureStackTrace = captureStackTrace; 1232 1233%SetProperty($Error.prototype, 'message', '', DONT_ENUM); 1234 1235// Global list of error objects visited during ErrorToString. This is 1236// used to detect cycles in error toString formatting. 1237var visited_errors = new InternalArray(); 1238var cyclic_error_marker = new $Object(); 1239 1240function GetPropertyWithoutInvokingMonkeyGetters(error, name) { 1241 var current = error; 1242 // Climb the prototype chain until we find the holder. 1243 while (current && !%HasOwnProperty(current, name)) { 1244 current = %GetPrototype(current); 1245 } 1246 if (IS_NULL(current)) return UNDEFINED; 1247 if (!IS_OBJECT(current)) return error[name]; 1248 // If the property is an accessor on one of the predefined errors that can be 1249 // generated statically by the compiler, don't touch it. This is to address 1250 // http://code.google.com/p/chromium/issues/detail?id=69187 1251 var desc = %GetOwnProperty(current, name); 1252 if (desc && desc[IS_ACCESSOR_INDEX]) { 1253 var isName = name === "name"; 1254 if (current === $ReferenceError.prototype) 1255 return isName ? "ReferenceError" : UNDEFINED; 1256 if (current === $SyntaxError.prototype) 1257 return isName ? "SyntaxError" : UNDEFINED; 1258 if (current === $TypeError.prototype) 1259 return isName ? "TypeError" : UNDEFINED; 1260 } 1261 // Otherwise, read normally. 1262 return error[name]; 1263} 1264 1265function ErrorToStringDetectCycle(error) { 1266 if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker; 1267 try { 1268 var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name"); 1269 name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name); 1270 var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message"); 1271 message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message); 1272 if (name === "") return message; 1273 if (message === "") return name; 1274 return name + ": " + message; 1275 } finally { 1276 visited_errors.length = visited_errors.length - 1; 1277 } 1278} 1279 1280function ErrorToString() { 1281 if (!IS_SPEC_OBJECT(this)) { 1282 throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]); 1283 } 1284 1285 try { 1286 return ErrorToStringDetectCycle(this); 1287 } catch(e) { 1288 // If this error message was encountered already return the empty 1289 // string for it instead of recursively formatting it. 1290 if (e === cyclic_error_marker) { 1291 return ''; 1292 } 1293 throw e; 1294 } 1295} 1296 1297 1298InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]); 1299 1300// Boilerplate for exceptions for stack overflows. Used from 1301// Isolate::StackOverflow(). 1302function SetUpStackOverflowBoilerplate() { 1303 var boilerplate = MakeRangeError('stack_overflow', []); 1304 1305 var error_string = boilerplate.name + ": " + boilerplate.message; 1306 1307 // Set the 'stack' property on the receiver. If the receiver is the same as 1308 // holder of this setter, the accessor pair is turned into a data property. 1309 var setter = function(v) { 1310 %DefineOrRedefineDataProperty(this, 'stack', v, NONE); 1311 // Tentatively clear the hidden property. If the receiver is the same as 1312 // holder, we release the raw stack trace this way. 1313 %GetAndClearOverflowedStackTrace(this); 1314 }; 1315 1316 // The raw stack trace is stored as a hidden property on the holder of this 1317 // getter, which may not be the same as the receiver. Find the holder to 1318 // retrieve the raw stack trace and then turn this accessor pair into a 1319 // data property. 1320 var getter = function() { 1321 var holder = this; 1322 while (!IS_ERROR(holder)) { 1323 holder = %GetPrototype(holder); 1324 if (IS_NULL(holder)) return MakeSyntaxError('illegal_access', []); 1325 } 1326 var stack = %GetAndClearOverflowedStackTrace(holder); 1327 // We may not have captured any stack trace. 1328 if (IS_UNDEFINED(stack)) return stack; 1329 1330 var result = FormatStackTrace(holder, error_string, GetStackFrames(stack)); 1331 // Replace this accessor to return result directly. 1332 %DefineOrRedefineAccessorProperty( 1333 holder, 'stack', function() { return result }, setter, DONT_ENUM); 1334 return result; 1335 }; 1336 1337 %DefineOrRedefineAccessorProperty( 1338 boilerplate, 'stack', getter, setter, DONT_ENUM); 1339 1340 return boilerplate; 1341} 1342 1343var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate(); 1344