Commit ffffa716 authored by lrn@chromium.org's avatar lrn@chromium.org

Lock the prototype of internal classes.

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
parent f6c063e1
...@@ -1314,12 +1314,13 @@ function ArrayIsArray(obj) { ...@@ -1314,12 +1314,13 @@ function ArrayIsArray(obj) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupArray() { function SetUpArray() {
// Setup non-enumerable constructor property on the Array.prototype %CheckIsBootstrapping();
// Set up non-enumerable constructor property on the Array.prototype
// object. // object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM); %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( InstallFunctions($Array, DONT_ENUM, $Array(
"isArray", ArrayIsArray "isArray", ArrayIsArray
)); ));
...@@ -1337,7 +1338,7 @@ function SetupArray() { ...@@ -1337,7 +1338,7 @@ function SetupArray() {
return f; 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. // set their names.
// Manipulate the length of some of the functions to meet // Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla. // expectations set by ECMA-262 or Mozilla.
...@@ -1368,19 +1369,13 @@ function SetupArray() { ...@@ -1368,19 +1369,13 @@ function SetupArray() {
%FinishArrayPrototypeSetup($Array.prototype); %FinishArrayPrototypeSetup($Array.prototype);
// The internal Array prototype doesn't need to be fancy, since it's never // 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 // exposed to user code.
// are necessary. // Adding only the functions that are actually used.
// The null __proto__ ensures that we never inherit any user created SetUpLockedPrototype(InternalArray, $Array(), $Array(
// getters or setters from, e.g., Object.prototype. "join", getFunction("join", ArrayJoin),
InternalArray.prototype.__proto__ = null; "pop", getFunction("pop", ArrayPop),
// Adding only the functions that are actually used, and a toString. "push", getFunction("push", ArrayPush)
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;
};
} }
SetUpArray();
SetupArray();
...@@ -1048,18 +1048,19 @@ function ResetDateCache() { ...@@ -1048,18 +1048,19 @@ function ResetDateCache() {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupDate() { function SetUpDate() {
// Setup non-enumerable properties of the Date object itself. %CheckIsBootstrapping();
// Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array( InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC, "UTC", DateUTC,
"parse", DateParse, "parse", DateParse,
"now", DateNow "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); %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. // set their names.
InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array( InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
"toString", DateToString, "toString", DateToString,
...@@ -1111,4 +1112,4 @@ function SetupDate() { ...@@ -1111,4 +1112,4 @@ function SetupDate() {
)); ));
} }
SetupDate(); SetUpDate();
...@@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) { ...@@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) {
return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
} }
function SetupJSON() { function SetUpJSON() {
%CheckIsBootstrapping();
InstallFunctions($JSON, DONT_ENUM, $Array( InstallFunctions($JSON, DONT_ENUM, $Array(
"parse", JSONParse, "parse", JSONParse,
"stringify", JSONStringify "stringify", JSONStringify
)); ));
} }
SetupJSON(); SetUpJSON()
...@@ -195,8 +195,9 @@ function MathTan(x) { ...@@ -195,8 +195,9 @@ function MathTan(x) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupMath() { function SetUpMath() {
// Setup math constants. %CheckIsBootstrapping();
// Set up math constants.
// ECMA-262, section 15.8.1.1. // ECMA-262, section 15.8.1.1.
%OptimizeObjectForAddingMultipleProperties($Math, 8); %OptimizeObjectForAddingMultipleProperties($Math, 8);
%SetProperty($Math, %SetProperty($Math,
...@@ -236,7 +237,7 @@ function SetupMath() { ...@@ -236,7 +237,7 @@ function SetupMath() {
DONT_ENUM | DONT_DELETE | READ_ONLY); DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Math); %ToFastProperties($Math);
// Setup non-enumerable functions of the Math object and // Set up non-enumerable functions of the Math object and
// set their names. // set their names.
InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array( InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array(
"random", MathRandom, "random", MathRandom,
...@@ -258,7 +259,6 @@ function SetupMath() { ...@@ -258,7 +259,6 @@ function SetupMath() {
"max", MathMax, "max", MathMax,
"min", MathMin "min", MathMin
)); ));
}; }
SetupMath(); SetUpMath();
...@@ -116,10 +116,11 @@ function MakeGenericError(constructor, type, args) { ...@@ -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'); %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) { %SetCode(Script, function(x) {
// Script objects can only be created by the VM. // Script objects can only be created by the VM.
throw new $Error("Not supported"); throw new $Error("Not supported");
...@@ -320,7 +321,7 @@ function MakeError(type, args) { ...@@ -320,7 +321,7 @@ function MakeError(type, args) {
* @return {number} 0 if input too small, -1 if input too large, * @return {number} 0 if input too small, -1 if input too large,
else the line number. else the line number.
*/ */
Script.prototype.lineFromPosition = function(position) { function ScriptLineFromPosition(position) {
var lower = 0; var lower = 0;
var upper = this.lineCount() - 1; var upper = this.lineCount() - 1;
var line_ends = this.line_ends; var line_ends = this.line_ends;
...@@ -359,8 +360,8 @@ Script.prototype.lineFromPosition = function(position) { ...@@ -359,8 +360,8 @@ Script.prototype.lineFromPosition = function(position) {
* @return {SourceLocation} * @return {SourceLocation}
* If line is negative or not in the source null is returned. * If line is negative or not in the source null is returned.
*/ */
Script.prototype.locationFromPosition = function (position, function ScriptLocationFromPosition(position,
include_resource_offset) { include_resource_offset) {
var line = this.lineFromPosition(position); var line = this.lineFromPosition(position);
if (line == -1) return null; if (line == -1) return null;
...@@ -368,7 +369,9 @@ Script.prototype.locationFromPosition = function (position, ...@@ -368,7 +369,9 @@ Script.prototype.locationFromPosition = function (position,
var line_ends = this.line_ends; var line_ends = this.line_ends;
var start = line == 0 ? 0 : line_ends[line - 1] + 1; var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line]; 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; var column = position - start;
// Adjust according to the offset within the resource. // Adjust according to the offset within the resource.
...@@ -393,11 +396,12 @@ Script.prototype.locationFromPosition = function (position, ...@@ -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_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_column The column in within the line. Default value is 0
* @param {number} opt_offset_position The offset from the begining of the * @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} * @return {SourceLocation}
* If line is negative or not in the source null is returned. * 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 // Default is the first line in the script. Lines in the script is relative
// to the offset within the resource. // to the offset within the resource.
var line = 0; var line = 0;
...@@ -439,7 +443,7 @@ Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_p ...@@ -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 * @return {SourceSlice} The source slice or null of the parameters where
* invalid * 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 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 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) { ...@@ -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 // Default is the first line in the script. Lines in the script are relative
// to the offset within the resource. // to the offset within the resource.
var line = 0; var line = 0;
...@@ -492,7 +496,7 @@ Script.prototype.sourceLine = function (opt_line) { ...@@ -492,7 +496,7 @@ Script.prototype.sourceLine = function (opt_line) {
* @return {number} * @return {number}
* Number of source lines. * Number of source lines.
*/ */
Script.prototype.lineCount = function() { function ScriptLineCount() {
// Return number of source lines. // Return number of source lines.
return this.line_ends.length; return this.line_ends.length;
}; };
...@@ -508,9 +512,10 @@ Script.prototype.lineCount = function() { ...@@ -508,9 +512,10 @@ Script.prototype.lineCount = function() {
* @return {?string} script name if present, value for //@ sourceURL comment * @return {?string} script name if present, value for //@ sourceURL comment
* otherwise. * otherwise.
*/ */
Script.prototype.nameOrSourceURL = function() { function ScriptNameOrSourceURL() {
if (this.name) if (this.name) {
return this.name; return this.name;
}
// TODO(608): the spaces in a regexp below had to be escaped as \040 // 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 // because this file is being processed by js2c whose handling of spaces
// in regexps is broken. Also, ['"] are excluded from allowed URLs to // in regexps is broken. Also, ['"] are excluded from allowed URLs to
...@@ -536,6 +541,20 @@ Script.prototype.nameOrSourceURL = function() { ...@@ -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 * Class for source location. A source location is a position within some
* source with the following properties: * source with the following properties:
...@@ -566,8 +585,6 @@ function SourceLocation(script, position, line, column, start, end) { ...@@ -566,8 +585,6 @@ function SourceLocation(script, position, line, column, start, end) {
this.end = end; this.end = end;
} }
SourceLocation.prototype.__proto__ = null;
const kLineLengthLimit = 78; const kLineLengthLimit = 78;
/** /**
...@@ -578,7 +595,7 @@ const kLineLengthLimit = 78; ...@@ -578,7 +595,7 @@ const kLineLengthLimit = 78;
* @param {number} opt_before The number of characters to prefer before the * @param {number} opt_before The number of characters to prefer before the
* position with a default value of 10 less that the limit * 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. // Find the actual limit to use.
var limit; var limit;
var before; var before;
...@@ -625,11 +642,20 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) { ...@@ -625,11 +642,20 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
* @return {String} * @return {String}
* Source text for this location. * Source text for this location.
*/ */
SourceLocation.prototype.sourceText = function () { function SourceLocationSourceText() {
return %_CallFunction(this.script.source, this.start, this.end, StringSubstring); 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 * Class for a source slice. A source slice is a part of a script source with
* the following properties: * the following properties:
...@@ -656,20 +682,23 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) { ...@@ -656,20 +682,23 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) {
this.to_position = to_position; this.to_position = to_position;
} }
SourceSlice.prototype.__proto__ = null;
/** /**
* Get the source text for a SourceSlice * Get the source text for a SourceSlice
* @return {String} Source text for this slice. The last line will include * @return {String} Source text for this slice. The last line will include
* the line terminating characters (if any) * the line terminating characters (if any)
*/ */
SourceSlice.prototype.sourceText = function () { function SourceSliceSourceText() {
return %_CallFunction(this.script.source, return %_CallFunction(this.script.source,
this.from_position, this.from_position,
this.to_position, this.to_position,
StringSubstring); 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 // Returns the offset of the given position within the containing
// line. // line.
...@@ -724,13 +753,11 @@ function CallSite(receiver, fun, pos) { ...@@ -724,13 +753,11 @@ function CallSite(receiver, fun, pos) {
this.pos = pos; this.pos = pos;
} }
CallSite.prototype.__proto__ = null; function CallSiteGetThis() {
CallSite.prototype.getThis = function () {
return this.receiver; return this.receiver;
}; };
CallSite.prototype.getTypeName = function () { function CallSiteGetTypeName() {
var constructor = this.receiver.constructor; var constructor = this.receiver.constructor;
if (!constructor) { if (!constructor) {
return %_CallFunction(this.receiver, ObjectToString); return %_CallFunction(this.receiver, ObjectToString);
...@@ -742,33 +769,33 @@ CallSite.prototype.getTypeName = function () { ...@@ -742,33 +769,33 @@ CallSite.prototype.getTypeName = function () {
return constructorName; return constructorName;
}; };
CallSite.prototype.isToplevel = function () { function CallSiteIsToplevel() {
if (this.receiver == null) { if (this.receiver == null) {
return true; return true;
} }
return IS_GLOBAL(this.receiver); return IS_GLOBAL(this.receiver);
}; };
CallSite.prototype.isEval = function () { function CallSiteIsEval() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script && script.compilation_type == COMPILATION_TYPE_EVAL; return script && script.compilation_type == COMPILATION_TYPE_EVAL;
}; };
CallSite.prototype.getEvalOrigin = function () { function CallSiteGetEvalOrigin() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return FormatEvalOrigin(script); return FormatEvalOrigin(script);
}; };
CallSite.prototype.getScriptNameOrSourceURL = function () { function CallSiteGetScriptNameOrSourceURL() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script ? script.nameOrSourceURL() : null; return script ? script.nameOrSourceURL() : null;
}; };
CallSite.prototype.getFunction = function () { function CallSiteGetFunction() {
return this.fun; return this.fun;
}; };
CallSite.prototype.getFunctionName = function () { function CallSiteGetFunctionName() {
// See if the function knows its own name // See if the function knows its own name
var name = this.fun.name; var name = this.fun.name;
if (name) { if (name) {
...@@ -784,7 +811,7 @@ CallSite.prototype.getFunctionName = function () { ...@@ -784,7 +811,7 @@ CallSite.prototype.getFunctionName = function () {
return null; return null;
}; };
CallSite.prototype.getMethodName = function () { function CallSiteGetMethodName() {
// See if we can find a unique property on the receiver that holds // See if we can find a unique property on the receiver that holds
// this function. // this function.
var ownName = this.fun.name; var ownName = this.fun.name;
...@@ -814,12 +841,12 @@ CallSite.prototype.getMethodName = function () { ...@@ -814,12 +841,12 @@ CallSite.prototype.getMethodName = function () {
return null; return null;
}; };
CallSite.prototype.getFileName = function () { function CallSiteGetFileName() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script ? script.name : null; return script ? script.name : null;
}; };
CallSite.prototype.getLineNumber = function () { function CallSiteGetLineNumber() {
if (this.pos == -1) { if (this.pos == -1) {
return null; return null;
} }
...@@ -831,7 +858,7 @@ CallSite.prototype.getLineNumber = function () { ...@@ -831,7 +858,7 @@ CallSite.prototype.getLineNumber = function () {
return location ? location.line + 1 : null; return location ? location.line + 1 : null;
}; };
CallSite.prototype.getColumnNumber = function () { function CallSiteGetColumnNumber() {
if (this.pos == -1) { if (this.pos == -1) {
return null; return null;
} }
...@@ -843,16 +870,16 @@ CallSite.prototype.getColumnNumber = function () { ...@@ -843,16 +870,16 @@ CallSite.prototype.getColumnNumber = function () {
return location ? location.column + 1: null; return location ? location.column + 1: null;
}; };
CallSite.prototype.isNative = function () { function CallSiteIsNative() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script ? (script.type == TYPE_NATIVE) : false; return script ? (script.type == TYPE_NATIVE) : false;
}; };
CallSite.prototype.getPosition = function () { function CallSiteGetPosition() {
return this.pos; return this.pos;
}; };
CallSite.prototype.isConstructor = function () { function CallSiteIsConstructor() {
var constructor = this.receiver ? this.receiver.constructor : null; var constructor = this.receiver ? this.receiver.constructor : null;
if (!constructor) { if (!constructor) {
return false; return false;
...@@ -860,6 +887,25 @@ CallSite.prototype.isConstructor = function () { ...@@ -860,6 +887,25 @@ CallSite.prototype.isConstructor = function () {
return this.fun === constructor; 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) { function FormatEvalOrigin(script) {
var sourceURL = script.nameOrSourceURL(); var sourceURL = script.nameOrSourceURL();
if (sourceURL) { if (sourceURL) {
...@@ -1001,6 +1047,7 @@ function FormatRawStackTrace(error, raw_stack) { ...@@ -1001,6 +1047,7 @@ function FormatRawStackTrace(error, raw_stack) {
} }
} }
function captureStackTrace(obj, cons_opt) { function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit; var stackTraceLimit = $Error.stackTraceLimit;
if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
...@@ -1016,7 +1063,7 @@ function captureStackTrace(obj, cons_opt) { ...@@ -1016,7 +1063,7 @@ function captureStackTrace(obj, cons_opt) {
}; };
(function () { function SetUpError() {
// Define special error type constructors. // Define special error type constructors.
function DefineError(f) { function DefineError(f) {
...@@ -1085,7 +1132,9 @@ function captureStackTrace(obj, cons_opt) { ...@@ -1085,7 +1132,9 @@ function captureStackTrace(obj, cons_opt) {
DefineError(function ReferenceError() { }); DefineError(function ReferenceError() { });
DefineError(function EvalError() { }); DefineError(function EvalError() { });
DefineError(function URIError() { }); DefineError(function URIError() { });
})(); }
SetUpError();
$Error.captureStackTrace = captureStackTrace; $Error.captureStackTrace = captureStackTrace;
......
...@@ -405,7 +405,8 @@ var lastMatchInfoOverride = null; ...@@ -405,7 +405,8 @@ var lastMatchInfoOverride = null;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupRegExp() { function SetUpRegExp() {
%CheckIsBootstrapping();
%FunctionSetInstanceClassName($RegExp, 'RegExp'); %FunctionSetInstanceClassName($RegExp, 'RegExp');
%FunctionSetPrototype($RegExp, new $Object()); %FunctionSetPrototype($RegExp, new $Object());
%SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM); %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
...@@ -484,5 +485,4 @@ function SetupRegExp() { ...@@ -484,5 +485,4 @@ function SetupRegExp() {
} }
} }
SetUpRegExp();
SetupRegExp();
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "accessors.h" #include "accessors.h"
#include "api.h" #include "api.h"
#include "arguments.h" #include "arguments.h"
#include "bootstrapper.h"
#include "codegen.h" #include "codegen.h"
#include "compilation-cache.h" #include "compilation-cache.h"
#include "compiler.h" #include "compiler.h"
...@@ -2153,6 +2154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { ...@@ -2153,6 +2154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
...@@ -8256,6 +8258,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { ...@@ -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) { RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
......
...@@ -79,6 +79,7 @@ namespace internal { ...@@ -79,6 +79,7 @@ namespace internal {
F(PreventExtensions, 1, 1)\ F(PreventExtensions, 1, 1)\
\ \
/* Utilities */ \ /* Utilities */ \
F(CheckIsBootstrapping, 0, 1) \
F(GetFunctionDelegate, 1, 1) \ F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \ F(GetConstructorDelegate, 1, 1) \
F(NewArgumentsFast, 3, 1) \ F(NewArgumentsFast, 3, 1) \
......
...@@ -911,50 +911,47 @@ function ReplaceResultBuilder(str) { ...@@ -911,50 +911,47 @@ function ReplaceResultBuilder(str) {
this.special_string = str; this.special_string = str;
} }
ReplaceResultBuilder.prototype.__proto__ = null; SetUpLockedPrototype(ReplaceResultBuilder,
$Array("elements", "special_string"), $Array(
"add", function(str) {
ReplaceResultBuilder.prototype.add = function(str) { str = TO_STRING_INLINE(str);
str = TO_STRING_INLINE(str); if (str.length > 0) this.elements.push(str);
if (str.length > 0) this.elements.push(str); },
} "addSpecialSlice", function(start, end) {
var len = end - start;
if (start < 0 || len <= 0) return;
ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { if (start < 0x80000 && len < 0x800) {
var len = end - start; this.elements.push((start << 11) | len);
if (start < 0 || len <= 0) return; } else {
if (start < 0x80000 && len < 0x800) { // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
this.elements.push((start << 11) | len); // so -len is a smi.
} else { var elements = this.elements;
// 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, elements.push(-len);
// so -len is a smi. elements.push(start);
}
},
"generate", function() {
var elements = this.elements; var elements = this.elements;
elements.push(-len); return %StringBuilderConcat(elements, elements.length, this.special_string);
elements.push(start);
} }
} ));
ReplaceResultBuilder.prototype.generate = function() {
var elements = this.elements;
return %StringBuilderConcat(elements, elements.length, this.special_string);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupString() { function SetUpString() {
// Setup the constructor property on the String prototype object. %CheckIsBootstrapping();
// Set up the constructor property on the String prototype object.
%SetProperty($String.prototype, "constructor", $String, DONT_ENUM); %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( InstallFunctions($String, DONT_ENUM, $Array(
"fromCharCode", StringFromCharCode "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( InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
"valueOf", StringValueOf, "valueOf", StringValueOf,
"toString", StringToString, "toString", StringToString,
...@@ -994,5 +991,4 @@ function SetupString() { ...@@ -994,5 +991,4 @@ function SetupString() {
)); ));
} }
SetUpString();
SetupString();
...@@ -392,8 +392,9 @@ function URIUnescape(str) { ...@@ -392,8 +392,9 @@ function URIUnescape(str) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupURI() { function SetUpUri() {
// Setup non-enumerable URI functions on the global object and set %CheckIsBootstrapping();
// Set up non-enumerable URI functions on the global object and set
// their names. // their names.
InstallFunctions(global, DONT_ENUM, $Array( InstallFunctions(global, DONT_ENUM, $Array(
"escape", URIEscape, "escape", URIEscape,
...@@ -405,4 +406,4 @@ function SetupURI() { ...@@ -405,4 +406,4 @@ function SetupURI() {
)); ));
} }
SetupURI(); SetUpUri();
...@@ -75,12 +75,48 @@ function InstallFunctions(object, attributes, functions) { ...@@ -75,12 +75,48 @@ function InstallFunctions(object, attributes, functions) {
// functions on String.prototype etc. and then restore the old function // functions on String.prototype etc. and then restore the old function
// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717 // with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
function InstallFunctionsOnHiddenPrototype(object, attributes, functions) { function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
%CheckIsBootstrapping();
var hidden_prototype = new $Object(); var hidden_prototype = new $Object();
%SetHiddenPrototype(object, hidden_prototype); %SetHiddenPrototype(object, hidden_prototype);
InstallFunctions(hidden_prototype, attributes, functions); 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) { ...@@ -171,8 +207,9 @@ function GlobalEval(x) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Set up global object.
function SetupGlobal() { function SetUpGlobal() {
%CheckIsBootstrapping();
// ECMA 262 - 15.1.1.1. // ECMA 262 - 15.1.1.1.
%SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE); %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
...@@ -182,7 +219,7 @@ function SetupGlobal() { ...@@ -182,7 +219,7 @@ function SetupGlobal() {
// ECMA-262 - 15.1.1.3. // ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE); %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( InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN, "isNaN", GlobalIsNaN,
"isFinite", GlobalIsFinite, "isFinite", GlobalIsFinite,
...@@ -192,8 +229,7 @@ function SetupGlobal() { ...@@ -192,8 +229,7 @@ function SetupGlobal() {
)); ));
} }
SetupGlobal(); SetUpGlobal();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Boolean (first part of definition) // Boolean (first part of definition)
...@@ -490,106 +526,83 @@ function PropertyDescriptor() { ...@@ -490,106 +526,83 @@ function PropertyDescriptor() {
this.hasSetter_ = false; this.hasSetter_ = false;
} }
PropertyDescriptor.prototype.__proto__ = null; SetUpLockedPrototype(PropertyDescriptor, $Array(
"value_",
PropertyDescriptor.prototype.toString = function() { "hasValue_",
return "[object PropertyDescriptor]"; "writable_",
}; "hasWritable_",
"enumerable_",
PropertyDescriptor.prototype.setValue = function(value) { "hasEnumerable_",
this.value_ = value; "configurable_",
this.hasValue_ = true; "hasConfigurable_",
} "get_",
"hasGetter_",
"set_",
PropertyDescriptor.prototype.getValue = function() { "hasSetter_"
return this.value_; ), $Array(
} "toString", function() {
return "[object PropertyDescriptor]";
},
PropertyDescriptor.prototype.hasValue = function() { "setValue", function(value) {
return this.hasValue_; this.value_ = value;
} this.hasValue_ = true;
},
"getValue", function() {
PropertyDescriptor.prototype.setEnumerable = function(enumerable) { return this.value_;
this.enumerable_ = enumerable; },
this.hasEnumerable_ = true; "hasValue", function() {
} return this.hasValue_;
},
"setEnumerable", function(enumerable) {
PropertyDescriptor.prototype.isEnumerable = function () { this.enumerable_ = enumerable;
return this.enumerable_; this.hasEnumerable_ = true;
} },
"isEnumerable", function () {
return this.enumerable_;
PropertyDescriptor.prototype.hasEnumerable = function() { },
return this.hasEnumerable_; "hasEnumerable", function() {
} return this.hasEnumerable_;
},
"setWritable", function(writable) {
PropertyDescriptor.prototype.setWritable = function(writable) { this.writable_ = writable;
this.writable_ = writable; this.hasWritable_ = true;
this.hasWritable_ = true; },
} "isWritable", function() {
return this.writable_;
},
PropertyDescriptor.prototype.isWritable = function() { "hasWritable", function() {
return this.writable_; return this.hasWritable_;
} },
"setConfigurable", function(configurable) {
this.configurable_ = configurable;
PropertyDescriptor.prototype.hasWritable = function() { this.hasConfigurable_ = true;
return this.hasWritable_; },
} "hasConfigurable", function() {
return this.hasConfigurable_;
},
PropertyDescriptor.prototype.setConfigurable = function(configurable) { "isConfigurable", function() {
this.configurable_ = configurable; return this.configurable_;
this.hasConfigurable_ = true; },
} "setGet", function(get) {
this.get_ = get;
this.hasGetter_ = true;
PropertyDescriptor.prototype.hasConfigurable = function() { },
return this.hasConfigurable_; "getGet", function() {
} return this.get_;
},
"hasGetter", function() {
PropertyDescriptor.prototype.isConfigurable = function() { return this.hasGetter_;
return this.configurable_; },
} "setSet", function(set) {
this.set_ = set;
this.hasSetter_ = true;
PropertyDescriptor.prototype.setGet = function(get) { },
this.get_ = get; "getSet", function() {
this.hasGetter_ = true; return this.set_;
} },
"hasSetter", function() {
return this.hasSetter_;
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_;
}
// Converts an array returned from Runtime_GetOwnProperty to an actual // Converts an array returned from Runtime_GetOwnProperty to an actual
...@@ -1177,10 +1190,11 @@ function ObjectIsExtensible(obj) { ...@@ -1177,10 +1190,11 @@ function ObjectIsExtensible(obj) {
%SetExpectedNumberOfProperties($Object, 4); %SetExpectedNumberOfProperties($Object, 4);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Object
function SetUpObject() {
function SetupObject() { %CheckIsBootstrapping();
// Setup non-enumerable functions on the Object.prototype object. // Set Up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array( InstallFunctions($Object.prototype, DONT_ENUM, $Array(
"toString", ObjectToString, "toString", ObjectToString,
"toLocaleString", ObjectToLocaleString, "toLocaleString", ObjectToLocaleString,
...@@ -1210,8 +1224,7 @@ function SetupObject() { ...@@ -1210,8 +1224,7 @@ function SetupObject() {
)); ));
} }
SetupObject(); SetUpObject();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Boolean // Boolean
...@@ -1242,14 +1255,16 @@ function BooleanValueOf() { ...@@ -1242,14 +1255,16 @@ function BooleanValueOf() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function SetupBoolean() { function SetUpBoolean () {
%CheckIsBootstrapping();
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString, "toString", BooleanToString,
"valueOf", BooleanValueOf "valueOf", BooleanValueOf
)); ));
} }
SetupBoolean(); SetUpBoolean();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Number // Number
...@@ -1363,9 +1378,10 @@ function NumberToPrecision(precision) { ...@@ -1363,9 +1378,10 @@ function NumberToPrecision(precision) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function SetupNumber() { function SetUpNumber() {
%CheckIsBootstrapping();
%OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); %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); %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
%OptimizeObjectForAddingMultipleProperties($Number, 5); %OptimizeObjectForAddingMultipleProperties($Number, 5);
...@@ -1394,7 +1410,7 @@ function SetupNumber() { ...@@ -1394,7 +1410,7 @@ function SetupNumber() {
DONT_ENUM | DONT_DELETE | READ_ONLY); DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Number); %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( InstallFunctions($Number.prototype, DONT_ENUM, $Array(
"toString", NumberToString, "toString", NumberToString,
"toLocaleString", NumberToLocaleString, "toLocaleString", NumberToLocaleString,
...@@ -1405,7 +1421,7 @@ function SetupNumber() { ...@@ -1405,7 +1421,7 @@ function SetupNumber() {
)); ));
} }
SetupNumber(); SetUpNumber();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -1534,11 +1550,12 @@ function NewFunction(arg1) { // length == 1 ...@@ -1534,11 +1550,12 @@ function NewFunction(arg1) { // length == 1
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function SetupFunction() { function SetUpFunction() {
%CheckIsBootstrapping();
InstallFunctions($Function.prototype, DONT_ENUM, $Array( InstallFunctions($Function.prototype, DONT_ENUM, $Array(
"bind", FunctionBind, "bind", FunctionBind,
"toString", FunctionToString "toString", FunctionToString
)); ));
} }
SetupFunction(); SetUpFunction();
...@@ -80,7 +80,8 @@ function WeakMapDelete(key) { ...@@ -80,7 +80,8 @@ function WeakMapDelete(key) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupWeakMap() { (function () {
%CheckIsBootstrapping();
// Set up the WeakMap constructor function. // Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor); %SetCode($WeakMap, WeakMapConstructor);
...@@ -97,7 +98,4 @@ function SetupWeakMap() { ...@@ -97,7 +98,4 @@ function SetupWeakMap() {
"has", WeakMapHas, "has", WeakMapHas,
"delete", WeakMapDelete "delete", WeakMapDelete
)); ));
} })();
SetupWeakMap();
// 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);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment