messages.js 50.2 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// -------------------------------------------------------------------

30 31 32 33
var kMessages = {
  // Error
  cyclic_proto:                  ["Cyclic __proto__ value"],
  code_gen_from_strings:         ["%0"],
34 35
  generator_running:             ["Generator is already running"],
  generator_finished:            ["Generator has already finished"],
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
  // TypeError
  unexpected_token:              ["Unexpected token ", "%0"],
  unexpected_token_number:       ["Unexpected number"],
  unexpected_token_string:       ["Unexpected string"],
  unexpected_token_identifier:   ["Unexpected identifier"],
  unexpected_reserved:           ["Unexpected reserved word"],
  unexpected_strict_reserved:    ["Unexpected strict mode reserved word"],
  unexpected_eos:                ["Unexpected end of input"],
  malformed_regexp:              ["Invalid regular expression: /", "%0", "/: ", "%1"],
  unterminated_regexp:           ["Invalid regular expression: missing /"],
  regexp_flags:                  ["Cannot supply flags when constructing one RegExp from another"],
  incompatible_method_receiver:  ["Method ", "%0", " called on incompatible receiver ", "%1"],
  invalid_lhs_in_assignment:     ["Invalid left-hand side in assignment"],
  invalid_lhs_in_for_in:         ["Invalid left-hand side in for-in"],
  invalid_lhs_in_postfix_op:     ["Invalid left-hand side expression in postfix operation"],
  invalid_lhs_in_prefix_op:      ["Invalid left-hand side expression in prefix operation"],
  multiple_defaults_in_switch:   ["More than one default clause in switch statement"],
  newline_after_throw:           ["Illegal newline after throw"],
  redeclaration:                 ["%0", " '", "%1", "' has already been declared"],
  no_catch_or_finally:           ["Missing catch or finally after try"],
  unknown_label:                 ["Undefined label '", "%0", "'"],
  uncaught_exception:            ["Uncaught ", "%0"],
  stack_trace:                   ["Stack Trace:\n", "%0"],
  called_non_callable:           ["%0", " is not a function"],
  undefined_method:              ["Object ", "%1", " has no method '", "%0", "'"],
  property_not_function:         ["Property '", "%0", "' of object ", "%1", " is not a function"],
  cannot_convert_to_primitive:   ["Cannot convert object to primitive value"],
  not_constructor:               ["%0", " is not a constructor"],
  not_defined:                   ["%0", " is not defined"],
  non_object_property_load:      ["Cannot read property '", "%0", "' of ", "%1"],
  non_object_property_store:     ["Cannot set property '", "%0", "' of ", "%1"],
  non_object_property_call:      ["Cannot call method '", "%0", "' of ", "%1"],
  with_expression:               ["%0", " has no properties"],
  illegal_invocation:            ["Illegal invocation"],
  no_setter_in_callback:         ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
  apply_non_function:            ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
  apply_wrong_args:              ["Function.prototype.apply: Arguments list has wrong type"],
  invalid_in_operator_use:       ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
  instanceof_function_expected:  ["Expecting a function in instanceof check, but got ", "%0"],
  instanceof_nonobject_proto:    ["Function has non-object prototype '", "%0", "' in instanceof check"],
76
  undefined_or_null_to_object:   ["Cannot convert undefined or null to object"],
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
  reduce_no_initial:             ["Reduce of empty array with no initial value"],
  getter_must_be_callable:       ["Getter must be a function: ", "%0"],
  setter_must_be_callable:       ["Setter must be a function: ", "%0"],
  value_and_accessor:            ["Invalid property.  A property cannot both have accessors and be writable or have a value, ", "%0"],
  proto_object_or_null:          ["Object prototype may only be an Object or null"],
  property_desc_object:          ["Property description must be an object: ", "%0"],
  redefine_disallowed:           ["Cannot redefine property: ", "%0"],
  define_disallowed:             ["Cannot define property:", "%0", ", object is not extensible."],
  non_extensible_proto:          ["%0", " is not extensible"],
  handler_non_object:            ["Proxy.", "%0", " called with non-object as handler"],
  proto_non_object:              ["Proxy.", "%0", " called with non-object as prototype"],
  trap_function_expected:        ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
  handler_trap_missing:          ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
  handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
  handler_returned_false:        ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
  handler_returned_undefined:    ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
  proxy_prop_not_configurable:   ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
  proxy_non_object_prop_names:   ["Trap '", "%1", "' returned non-object ", "%0"],
  proxy_repeated_prop_name:      ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
  invalid_weakmap_key:           ["Invalid value used as weak map key"],
97
  invalid_weakset_value:         ["Invalid value used in weak set"],
98 99 100 101
  not_date_object:               ["this is not a Date object."],
  observe_non_object:            ["Object.", "%0", " cannot ", "%0", " non-object"],
  observe_non_function:          ["Object.", "%0", " cannot deliver to non-function"],
  observe_callback_frozen:       ["Object.observe cannot deliver to a frozen function object"],
102
  observe_invalid_accept:        ["Object.observe accept must be an array of strings."],
103
  observe_type_non_string:       ["Invalid changeRecord with non-string 'type' property"],
104 105
  observe_perform_non_string:    ["Invalid non-string changeType"],
  observe_perform_non_function:  ["Cannot perform non-function"],
106
  observe_notify_non_notifier:   ["notify called on non-notifier object"],
107
  proto_poison_pill:             ["Generic use of __proto__ accessor not allowed"],
108
  not_typed_array:               ["this is not a typed array."],
109
  invalid_argument:              ["invalid_argument"],
110
  data_view_not_array_buffer:    ["First argument to DataView constructor must be an ArrayBuffer"],
111
  constructor_not_function:      ["Constructor ", "%0", " requires 'new'"],
112 113
  // RangeError
  invalid_array_length:          ["Invalid array length"],
114
  invalid_array_buffer_length:   ["Invalid array buffer length"],
115 116
  invalid_typed_array_offset:    ["Start offset is too large:"],
  invalid_typed_array_length:    ["Invalid typed array length"],
117
  invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
118 119
  typed_array_set_source_too_large:
                                 ["Source is too large"],
120 121
  typed_array_set_negative_offset:
                                 ["Start offset is negative"],
122
  invalid_data_view_offset:      ["Start offset is outside the bounds of the buffer"],
123
  invalid_data_view_length:      ["Invalid data view length"],
124 125 126
  invalid_data_view_accessor_offset:
                                 ["Offset is outside the bounds of the DataView"],

127 128
  stack_overflow:                ["Maximum call stack size exceeded"],
  invalid_time_value:            ["Invalid time value"],
129
  invalid_count_value:           ["Invalid count value"],
130
  // SyntaxError
131 132 133
  paren_in_arg_string:           ["Function arg string contains parenthesis"],
  not_isvar:                     ["builtin %IS_VAR: not a variable"],
  single_function_literal:       ["Single function literal required"],
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  invalid_regexp_flags:          ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
  invalid_regexp:                ["Invalid RegExp pattern /", "%0", "/"],
  illegal_break:                 ["Illegal break statement"],
  illegal_continue:              ["Illegal continue statement"],
  illegal_return:                ["Illegal return statement"],
  illegal_let:                   ["Illegal let declaration outside extended mode"],
  error_loading_debugger:        ["Error loading debugger"],
  no_input_to_regexp:            ["No input to ", "%0"],
  invalid_json:                  ["String '", "%0", "' is not valid JSON"],
  circular_structure:            ["Converting circular structure to JSON"],
  called_on_non_object:          ["%0", " called on non-object"],
  called_on_null_or_undefined:   ["%0", " called on null or undefined"],
  array_indexof_not_defined:     ["Array.getIndexOf: Argument undefined"],
  object_not_extensible:         ["Can't add property ", "%0", ", object is not extensible"],
  illegal_access:                ["Illegal access"],
  invalid_preparser_data:        ["Invalid preparser data for function ", "%0"],
  strict_mode_with:              ["Strict mode code may not include a with statement"],
  strict_catch_variable:         ["Catch variable may not be eval or arguments in strict mode"],
  too_many_arguments:            ["Too many arguments in function call (only 32766 allowed)"],
  too_many_parameters:           ["Too many parameters in function definition (only 32766 allowed)"],
  too_many_variables:            ["Too many variables declared (only 131071 allowed)"],
  strict_param_name:             ["Parameter name eval or arguments is not allowed in strict mode"],
  strict_param_dupe:             ["Strict mode function may not have duplicate parameter names"],
  strict_var_name:               ["Variable name may not be eval or arguments in strict mode"],
  strict_function_name:          ["Function name may not be eval or arguments in strict mode"],
  strict_octal_literal:          ["Octal literals are not allowed in strict mode."],
  strict_duplicate_property:     ["Duplicate data property in object literal not allowed in strict mode"],
  accessor_data_property:        ["Object literal may not have data and accessor property with the same name"],
  accessor_get_set:              ["Object literal may not have multiple get/set accessors with the same name"],
  strict_lhs_assignment:         ["Assignment to eval or arguments is not allowed in strict mode"],
  strict_lhs_postfix:            ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
  strict_lhs_prefix:             ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
  strict_reserved_word:          ["Use of future reserved word in strict mode"],
  strict_delete:                 ["Delete of an unqualified identifier in strict mode."],
  strict_delete_property:        ["Cannot delete property '", "%0", "' of ", "%1"],
  strict_const:                  ["Use of const in strict mode."],
  strict_function:               ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
  strict_read_only_property:     ["Cannot assign to read only property '", "%0", "' of ", "%1"],
  strict_cannot_assign:          ["Cannot assign to read only '", "%0", "' in strict mode"],
  strict_poison_pill:            ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
  strict_caller:                 ["Illegal access to a strict mode caller function."],
  unprotected_let:               ["Illegal let declaration in unprotected statement context."],
  unprotected_const:             ["Illegal const declaration in unprotected statement context."],
  cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
  redef_external_array_element:  ["Cannot redefine a property of an object with external array elements"],
  harmony_const_assign:          ["Assignment to constant variable."],
180
  symbol_to_string:              ["Conversion from symbol to string"],
181 182
  invalid_module_path:           ["Module does not export '", "%0", "', or export is not itself a module"],
  module_type_error:             ["Module '", "%0", "' used improperly"],
183
  module_export_undefined:       ["Export '", "%0", "' is not defined in module"]
184 185 186 187
};


