Commit c094da92 authored by rossberg's avatar rossberg Committed by Commit bot

[strong] Make functions and generators non-extensible non-constructors

R=dslomov@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#26854}
parent 238ad54d
......@@ -6235,7 +6235,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 = 74;
static const int kContextEmbedderDataIndex = 76;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
......
......@@ -140,6 +140,7 @@ class Genesis BASE_EMBEDDED {
Handle<JSFunction> GetGeneratorPoisonFunction();
void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
void CreateStrongModeFunctionMaps(Handle<JSFunction> empty);
// Make the "arguments" and "caller" properties throw a TypeError on access.
void PoisonArgumentsAndCaller(Handle<Map> map);
......@@ -256,18 +257,21 @@ class Genesis BASE_EMBEDDED {
function_mode == FUNCTION_WITH_READONLY_PROTOTYPE);
}
Handle<Map> CreateFunctionMap(FunctionMode function_mode);
Handle<Map> CreateSloppyFunctionMap(FunctionMode function_mode);
void SetFunctionInstanceDescriptor(Handle<Map> map,
FunctionMode function_mode);
void MakeFunctionInstancePrototypeWritable();
Handle<Map> CreateStrictFunctionMap(
FunctionMode function_mode,
Handle<JSFunction> empty_function);
Handle<Map> CreateStrictFunctionMap(FunctionMode function_mode,
Handle<JSFunction> empty_function);
Handle<Map> CreateStrongFunctionMap(Handle<JSFunction> empty_function,
bool is_constructor);
void SetStrictFunctionInstanceDescriptor(Handle<Map> map,
FunctionMode function_mode);
void SetStrongFunctionInstanceDescriptor(Handle<Map> map);
static bool CompileBuiltin(Isolate* isolate, int index);
static bool CompileExperimentalBuiltin(Isolate* isolate, int index);
......@@ -422,7 +426,7 @@ void Genesis::SetFunctionInstanceDescriptor(
}
Handle<Map> Genesis::CreateFunctionMap(FunctionMode function_mode) {
Handle<Map> Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetFunctionInstanceDescriptor(map, function_mode);
map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
......@@ -437,7 +441,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// Functions with this map will not have a 'prototype' property, and
// can not be used as constructors.
Handle<Map> function_without_prototype_map =
CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
native_context()->set_sloppy_function_without_prototype_map(
*function_without_prototype_map);
......@@ -445,7 +449,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// of builtins.
// Later the map is replaced with writable prototype map, allocated below.
Handle<Map> function_map =
CreateFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE);
CreateSloppyFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE);
native_context()->set_sloppy_function_map(*function_map);
native_context()->set_sloppy_function_with_readonly_prototype_map(
*function_map);
......@@ -453,7 +457,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// The final map for functions. Writeable prototype.
// This map is installed in MakeFunctionInstancePrototypeWritable.
sloppy_function_map_writable_prototype_ =
CreateFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE);
CreateSloppyFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE);
Factory* factory = isolate->factory();
......@@ -501,7 +505,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
// Allocate the function map first and then patch the prototype later
Handle<Map> empty_function_map =
CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
DCHECK(!empty_function_map->is_dictionary_map());
empty_function_map->SetPrototype(object_function_prototype);
empty_function_map->set_is_prototype_map(true);
......@@ -583,6 +587,29 @@ void Genesis::SetStrictFunctionInstanceDescriptor(
}
void Genesis::SetStrongFunctionInstanceDescriptor(Handle<Map> map) {
Map::EnsureDescriptorSlack(map, 2);
PropertyAttributes ro_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
Handle<AccessorInfo> length =
Accessors::FunctionLengthInfo(isolate(), ro_attribs);
{ // Add length.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
length, ro_attribs);
map->AppendDescriptor(&d);
}
Handle<AccessorInfo> name =
Accessors::FunctionNameInfo(isolate(), ro_attribs);
{ // Add name.
AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
ro_attribs);
map->AppendDescriptor(&d);
}
}
// ECMAScript 5th Edition, 13.2.3
Handle<JSFunction> Genesis::GetStrictPoisonFunction() {
if (strict_poison_function.is_null()) {
......@@ -628,6 +655,18 @@ Handle<Map> Genesis::CreateStrictFunctionMap(
}
Handle<Map> Genesis::CreateStrongFunctionMap(
Handle<JSFunction> empty_function, bool is_constructor) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetStrongFunctionInstanceDescriptor(map);
map->set_function_with_prototype(is_constructor);
map->SetPrototype(empty_function);
map->set_is_extensible(is_constructor);
// TODO(rossberg): mark strong
return map;
}
void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
// Allocate map for the prototype-less strict mode instances.
Handle<Map> strict_function_without_prototype_map =
......@@ -659,6 +698,16 @@ void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
}
void Genesis::CreateStrongModeFunctionMaps(Handle<JSFunction> empty) {
// Allocate map for strong mode instances, which never have prototypes.
Handle<Map> strong_function_map = CreateStrongFunctionMap(empty, false);
native_context()->set_strong_function_map(*strong_function_map);
// Constructors do, though.
Handle<Map> strong_constructor_map = CreateStrongFunctionMap(empty, true);
native_context()->set_strong_constructor_map(*strong_constructor_map);
}
static void SetAccessors(Handle<Map> map,
Handle<String> name,
Handle<JSFunction> func) {
......@@ -2023,6 +2072,13 @@ bool Genesis::InstallNatives() {
native_context()->set_strict_generator_function_map(
*strict_generator_function_map);
Handle<Map> strong_function_map(native_context()->strong_function_map());
Handle<Map> strong_generator_function_map =
Map::Copy(strong_function_map, "StrongGeneratorFunction");
strong_generator_function_map->SetPrototype(generator_function_prototype);
native_context()->set_strong_generator_function_map(
*strong_generator_function_map);
Handle<JSFunction> object_function(native_context()->object_function());
Handle<Map> generator_object_prototype_map = Map::Create(isolate(), 0);
generator_object_prototype_map->SetPrototype(generator_object_prototype);
......@@ -2811,6 +2867,7 @@ Genesis::Genesis(Isolate* isolate,
CreateRoots();
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
CreateStrictModeFunctionMaps(empty_function);
CreateStrongModeFunctionMaps(empty_function);
Handle<GlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
HookUpGlobalProxy(global_object, global_proxy);
......
......@@ -125,10 +125,12 @@ enum BindingFlags {
V(SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \
sloppy_function_with_readonly_prototype_map) \
V(STRICT_FUNCTION_MAP_INDEX, Map, strict_function_map) \
V(STRONG_FUNCTION_MAP_INDEX, Map, strong_function_map) \
V(SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
sloppy_function_without_prototype_map) \
V(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
strict_function_without_prototype_map) \
V(STRONG_CONSTRUCTOR_MAP_INDEX, Map, strong_constructor_map) \
V(BOUND_FUNCTION_MAP_INDEX, Map, bound_function_map) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
V(SLOPPY_ARGUMENTS_MAP_INDEX, Map, sloppy_arguments_map) \
......@@ -176,6 +178,7 @@ enum BindingFlags {
native_object_notifier_perform_change) \
V(SLOPPY_GENERATOR_FUNCTION_MAP_INDEX, Map, sloppy_generator_function_map) \
V(STRICT_GENERATOR_FUNCTION_MAP_INDEX, Map, strict_generator_function_map) \
V(STRONG_GENERATOR_FUNCTION_MAP_INDEX, Map, strong_generator_function_map) \
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, generator_object_prototype_map) \
V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map) \
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
......@@ -319,8 +322,10 @@ class Context: public FixedArray {
SLOPPY_FUNCTION_MAP_INDEX,
SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX,
STRICT_FUNCTION_MAP_INDEX,
STRONG_FUNCTION_MAP_INDEX,
SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
STRONG_CONSTRUCTOR_MAP_INDEX,
BOUND_FUNCTION_MAP_INDEX,
INITIAL_OBJECT_PROTOTYPE_INDEX,
INITIAL_ARRAY_PROTOTYPE_INDEX,
......@@ -406,6 +411,7 @@ class Context: public FixedArray {
NATIVE_OBJECT_NOTIFIER_PERFORM_CHANGE,
SLOPPY_GENERATOR_FUNCTION_MAP_INDEX,
STRICT_GENERATOR_FUNCTION_MAP_INDEX,
STRONG_GENERATOR_FUNCTION_MAP_INDEX,
GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
ITERATOR_RESULT_MAP_INDEX,
MAP_ITERATOR_MAP_INDEX,
......@@ -570,18 +576,27 @@ class Context: public FixedArray {
static int FunctionMapIndex(LanguageMode language_mode, FunctionKind kind) {
if (IsGeneratorFunction(kind)) {
return is_strict(language_mode) ? STRICT_GENERATOR_FUNCTION_MAP_INDEX
return is_strong(language_mode) ? STRONG_GENERATOR_FUNCTION_MAP_INDEX :
is_strict(language_mode) ? STRICT_GENERATOR_FUNCTION_MAP_INDEX
: SLOPPY_GENERATOR_FUNCTION_MAP_INDEX;
}
if (IsConstructor(kind)) {
return is_strong(language_mode) ? STRONG_CONSTRUCTOR_MAP_INDEX :
is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
: SLOPPY_FUNCTION_MAP_INDEX;
}
if (IsArrowFunction(kind) || IsConciseMethod(kind) ||
IsAccessorFunction(kind)) {
return is_strict(language_mode)
? STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX
: SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX;
return is_strong(language_mode) ? STRONG_FUNCTION_MAP_INDEX :
is_strict(language_mode) ?
STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX :
SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX;
}
return is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
return is_strong(language_mode) ? STRONG_FUNCTION_MAP_INDEX :
is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX
: SLOPPY_FUNCTION_MAP_INDEX;
}
......
......@@ -6,28 +6,82 @@
'use strong';
function f() {}
function* g() {}
(function NoArguments() {
assertThrows("'use strong'; arguments", SyntaxError);
assertThrows("'use strong'; function f() { arguments }", SyntaxError);
assertThrows("'use strong'; function* g() { arguments }", SyntaxError);
assertThrows("'use strong'; let f = function() { arguments }", SyntaxError);
assertThrows("'use strong'; let g = function*() { arguments }", SyntaxError);
assertThrows("'use strong'; let f = () => arguments", SyntaxError);
// The following are strict mode errors already.
assertThrows("'use strong'; let arguments", SyntaxError);
assertThrows("'use strong'; function f(arguments) {}", SyntaxError);
assertThrows("'use strong'; function* g(arguments) {}", SyntaxError);
assertThrows("'use strong'; let f = (arguments) => {}", SyntaxError);
})();
function g() {}
(function NoArgumentsProperty() {
assertFalse(f.hasOwnProperty("arguments"));
assertFalse(g.hasOwnProperty("arguments"));
assertThrows(function(){ f.arguments = 0 }, TypeError);
assertThrows(function(){ g.arguments = 0 }, TypeError);
})();
(function NoCaller() {
assertFalse(f.hasOwnProperty("caller"));
assertFalse(g.hasOwnProperty("caller"));
assertThrows(function(){ f.caller = 0 }, TypeError);
assertThrows(function(){ g.caller = 0 }, TypeError);
})();
(function NoCallee() {
assertFalse("callee" in f);
assertFalse("callee" in g);
assertThrows(function(){ f.callee = 0 }, TypeError);
assertThrows(function(){ g.callee = 0 }, TypeError);
})();
(function LexicalFunctionBindings(global) {
(function LexicalBindings(global) {
assertEquals('function', typeof f);
assertEquals('function', typeof g);
assertEquals(undefined, global.f);
assertEquals(undefined, global.g);
})(this);
(function ImmutableFunctionBindings() {
function f() {}
assertThrows(function(){ eval("g = 0") }, TypeError);
assertThrows(function(){ eval("f = 0") }, TypeError);
assertEquals('function', typeof g);
(function ImmutableBindings() {
function f2() {}
function* g2() {}
assertThrows(function(){ f = 0 }, TypeError);
assertThrows(function(){ g = 0 }, TypeError);
assertThrows(function(){ f2 = 0 }, TypeError);
assertThrows(function(){ g2 = 0 }, TypeError);
assertEquals('function', typeof f);
assertEquals('function', typeof g);
assertEquals('function', typeof f2);
assertEquals('function', typeof g2);
})();
(function NonExtensible() {
assertThrows(function(){ f.a = 0 }, TypeError);
assertThrows(function(){ g.a = 0 }, TypeError);
assertThrows(function(){ Object.defineProperty(f, "a", {value: 0}) }, TypeError);
assertThrows(function(){ Object.defineProperty(g, "a", {value: 0}) }, TypeError);
assertThrows(function(){ Object.setPrototypeOf(f, {}) }, TypeError);
assertThrows(function(){ Object.setPrototypeOf(g, {}) }, TypeError);
})();
(function NoPrototype() {
assertFalse("prototype" in f);
assertFalse(g.hasOwnProperty("prototype"));
assertThrows(function(){ f.prototype = 0 }, TypeError);
assertThrows(function(){ g.prototype = 0 }, TypeError);
assertThrows(function(){ f.prototype.a = 0 }, TypeError);
})();
(function NonConstructor() {
assertThrows(function(){ new f }, TypeError);
assertThrows(function(){ new g }, TypeError);
})();
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