Remove separate maps for function instances

ES3 specified that functions created via Function() would have
enumerable prototypes, unlike function literals.  For this reason, V8
has always had two prototypes for functions: "function_map" for
literals, and "function_instance_map" for "function instances": those
functions created by Function().

However, since 2009 or so, both maps have been the same!  Both have had
writable, non-enumerable prototypes.  Moreover, ES5 changed to specify
that function instances would have non-enumerable prototypes.

This patch removes the separate maps for function instances in sloppy
and strict mode.

R=mstarzinger@chromium.org
TEST=mjsunit/function-prototype
BUG=

Review URL: https://codereview.chromium.org/14829005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14619 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
wingo@igalia.com 2013-05-10 12:59:20 +00:00
parent 0a224352ad
commit 3f09e0a3d8
7 changed files with 37 additions and 63 deletions

View File

@ -5025,7 +5025,7 @@ class Internals {
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
static const int kContextHeaderSize = 2 * kApiPointerSize;
static const int kContextEmbedderDataIndex = 65;
static const int kContextEmbedderDataIndex = 63;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;

View File

@ -281,12 +281,12 @@ class Genesis BASE_EMBEDDED {
Handle<Context> result_;
Handle<Context> native_context_;
// Function instance maps. Function literal maps are created initially with
// a read only prototype for the processing of JS builtins. Later the function
// instance maps are replaced in order to make prototype writable.
// These are the final, writable prototype, maps.
Handle<Map> function_instance_map_writable_prototype_;
Handle<Map> strict_mode_function_instance_map_writable_prototype_;
// Function maps. Function maps are created initially with a read only
// prototype for the processing of JS builtins. Later the function maps are
// replaced in order to make prototype writable. These are the final, writable
// prototype, maps.
Handle<Map> function_map_writable_prototype_;
Handle<Map> strict_mode_function_map_writable_prototype_;
Handle<JSFunction> throw_type_error_function;
BootstrapperActive active_;
@ -437,12 +437,6 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// Allocate the map for function instances. Maps are allocated first and their
// prototypes patched later, once empty function is created.
// Please note that the prototype property for function instances must be
// writable.
Handle<Map> function_instance_map =
CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
native_context()->set_function_instance_map(*function_instance_map);
// Functions with this map will not have a 'prototype' property, and
// can not be used as constructors.
Handle<Map> function_without_prototype_map =
@ -458,8 +452,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// The final map for functions. Writeable prototype.
// This map is installed in MakeFunctionInstancePrototypeWritable.
function_instance_map_writable_prototype_ =
CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
function_map_writable_prototype_ = CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
Factory* factory = isolate->factory();
Heap* heap = isolate->heap();
@ -509,10 +502,9 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// Set prototypes for the function maps.
native_context()->function_map()->set_prototype(*empty_function);
native_context()->function_instance_map()->set_prototype(*empty_function);
native_context()->function_without_prototype_map()->
set_prototype(*empty_function);
function_instance_map_writable_prototype_->set_prototype(*empty_function);
function_map_writable_prototype_->set_prototype(*empty_function);
// Allocate the function map first and then patch the prototype later
Handle<Map> empty_function_map = CreateFunctionMap(DONT_ADD_PROTOTYPE);
@ -601,12 +593,6 @@ Handle<Map> Genesis::CreateStrictModeFunctionMap(
void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
// Allocate map for the strict mode function instances.
Handle<Map> strict_mode_function_instance_map =
CreateStrictModeFunctionMap(ADD_WRITEABLE_PROTOTYPE, empty);
native_context()->set_strict_mode_function_instance_map(
*strict_mode_function_instance_map);
// Allocate map for the prototype-less strict mode instances.
Handle<Map> strict_mode_function_without_prototype_map =
CreateStrictModeFunctionMap(DONT_ADD_PROTOTYPE, empty);
@ -623,15 +609,13 @@ void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
// The final map for the strict mode functions. Writeable prototype.
// This map is installed in MakeFunctionInstancePrototypeWritable.
strict_mode_function_instance_map_writable_prototype_ =
strict_mode_function_map_writable_prototype_ =
CreateStrictModeFunctionMap(ADD_WRITEABLE_PROTOTYPE, empty);
// Complete the callbacks.
PoisonArgumentsAndCaller(strict_mode_function_instance_map);
PoisonArgumentsAndCaller(strict_mode_function_without_prototype_map);
PoisonArgumentsAndCaller(strict_mode_function_map);
PoisonArgumentsAndCaller(
strict_mode_function_instance_map_writable_prototype_);
PoisonArgumentsAndCaller(strict_mode_function_map_writable_prototype_);
}
@ -2522,14 +2506,13 @@ void Genesis::MakeFunctionInstancePrototypeWritable() {
// The maps with writable prototype are created in CreateEmptyFunction
// and CreateStrictModeFunctionMaps respectively. Initially the maps are
// created with read-only prototype for JS builtins processing.
ASSERT(!function_instance_map_writable_prototype_.is_null());
ASSERT(!strict_mode_function_instance_map_writable_prototype_.is_null());
ASSERT(!function_map_writable_prototype_.is_null());
ASSERT(!strict_mode_function_map_writable_prototype_.is_null());
// Replace function instance maps to make prototype writable.
native_context()->set_function_map(
*function_instance_map_writable_prototype_);
native_context()->set_function_map(*function_map_writable_prototype_);
native_context()->set_strict_mode_function_map(
*strict_mode_function_instance_map_writable_prototype_);
*strict_mode_function_map_writable_prototype_);
}

View File

@ -138,9 +138,6 @@ enum BindingFlags {
V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
V(STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
strict_mode_function_without_prototype_map) \
V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
V(STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX, Map, \
strict_mode_function_instance_map) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)\
V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
V(ALIASED_ARGUMENTS_BOILERPLATE_INDEX, JSObject, \
@ -260,8 +257,6 @@ class Context: public FixedArray {
STRICT_MODE_FUNCTION_MAP_INDEX,
FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
FUNCTION_INSTANCE_MAP_INDEX,
STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX,
INITIAL_OBJECT_PROTOTYPE_INDEX,
BOOLEAN_FUNCTION_INDEX,
NUMBER_FUNCTION_INDEX,

View File

@ -9216,26 +9216,6 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
// This utility adjusts the property attributes for newly created Function
// object ("new Function(...)") by changing the map.
// All it does is changing the prototype property to enumerable
// as specified in ECMA262, 15.3.5.2.
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
Handle<Map> map = func->shared()->is_classic_mode()
? isolate->function_instance_map()
: isolate->strict_mode_function_instance_map();
ASSERT(func->map()->instance_type() == map->instance_type());
ASSERT(func->map()->instance_size() == map->instance_size());
func->set_map(*map);
return *func;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
// Allocate a block of memory in NewSpace (filled with a filler).
// Use as fallback for allocation in generated code when NewSpace

View File

@ -100,7 +100,6 @@ namespace internal {
F(GetOptimizationStatus, 1, 1) \
F(GetOptimizationCount, 1, 1) \
F(CompileForOnStackReplacement, 1, 1) \
F(SetNewFunctionAttributes, 1, 1) \
F(AllocateInNewSpace, 1, 1) \
F(AllocateInOldPointerSpace, 1, 1) \
F(SetNativeFlag, 1, 1) \

View File

@ -1775,13 +1775,11 @@ function NewFunction(arg1) { // length == 1
var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
var source = '(function(' + p + ') {\n' + body + '\n})';
// The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
var global_receiver = %GlobalReceiver(global);
var f = %_CallFunction(global_receiver, %CompileString(source, true));
%FunctionMarkNameShouldPrintAsAnonymous(f);
return %SetNewFunctionAttributes(f);
return f;
}

View File

@ -90,9 +90,28 @@ assertEquals(F.prototype, GetPrototypeOf(F));
// in GetPrototypeOf and go to a monomorphic IC load instead.
assertEquals(87, GetPrototypeOf({prototype:87}));
// Check the prototype is not enumerable, for compatibility with
// safari. This is deliberately incompatible with ECMA262, 15.3.5.2.
// Check the prototype is not enumerable, as per ES5 section 15.3.5.2. Note
// that this is in difference to ES3, which specified that function instances
// would have enumerable prototypes (section 15.3.5.2 also).
var foo = new Function("return x");
var result = ""
for (var n in foo) result += n;
assertEquals(result, "");
f = new Function('return 1;')
var desc = Object.getOwnPropertyDescriptor(f, "prototype");
assertFalse(desc.configurable);
assertFalse(desc.enumerable);
assertTrue(desc.writable);
f = Function('return 1;')
var desc = Object.getOwnPropertyDescriptor(f, "prototype");
assertFalse(desc.configurable);
assertFalse(desc.enumerable);
assertTrue(desc.writable);
f = function () { return 1; }
var desc = Object.getOwnPropertyDescriptor(f, "prototype");
assertFalse(desc.configurable);
assertFalse(desc.enumerable);
assertTrue(desc.writable);