function FormatString(format, args) {
188 189 190 191
  var result = "";
  var arg_num = 0;
  for (var i = 0; i < format.length; i++) {
    var str = format[i];
192 193 194 195 196
    if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
      // Two-char string starts with "%".
      var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
      if (arg_num < 4) {
        // str is one of %0, %1, %2 or %3.
197
        try {
198
          str = NoSideEffectToString(args[arg_num]);
199
        } catch (e) {
200 201 202 203 204 205
          if (%IsJSModule(args[arg_num]))
            str = "module";
          else if (IS_SPEC_OBJECT(args[arg_num]))
            str = "object";
          else
            str = "#<error>";
206
        }
207
      }
208
    }
209
    result += str;
210 211
  }
  return result;
212
}
213 214


215 216 217 218 219 220
function NoSideEffectToString(obj) {
  if (IS_STRING(obj)) return obj;
  if (IS_NUMBER(obj)) return %_NumberToString(obj);
  if (IS_BOOLEAN(obj)) return x ? 'true' : 'false';
  if (IS_UNDEFINED(obj)) return 'undefined';
  if (IS_NULL(obj)) return 'null';
221
  if (IS_FUNCTION(obj)) return  %_CallFunction(obj, FunctionToString);
222
  if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
223
    var constructor = %GetDataProperty(obj, "constructor");
224 225 226 227 228 229 230
    if (typeof constructor == "function") {
      var constructorName = constructor.name;
      if (IS_STRING(constructorName) && constructorName !== "") {
        return "#<" + constructorName + ">";
      }
    }
  }
231 232 233
  if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
    return %_CallFunction(obj, ErrorToString);
  }
234 235 236
  return %_CallFunction(obj, ObjectToString);
}

