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