The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / messages.js @ f230a1cf

History | View | Annotate | Download (50.2 KB)

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

    
28
// -------------------------------------------------------------------
29

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

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

    
186

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

    
214

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

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

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

    
258

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

    
271

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

    
285

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

    
291

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

    
303

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

    
311

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

    
321

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

    
333

    
334
function MakeTypeError(type, args) {
335
  return MakeGenericError($TypeError, type, args);
336
}
337

    
338

    
339
function MakeRangeError(type, args) {
340
  return MakeGenericError($RangeError, type, args);
341
}
342

    
343

    
344
function MakeSyntaxError(type, args) {
345
  return MakeGenericError($SyntaxError, type, args);
346
}
347

    
348

    
349
function MakeReferenceError(type, args) {
350
  return MakeGenericError($ReferenceError, type, args);
351
}
352

    
353

    
354
function MakeEvalError(type, args) {
355
  return MakeGenericError($EvalError, type, args);
356
}
357

    
358

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

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

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

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

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

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

    
397
  return -1;
398
}
399

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

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

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

    
430
  return new SourceLocation(this, position, line, column, start, end);
431
}
432

    
433

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

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

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

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

    
476
    return this.locationFromPosition(
477
        this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
478
  }
479
}
480

    
481

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

    
498
  // Adjust according to the offset within the resource.
499
  from_line -= this.line_offset;
500
  to_line -= this.line_offset;
501
  if (from_line < 0) from_line = 0;
502
  if (to_line > this.lineCount()) to_line = this.lineCount();
503

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

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

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

    
522

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

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

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

    
543

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

    
554

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

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

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

    
603

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

    
618

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

    
649
var kLineLengthLimit = 78;
650

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

    
683
  // If the [start, end[ interval is too big we restrict
684
  // it in one or both ends. We make sure to always produce
685
  // restricted intervals of maximum allowed size.
686
  if (this.end - this.start > limit) {
687
    var start_limit = this.position - before;
688
    var end_limit = this.position + limit - before;
689
    if (this.start < start_limit && end_limit < this.end) {
690
      this.start = start_limit;
691
      this.end = end_limit;
692
    } else if (this.start < start_limit) {
693
      this.start = this.end - limit;
694
    } else {
695
      this.end = this.start + limit;
696
    }
697
  }
698
}
699

    
700

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

    
713

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

    
722

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

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

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

    
766

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

    
778

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

    
783
// ----------------------------------------------------------------------------
784
// Error implementation
785

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1017

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

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

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

    
1053
  return eval_origin;
1054
}
1055

    
1056

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

    
1069

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

    
1085

    
1086
// Flag to prevent recursive call of Error.prepareStackTrace.
1087
var formatting_custom_stack_trace = false;
1088

    
1089

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

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

    
1126

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

    
1141

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

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

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

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

    
1181

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

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

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

    
1238
SetUpError();
1239

    
1240
$Error.captureStackTrace = captureStackTrace;
1241

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

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

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

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

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

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

    
1305

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

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

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

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

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

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

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

    
1347
  return boilerplate;
1348
}
1349

    
1350
var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate();