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