237 238 239 240 241 242
// To determine whether we can safely stringify an object using ErrorToString
// without the risk of side-effects, we need to check whether the object is
// either an instance of a native error type (via '%_ClassOf'), or has $Error
// in its prototype chain and hasn't overwritten 'toString' with something
// strange and unusual.
function CanBeSafelyTreatedAsAnErrorObject(obj) {
243 244 245 246 247 248 249 250 251 252
  switch (%_ClassOf(obj)) {
    case 'Error':
    case 'EvalError':
    case 'RangeError':
    case 'ReferenceError':
    case 'SyntaxError':
    case 'TypeError':
    case 'URIError':
      return true;
  }
253 254 255

  var objToString = %GetDataProperty(obj, "toString");
  return obj instanceof $Error && objToString === ErrorToString;
256 257 258
}


259 260 261 262 263
// When formatting internally created error messages, do not
// invoke overwritten error toString methods but explicitly use
// the error to string method. This is to avoid leaking error
// objects between script tags in a browser setting.
function ToStringCheckErrorObject(obj) {
264
  if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
265
    return %_CallFunction(obj, ErrorToString);
266 267 268 269 270 271
  } else {
    return ToString(obj);
  }
}


272
function ToDetailString(obj) {
273
  if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
274
    var constructor = obj.constructor;
275 276 277 278 279
    if (typeof constructor == "function") {
      var constructorName = constructor.name;
      if (IS_STRING(constructorName) && constructorName !== "") {
        return "#<" + constructorName + ">";
      }
280
    }
281
  }
282
  return ToStringCheckErrorObject(obj);
283
}
284 285 286


function MakeGenericError(constructor, type, args) {
287 288
  if (IS_UNDEFINED(args)) args = [];
  return new constructor(FormatMessage(type, args));
289
}
290 291 292


/**
293
 * Set up the Script function and constructor.
294 295
 */
%FunctionSetInstanceClassName(Script, 'Script');
296 297
%SetProperty(Script.prototype, 'constructor', Script,
             DONT_ENUM | DONT_DELETE | READ_ONLY);
298 299 300 301 302 303 304
%SetCode(Script, function(x) {
  // Script objects can only be created by the VM.
  throw new $Error("Not supported");
});


// Helper functions; called from the runtime system.
305 306 307 308
function FormatMessage(type, args) {
  var format = kMessages[type];
  if (!format) return "<unknown message " + type + ">";
  return FormatString(format, args);
309
}
310 311 312


function GetLineNumber(message) {
313 314 315 316
  var start_position = %MessageGetStartPosition(message);
  if (start_position == -1) return kNoLineNumberInfo;
  var script = %MessageGetScript(message);
  var location = script.locationFromPosition(start_position, true);
317
  if (location == null) return kNoLineNumberInfo;
318
  return location.line + 1;
319
}
320 321 322 323 324


// Returns the source code line containing the given source
// position, or the empty string if the position is invalid.
function GetSourceLine(message) {
325 326 327
  var script = %MessageGetScript(message);
  var start_position = %MessageGetStartPosition(message);
  var location = script.locationFromPosition(start_position, true);
328 329 330
  if (location == null) return "";
  location.restrict();
  return location.sourceText();
331
}
332 333 334 335


function MakeTypeError(type, args) {
  return MakeGenericError($TypeError, type, args);
336
}
337 338 339 340


function MakeRangeError(type, args) {
  return MakeGenericError($RangeError, type, args);
341
}
342 343 344 345


function MakeSyntaxError(type, args) {
  return MakeGenericError($SyntaxError, type, args);
346
}
347 348 349 350


function MakeReferenceError(type, args) {
  return MakeGenericError($ReferenceError, type, args);
351
}
352 353 354 355


function MakeEvalError(type, args) {
  return MakeGenericError($EvalError, type, args);
356
}
357 358 359 360


function MakeError(type, args) {
  return MakeGenericError($Error, type, args);
361
}
362

363 364 365 366 367 368
/**
 * Find a line number given a specific source position.
 * @param {number} position The source position.
 * @return {number} 0 if input too small, -1 if input too large,
       else the line number.
 */
369
function ScriptLineFromPosition(position) {
370 371
  var lower = 0;
  var upper = this.lineCount() - 1;
372
  var line_ends = this.line_ends;
373 374

  // We'll never find invalid positions so bail right away.
375
  if (position > line_ends[upper]) {
376 377 378 379
    return -1;
  }

  // This means we don't have to safe-guard indexing line_ends[i - 1].
380
  if (position <= line_ends[0]) {
381 382 383 384 385 386 387
    return 0;
  }

  // Binary search to find line # from position range.
  while (upper >= 1) {
    var i = (lower + upper) >> 1;

388
    if (position > line_ends[i]) {
389
      lower = i + 1;
390
    } else if (position <= line_ends[i - 1]) {
391 392 393 394 395
      upper = i - 1;
    } else {
      return i;
    }
  }
396

397 398
  return -1;
}
399 400 401 402

/**
 * Get information on a specific source position.
 * @param {number} position The source position
403 404
 * @param {boolean} include_resource_offset Set to true to have the resource
 *     offset added to the location
405 406 407
 * @return {SourceLocation}
 *     If line is negative or not in the source null is returned.
 */
408 409
function ScriptLocationFromPosition(position,
                                    include_resource_offset) {
410
  var line = this.lineFromPosition(position);
411
  if (line == -1) return null;
412

413
  // Determine start, end and column.
414 415 416
  var line_ends = this.line_ends;
  var start = line == 0 ? 0 : line_ends[line - 1] + 1;
  var end = line_ends[line];
417 418 419
  if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
    end--;
  }
420 421 422
  var column = position - start;

  // Adjust according to the offset within the resource.
423 424 425 426 427
  if (include_resource_offset) {
    line += this.line_offset;
    if (line == this.line_offset) {
      column += this.column_offset;
    }
428 429 430
  }

  return new SourceLocation(this, position, line, column, start, end);
431
}
432 433 434 435 436 437 438 439 440 441 442 443


/**
 * Get information on a specific source line and column possibly offset by a
 * fixed source position. This function is used to find a source position from
 * a line and column position. The fixed source position offset is typically
 * used to find a source position in a function based on a line and column in
 * the source for the function alone. The offset passed will then be the
 * start position of the source for the function within the full script source.
 * @param {number} opt_line The line within the source. Default value is 0
 * @param {number} opt_column The column in within the line. Default value is 0
 * @param {number} opt_offset_position The offset from the begining of the
444 445
 *     source from where the line and column calculation starts.
 *     Default value is 0
446 447 448
 * @return {SourceLocation}
 *     If line is negative or not in the source null is returned.
 */
