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:
parent
0a224352ad
commit
3f09e0a3d8
@ -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;
|
||||
|
@ -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_);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user