Cleanup of messages.js.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 1 Sep 2011 07:39:22 +0000 (07:39 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 1 Sep 2011 07:39:22 +0000 (07:39 +0000)
Lock down some otherwise modifiable objects that don't need it.

Review URL: http://codereview.chromium.org/7828003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9089 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/math.js
src/messages.js
src/runtime.js

index 70b8c57cae5c48058c14ce76fdf756f2aabb3739..31306e79d18e1e98cba7e2ee7f697ef303f91543 100644 (file)
@@ -38,7 +38,7 @@ const $abs = MathAbs;
 function MathConstructor() {}
 %FunctionSetInstanceClassName(MathConstructor, 'Math');
 const $Math = new MathConstructor();
-$Math.__proto__ = global.Object.prototype;
+$Math.__proto__ = $Object.prototype;
 %SetProperty(global, "Math", $Math, DONT_ENUM);
 
 // ECMA 262 - 15.8.2.1
index cbbb70eb1a8e37392676cc8258cdfb17afacd89b..0109253b9fd13b20a3ad56cde1a646e87951486d 100644 (file)
@@ -44,11 +44,11 @@ var kNoLineNumberInfo = 0;
 // If this object gets passed to an error constructor the error will
 // get an accessor for .message that constructs a descriptive error
 // message on access.
-var kAddMessageAccessorsMarker = { };
+const kAddMessageAccessorsMarker = { };
 
-var kMessages = 0;
-
-var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ];
+// This will be lazily initialized when first needed (and forcibly
+// overwritten even though it's const).
+const kMessages = 0;
 
 function FormatString(format, message) {
   var args = %MessageGetArguments(message);
@@ -56,14 +56,16 @@ function FormatString(format, message) {
   var arg_num = 0;
   for (var i = 0; i < format.length; i++) {
     var str = format[i];
-    for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) {
-      if (str == kReplacementMarkers[arg_num]) {
+    if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
+      // Two-char string starts with "%".
+      var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
+      if (arg_num < 4) {
+        // str is one of %0, %1, %2 or %3.
         try {
           str = ToDetailString(args[arg_num]);
         } catch (e) {
           str = "#<error>";
         }
-        break;
       }
     }
     result += str;
@@ -102,18 +104,16 @@ function ToStringCheckErrorObject(obj) {
 
 
 function ToDetailString(obj) {
-  if (obj != null && IS_OBJECT(obj) &&
-      obj.toString === $Object.prototype.toString) {
+  if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
     var constructor = obj.constructor;
-    if (!constructor) return ToStringCheckErrorObject(obj);
-    var constructorName = constructor.name;
-    if (!constructorName || !IS_STRING(constructorName)) {
-      return ToStringCheckErrorObject(obj);
+    if (typeof constructor == "function") {
+      var constructorName = constructor.name;
+      if (IS_STRING(constructorName) && constructorName !== "") {
+        return "#<" + constructorName + ">";
+      }
     }
-    return "#<" + constructorName + ">";
-  } else {
-    return ToStringCheckErrorObject(obj);
   }
+  return ToStringCheckErrorObject(obj);
 }
 
 
@@ -142,116 +142,132 @@ function MakeGenericError(constructor, type, args) {
 // Helper functions; called from the runtime system.
 function FormatMessage(message) {
   if (kMessages === 0) {
-    kMessages = {
+    var messagesDictionary = [
       // Error
-      cyclic_proto:                 ["Cyclic __proto__ value"],
-      code_gen_from_strings:        ["Code generation from strings disallowed for this context"],
+      "cyclic_proto",                 ["Cyclic __proto__ value"],
+      "code_gen_from_strings",        ["Code generation from strings disallowed for this context"],
       // TypeError
-      unexpected_token:             ["Unexpected token ", "%0"],
-      unexpected_token_number:      ["Unexpected number"],
-      unexpected_token_string:      ["Unexpected string"],
-      unexpected_token_identifier:  ["Unexpected identifier"],
-      unexpected_reserved:          ["Unexpected reserved word"],
-      unexpected_strict_reserved:   ["Unexpected strict mode reserved word"],
-      unexpected_eos:               ["Unexpected end of input"],
-      malformed_regexp:             ["Invalid regular expression: /", "%0", "/: ", "%1"],
-      unterminated_regexp:          ["Invalid regular expression: missing /"],
-      regexp_flags:                 ["Cannot supply flags when constructing one RegExp from another"],
-      incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
-      invalid_lhs_in_assignment:    ["Invalid left-hand side in assignment"],
-      invalid_lhs_in_for_in:        ["Invalid left-hand side in for-in"],
-      invalid_lhs_in_postfix_op:    ["Invalid left-hand side expression in postfix operation"],
-      invalid_lhs_in_prefix_op:     ["Invalid left-hand side expression in prefix operation"],
-      multiple_defaults_in_switch:  ["More than one default clause in switch statement"],
-      newline_after_throw:          ["Illegal newline after throw"],
-      redeclaration:                ["%0", " '", "%1", "' has already been declared"],
-      no_catch_or_finally:          ["Missing catch or finally after try"],
-      unknown_label:                ["Undefined label '", "%0", "'"],
-      uncaught_exception:           ["Uncaught ", "%0"],
-      stack_trace:                  ["Stack Trace:\n", "%0"],
-      called_non_callable:          ["%0", " is not a function"],
-      undefined_method:             ["Object ", "%1", " has no method '", "%0", "'"],
-      property_not_function:        ["Property '", "%0", "' of object ", "%1", " is not a function"],
-      cannot_convert_to_primitive:  ["Cannot convert object to primitive value"],
-      not_constructor:              ["%0", " is not a constructor"],
-      not_defined:                  ["%0", " is not defined"],
-      non_object_property_load:     ["Cannot read property '", "%0", "' of ", "%1"],
-      non_object_property_store:    ["Cannot set property '", "%0", "' of ", "%1"],
-      non_object_property_call:     ["Cannot call method '", "%0", "' of ", "%1"],
-      with_expression:              ["%0", " has no properties"],
-      illegal_invocation:           ["Illegal invocation"],
-      no_setter_in_callback:        ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
-      apply_non_function:           ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
-      apply_wrong_args:             ["Function.prototype.apply: Arguments list has wrong type"],
-      invalid_in_operator_use:      ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
-      instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
-      instanceof_nonobject_proto:   ["Function has non-object prototype '", "%0", "' in instanceof check"],
-      null_to_object:               ["Cannot convert null to object"],
-      reduce_no_initial:            ["Reduce of empty array with no initial value"],
-      getter_must_be_callable:      ["Getter must be a function: ", "%0"],
-      setter_must_be_callable:      ["Setter must be a function: ", "%0"],
-      value_and_accessor:           ["Invalid property.  A property cannot both have accessors and be writable or have a value: ", "%0"],
-      proto_object_or_null:         ["Object prototype may only be an Object or null"],
-      property_desc_object:         ["Property description must be an object: ", "%0"],
-      redefine_disallowed:          ["Cannot redefine property: ", "%0"],
-      define_disallowed:            ["Cannot define property:", "%0", ", object is not extensible."],
-      non_extensible_proto:         ["%0", " is not extensible"],
-      handler_non_object:           ["Proxy.", "%0", " called with non-object as handler"],
-      handler_trap_missing:         ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
-      handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
-      handler_returned_false:       ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
-      handler_returned_undefined:   ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
-      proxy_prop_not_configurable:  ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
-      proxy_non_object_prop_names:  ["Trap ", "%1", " returned non-object ", "%0"],
-      proxy_repeated_prop_name:     ["Trap ", "%1", " returned repeated property name ", "%2"],
-      invalid_weakmap_key:          ["Invalid value used as weak map key"],
+      "unexpected_token",             ["Unexpected token ", "%0"],
+      "unexpected_token_number",      ["Unexpected number"],
+      "unexpected_token_string",      ["Unexpected string"],
+      "unexpected_token_identifier",  ["Unexpected identifier"],
+      "unexpected_reserved",          ["Unexpected reserved word"],
+      "unexpected_strict_reserved",   ["Unexpected strict mode reserved word"],
+      "unexpected_eos",               ["Unexpected end of input"],
+      "malformed_regexp",             ["Invalid regular expression: /", "%0", "/: ", "%1"],
+      "unterminated_regexp",          ["Invalid regular expression: missing /"],
+      "regexp_flags",                 ["Cannot supply flags when constructing one RegExp from another"],
+      "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
+      "invalid_lhs_in_assignment",    ["Invalid left-hand side in assignment"],
+      "invalid_lhs_in_for_in",        ["Invalid left-hand side in for-in"],
+      "invalid_lhs_in_postfix_op",    ["Invalid left-hand side expression in postfix operation"],
+      "invalid_lhs_in_prefix_op",     ["Invalid left-hand side expression in prefix operation"],
+      "multiple_defaults_in_switch",  ["More than one default clause in switch statement"],
+      "newline_after_throw",          ["Illegal newline after throw"],
+      "redeclaration",                ["%0", " '", "%1", "' has already been declared"],
+      "no_catch_or_finally",          ["Missing catch or finally after try"],
+      "unknown_label",                ["Undefined label '", "%0", "'"],
+      "uncaught_exception",           ["Uncaught ", "%0"],
+      "stack_trace",                  ["Stack Trace:\n", "%0"],
+      "called_non_callable",          ["%0", " is not a function"],
+      "undefined_method",             ["Object ", "%1", " has no method '", "%0", "'"],
+      "property_not_function",        ["Property '", "%0", "' of object ", "%1", " is not a function"],
+      "cannot_convert_to_primitive",  ["Cannot convert object to primitive value"],
+      "not_constructor",              ["%0", " is not a constructor"],
+      "not_defined",                  ["%0", " is not defined"],
+      "non_object_property_load",     ["Cannot read property '", "%0", "' of ", "%1"],
+      "non_object_property_store",    ["Cannot set property '", "%0", "' of ", "%1"],
+      "non_object_property_call",     ["Cannot call method '", "%0", "' of ", "%1"],
+      "with_expression",              ["%0", " has no properties"],
+      "illegal_invocation",           ["Illegal invocation"],
+      "no_setter_in_callback",        ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
+      "apply_non_function",           ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
+      "apply_wrong_args",             ["Function.prototype.apply: Arguments list has wrong type"],
+      "invalid_in_operator_use",      ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
+      "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
+      "instanceof_nonobject_proto",   ["Function has non-object prototype '", "%0", "' in instanceof check"],
+      "null_to_object",               ["Cannot convert null to object"],
+      "reduce_no_initial",            ["Reduce of empty array with no initial value"],
+      "getter_must_be_callable",      ["Getter must be a function: ", "%0"],
+      "setter_must_be_callable",      ["Setter must be a function: ", "%0"],
+      "value_and_accessor",           ["Invalid property.  A property cannot both have accessors and be writable or have a value, ", "%0"],
+      "proto_object_or_null",         ["Object prototype may only be an Object or null"],
+      "property_desc_object",         ["Property description must be an object: ", "%0"],
+      "redefine_disallowed",          ["Cannot redefine property: ", "%0"],
+      "define_disallowed",            ["Cannot define property:", "%0", ", object is not extensible."],
+      "non_extensible_proto",         ["%0", " is not extensible"],
+      "handler_non_object",           ["Proxy.", "%0", " called with non-object as handler"],
+      "handler_trap_missing",         ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
+      "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
+      "handler_returned_false",       ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
+      "handler_returned_undefined",   ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
+      "proxy_prop_not_configurable",  ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
+      "proxy_non_object_prop_names",  ["Trap ", "%1", " returned non-object ", "%0"],
+      "proxy_repeated_prop_name",     ["Trap ", "%1", " returned repeated property name ", "%2"],
+      "invalid_weakmap_key",          ["Invalid value used as weak map key"],
       // RangeError
-      invalid_array_length:         ["Invalid array length"],
-      stack_overflow:               ["Maximum call stack size exceeded"],
+      "invalid_array_length",         ["Invalid array length"],
+      "stack_overflow",               ["Maximum call stack size exceeded"],
       // SyntaxError
-      unable_to_parse:              ["Parse error"],
-      invalid_regexp_flags:         ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
-      invalid_regexp:               ["Invalid RegExp pattern /", "%0", "/"],
-      illegal_break:                ["Illegal break statement"],
-      illegal_continue:             ["Illegal continue statement"],
-      illegal_return:               ["Illegal return statement"],
-      error_loading_debugger:       ["Error loading debugger"],
-      no_input_to_regexp:           ["No input to ", "%0"],
-      invalid_json:                 ["String '", "%0", "' is not valid JSON"],
-      circular_structure:           ["Converting circular structure to JSON"],
-      obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"],
-      called_on_null_or_undefined:  ["%0", " called on null or undefined"],
-      array_indexof_not_defined:    ["Array.getIndexOf: Argument undefined"],
-      object_not_extensible:        ["Can't add property ", "%0", ", object is not extensible"],
-      illegal_access:               ["Illegal access"],
-      invalid_preparser_data:       ["Invalid preparser data for function ", "%0"],
-      strict_mode_with:             ["Strict mode code may not include a with statement"],
-      strict_catch_variable:        ["Catch variable may not be eval or arguments in strict mode"],
-      too_many_arguments:           ["Too many arguments in function call (only 32766 allowed)"],
-      too_many_parameters:          ["Too many parameters in function definition (only 32766 allowed)"],
-      too_many_variables:           ["Too many variables declared (only 32767 allowed)"],
-      strict_param_name:            ["Parameter name eval or arguments is not allowed in strict mode"],
-      strict_param_dupe:            ["Strict mode function may not have duplicate parameter names"],
-      strict_var_name:              ["Variable name may not be eval or arguments in strict mode"],
-      strict_function_name:         ["Function name may not be eval or arguments in strict mode"],
-      strict_octal_literal:         ["Octal literals are not allowed in strict mode."],
-      strict_duplicate_property:    ["Duplicate data property in object literal not allowed in strict mode"],
-      accessor_data_property:       ["Object literal may not have data and accessor property with the same name"],
-      accessor_get_set:             ["Object literal may not have multiple get/set accessors with the same name"],
-      strict_lhs_assignment:        ["Assignment to eval or arguments is not allowed in strict mode"],
-      strict_lhs_postfix:           ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
-      strict_lhs_prefix:            ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
-      strict_reserved_word:         ["Use of future reserved word in strict mode"],
-      strict_delete:                ["Delete of an unqualified identifier in strict mode."],
-      strict_delete_property:       ["Cannot delete property '", "%0", "' of ", "%1"],
-      strict_const:                 ["Use of const in strict mode."],
-      strict_function:              ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
-      strict_read_only_property:    ["Cannot assign to read only property '", "%0", "' of ", "%1"],
-      strict_cannot_assign:         ["Cannot assign to read only '", "%0", "' in strict mode"],
-      strict_poison_pill:           ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
-      strict_caller:                ["Illegal access to a strict mode caller function."],
-      unprotected_let:              ["Illegal let declaration in unprotected statement context."],
-    };
+      "unable_to_parse",              ["Parse error"],
+      "invalid_regexp_flags",         ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
+      "invalid_regexp",               ["Invalid RegExp pattern /", "%0", "/"],
+      "illegal_break",                ["Illegal break statement"],
+      "illegal_continue",             ["Illegal continue statement"],
+      "illegal_return",               ["Illegal return statement"],
+      "error_loading_debugger",       ["Error loading debugger"],
+      "no_input_to_regexp",           ["No input to ", "%0"],
+      "invalid_json",                 ["String '", "%0", "' is not valid JSON"],
+      "circular_structure",           ["Converting circular structure to JSON"],
+      "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"],
+      "called_on_null_or_undefined",  ["%0", " called on null or undefined"],
+      "array_indexof_not_defined",    ["Array.getIndexOf: Argument undefined"],
+      "object_not_extensible",        ["Can't add property ", "%0", ", object is not extensible"],
+      "illegal_access",               ["Illegal access"],
+      "invalid_preparser_data",       ["Invalid preparser data for function ", "%0"],
+      "strict_mode_with",             ["Strict mode code may not include a with statement"],
+      "strict_catch_variable",        ["Catch variable may not be eval or arguments in strict mode"],
+      "too_many_arguments",           ["Too many arguments in function call (only 32766 allowed)"],
+      "too_many_parameters",          ["Too many parameters in function definition (only 32766 allowed)"],
+      "too_many_variables",           ["Too many variables declared (only 32767 allowed)"],
+      "strict_param_name",            ["Parameter name eval or arguments is not allowed in strict mode"],
+      "strict_param_dupe",            ["Strict mode function may not have duplicate parameter names"],
+      "strict_var_name",              ["Variable name may not be eval or arguments in strict mode"],
+      "strict_function_name",         ["Function name may not be eval or arguments in strict mode"],
+      "strict_octal_literal",         ["Octal literals are not allowed in strict mode."],
+      "strict_duplicate_property",    ["Duplicate data property in object literal not allowed in strict mode"],
+      "accessor_data_property",       ["Object literal may not have data and accessor property with the same name"],
+      "accessor_get_set",             ["Object literal may not have multiple get/set accessors with the same name"],
+      "strict_lhs_assignment",        ["Assignment to eval or arguments is not allowed in strict mode"],
+      "strict_lhs_postfix",           ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
+      "strict_lhs_prefix",            ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
+      "strict_reserved_word",         ["Use of future reserved word in strict mode"],
+      "strict_delete",                ["Delete of an unqualified identifier in strict mode."],
+      "strict_delete_property",       ["Cannot delete property '", "%0", "' of ", "%1"],
+      "strict_const",                 ["Use of const in strict mode."],
+      "strict_function",              ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
+      "strict_read_only_property",    ["Cannot assign to read only property '", "%0", "' of ", "%1"],
+      "strict_cannot_assign",         ["Cannot assign to read only '", "%0", "' in strict mode"],
+      "strict_poison_pill",           ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
+      "strict_caller",                ["Illegal access to a strict mode caller function."],
+      "unprotected_let",              ["Illegal let declaration in unprotected statement context."],
+    ];
+    var messages = { __proto__ : null };
+    var desc = new PropertyDescriptor();
+    desc.setConfigurable(false);
+    desc.setEnumerable(false);
+    desc.setWritable(false);
+    for (var i = 0; i < messagesDictionary.length; i += 2) {
+      var key = messagesDictionary[i];
+      var format = messagesDictionary[i + 1];
+      ObjectFreeze(format);
+      desc.setValue(format);
+      DefineOwnProperty(messages, key, desc);
+    }
+    %PreventExtensions(messages);
+    %IgnoreAttributesAndSetProperty(builtins, "kMessages",
+                                    messages,
+                                    DONT_DELETE | DONT_ENUM | READ_ONLY);
   }
   var message_type = %MessageGetType(message);
   var format = kMessages[message_type];
@@ -998,64 +1014,6 @@ function FormatRawStackTrace(error, raw_stack) {
   }
 }
 
-function DefineError(f) {
-  // Store the error function in both the global object
-  // and the runtime object. The function is fetched
-  // from the runtime object when throwing errors from
-  // within the runtime system to avoid strange side
-  // effects when overwriting the error functions from
-  // user code.
-  var name = f.name;
-  %SetProperty(global, name, f, DONT_ENUM);
-  this['$' + name] = f;
-  // Configure the error function.
-  if (name == 'Error') {
-    // The prototype of the Error object must itself be an error.
-    // However, it can't be an instance of the Error object because
-    // it hasn't been properly configured yet.  Instead we create a
-    // special not-a-true-error-but-close-enough object.
-    function ErrorPrototype() {}
-    %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
-    %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
-    %FunctionSetPrototype(f, new ErrorPrototype());
-  } else {
-    %FunctionSetPrototype(f, new $Error());
-  }
-  %FunctionSetInstanceClassName(f, 'Error');
-  %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
-  // The name property on the prototype of error objects is not
-  // specified as being read-one and dont-delete. However, allowing
-  // overwriting allows leaks of error objects between script blocks
-  // in the same context in a browser setting. Therefore we fix the
-  // name.
-  %SetProperty(f.prototype, "name", name, DONT_ENUM | DONT_DELETE | READ_ONLY);
-  %SetCode(f, function(m) {
-    if (%_IsConstructCall()) {
-      // Define all the expected properties directly on the error
-      // object. This avoids going through getters and setters defined
-      // on prototype objects.
-      %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
-      %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
-      %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
-      if (m === kAddMessageAccessorsMarker) {
-        // DefineOneShotAccessor always inserts a message property and
-        // ignores setters.
-        DefineOneShotAccessor(this, 'message', function (obj) {
-            return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
-        });
-      } else if (!IS_UNDEFINED(m)) {
-        %IgnoreAttributesAndSetProperty(this,
-                                        'message',
-                                        ToString(m),
-                                        DONT_ENUM);
-      }
-      captureStackTrace(this, f);
-    } else {
-      return new f(m);
-    }
-  });
-}
-
 function captureStackTrace(obj, cons_opt) {
   var stackTraceLimit = $Error.stackTraceLimit;
   if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
@@ -1070,52 +1028,98 @@ function captureStackTrace(obj, cons_opt) {
   });
 };
 
-$Math.__proto__ = global.Object.prototype;
-
-// DefineError is a native function. Use explicit receiver. Otherwise
-// the receiver will be 'undefined'.
-this.DefineError(function Error() { });
-this.DefineError(function TypeError() { });
-this.DefineError(function RangeError() { });
-this.DefineError(function SyntaxError() { });
-this.DefineError(function ReferenceError() { });
-this.DefineError(function EvalError() { });
-this.DefineError(function URIError() { });
 
-$Error.captureStackTrace = captureStackTrace;
+(function () {
+  // Define special error type constructors.
+
+  function DefineError(f) {
+    // Store the error function in both the global object
+    // and the runtime object. The function is fetched
+    // from the runtime object when throwing errors from
+    // within the runtime system to avoid strange side
+    // effects when overwriting the error functions from
+    // user code.
+    var name = f.name;
+    %SetProperty(global, name, f, DONT_ENUM);
+    builtins['$' + name] = f;
+    // Configure the error function.
+    if (name == 'Error') {
+      // The prototype of the Error object must itself be an error.
+      // However, it can't be an instance of the Error object because
+      // it hasn't been properly configured yet.  Instead we create a
+      // special not-a-true-error-but-close-enough object.
+      function ErrorPrototype() {}
+      %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
+      %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
+      %FunctionSetPrototype(f, new ErrorPrototype());
+    } else {
+      %FunctionSetPrototype(f, new $Error());
+    }
+    %FunctionSetInstanceClassName(f, 'Error');
+    %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
+    // The name property on the prototype of error objects is not
+    // specified as being read-one and dont-delete. However, allowing
+    // overwriting allows leaks of error objects between script blocks
+    // in the same context in a browser setting. Therefore we fix the
+    // name.
+    %SetProperty(f.prototype, "name", name,
+                 DONT_ENUM | DONT_DELETE | READ_ONLY)  ;
+    %SetCode(f, function(m) {
+      if (%_IsConstructCall()) {
+        // Define all the expected properties directly on the error
+        // object. This avoids going through getters and setters defined
+        // on prototype objects.
+        %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
+        %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
+        %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
+        if (m === kAddMessageAccessorsMarker) {
+          // DefineOneShotAccessor always inserts a message property and
+          // ignores setters.
+          DefineOneShotAccessor(this, 'message', function (obj) {
+              return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
+          });
+        } else if (!IS_UNDEFINED(m)) {
+          %IgnoreAttributesAndSetProperty(this,
+                                          'message',
+                                          ToString(m),
+                                          DONT_ENUM);
+        }
+        captureStackTrace(this, f);
+      } else {
+        return new f(m);
+      }
+    });
+  }
 
-// Setup extra properties of the Error.prototype object.
-function setErrorMessage() {
-  var desc = {value: '',
-              enumerable: false,
-              configurable: true,
-              writable: true };
-  DefineOwnProperty($Error.prototype,
-                    'message',
-                    ToPropertyDescriptor(desc),
-                    true);
+  DefineError(function Error() { });
+  DefineError(function TypeError() { });
+  DefineError(function RangeError() { });
+  DefineError(function SyntaxError() { });
+  DefineError(function ReferenceError() { });
+  DefineError(function EvalError() { });
+  DefineError(function URIError() { });
+})();
 
-}
+$Error.captureStackTrace = captureStackTrace;
 
-setErrorMessage();
+%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
 
 // Global list of error objects visited during errorToString. This is
 // used to detect cycles in error toString formatting.
-var visited_errors = new $Array();
-var cyclic_error_marker = new $Object();
+const visited_errors = new InternalArray();
+const cyclic_error_marker = new $Object();
 
-function errorToStringDetectCycle() {
-  if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker;
+function errorToStringDetectCycle(error) {
+  if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
   try {
-    var type = this.type;
-    if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) {
-      var formatted = FormatMessage(%NewMessageObject(type, this.arguments));
-      return this.name + ": " + formatted;
+    var type = error.type;
+    var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
+    if (type && !hasMessage) {
+      var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
+      return error.name + ": " + formatted;
     }
-    var message = %_CallFunction(this, "message", ObjectHasOwnProperty)
-        ? (": " + this.message)
-        : "";
-    return this.name + message;
+    var message = hasMessage ? (": " + error.message) : "";
+    return error.name + message;
   } finally {
     visited_errors.length = visited_errors.length - 1;
   }
@@ -1131,7 +1135,7 @@ function errorToString() {
   function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
 
   try {
-    return %_CallFunction(this, errorToStringDetectCycle);
+    return errorToStringDetectCycle(this);
   } catch(e) {
     // If this error message was encountered already return the empty
     // string for it instead of recursively formatting it.
index 4b600df7360b3431f9a3834937a022e35d1a4648..61deb9baa0cf39fc3ddc42fb2ea4c5f893debbe3 100644 (file)
@@ -48,6 +48,7 @@ const $Number = global.Number;
 const $Function = global.Function;
 const $Boolean = global.Boolean;
 const $NaN = 0/0;
+const builtins = this;
 
 // ECMA-262 Section 11.9.3.
 function EQUALS(y) {