449
function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
450 451 452 453 454 455
  // Default is the first line in the script. Lines in the script is relative
  // to the offset within the resource.
  var line = 0;
  if (!IS_UNDEFINED(opt_line)) {
    line = opt_line - this.line_offset;
  }
456

457 458 459 460
  // Default is first column. If on the first line add the offset within the
  // resource.
  var column = opt_column || 0;
  if (line == 0) {
461
    column -= this.column_offset;
462 463 464 465 466
  }

  var offset_position = opt_offset_position || 0;
  if (line < 0 || column < 0 || offset_position < 0) return null;
  if (line == 0) {
467
    return this.locationFromPosition(offset_position + column, false);
468
  } else {
469 470 471 472 473
    // Find the line where the offset position is located.
    var offset_line = this.lineFromPosition(offset_position);

    if (offset_line == -1 || offset_line + line >= this.lineCount()) {
      return null;
474
    }
475

476 477
    return this.locationFromPosition(
        this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
478 479 480 481 482 483 484 485 486 487 488 489 490 491
  }
}


/**
 * Get a slice of source code from the script. The boundaries for the slice is
 * specified in lines.
 * @param {number} opt_from_line The first line (zero bound) in the slice.
 *     Default is 0
 * @param {number} opt_to_column The last line (zero bound) in the slice (non
 *     inclusive). Default is the number of lines in the script
 * @return {SourceSlice} The source slice or null of the parameters where
 *     invalid
 */
492
function ScriptSourceSlice(opt_from_line, opt_to_line) {
493 494 495 496
  var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
                                              : opt_from_line;
  var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
                                          : opt_to_line;
497 498 499 500 501 502 503

  // Adjust according to the offset within the resource.
  from_line -= this.line_offset;
  to_line -= this.line_offset;
  if (from_line < 0) from_line = 0;
  if (to_line > this.lineCount()) to_line = this.lineCount();

504
  // Check parameters.
505 506 507 508 509 510
  if (from_line >= this.lineCount() ||
      to_line < 0 ||
      from_line > to_line) {
    return null;
  }

511 512 513
  var line_ends = this.line_ends;
  var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
  var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
514 515

  // Return a source slice with line numbers re-adjusted to the resource.
516 517 518 519
  return new SourceSlice(this,
                         from_line + this.line_offset,
                         to_line + this.line_offset,
                          from_position, to_position);
520 521 522
}


523
function ScriptSourceLine(opt_line) {
524 525 526 527 528 529
  // Default is the first line in the script. Lines in the script are relative
  // to the offset within the resource.
  var line = 0;
  if (!IS_UNDEFINED(opt_line)) {
    line = opt_line - this.line_offset;
  }
530 531

  // Check parameter.
532 533 534 535
  if (line < 0 || this.lineCount() <= line) {
    return null;
  }

536
  // Return the source line.
537 538 539
  var line_ends = this.line_ends;
  var start = line == 0 ? 0 : line_ends[line - 1] + 1;
  var end = line_ends[line];
540
  return %_CallFunction(this.source, start, end, StringSubstring);
541 542 543 544 545 546 547 548
}


/**
 * Returns the number of source lines.
 * @return {number}
 *     Number of source lines.
 */
549
function ScriptLineCount() {
550 551
  // Return number of source lines.
  return this.line_ends.length;
552
}
553 554


555
/**
556 557
 * If sourceURL comment is available and script starts at zero returns sourceURL
 * comment contents. Otherwise, script name is returned. See
558
 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
559 560
 * and Source Map Revision 3 proposal for details on using //# sourceURL and
 * deprecated //@ sourceURL comment to identify scripts that don't have name.
561
 *
562 563
 * @return {?string} script name if present, value for //# sourceURL or
 * deprecated //@ sourceURL comment otherwise.
564
 */
