Lock the prototype of internal classes.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Sep 2011 07:30:35 +0000 (07:30 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Sep 2011 07:30:35 +0000 (07:30 +0000)
Prototypes and their properties and methods are locked down to prevent fiddling with their operation, even if the build-in object leaks.

Made some built-in functions only work during bootstrapping.

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

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

13 files changed:
src/array.js
src/date.js
src/json.js
src/math.js
src/messages.js
src/regexp.js
src/runtime.cc
src/runtime.h
src/string.js
src/uri.js
src/v8natives.js
src/weakmap.js
test/mjsunit/builtins.js [new file with mode: 0644]

index 281c507f5a6d6e83b4dd196e3170a0538950fa33..32a370fda862f81c293b3b39f6a075438ae96ec5 100644 (file)
@@ -1314,12 +1314,13 @@ function ArrayIsArray(obj) {
 
 
 // -------------------------------------------------------------------
-function SetupArray() {
-  // Setup non-enumerable constructor property on the Array.prototype
+function SetUpArray() {
+  %CheckIsBootstrapping();
+  // Set up non-enumerable constructor property on the Array.prototype
   // object.
   %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
 
-  // Setup non-enumerable functions on the Array object.
+  // Set up non-enumerable functions on the Array object.
   InstallFunctions($Array, DONT_ENUM, $Array(
     "isArray", ArrayIsArray
   ));
@@ -1337,7 +1338,7 @@ function SetupArray() {
     return f;
   }
 
-  // Setup non-enumerable functions of the Array.prototype object and
+  // Set up non-enumerable functions of the Array.prototype object and
   // set their names.
   // Manipulate the length of some of the functions to meet
   // expectations set by ECMA-262 or Mozilla.
@@ -1368,19 +1369,13 @@ function SetupArray() {
   %FinishArrayPrototypeSetup($Array.prototype);
 
   // The internal Array prototype doesn't need to be fancy, since it's never
-  // exposed to user code, so no hidden prototypes or DONT_ENUM attributes
-  // are necessary.
-  // The null __proto__ ensures that we never inherit any user created
-  // getters or setters from, e.g., Object.prototype.
-  InternalArray.prototype.__proto__ = null;
-  // Adding only the functions that are actually used, and a toString.
-  InternalArray.prototype.join = getFunction("join", ArrayJoin);
-  InternalArray.prototype.pop = getFunction("pop", ArrayPop);
-  InternalArray.prototype.push = getFunction("push", ArrayPush);
-  InternalArray.prototype.toString = function() {
-    return "Internal Array, length " + this.length;
-  };
+  // exposed to user code.
+  // Adding only the functions that are actually used.
+  SetUpLockedPrototype(InternalArray, $Array(), $Array(
+    "join", getFunction("join", ArrayJoin),
+    "pop", getFunction("pop", ArrayPop),
+    "push", getFunction("push", ArrayPush)
+  ));
 }
 
-
-SetupArray();
+SetUpArray();
index 79b846d4a7060efc938990330cf8396b07224073..ccefce57638812366eb32776b5cbdc6c1d79ebaf 100644 (file)
@@ -1048,18 +1048,19 @@ function ResetDateCache() {
 
 // -------------------------------------------------------------------
 
-function SetupDate() {
-  // Setup non-enumerable properties of the Date object itself.
+function SetUpDate() {
+  %CheckIsBootstrapping();
+  // Set up non-enumerable properties of the Date object itself.
   InstallFunctions($Date, DONT_ENUM, $Array(
     "UTC", DateUTC,
     "parse", DateParse,
     "now", DateNow
   ));
 
-  // Setup non-enumerable constructor property of the Date prototype object.
+  // Set up non-enumerable constructor property of the Date prototype object.
   %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
 
-  // Setup non-enumerable functions of the Date prototype object and
+  // Set up non-enumerable functions of the Date prototype object and
   // set their names.
   InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
     "toString", DateToString,
@@ -1111,4 +1112,4 @@ function SetupDate() {
   ));
 }
 
-SetupDate();
+SetUpDate();
index 8fd410fa4d90a945d67b59fc93df80129993a337..a491bcc1517b890c271099a52b228764aa814fd7 100644 (file)
@@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) {
   return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
 }
 
-function SetupJSON() {
+function SetUpJSON() {
+  %CheckIsBootstrapping();
   InstallFunctions($JSON, DONT_ENUM, $Array(
     "parse", JSONParse,
     "stringify", JSONStringify
   ));
 }
 
-SetupJSON();
+SetUpJSON()
index 31306e79d18e1e98cba7e2ee7f697ef303f91543..b5a6d1811757aaaa7b0f35fc863b4a471e47b341 100644 (file)
@@ -195,8 +195,9 @@ function MathTan(x) {
 
 // -------------------------------------------------------------------
 
-function SetupMath() {
-  // Setup math constants.
+function SetUpMath() {
+  %CheckIsBootstrapping();
+  // Set up math constants.
   // ECMA-262, section 15.8.1.1.
   %OptimizeObjectForAddingMultipleProperties($Math, 8);
   %SetProperty($Math,
@@ -236,7 +237,7 @@ function SetupMath() {
                DONT_ENUM |  DONT_DELETE | READ_ONLY);
   %ToFastProperties($Math);
 
-  // Setup non-enumerable functions of the Math object and
+  // Set up non-enumerable functions of the Math object and
   // set their names.
   InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array(
     "random", MathRandom,
@@ -258,7 +259,6 @@ function SetupMath() {
     "max", MathMax,
     "min", MathMin
   ));
-};
-
+}
 
-SetupMath();
+SetUpMath();
index e38dc3e9dcde521a022acf892b996d89010be0f1..3c85d9416af035f37c302e4e7df5c29fee9c234b 100644 (file)
@@ -116,10 +116,11 @@ function MakeGenericError(constructor, type, args) {
 
 
 /**
- * Setup the Script function and constructor.
+ * Set up the Script function and constructor.
  */
 %FunctionSetInstanceClassName(Script, 'Script');
-%SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM);
+%SetProperty(Script.prototype, 'constructor', Script,
+             DONT_ENUM | DONT_DELETE | READ_ONLY);
 %SetCode(Script, function(x) {
   // Script objects can only be created by the VM.
   throw new $Error("Not supported");
@@ -320,7 +321,7 @@ function MakeError(type, args) {
  * @return {number} 0 if input too small, -1 if input too large,
        else the line number.
  */
-Script.prototype.lineFromPosition = function(position) {
+function ScriptLineFromPosition(position) {
   var lower = 0;
   var upper = this.lineCount() - 1;
   var line_ends = this.line_ends;
@@ -359,8 +360,8 @@ Script.prototype.lineFromPosition = function(position) {
  * @return {SourceLocation}
  *     If line is negative or not in the source null is returned.
  */
-Script.prototype.locationFromPosition = function (position,
-                                                  include_resource_offset) {
+function ScriptLocationFromPosition(position,
+                                    include_resource_offset) {
   var line = this.lineFromPosition(position);
   if (line == -1) return null;
 
@@ -368,7 +369,9 @@ Script.prototype.locationFromPosition = function (position,
   var line_ends = this.line_ends;
   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
   var end = line_ends[line];
-  if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') end--;
+  if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
+    end--;
+  }
   var column = position - start;
 
   // Adjust according to the offset within the resource.
@@ -393,11 +396,12 @@ Script.prototype.locationFromPosition = function (position,
  * @param {number} opt_line The line within the source. Default value is 0
  * @param {number} opt_column The column in within the line. Default value is 0
  * @param {number} opt_offset_position The offset from the begining of the
- *     source from where the line and column calculation starts. Default value is 0
+ *     source from where the line and column calculation starts.
+ *     Default value is 0
  * @return {SourceLocation}
  *     If line is negative or not in the source null is returned.
  */
-Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_position) {
+function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
   // Default is the first line in the script. Lines in the script is relative
   // to the offset within the resource.
   var line = 0;
@@ -439,7 +443,7 @@ Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_p
  * @return {SourceSlice} The source slice or null of the parameters where
  *     invalid
  */
-Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
+function ScriptSourceSlice(opt_from_line, opt_to_line) {
   var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line;
   var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
 
@@ -466,7 +470,7 @@ Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
 }
 
 
-Script.prototype.sourceLine = function (opt_line) {
+function ScriptSourceLine(opt_line) {
   // Default is the first line in the script. Lines in the script are relative
   // to the offset within the resource.
   var line = 0;
@@ -492,7 +496,7 @@ Script.prototype.sourceLine = function (opt_line) {
  * @return {number}
  *     Number of source lines.
  */
-Script.prototype.lineCount = function() {
+function ScriptLineCount() {
   // Return number of source lines.
   return this.line_ends.length;
 };
@@ -508,9 +512,10 @@ Script.prototype.lineCount = function() {
  * @return {?string} script name if present, value for //@ sourceURL comment
  * otherwise.
  */
-Script.prototype.nameOrSourceURL = function() {
-  if (this.name)
+function ScriptNameOrSourceURL() {
+  if (this.name) {
     return this.name;
+  }
   // TODO(608): the spaces in a regexp below had to be escaped as \040
   // because this file is being processed by js2c whose handling of spaces
   // in regexps is broken. Also, ['"] are excluded from allowed URLs to
@@ -536,6 +541,20 @@ Script.prototype.nameOrSourceURL = function() {
 }
 
 
+SetUpLockedPrototype(Script,
+  $Array("source", "name", "line_ends", "line_offset", "column_offset"),
+  $Array(
+    "lineFromPosition", ScriptLineFromPosition,
+    "locationFromPosition", ScriptLocationFromPosition,
+    "locationFromLine", ScriptLocationFromLine,
+    "sourceSlice", ScriptSourceSlice,
+    "sourceLine", ScriptSourceLine,
+    "lineCount", ScriptLineCount,
+    "nameOrSourceURL", ScriptNameOrSourceURL
+  )
+);
+
+
 /**
  * Class for source location. A source location is a position within some
  * source with the following properties:
@@ -566,8 +585,6 @@ function SourceLocation(script, position, line, column, start, end) {
   this.end = end;
 }
 
-SourceLocation.prototype.__proto__ = null;
-
 const kLineLengthLimit = 78;
 
 /**
@@ -578,7 +595,7 @@ const kLineLengthLimit = 78;
  * @param {number} opt_before The number of characters to prefer before the
  *     position with a default value of 10 less that the limit
  */
-SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
+function SourceLocationRestrict(opt_limit, opt_before) {
   // Find the actual limit to use.
   var limit;
   var before;
@@ -625,11 +642,20 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
  * @return {String}
  *     Source text for this location.
  */
-SourceLocation.prototype.sourceText = function () {
+function SourceLocationSourceText() {
   return %_CallFunction(this.script.source, this.start, this.end, StringSubstring);
 };
 
 
+SetUpLockedPrototype(SourceLocation,
+  $Array("script", "position", "line", "column", "start", "end"),
+  $Array(
+    "restrict", SourceLocationRestrict,
+    "sourceText", SourceLocationSourceText
+  )
+);
+
+
 /**
  * Class for a source slice. A source slice is a part of a script source with
  * the following properties:
@@ -656,20 +682,23 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) {
   this.to_position = to_position;
 }
 
-SourceSlice.prototype.__proto__ = null;
-
 /**
  * Get the source text for a SourceSlice
  * @return {String} Source text for this slice. The last line will include
  *     the line terminating characters (if any)
  */
-SourceSlice.prototype.sourceText = function () {
+function SourceSliceSourceText() {
   return %_CallFunction(this.script.source,
                         this.from_position,
                         this.to_position,
                         StringSubstring);
 };
 
+SetUpLockedPrototype(SourceSlice,
+  $Array("script", "from_line", "to_line", "from_position", "to_position"),
+  $Array("sourceText", SourceSliceSourceText)
+);
+
 
 // Returns the offset of the given position within the containing
 // line.
@@ -724,13 +753,11 @@ function CallSite(receiver, fun, pos) {
   this.pos = pos;
 }
 
-CallSite.prototype.__proto__ = null;
-
-CallSite.prototype.getThis = function () {
+function CallSiteGetThis() {
   return this.receiver;
 };
 
-CallSite.prototype.getTypeName = function () {
+function CallSiteGetTypeName() {
   var constructor = this.receiver.constructor;
   if (!constructor) {
     return %_CallFunction(this.receiver, ObjectToString);
@@ -742,33 +769,33 @@ CallSite.prototype.getTypeName = function () {
   return constructorName;
 };
 
-CallSite.prototype.isToplevel = function () {
+function CallSiteIsToplevel() {
   if (this.receiver == null) {
     return true;
   }
   return IS_GLOBAL(this.receiver);
 };
 
-CallSite.prototype.isEval = function () {
+function CallSiteIsEval() {
   var script = %FunctionGetScript(this.fun);
   return script && script.compilation_type == COMPILATION_TYPE_EVAL;
 };
 
-CallSite.prototype.getEvalOrigin = function () {
+function CallSiteGetEvalOrigin() {
   var script = %FunctionGetScript(this.fun);
   return FormatEvalOrigin(script);
 };
 
-CallSite.prototype.getScriptNameOrSourceURL = function () {
+function CallSiteGetScriptNameOrSourceURL() {
   var script = %FunctionGetScript(this.fun);
   return script ? script.nameOrSourceURL() : null;
 };
 
-CallSite.prototype.getFunction = function () {
+function CallSiteGetFunction() {
   return this.fun;
 };
 
-CallSite.prototype.getFunctionName = function () {
+function CallSiteGetFunctionName() {
   // See if the function knows its own name
   var name = this.fun.name;
   if (name) {
@@ -784,7 +811,7 @@ CallSite.prototype.getFunctionName = function () {
   return null;
 };
 
-CallSite.prototype.getMethodName = function () {
+function CallSiteGetMethodName() {
   // See if we can find a unique property on the receiver that holds
   // this function.
   var ownName = this.fun.name;
@@ -814,12 +841,12 @@ CallSite.prototype.getMethodName = function () {
   return null;
 };
 
-CallSite.prototype.getFileName = function () {
+function CallSiteGetFileName() {
   var script = %FunctionGetScript(this.fun);
   return script ? script.name : null;
 };
 
-CallSite.prototype.getLineNumber = function () {
+function CallSiteGetLineNumber() {
   if (this.pos == -1) {
     return null;
   }
@@ -831,7 +858,7 @@ CallSite.prototype.getLineNumber = function () {
   return location ? location.line + 1 : null;
 };
 
-CallSite.prototype.getColumnNumber = function () {
+function CallSiteGetColumnNumber() {
   if (this.pos == -1) {
     return null;
   }
@@ -843,16 +870,16 @@ CallSite.prototype.getColumnNumber = function () {
   return location ? location.column + 1: null;
 };
 
-CallSite.prototype.isNative = function () {
+function CallSiteIsNative() {
   var script = %FunctionGetScript(this.fun);
   return script ? (script.type == TYPE_NATIVE) : false;
 };
 
-CallSite.prototype.getPosition = function () {
+function CallSiteGetPosition() {
   return this.pos;
 };
 
-CallSite.prototype.isConstructor = function () {
+function CallSiteIsConstructor() {
   var constructor = this.receiver ? this.receiver.constructor : null;
   if (!constructor) {
     return false;
@@ -860,6 +887,25 @@ CallSite.prototype.isConstructor = function () {
   return this.fun === constructor;
 };
 
+SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
+  "getThis", CallSiteGetThis,
+  "getTypeName", CallSiteGetTypeName,
+  "isToplevel", CallSiteIsToplevel,
+  "isEval", CallSiteIsEval,
+  "getEvalOrigin", CallSiteGetEvalOrigin,
+  "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
+  "getFunction", CallSiteGetFunction,
+  "getFunctionName", CallSiteGetFunctionName,
+  "getMethodName", CallSiteGetMethodName,
+  "getFileName", CallSiteGetFileName,
+  "getLineNumber", CallSiteGetLineNumber,
+  "getColumnNumber", CallSiteGetColumnNumber,
+  "isNative", CallSiteIsNative,
+  "getPosition", CallSiteGetPosition,
+  "isConstructor", CallSiteIsConstructor
+));
+
+
 function FormatEvalOrigin(script) {
   var sourceURL = script.nameOrSourceURL();
   if (sourceURL) {
@@ -1001,6 +1047,7 @@ function FormatRawStackTrace(error, raw_stack) {
   }
 }
 
+
 function captureStackTrace(obj, cons_opt) {
   var stackTraceLimit = $Error.stackTraceLimit;
   if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
@@ -1016,7 +1063,7 @@ function captureStackTrace(obj, cons_opt) {
 };
 
 
-(function () {
+function SetUpError() {
   // Define special error type constructors.
 
   function DefineError(f) {
@@ -1085,7 +1132,9 @@ function captureStackTrace(obj, cons_opt) {
   DefineError(function ReferenceError() { });
   DefineError(function EvalError() { });
   DefineError(function URIError() { });
-})();
+}
+
+SetUpError();
 
 $Error.captureStackTrace = captureStackTrace;
 
index a7f42d59c25ef2e5723df1ac70db16ab05aeb13b..38d4496153909f41d98ada01cd18ee5fa367fe63 100644 (file)
@@ -405,7 +405,8 @@ var lastMatchInfoOverride = null;
 
 // -------------------------------------------------------------------
 
-function SetupRegExp() {
+function SetUpRegExp() {
+  %CheckIsBootstrapping();
   %FunctionSetInstanceClassName($RegExp, 'RegExp');
   %FunctionSetPrototype($RegExp, new $Object());
   %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
@@ -484,5 +485,4 @@ function SetupRegExp() {
   }
 }
 
-
-SetupRegExp();
+SetUpRegExp();
index d1fe1c7c1675377ead4e8d7bdc8d7717630abe07..e894bf242cbb5b0a298910226d234e842646c2e8 100644 (file)
@@ -32,6 +32,7 @@
 #include "accessors.h"
 #include "api.h"
 #include "arguments.h"
+#include "bootstrapper.h"
 #include "codegen.h"
 #include "compilation-cache.h"
 #include "compiler.h"
@@ -2153,6 +2154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
 
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
+  RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
   HandleScope scope(isolate);
   ASSERT(args.length() == 2);
 
@@ -8256,6 +8258,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
+  RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
+  return isolate->heap()->undefined_value();
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
   HandleScope scope(isolate);
   ASSERT(args.length() == 1);
index 7db26db90d5f723e797e78becaf2a20dc50dc9f0..ddd529588b3bfa9b71c3f5e0decf7a9dd8518b2f 100644 (file)
@@ -79,6 +79,7 @@ namespace internal {
   F(PreventExtensions, 1, 1)\
   \
   /* Utilities */ \
+  F(CheckIsBootstrapping, 0, 1) \
   F(GetFunctionDelegate, 1, 1) \
   F(GetConstructorDelegate, 1, 1) \
   F(NewArgumentsFast, 3, 1) \
index a70eeade83b9d68b51937611b621b628fa6be286..6f68ce089096db33a4e5c3f52a9a4ead7595400c 100644 (file)
@@ -911,50 +911,47 @@ function ReplaceResultBuilder(str) {
   this.special_string = str;
 }
 
-ReplaceResultBuilder.prototype.__proto__ = null;
-
-
-ReplaceResultBuilder.prototype.add = function(str) {
-  str = TO_STRING_INLINE(str);
-  if (str.length > 0) this.elements.push(str);
-}
-
-
-ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
-  var len = end - start;
-  if (start < 0 || len <= 0) return;
-  if (start < 0x80000 && len < 0x800) {
-    this.elements.push((start << 11) | len);
-  } else {
-    // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
-    // so -len is a smi.
+SetUpLockedPrototype(ReplaceResultBuilder,
+  $Array("elements", "special_string"), $Array(
+  "add", function(str) {
+    str = TO_STRING_INLINE(str);
+    if (str.length > 0) this.elements.push(str);
+  },
+  "addSpecialSlice", function(start, end) {
+    var len = end - start;
+    if (start < 0 || len <= 0) return;
+    if (start < 0x80000 && len < 0x800) {
+      this.elements.push((start << 11) | len);
+    } else {
+      // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
+      // so -len is a smi.
+      var elements = this.elements;
+      elements.push(-len);
+      elements.push(start);
+    }
+  },
+  "generate", function() {
     var elements = this.elements;
-    elements.push(-len);
-    elements.push(start);
+    return %StringBuilderConcat(elements, elements.length, this.special_string);
   }
-}
-
-
-ReplaceResultBuilder.prototype.generate = function() {
-  var elements = this.elements;
-  return %StringBuilderConcat(elements, elements.length, this.special_string);
-}
+));
 
 
 // -------------------------------------------------------------------
 
-function SetupString() {
-  // Setup the constructor property on the String prototype object.
+function SetUpString() {
+  %CheckIsBootstrapping();
+  // Set up the constructor property on the String prototype object.
   %SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
 
 
-  // Setup the non-enumerable functions on the String object.
+  // Set up the non-enumerable functions on the String object.
   InstallFunctions($String, DONT_ENUM, $Array(
     "fromCharCode", StringFromCharCode
   ));
 
 
-  // Setup the non-enumerable functions on the String prototype object.
+  // Set up the non-enumerable functions on the String prototype object.
   InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
     "valueOf", StringValueOf,
     "toString", StringToString,
@@ -994,5 +991,4 @@ function SetupString() {
   ));
 }
 
-
-SetupString();
+SetUpString();
index 72ca6f1565daa2d1b755e73622486afa4e1ddfc5..c910d756b4c4cdc96336ba49cf0ea25bc3611fb6 100644 (file)
@@ -392,8 +392,9 @@ function URIUnescape(str) {
 
 // -------------------------------------------------------------------
 
-function SetupURI() {
-  // Setup non-enumerable URI functions on the global object and set
+function SetUpUri() {
+  %CheckIsBootstrapping();
+  // Set up non-enumerable URI functions on the global object and set
   // their names.
   InstallFunctions(global, DONT_ENUM, $Array(
     "escape", URIEscape,
@@ -405,4 +406,4 @@ function SetupURI() {
   ));
 }
 
-SetupURI();
+SetUpUri();
index 137b758b911375de50ae6e2467e08b949fec67f9..03d1585a041acc0f973da82c3269a1b374a45c8f 100644 (file)
@@ -75,12 +75,48 @@ function InstallFunctions(object, attributes, functions) {
 // functions on String.prototype etc. and then restore the old function
 // with delete.  See http://code.google.com/p/chromium/issues/detail?id=1717
 function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
+  %CheckIsBootstrapping();
   var hidden_prototype = new $Object();
   %SetHiddenPrototype(object, hidden_prototype);
   InstallFunctions(hidden_prototype, attributes, functions);
 }
 
 
+// Prevents changes to the prototype of a built-infunction.
+// The "prototype" property of the function object is made non-configurable,
+// and the prototype object is made non-extensible. The latter prevents
+// changing the __proto__ property.
+function SetUpLockedPrototype(constructor, fields, methods) {
+  %CheckIsBootstrapping();
+  var prototype = constructor.prototype;
+  // Install functions first, because this function is used to initialize
+  // PropertyDescriptor itself.
+  var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
+  if (property_count >= 4) {
+    %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
+  }
+  if (fields) {
+    for (var i = 0; i < fields.length; i++) {
+      %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
+    }
+  }
+  for (var i = 0; i < methods.length; i += 2) {
+    var key = methods[i];
+    var f = methods[i + 1];
+    %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
+    %SetNativeFlag(f);
+  }
+  prototype.__proto__ = null;
+  %PreventExtensions(prototype);
+  %ToFastProperties(prototype);
+
+  var desc = GetOwnProperty(constructor, "prototype");
+  desc.setWritable(false);
+  desc.setConfigurable(false);
+  DefineOwnProperty(constructor, "prototype", desc, false);
+}
+
+
 // ----------------------------------------------------------------------------
 
 
@@ -171,8 +207,9 @@ function GlobalEval(x) {
 
 // ----------------------------------------------------------------------------
 
-
-function SetupGlobal() {
+// Set up global object.
+function SetUpGlobal() {
+  %CheckIsBootstrapping();
   // ECMA 262 - 15.1.1.1.
   %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
 
@@ -182,7 +219,7 @@ function SetupGlobal() {
   // ECMA-262 - 15.1.1.3.
   %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
 
-  // Setup non-enumerable function on the global object.
+  // Set up non-enumerable function on the global object.
   InstallFunctions(global, DONT_ENUM, $Array(
     "isNaN", GlobalIsNaN,
     "isFinite", GlobalIsFinite,
@@ -192,8 +229,7 @@ function SetupGlobal() {
   ));
 }
 
-SetupGlobal();
-
+SetUpGlobal();
 
 // ----------------------------------------------------------------------------
 // Boolean (first part of definition)
@@ -490,106 +526,83 @@ function PropertyDescriptor() {
   this.hasSetter_ = false;
 }
 
-PropertyDescriptor.prototype.__proto__ = null;
-
-PropertyDescriptor.prototype.toString = function() {
-  return "[object PropertyDescriptor]";
-};
-
-PropertyDescriptor.prototype.setValue = function(value) {
-  this.value_ = value;
-  this.hasValue_ = true;
-}
-
-
-PropertyDescriptor.prototype.getValue = function() {
-  return this.value_;
-}
-
-
-PropertyDescriptor.prototype.hasValue = function() {
-  return this.hasValue_;
-}
-
-
-PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
-  this.enumerable_ = enumerable;
-  this.hasEnumerable_ = true;
-}
-
-
-PropertyDescriptor.prototype.isEnumerable = function () {
-  return this.enumerable_;
-}
-
-
-PropertyDescriptor.prototype.hasEnumerable = function() {
-  return this.hasEnumerable_;
-}
-
-
-PropertyDescriptor.prototype.setWritable = function(writable) {
-  this.writable_ = writable;
-  this.hasWritable_ = true;
-}
-
-
-PropertyDescriptor.prototype.isWritable = function() {
-  return this.writable_;
-}
-
-
-PropertyDescriptor.prototype.hasWritable = function() {
-  return this.hasWritable_;
-}
-
-
-PropertyDescriptor.prototype.setConfigurable = function(configurable) {
-  this.configurable_ = configurable;
-  this.hasConfigurable_ = true;
-}
-
-
-PropertyDescriptor.prototype.hasConfigurable = function() {
-  return this.hasConfigurable_;
-}
-
-
-PropertyDescriptor.prototype.isConfigurable = function() {
-  return this.configurable_;
-}
-
-
-PropertyDescriptor.prototype.setGet = function(get) {
-  this.get_ = get;
-  this.hasGetter_ = true;
-}
-
-
-PropertyDescriptor.prototype.getGet = function() {
-  return this.get_;
-}
-
-
-PropertyDescriptor.prototype.hasGetter = function() {
-  return this.hasGetter_;
-}
-
-
-PropertyDescriptor.prototype.setSet = function(set) {
-  this.set_ = set;
-  this.hasSetter_ = true;
-}
-
-
-PropertyDescriptor.prototype.getSet = function() {
-  return this.set_;
-}
-
-
-PropertyDescriptor.prototype.hasSetter = function() {
-  return this.hasSetter_;
-}
+SetUpLockedPrototype(PropertyDescriptor, $Array(
+    "value_",
+    "hasValue_",
+    "writable_",
+    "hasWritable_",
+    "enumerable_",
+    "hasEnumerable_",
+    "configurable_",
+    "hasConfigurable_",
+    "get_",
+    "hasGetter_",
+    "set_",
+    "hasSetter_"
+  ), $Array(
+    "toString", function() {
+      return "[object PropertyDescriptor]";
+    },
+    "setValue", function(value) {
+      this.value_ = value;
+      this.hasValue_ = true;
+    },
+    "getValue", function() {
+      return this.value_;
+    },
+    "hasValue", function() {
+      return this.hasValue_;
+    },
+    "setEnumerable", function(enumerable) {
+      this.enumerable_ = enumerable;
+        this.hasEnumerable_ = true;
+    },
+    "isEnumerable", function () {
+      return this.enumerable_;
+    },
+    "hasEnumerable", function() {
+      return this.hasEnumerable_;
+    },
+    "setWritable", function(writable) {
+      this.writable_ = writable;
+      this.hasWritable_ = true;
+    },
+    "isWritable", function() {
+      return this.writable_;
+    },
+    "hasWritable", function() {
+      return this.hasWritable_;
+    },
+    "setConfigurable", function(configurable) {
+      this.configurable_ = configurable;
+      this.hasConfigurable_ = true;
+    },
+    "hasConfigurable", function() {
+      return this.hasConfigurable_;
+    },
+    "isConfigurable", function() {
+      return this.configurable_;
+    },
+    "setGet", function(get) {
+      this.get_ = get;
+        this.hasGetter_ = true;
+    },
+    "getGet", function() {
+      return this.get_;
+    },
+    "hasGetter", function() {
+      return this.hasGetter_;
+    },
+    "setSet", function(set) {
+      this.set_ = set;
+      this.hasSetter_ = true;
+    },
+    "getSet", function() {
+      return this.set_;
+    },
+    "hasSetter", function() {
+      return this.hasSetter_;
+  }));
 
 
 // Converts an array returned from Runtime_GetOwnProperty to an actual
@@ -1177,10 +1190,11 @@ function ObjectIsExtensible(obj) {
 %SetExpectedNumberOfProperties($Object, 4);
 
 // ----------------------------------------------------------------------------
+// Object
 
-
-function SetupObject() {
-  // Setup non-enumerable functions on the Object.prototype object.
+function SetUpObject() {
+  %CheckIsBootstrapping();
+  // Set Up non-enumerable functions on the Object.prototype object.
   InstallFunctions($Object.prototype, DONT_ENUM, $Array(
     "toString", ObjectToString,
     "toLocaleString", ObjectToLocaleString,
@@ -1210,8 +1224,7 @@ function SetupObject() {
   ));
 }
 
-SetupObject();
-
+SetUpObject();
 
 // ----------------------------------------------------------------------------
 // Boolean
@@ -1242,14 +1255,16 @@ function BooleanValueOf() {
 // ----------------------------------------------------------------------------
 
 
-function SetupBoolean() {
+function SetUpBoolean () {
+  %CheckIsBootstrapping();
   InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
     "toString", BooleanToString,
     "valueOf", BooleanValueOf
   ));
 }
 
-SetupBoolean();
+SetUpBoolean();
+
 
 // ----------------------------------------------------------------------------
 // Number
@@ -1363,9 +1378,10 @@ function NumberToPrecision(precision) {
 
 // ----------------------------------------------------------------------------
 
-function SetupNumber() {
+function SetUpNumber() {
+  %CheckIsBootstrapping();
   %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
-  // Setup the constructor property on the Number prototype object.
+  // Set up the constructor property on the Number prototype object.
   %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
 
   %OptimizeObjectForAddingMultipleProperties($Number, 5);
@@ -1394,7 +1410,7 @@ function SetupNumber() {
                DONT_ENUM | DONT_DELETE | READ_ONLY);
   %ToFastProperties($Number);
 
-  // Setup non-enumerable functions on the Number prototype object.
+  // Set up non-enumerable functions on the Number prototype object.
   InstallFunctions($Number.prototype, DONT_ENUM, $Array(
     "toString", NumberToString,
     "toLocaleString", NumberToLocaleString,
@@ -1405,7 +1421,7 @@ function SetupNumber() {
   ));
 }
 
-SetupNumber();
+SetUpNumber();
 
 
 // ----------------------------------------------------------------------------
@@ -1534,11 +1550,12 @@ function NewFunction(arg1) {  // length == 1
 
 // ----------------------------------------------------------------------------
 
-function SetupFunction() {
+function SetUpFunction() {
+  %CheckIsBootstrapping();
   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
     "bind", FunctionBind,
     "toString", FunctionToString
   ));
 }
 
-SetupFunction();
+SetUpFunction();
index 3d261e5afda2e18502f3af41661b96cdd977258b..6c15e30fb6f3b6dfb82d565e1293818f3221165a 100644 (file)
@@ -80,7 +80,8 @@ function WeakMapDelete(key) {
 
 // -------------------------------------------------------------------
 
-function SetupWeakMap() {
+(function () {
+  %CheckIsBootstrapping();
   // Set up the WeakMap constructor function.
   %SetCode($WeakMap, WeakMapConstructor);
 
@@ -97,7 +98,4 @@ function SetupWeakMap() {
     "has", WeakMapHas,
     "delete", WeakMapDelete
   ));
-}
-
-
-SetupWeakMap();
+})();
diff --git a/test/mjsunit/builtins.js b/test/mjsunit/builtins.js
new file mode 100644 (file)
index 0000000..340b03d
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-natives-as=builtins
+
+// Checks that all function properties of the builtin object are neither
+// writable nor configurable. Also, theose functions that are actually
+// constructors (recognized by having properties on their .prototype object),
+// have only unconfigurable properties on the prototype, and the methods
+// are also non-writable.
+
+var names = Object.getOwnPropertyNames(builtins);
+
+function isFunction(obj) {
+  return typeof obj == "function";
+}
+
+function checkConstructor(func, name) {
+  // A constructor is a function with a prototype and properties on the
+  // prototype object besides "constructor";
+  if (name.charAt(0) == "$") return;
+  if (typeof func.prototype != "object") return;
+  var propNames = Object.getOwnPropertyNames(func.prototype);
+  if (propNames.length == 0 ||
+      (propNames.length == 1 && propNames[0] == "constructor")) {
+    // Not a constructor.
+    return;
+  }
+  var proto_desc = Object.getOwnPropertyDescriptor(func, "prototype");
+  assertTrue(proto_desc.hasOwnProperty("value"), name);
+  assertFalse(proto_desc.writable, name);
+  assertFalse(proto_desc.configurable, name);
+  var prototype = proto_desc.value;
+  assertEquals(null, prototype.__proto__, name);
+  assertFalse(Object.isExtensible(prototype), name);
+  for (var i = 0; i < propNames.length; i++) {
+    var propName = propNames[i];
+    if (propName == "constructor") continue;
+    var testName = name + "-" + propName;
+    var propDesc = Object.getOwnPropertyDescriptor(prototype, propName);
+    assertTrue(propDesc.hasOwnProperty("value"), testName);
+    assertFalse(propDesc.configurable, testName);
+    if (isFunction(propDesc.value)) {
+      assertFalse(propDesc.writable, testName);
+    }
+  }
+}
+
+for (var i = 0; i < names.length; i++) {
+  var name = names[i];
+  var desc = Object.getOwnPropertyDescriptor(builtins, name);
+  assertTrue(desc.hasOwnProperty("value"));
+  var value = desc.value;
+  if (isFunction(value)) {
+    assertFalse(desc.writable, name);
+    assertFalse(desc.configurable, name);
+    checkConstructor(value, name);
+  }
+}