565
function ScriptNameOrSourceURL() {
566
  if (this.line_offset > 0 || this.column_offset > 0) {
567
    return this.name;
568
  }
569 570 571

  // The result is cached as on long scripts it takes noticable time to search
  // for the sourceURL.
572 573 574
  if (this.hasCachedNameOrSourceURL) {
    return this.cachedNameOrSourceURL;
  }
575 576
  this.hasCachedNameOrSourceURL = true;

577
  // TODO(608): the spaces in a regexp below had to be escaped as \040
578 579 580
  // because this file is being processed by js2c whose handling of spaces
  // in regexps is broken. Also, ['"] are excluded from allowed URLs to
  // avoid matches against sources that invoke evals with sourceURL.
581 582 583 584
  // A better solution would be to detect these special comments in
  // the scanner/parser.
  var source = ToString(this.source);
  var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
585
  this.cachedNameOrSourceURL = this.name;
586 587
  if (sourceUrlPos > 4) {
    var sourceUrlPattern =
588
        /\/\/[#@][\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
589 590 591
    // Don't reuse lastMatchInfo here, so we create a new array with room
    // for four captures (array with length one longer than the index
    // of the fourth capture, where the numbering is zero-based).
592
    var matchInfo = new InternalArray(CAPTURE(3) + 1);
593 594 595
    var match =
        %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
    if (match) {
596
      this.cachedNameOrSourceURL =
597
          %_SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
598 599
    }
  }
600
  return this.cachedNameOrSourceURL;
601 602 603
}


604
SetUpLockedPrototype(Script,
605 606
  $Array("source", "name", "line_ends", "line_offset", "column_offset",
         "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
607 608 609 610 611 612 613 614 615 616 617 618
  $Array(
    "lineFromPosition", ScriptLineFromPosition,
    "locationFromPosition", ScriptLocationFromPosition,
    "locationFromLine", ScriptLocationFromLine,
    "sourceSlice", ScriptSourceSlice,
    "sourceLine", ScriptSourceLine,
    "lineCount", ScriptLineCount,
    "nameOrSourceURL", ScriptNameOrSourceURL
  )
);


619 620 621 622 623 624 625 626 627
/**
 * Class for source location. A source location is a position within some
 * source with the following properties:
 *   script   : script object for the source
 *   line     : source line number
 *   column   : source column within the line
 *   position : position within the source
 *   start    : position of start of source context (inclusive)
 *   end      : position of end of source context (not inclusive)
628 629 630 631
 * Source text for the source context is the character interval
 * [start, end[. In most cases end will point to a newline character.
 * It might point just past the final position of the source if the last
 * source line does not end with a newline character.
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
 * @param {Script} script The Script object for which this is a location
 * @param {number} position Source position for the location
 * @param {number} line The line number for the location
 * @param {number} column The column within the line for the location
 * @param {number} start Source position for start of source context
 * @param {number} end Source position for end of source context
 * @constructor
 */
function SourceLocation(script, position, line, column, start, end) {
  this.script = script;
  this.position = position;
  this.line = line;
  this.column = column;
  this.start = start;
  this.end = end;
647
}
648

649
var kLineLengthLimit = 78;
650 651 652 653 654 655 656 657 658

/**
 * Restrict source location start and end positions to make the source slice
 * no more that a certain number of characters wide.
 * @param {number} opt_limit The with limit of the source text with a default
 *     of 78
 * @param {number} opt_before The number of characters to prefer before the
 *     position with a default value of 10 less that the limit
 */
659
function SourceLocationRestrict(opt_limit, opt_before) {
660 661 662 663 664 665 666 667 668 669 670 671 672 673
  // Find the actual limit to use.
  var limit;
  var before;
  if (!IS_UNDEFINED(opt_limit)) {
    limit = opt_limit;
  } else {
    limit = kLineLengthLimit;
  }
  if (!IS_UNDEFINED(opt_before)) {
    before = opt_before;
  } else {
    // If no before is specified center for small limits and perfer more source
    // before the the position that after for longer limits.
    if (limit <= 20) {
674
      before = $floor(limit / 2);
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
    } else {
      before = limit - 10;
    }
  }
  if (before >= limit) {
    before = limit - 1;
  }

  // If the [start, end[ interval is too big we restrict
  // it in one or both ends. We make sure to always produce
  // restricted intervals of maximum allowed size.
  if (this.end - this.start > limit) {
    var start_limit = this.position - before;
    var end_limit = this.position + limit - before;
    if (this.start < start_limit && end_limit < this.end) {
      this.start = start_limit;
      this.end = end_limit;
    } else if (this.start < start_limit) {
      this.start = this.end - limit;
    } else {
      this.end = this.start + limit;
    }
  }
698
}
699 700 701 702 703 704 705


/**
 * Get the source text for a SourceLocation
 * @return {String}
 *     Source text for this location.
 */
706
function SourceLocationSourceText() {
707 708 709 710 711
  return %_CallFunction(this.script.source,
                        this.start,
                        this.end,
                        StringSubstring);
}
712 713


714 715 716 717 718
SetUpLockedPrototype(SourceLocation,
  $Array("script", "position", "line", "column", "start", "end"),
  $Array(
    "restrict", SourceLocationRestrict,
    "sourceText", SourceLocationSourceText
719
 )
720 721 722
);


723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
/**
 * Class for a source slice. A source slice is a part of a script source with
 * the following properties:
 *   script        : script object for the source
 *   from_line     : line number for the first line in the slice
 *   to_line       : source line number for the last line in the slice
 *   from_position : position of the first character in the slice
 *   to_position   : position of the last character in the slice
 * The to_line and to_position are not included in the slice, that is the lines
 * in the slice are [from_line, to_line[. Likewise the characters in the slice
 * are [from_position, to_position[.
 * @param {Script} script The Script object for the source slice
 * @param {number} from_line
 * @param {number} to_line
 * @param {number} from_position
 * @param {number} to_position
 * @constructor
 */
function SourceSlice(script, from_line, to_line, from_position, to_position) {
  this.script = script;
  this.from_line = from_line;
  this.to_line = to_line;
  this.from_position = from_position;
  this.to_position = to_position;
}

/**
 * Get the source text for a SourceSlice
 * @return {String} Source text for this slice. The last line will include
 *     the line terminating characters (if any)
 */
754
function SourceSliceSourceText() {
755 756 757 758
  return %_CallFunction(this.script.source,
                        this.from_position,
                        this.to_position,
                        StringSubstring);
759
}
760

761 762 763 764 765
SetUpLockedPrototype(SourceSlice,
  $Array("script", "from_line", "to_line", "from_position", "to_position"),
  $Array("sourceText", SourceSliceSourceText)
);

766 767 768 769

// Returns the offset of the given position within the containing
// line.
function GetPositionInLine(message) {
770 771 772
  var script = %MessageGetScript(message);
  var start_position = %MessageGetStartPosition(message);
  var location = script.locationFromPosition(start_position, false);
773 774
  if (location == null) return -1;
  location.restrict();
775
  return start_position - location.start;
776
}
777 778 779


function GetStackTraceLine(recv, fun, pos, isGlobal) {
780
  return new CallSite(recv, fun, pos, false).toString();
781
}
782 783 784 785

// ----------------------------------------------------------------------------
// Error implementation

786 787 788 789 790 791 792 793 794 795
var CallSiteReceiverKey = %CreateSymbol("receiver");
var CallSiteFunctionKey = %CreateSymbol("function");
var CallSitePositionKey = %CreateSymbol("position");
var CallSiteStrictModeKey = %CreateSymbol("strict mode");

function CallSite(receiver, fun, pos, strict_mode) {
  this[CallSiteReceiverKey] = receiver;
  this[CallSiteFunctionKey] = fun;
  this[CallSitePositionKey] = pos;
  this[CallSiteStrictModeKey] = strict_mode;
796 797
}

798
function CallSiteGetThis() {
799
  return this[CallSiteStrictModeKey] ? UNDEFINED : this[CallSiteReceiverKey];
800
}
801

802
function CallSiteGetTypeName() {
803
  return GetTypeName(this[CallSiteReceiverKey], false);
804
}
805

806
function CallSiteIsToplevel() {
807
  if (this[CallSiteReceiverKey] == null) {
808
    return true;
809
  }
810
  return IS_GLOBAL(this[CallSiteReceiverKey]);
811
}
812

813
function CallSiteIsEval() {
814
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
815
  return script && script.compilation_type == COMPILATION_TYPE_EVAL;
816
}
817

818
function CallSiteGetEvalOrigin() {
819
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
820
  return FormatEvalOrigin(script);
821
}
822

823
function CallSiteGetScriptNameOrSourceURL() {
824
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
825
  return script ? script.nameOrSourceURL() : null;
826
}
827

828
function CallSiteGetFunction() {
829
  return this[CallSiteStrictModeKey] ? UNDEFINED : this[CallSiteFunctionKey];
830
}
831

832
function CallSiteGetFunctionName() {
833
  // See if the function knows its own name
834
  var name = this[CallSiteFunctionKey].name;
835
  if (name) {
836
    return name;
837
  }
838
  name = %FunctionGetInferredName(this[CallSiteFunctionKey]);
839 840
  if (name) {
    return name;
841 842
  }
  // Maybe this is an evaluation?
843
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
844
  if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
845
    return "eval";
846
  }
847
  return null;
848
}
849

850
function CallSiteGetMethodName() {
851 852
  // See if we can find a unique property on the receiver that holds
  // this function.
853 854 855 856 857 858 859
  var receiver = this[CallSiteReceiverKey];
  var fun = this[CallSiteFunctionKey];
  var ownName = fun.name;
  if (ownName && receiver &&
      (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun ||
       %_CallFunction(receiver, ownName, ObjectLookupSetter) === fun ||
       (IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) {
860 861 862
    // To handle DontEnum properties we guess that the method has
    // the same name as the function.
    return ownName;
863
  }
864
  var name = null;
865 866 867 868
  for (var prop in receiver) {
    if (%_CallFunction(receiver, prop, ObjectLookupGetter) === fun ||
        %_CallFunction(receiver, prop, ObjectLookupSetter) === fun ||
        (IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) {
869
      // If we find more than one match bail out to avoid confusion.
870
      if (name) {
871
        return null;
872
      }
873 874 875
      name = prop;
    }
  }
876
  if (name) {
877
    return name;
878
  }
879
  return null;
880
}
881

882
function CallSiteGetFileName() {
883
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
884
  return script ? script.name : null;
885
}
886

887
function CallSiteGetLineNumber() {
888
  if (this[CallSitePositionKey] == -1) {
889
    return null;
890
  }
891
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
892 893
  var location = null;
  if (script) {
894
    location = script.locationFromPosition(this[CallSitePositionKey], true);
895 896
  }
  return location ? location.line + 1 : null;
897
}
898

899
function CallSiteGetColumnNumber() {
900
  if (this[CallSitePositionKey] == -1) {
901
    return null;
902
  }
903
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
904 905
  var location = null;
  if (script) {
906
    location = script.locationFromPosition(this[CallSitePositionKey], true);
907
  }
908
  return location ? location.column + 1: null;
909
}
910

911
function CallSiteIsNative() {
912
  var script = %FunctionGetScript(this[CallSiteFunctionKey]);
913
  return script ? (script.type == TYPE_NATIVE) : false;
914
}
915

916
function CallSiteGetPosition() {
917
  return this[CallSitePositionKey];
918
}
919

920
function CallSiteIsConstructor() {
921
  var receiver = this[CallSiteReceiverKey];
922 923
  var constructor = (receiver != null && IS_OBJECT(receiver))
                        ? %GetDataProperty(receiver, "constructor") : null;
924
  if (!constructor) return false;
925
  return this[CallSiteFunctionKey] === constructor;
926
}
927

928 929 930 931 932 933
function CallSiteToString() {
  var fileName;
  var fileLocation = "";
  if (this.isNative()) {
    fileLocation = "native";
  } else {
934 935 936 937 938 939 940 941 942
    if (this.isEval()) {
      fileName = this.getScriptNameOrSourceURL();
      if (!fileName) {
        fileLocation = this.getEvalOrigin();
        fileLocation += ", ";  // Expecting source position to follow.
      }
    } else {
      fileName = this.getFileName();
    }
943

944 945 946 947 948 949 950 951
    if (fileName) {
      fileLocation += fileName;
    } else {
      // Source code does not originate from a file and is not native, but we
      // can still get the source position inside the source string, e.g. in
      // an eval string.
      fileLocation += "<anonymous>";
    }
952 953 954 955 956 957 958 959 960 961 962
    var lineNumber = this.getLineNumber();
    if (lineNumber != null) {
      fileLocation += ":" + lineNumber;
      var columnNumber = this.getColumnNumber();
      if (columnNumber) {
        fileLocation += ":" + columnNumber;
      }
    }
  }

  var line = "";
963 964
  var functionName = this.getFunctionName();
  var addSuffix = true;
965 966 967
  var isConstructor = this.isConstructor();
  var isMethodCall = !(this.isToplevel() || isConstructor);
  if (isMethodCall) {
968
    var typeName = GetTypeName(this[CallSiteReceiverKey], true);
969 970
    var methodName = this.getMethodName();
    if (functionName) {
971 972
      if (typeName &&
          %_CallFunction(functionName, typeName, StringIndexOf) != 0) {
973 974
        line += typeName + ".";
      }
975
      line += functionName;
976 977 978
      if (methodName &&
          (%_CallFunction(functionName, "." + methodName, StringIndexOf) !=
           functionName.length - methodName.length - 1)) {
979 980 981
        line += " [as " + methodName + "]";
      }
    } else {
982
      line += typeName + "." + (methodName || "<anonymous>");
983 984 985 986 987 988 989
    }
  } else if (isConstructor) {
    line += "new " + (functionName || "<anonymous>");
  } else if (functionName) {
    line += functionName;
  } else {
    line += fileLocation;
990
    addSuffix = false;
991
  }
992
  if (addSuffix) {
993 994 995 996 997
    line += " (" + fileLocation + ")";
  }
  return line;
}

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
  "getThis", CallSiteGetThis,
  "getTypeName", CallSiteGetTypeName,
  "isToplevel", CallSiteIsToplevel,
  "isEval", CallSiteIsEval,
  "getEvalOrigin", CallSiteGetEvalOrigin,
  "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
  "getFunction", CallSiteGetFunction,
  "getFunctionName", CallSiteGetFunctionName,
  "getMethodName", CallSiteGetMethodName,
  "getFileName", CallSiteGetFileName,
  "getLineNumber", CallSiteGetLineNumber,
  "getColumnNumber", CallSiteGetColumnNumber,
  "isNative", CallSiteIsNative,
  "getPosition", CallSiteGetPosition,
1013 1014
  "isConstructor", CallSiteIsConstructor,
  "toString", CallSiteToString
1015 1016 1017
));


1018
function FormatEvalOrigin(script) {
1019
  var sourceURL = script.nameOrSourceURL();
1020
  if (sourceURL) {
1021
    return sourceURL;
1022
  }
1023 1024

  var eval_origin = "eval at ";
1025 1026 1027 1028 1029
  if (script.eval_from_function_name) {
    eval_origin += script.eval_from_function_name;
  } else {
    eval_origin +=  "<anonymous>";
  }
1030

1031 1032
  var eval_from_script = script.eval_from_script;
  if (eval_from_script) {
1033
    if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
1034
      // eval script originated from another eval.
1035
      eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
1036
    } else {
1037
      // eval script originated from "real" source.
1038 1039
      if (eval_from_script.name) {
        eval_origin += " (" + eval_from_script.name;
1040 1041
        var location = eval_from_script.locationFromPosition(
            script.eval_from_script_position, true);
1042 1043 1044 1045
        if (location) {
          eval_origin += ":" + (location.line + 1);
          eval_origin += ":" + (location.column + 1);
        }
1046
        eval_origin += ")";
1047 1048 1049 1050 1051
      } else {
        eval_origin += " (unknown source)";
      }
    }
  }
1052

1053
  return eval_origin;
1054
}
1055

1056 1057

function FormatErrorString(error) {
1058
  try {
1059
    return %_CallFunction(error, ErrorToString);
1060 1061
  } catch (e) {
    try {
1062
      return "<error: " + e + ">";
1063
    } catch (ee) {
1064
      return "<error>";
1065 1066
    }
  }
1067 1068 1069 1070
}


function GetStackFrames(raw_stack) {
1071
  var frames = new InternalArray();
1072 1073
  var non_strict_frames = raw_stack[0];
  for (var i = 1; i < raw_stack.length; i += 4) {
1074 1075 1076 1077 1078
    var recv = raw_stack[i];
    var fun = raw_stack[i + 1];
    var code = raw_stack[i + 2];
    var pc = raw_stack[i + 3];
    var pos = %FunctionGetPositionForOffset(code, pc);
1079 1080
    non_strict_frames--;
    frames.push(new CallSite(recv, fun, pos, (non_strict_frames < 0)));
1081 1082 1083 1084 1085
  }
  return frames;
}


1086 1087 1088 1089 1090 1091 1092 1093 1094
// Flag to prevent recursive call of Error.prepareStackTrace.
var formatting_custom_stack_trace = false;


function FormatStackTrace(obj, error_string, frames) {
  if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
    var array = [];
    %MoveArrayContents(frames, array);
    formatting_custom_stack_trace = true;
1095
    var stack_trace = UNDEFINED;
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
    try {
      stack_trace = $Error.prepareStackTrace(obj, array);
    } catch (e) {
      throw e;  // The custom formatting function threw.  Rethrow.
    } finally {
      formatting_custom_stack_trace = false;
    }
    return stack_trace;
  }

1106
  var lines = new InternalArray();
1107
  lines.push(error_string);
1108 1109
  for (var i = 0; i < frames.length; i++) {
    var frame = frames[i];
1110
    var line;
1111
    try {
1112
      line = frame.toString();
1113 1114
    } catch (e) {
      try {
1115
        line = "<error: " + e + ">";
1116 1117
      } catch (ee) {
        // Any code that reaches this point is seriously nasty!
1118
        line = "<error>";
1119 1120 1121 1122
      }
    }
    lines.push("    at " + line);
  }
1123
  return %_CallFunction(lines, "\n", ArrayJoin);
1124 1125 1126
}


1127 1128
function GetTypeName(receiver, requireConstructor) {
  var constructor = receiver.constructor;
1129 1130
  if (!constructor) {
    return requireConstructor ? null :
1131
        %_CallFunction(receiver, ObjectToString);
1132 1133 1134 1135
  }
  var constructorName = constructor.name;
  if (!constructorName) {
    return requireConstructor ? null :
1136
        %_CallFunction(receiver, ObjectToString);
1137 1138 1139
  }
  return constructorName;
}
1140

1141

1142 1143
function captureStackTrace(obj, cons_opt) {
  var stackTraceLimit = $Error.stackTraceLimit;
1144
  if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
1145
  if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
1146
    stackTraceLimit = 10000;
1147
  }
1148 1149 1150 1151 1152
  var stack = %CollectStackTrace(obj,
                                 cons_opt ? cons_opt : captureStackTrace,
                                 stackTraceLimit);

  var error_string = FormatErrorString(obj);
1153 1154 1155 1156
  // The holder of this getter ('obj') may not be the receiver ('this').
  // When this getter is called the first time, we use the context values to
  // format a stack trace string and turn this accessor pair into a data
  // property (on the holder).
1157
  var getter = function() {
1158
    // Stack is still a raw array awaiting to be formatted.
1159
    var result = FormatStackTrace(obj, error_string, GetStackFrames(stack));
1160 1161 1162
    // Turn this accessor into a data property.
    %DefineOrRedefineDataProperty(obj, 'stack', result, NONE);
    // Release context values.
1163
    stack = error_string = UNDEFINED;
1164
    return result;
1165
  };
1166

1167 1168
  // Set the 'stack' property on the receiver.  If the receiver is the same as
  // holder of this setter, the accessor pair is turned into a data property.
1169
  var setter = function(v) {
1170
    // Set data property on the receiver (not necessarily holder).
1171
    %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
1172 1173
    if (this === obj) {
      // Release context values if holder is the same as the receiver.
1174
      stack = error_string = UNDEFINED;
1175
    }
1176 1177 1178
  };

  %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM);
1179
}
1180

1181

1182
function SetUpError() {
1183 1184
  // Define special error type constructors.

1185
  var DefineError = function(f) {
1186 1187 1188 1189 1190 1191 1192 1193
    // Store the error function in both the global object
    // and the runtime object. The function is fetched
    // from the runtime object when throwing errors from
    // within the runtime system to avoid strange side
    // effects when overwriting the error functions from
    // user code.
    var name = f.name;
    %SetProperty(global, name, f, DONT_ENUM);
1194
    %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1195 1196 1197 1198 1199 1200
    // Configure the error function.
    if (name == 'Error') {
      // The prototype of the Error object must itself be an error.
      // However, it can't be an instance of the Error object because
      // it hasn't been properly configured yet.  Instead we create a
      // special not-a-true-error-but-close-enough object.
1201
      var ErrorPrototype = function() {};
1202 1203 1204 1205 1206 1207 1208 1209
      %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
      %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
      %FunctionSetPrototype(f, new ErrorPrototype());
    } else {
      %FunctionSetPrototype(f, new $Error());
    }
    %FunctionSetInstanceClassName(f, 'Error');
    %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
1210
    %SetProperty(f.prototype, "name", name, DONT_ENUM);
1211 1212 1213 1214 1215
    %SetCode(f, function(m) {
      if (%_IsConstructCall()) {
        // Define all the expected properties directly on the error
        // object. This avoids going through getters and setters defined
        // on prototype objects.
1216
        %IgnoreAttributesAndSetProperty(this, 'stack', UNDEFINED, DONT_ENUM);
1217
        if (!IS_UNDEFINED(m)) {
1218 1219
          %IgnoreAttributesAndSetProperty(
            this, 'message', ToString(m), DONT_ENUM);
1220 1221 1222 1223 1224 1225
        }
        captureStackTrace(this, f);
      } else {
        return new f(m);
      }
    });
1226
    %SetNativeFlag(f);
1227
  };
1228

1229 1230 1231 1232 1233 1234 1235
  DefineError(function Error() { });
  DefineError(function TypeError() { });
  DefineError(function RangeError() { });
  DefineError(function SyntaxError() { });
  DefineError(function ReferenceError() { });
  DefineError(function EvalError() { });
  DefineError(function URIError() { });
1236 1237 1238
}

SetUpError();
1239

1240
$Error.captureStackTrace = captureStackTrace;
1241

1242
%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
1243

1244
// Global list of error objects visited during ErrorToString. This is
1245
// used to detect cycles in error toString formatting.
1246 1247
var visited_errors = new InternalArray();
var cyclic_error_marker = new $Object();
1248

1249 1250 1251
function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
  // Climb the prototype chain until we find the holder.
  while (error && !%HasLocalProperty(error, name)) {
1252
    error = %GetPrototype(error);
1253
  }
1254
  if (IS_NULL(error)) return UNDEFINED;
1255 1256 1257 1258 1259 1260 1261 1262
  if (!IS_OBJECT(error)) return error[name];
  // If the property is an accessor on one of the predefined errors that can be
  // generated statically by the compiler, don't touch it. This is to address
  // http://code.google.com/p/chromium/issues/detail?id=69187
  var desc = %GetOwnProperty(error, name);
  if (desc && desc[IS_ACCESSOR_INDEX]) {
    var isName = name === "name";
    if (error === $ReferenceError.prototype)
1263
      return isName ? "ReferenceError" : UNDEFINED;
1264
    if (error === $SyntaxError.prototype)
1265
      return isName ? "SyntaxError" : UNDEFINED;
1266
    if (error === $TypeError.prototype)
1267
      return isName ? "TypeError" : UNDEFINED;
1268 1269 1270 1271 1272
  }
  // Otherwise, read normally.
  return error[name];
}

1273
function ErrorToStringDetectCycle(error) {
1274
  if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
1275
  try {
1276
    var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
1277
    name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
1278
    var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
1279 1280 1281 1282
    message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
    if (name === "") return message;
    if (message === "") return name;
    return name + ": " + message;
1283
  } finally {
1284
    visited_errors.length = visited_errors.length - 1;
1285 1286 1287
  }
}

1288
function ErrorToString() {
1289 1290
  if (!IS_SPEC_OBJECT(this)) {
    throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
1291
  }
1292 1293

  try {
1294
    return ErrorToStringDetectCycle(this);
1295
  } catch(e) {
1296 1297
    // If this error message was encountered already return the empty
    // string for it instead of recursively formatting it.
1298
    if (e === cyclic_error_marker) {
1299 1300 1301
      return '';
    }
    throw e;
1302
  }
1303
}
1304

1305

1306
InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
1307 1308

// Boilerplate for exceptions for stack overflows. Used from
1309
// Isolate::StackOverflow().
1310 1311 1312
function SetUpStackOverflowBoilerplate() {
  var boilerplate = MakeRangeError('stack_overflow', []);

1313 1314
  var error_string = boilerplate.name + ": " + boilerplate.message;

1315 1316 1317 1318 1319
  // The raw stack trace is stored as a hidden property on the holder of this
  // getter, which may not be the same as the receiver.  Find the holder to
  // retrieve the raw stack trace and then turn this accessor pair into a
  // data property.
  var getter = function() {
1320 1321 1322
    var holder = this;
    while (!IS_ERROR(holder)) {
      holder = %GetPrototype(holder);
1323
      if (IS_NULL(holder)) return MakeSyntaxError('illegal_access', []);
1324
    }
1325 1326 1327 1328
    var stack = %GetAndClearOverflowedStackTrace(holder);
    // We may not have captured any stack trace.
    if (IS_UNDEFINED(stack)) return stack;

1329
    var result = FormatStackTrace(holder, error_string, GetStackFrames(stack));
1330 1331 1332 1333
    // Replace this accessor with a data property.
    %DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
    return result;
  };
1334

1335 1336 1337
  // Set the 'stack' property on the receiver.  If the receiver is the same as
  // holder of this setter, the accessor pair is turned into a data property.
  var setter = function(v) {
1338
    %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
1339 1340 1341 1342
    // Tentatively clear the hidden property. If the receiver is the same as
    // holder, we release the raw stack trace this way.
    %GetAndClearOverflowedStackTrace(this);
  };
1343 1344 1345 1346 1347 1348 1349 1350

  %DefineOrRedefineAccessorProperty(
      boilerplate, 'stack', getter, setter, DONT_ENUM);

  return boilerplate;
}

var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate();