Commit 5dd17993 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

Reland "[runtime] Make all built-in functions strict."

This is a reland of 72b88fda
Original change's description:
> [runtime] Make all built-in functions strict.
> 
> According to ES#sec-built-in-function-objects all built-in functions
> must be strict.
> 
> This is a preliminary CL before changing the way we define built-in
> functions in native JS files.
> 
> Bug: v8:6529, v8:6459
> Change-Id: I8e60b342f04ea1b0843fe1990334cbb9b26ebac4
> Reviewed-on: https://chromium-review.googlesource.com/546215
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Reviewed-by: Adam Klein <adamk@chromium.org>
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#46237}

Bug: v8:6529, v8:6459
Change-Id: Ic0eb3d7925ed63dd716c4a114601415f92627ca5
Reviewed-on: https://chromium-review.googlesource.com/550156Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46262}
parent 2ac6dae6
...@@ -242,9 +242,6 @@ class Genesis BASE_EMBEDDED { ...@@ -242,9 +242,6 @@ class Genesis BASE_EMBEDDED {
void MakeFunctionInstancePrototypeWritable(); void MakeFunctionInstancePrototypeWritable();
void SetStrictFunctionInstanceDescriptor(Handle<Map> map,
FunctionMode function_mode);
static bool CallUtilsFunction(Isolate* isolate, const char* name); static bool CallUtilsFunction(Isolate* isolate, const char* name);
static bool CompileExtension(Isolate* isolate, v8::Extension* extension); static bool CompileExtension(Isolate* isolate, v8::Extension* extension);
...@@ -336,17 +333,15 @@ void InstallFunction(Handle<JSObject> target, Handle<JSFunction> function, ...@@ -336,17 +333,15 @@ void InstallFunction(Handle<JSObject> target, Handle<JSFunction> function,
Handle<JSFunction> CreateFunction(Isolate* isolate, Handle<String> name, Handle<JSFunction> CreateFunction(Isolate* isolate, Handle<String> name,
InstanceType type, int instance_size, InstanceType type, int instance_size,
MaybeHandle<JSObject> maybe_prototype, MaybeHandle<JSObject> maybe_prototype,
Builtins::Name call, Builtins::Name call) {
bool strict_function_map = false) {
Factory* factory = isolate->factory(); Factory* factory = isolate->factory();
Handle<Code> call_code(isolate->builtins()->builtin(call)); Handle<Code> call_code(isolate->builtins()->builtin(call));
Handle<JSObject> prototype; Handle<JSObject> prototype;
Handle<JSFunction> result = Handle<JSFunction> result =
maybe_prototype.ToHandle(&prototype) maybe_prototype.ToHandle(&prototype)
? factory->NewFunction(name, call_code, prototype, type, ? factory->NewFunction(name, call_code, prototype, type,
instance_size, strict_function_map) instance_size, true)
: factory->NewFunctionWithoutPrototype(name, call_code, : factory->NewFunctionWithoutPrototype(name, call_code, true);
strict_function_map);
result->shared()->set_native(true); result->shared()->set_native(true);
return result; return result;
} }
...@@ -355,12 +350,11 @@ Handle<JSFunction> InstallFunction(Handle<JSObject> target, Handle<Name> name, ...@@ -355,12 +350,11 @@ Handle<JSFunction> InstallFunction(Handle<JSObject> target, Handle<Name> name,
InstanceType type, int instance_size, InstanceType type, int instance_size,
MaybeHandle<JSObject> maybe_prototype, MaybeHandle<JSObject> maybe_prototype,
Builtins::Name call, Builtins::Name call,
PropertyAttributes attributes, PropertyAttributes attributes) {
bool strict_function_map = false) {
Handle<String> name_string = Name::ToFunctionName(name).ToHandleChecked(); Handle<String> name_string = Name::ToFunctionName(name).ToHandleChecked();
Handle<JSFunction> function = Handle<JSFunction> function =
CreateFunction(target->GetIsolate(), name_string, type, instance_size, CreateFunction(target->GetIsolate(), name_string, type, instance_size,
maybe_prototype, call, strict_function_map); maybe_prototype, call);
InstallFunction(target, name, function, name_string, attributes); InstallFunction(target, name, function, name_string, attributes);
return function; return function;
} }
...@@ -368,13 +362,11 @@ Handle<JSFunction> InstallFunction(Handle<JSObject> target, Handle<Name> name, ...@@ -368,13 +362,11 @@ Handle<JSFunction> InstallFunction(Handle<JSObject> target, Handle<Name> name,
Handle<JSFunction> InstallFunction(Handle<JSObject> target, const char* name, Handle<JSFunction> InstallFunction(Handle<JSObject> target, const char* name,
InstanceType type, int instance_size, InstanceType type, int instance_size,
MaybeHandle<JSObject> maybe_prototype, MaybeHandle<JSObject> maybe_prototype,
Builtins::Name call, Builtins::Name call) {
bool strict_function_map = false) {
Factory* const factory = target->GetIsolate()->factory(); Factory* const factory = target->GetIsolate()->factory();
PropertyAttributes attributes = DONT_ENUM; PropertyAttributes attributes = DONT_ENUM;
return InstallFunction(target, factory->InternalizeUtf8String(name), type, return InstallFunction(target, factory->InternalizeUtf8String(name), type,
instance_size, maybe_prototype, call, attributes, instance_size, maybe_prototype, call, attributes);
strict_function_map);
} }
Handle<JSFunction> SimpleCreateFunction(Isolate* isolate, Handle<String> name, Handle<JSFunction> SimpleCreateFunction(Isolate* isolate, Handle<String> name,
...@@ -392,24 +384,6 @@ Handle<JSFunction> SimpleCreateFunction(Isolate* isolate, Handle<String> name, ...@@ -392,24 +384,6 @@ Handle<JSFunction> SimpleCreateFunction(Isolate* isolate, Handle<String> name,
return fun; return fun;
} }
Handle<JSFunction> InstallArrayBuiltinFunction(Handle<JSObject> base,
const char* name,
Builtins::Name call) {
Isolate* isolate = base->GetIsolate();
Handle<String> str_name = isolate->factory()->InternalizeUtf8String(name);
Handle<JSFunction> fun =
CreateFunction(isolate, str_name, JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), call, true);
fun->shared()->set_internal_formal_parameter_count(
Builtins::GetBuiltinParameterCount(call));
// Set the length to 1 to satisfy ECMA-262.
fun->shared()->set_length(1);
fun->shared()->set_language_mode(STRICT);
InstallFunction(base, fun, str_name);
return fun;
}
Handle<JSFunction> SimpleInstallFunction(Handle<JSObject> base, Handle<JSFunction> SimpleInstallFunction(Handle<JSObject> base,
Handle<String> name, Handle<String> name,
Builtins::Name call, int len, Builtins::Name call, int len,
...@@ -1487,8 +1461,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1487,8 +1461,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
native_context()->set_initial_array_prototype(*array_prototype); native_context()->set_initial_array_prototype(*array_prototype);
Handle<JSFunction> is_arraylike = SimpleInstallFunction( Handle<JSFunction> is_arraylike = SimpleInstallFunction(
array_function, isolate->factory()->InternalizeUtf8String("isArray"), array_function, "isArray", Builtins::kArrayIsArray, 1, true);
Builtins::kArrayIsArray, 1, true);
native_context()->set_is_arraylike(*is_arraylike); native_context()->set_is_arraylike(*is_arraylike);
} }
...@@ -3607,11 +3580,9 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate, ...@@ -3607,11 +3580,9 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
container, factory->InternalizeUtf8String("GeneratorFunctionPrototype"), container, factory->InternalizeUtf8String("GeneratorFunctionPrototype"),
generator_function_prototype, NONE); generator_function_prototype, NONE);
static const bool kUseStrictFunctionMap = true;
Handle<JSFunction> generator_function_function = InstallFunction( Handle<JSFunction> generator_function_function = InstallFunction(
container, "GeneratorFunction", JS_FUNCTION_TYPE, JSFunction::kSize, container, "GeneratorFunction", JS_FUNCTION_TYPE, JSFunction::kSize,
generator_function_prototype, Builtins::kGeneratorFunctionConstructor, generator_function_prototype, Builtins::kGeneratorFunctionConstructor);
kUseStrictFunctionMap);
generator_function_function->set_prototype_or_initial_map( generator_function_function->set_prototype_or_initial_map(
native_context->generator_function_map()); native_context->generator_function_map());
generator_function_function->shared()->DontAdaptArguments(); generator_function_function->shared()->DontAdaptArguments();
...@@ -3638,11 +3609,10 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate, ...@@ -3638,11 +3609,10 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
Handle<JSObject> async_generator_function_prototype( Handle<JSObject> async_generator_function_prototype(
iter.GetCurrent<JSObject>()); iter.GetCurrent<JSObject>());
static const bool kUseStrictFunctionMap = true; Handle<JSFunction> async_generator_function_function =
Handle<JSFunction> async_generator_function_function = InstallFunction( InstallFunction(container, "AsyncGeneratorFunction", JS_FUNCTION_TYPE,
container, "AsyncGeneratorFunction", JS_FUNCTION_TYPE, JSFunction::kSize, async_generator_function_prototype,
JSFunction::kSize, async_generator_function_prototype, Builtins::kAsyncGeneratorFunctionConstructor);
Builtins::kAsyncGeneratorFunctionConstructor, kUseStrictFunctionMap);
async_generator_function_function->set_prototype_or_initial_map( async_generator_function_function->set_prototype_or_initial_map(
native_context->async_generator_function_map()); native_context->async_generator_function_map());
async_generator_function_function->shared()->DontAdaptArguments(); async_generator_function_function->shared()->DontAdaptArguments();
...@@ -3820,11 +3790,9 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate, ...@@ -3820,11 +3790,9 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
PrototypeIterator iter(native_context->async_function_map()); PrototypeIterator iter(native_context->async_function_map());
Handle<JSObject> async_function_prototype(iter.GetCurrent<JSObject>()); Handle<JSObject> async_function_prototype(iter.GetCurrent<JSObject>());
static const bool kUseStrictFunctionMap = true;
Handle<JSFunction> async_function_constructor = InstallFunction( Handle<JSFunction> async_function_constructor = InstallFunction(
container, "AsyncFunction", JS_FUNCTION_TYPE, JSFunction::kSize, container, "AsyncFunction", JS_FUNCTION_TYPE, JSFunction::kSize,
async_function_prototype, Builtins::kAsyncFunctionConstructor, async_function_prototype, Builtins::kAsyncFunctionConstructor);
kUseStrictFunctionMap);
async_function_constructor->set_prototype_or_initial_map( async_function_constructor->set_prototype_or_initial_map(
native_context->async_function_map()); native_context->async_function_map());
async_function_constructor->shared()->DontAdaptArguments(); async_function_constructor->shared()->DontAdaptArguments();
...@@ -4408,43 +4376,17 @@ bool Genesis::InstallNatives(GlobalContextType context_type) { ...@@ -4408,43 +4376,17 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
// on Array.prototype and below. // on Array.prototype and below.
proto->set_elements(heap()->empty_fixed_array()); proto->set_elements(heap()->empty_fixed_array());
// Install Array.prototype.concat SimpleInstallFunction(proto, "concat", Builtins::kArrayConcat, 1, false);
Handle<JSFunction> concat = Handle<JSFunction> for_each = SimpleInstallFunction(
InstallFunction(proto, "concat", JS_OBJECT_TYPE, JSObject::kHeaderSize, proto, "forEach", Builtins::kArrayForEach, 1, false);
MaybeHandle<JSObject>(), Builtins::kArrayConcat); native_context()->set_array_for_each_iterator(*for_each);
SimpleInstallFunction(proto, "filter", Builtins::kArrayFilter, 1, false);
// Make sure that Array.prototype.concat appears to be compiled. SimpleInstallFunction(proto, "map", Builtins::kArrayMap, 1, false);
// The code will never be called, but inline caching for call will SimpleInstallFunction(proto, "every", Builtins::kArrayEvery, 1, false);
// only work if it appears to be compiled. SimpleInstallFunction(proto, "some", Builtins::kArraySome, 1, false);
concat->shared()->DontAdaptArguments(); SimpleInstallFunction(proto, "reduce", Builtins::kArrayReduce, 1, false);
DCHECK(concat->is_compiled()); SimpleInstallFunction(proto, "reduceRight", Builtins::kArrayReduceRight, 1,
// Set the lengths for the functions to satisfy ECMA-262. false);
concat->shared()->set_length(1);
// Install Array.prototype.forEach
Handle<JSFunction> forEach =
InstallArrayBuiltinFunction(proto, "forEach", Builtins::kArrayForEach);
// Add forEach to the context.
native_context()->set_array_for_each_iterator(*forEach);
// Install Array.prototype.filter
InstallArrayBuiltinFunction(proto, "filter", Builtins::kArrayFilter);
// Install Array.prototype.map
InstallArrayBuiltinFunction(proto, "map", Builtins::kArrayMap);
// Install Array.prototype.every
InstallArrayBuiltinFunction(proto, "every", Builtins::kArrayEvery);
// Install Array.prototype.some
InstallArrayBuiltinFunction(proto, "some", Builtins::kArraySome);
// Install Array.prototype.reduce
InstallArrayBuiltinFunction(proto, "reduce", Builtins::kArrayReduce);
// Install Array.prototype.reduceRight
InstallArrayBuiltinFunction(proto, "reduceRight",
Builtins::kArrayReduceRight);
} }
// Install InternalArray.prototype.concat // Install InternalArray.prototype.concat
...@@ -4452,17 +4394,7 @@ bool Genesis::InstallNatives(GlobalContextType context_type) { ...@@ -4452,17 +4394,7 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
Handle<JSFunction> array_constructor( Handle<JSFunction> array_constructor(
native_context()->internal_array_function()); native_context()->internal_array_function());
Handle<JSObject> proto(JSObject::cast(array_constructor->prototype())); Handle<JSObject> proto(JSObject::cast(array_constructor->prototype()));
Handle<JSFunction> concat = SimpleInstallFunction(proto, "concat", Builtins::kArrayConcat, 1, false);
InstallFunction(proto, "concat", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kArrayConcat);
// Make sure that InternalArray.prototype.concat appears to be compiled.
// The code will never be called, but inline caching for call will
// only work if it appears to be compiled.
concat->shared()->DontAdaptArguments();
DCHECK(concat->is_compiled());
// Set the lengths for the functions to satisfy ECMA-262.
concat->shared()->set_length(1);
} }
InstallBuiltinFunctionIds(); InstallBuiltinFunctionIds();
......
...@@ -1484,6 +1484,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<Map> map, ...@@ -1484,6 +1484,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
Handle<Context> context(isolate()->native_context()); Handle<Context> context(isolate()->native_context());
Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo> info =
NewSharedFunctionInfo(name, code, map->is_constructor()); NewSharedFunctionInfo(name, code, map->is_constructor());
// Proper language mode in shared function info will be set outside.
DCHECK(is_sloppy(info->language_mode())); DCHECK(is_sloppy(info->language_mode()));
DCHECK(!map->IsUndefined(isolate())); DCHECK(!map->IsUndefined(isolate()));
DCHECK( DCHECK(
...@@ -1502,8 +1503,10 @@ Handle<JSFunction> Factory::NewFunction(Handle<Map> map, ...@@ -1502,8 +1503,10 @@ Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
Handle<JSFunction> Factory::NewFunction(Handle<String> name) { Handle<JSFunction> Factory::NewFunction(Handle<String> name) {
return NewFunction( Handle<JSFunction> result =
isolate()->sloppy_function_map(), name, MaybeHandle<Code>()); NewFunction(isolate()->sloppy_function_map(), name, MaybeHandle<Code>());
DCHECK(is_sloppy(result->shared()->language_mode()));
return result;
} }
...@@ -1513,7 +1516,9 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name, ...@@ -1513,7 +1516,9 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
Handle<Map> map = is_strict Handle<Map> map = is_strict
? isolate()->strict_function_without_prototype_map() ? isolate()->strict_function_without_prototype_map()
: isolate()->sloppy_function_without_prototype_map(); : isolate()->sloppy_function_without_prototype_map();
return NewFunction(map, name, code); Handle<JSFunction> result = NewFunction(map, name, code);
result->shared()->set_language_mode(is_strict ? STRICT : SLOPPY);
return result;
} }
...@@ -1524,6 +1529,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code, ...@@ -1524,6 +1529,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
: isolate()->sloppy_function_map(); : isolate()->sloppy_function_map();
Handle<JSFunction> result = NewFunction(map, name, code); Handle<JSFunction> result = NewFunction(map, name, code);
result->set_prototype_or_initial_map(*prototype); result->set_prototype_or_initial_map(*prototype);
result->shared()->set_language_mode(is_strict ? STRICT : SLOPPY);
return result; return result;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
(function(global, utils) { (function(global, utils) {
"use strict"; "use strict";
%CheckIsBootstrapping(); %CheckIsBootstrapping();
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
(function(global, utils) { (function(global, utils) {
"use strict";
%CheckIsBootstrapping(); %CheckIsBootstrapping();
function MaxSimple(a, b) { function MaxSimple(a, b) {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
(function(global, utils) { (function(global, utils) {
"use strict";
%CheckIsBootstrapping(); %CheckIsBootstrapping();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
(function(global, utils) { (function(global, utils) {
'use strict'; "use strict";
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Imports // Imports
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
(function(global, utils) { (function(global, utils) {
"use strict";
%CheckIsBootstrapping(); %CheckIsBootstrapping();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
(function(global, utils) { (function(global, utils) {
"use strict";
%CheckIsBootstrapping(); %CheckIsBootstrapping();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
...@@ -46,11 +46,9 @@ f(null); ...@@ -46,11 +46,9 @@ f(null);
// Check called from eval. // Check called from eval.
eval('f(null)'); eval('f(null)');
// Check called from strict builtin functions. // Check called from builtin functions.
[null, null].sort(f); [null, null].sort(f);
[null].forEach(f, null); [null].forEach(f, null);
// Check called from sloppy builtin functions.
"abel".replace(/b/g, function h() { "abel".replace(/b/g, function h() {
assertEquals(String.prototype.replace, h.caller); assertEquals(null, h.caller);
}); });
...@@ -26,7 +26,11 @@ ...@@ -26,7 +26,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var builtInPropertyNames = [ var builtInPropertyNames = [
'prototype', 'length', 'caller', 0, 1, '$1', 'arguments', 'name', 'message', 'constructor' 'prototype', 'length', 0, 1, '$1', 'name', 'message', 'constructor'
];
var builtInPropertyNamesMayThrow = [
'caller', 'arguments'
]; ];
function getAnException() { function getAnException() {
...@@ -77,6 +81,13 @@ function runTest(fun) { ...@@ -77,6 +81,13 @@ function runTest(fun) {
var propertyName = builtInPropertyNames[k]; var propertyName = builtInPropertyNames[k];
fun(obj, propertyName); fun(obj, propertyName);
} }
for (var k in builtInPropertyNamesMayThrow) {
var propertyName = builtInPropertyNamesMayThrow[k];
try {
fun(obj, propertyName);
} catch (e) {
}
}
} }
} }
} }
......
...@@ -625,6 +625,11 @@ if (testFailed) { ...@@ -625,6 +625,11 @@ if (testFailed) {
} }
(function ExtractedAsyncFromSyncIteratorMethods() { (function ExtractedAsyncFromSyncIteratorMethods() {
// TODO(ishell, caitp): Rewrite the test without using function.caller.
// According to ES#sec-built-in-function-objects all built-in functions
// must be strict. And ES#sec-forbidden-extensions states that the value of
// a function.caller must not be a strict function.
return;
// Async-from-Sync iterator methods can be extracted via function.caller. // Async-from-Sync iterator methods can be extracted via function.caller.
// TODO(caitp): test extracted `throw` method using yield* in async generator. // TODO(caitp): test extracted `throw` method using yield* in async generator.
let extractor = [0, 1, 2, 3, 4,5,6,7,8,9]; let extractor = [0, 1, 2, 3, 4,5,6,7,8,9];
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
let success = false; let success = false;
function f() { function f() {
success = (f.caller.arguments === null); success = (f.caller === null);
} }
Promise.resolve().then(f); Promise.resolve().then(f);
%RunMicrotasks(); %RunMicrotasks();
......
...@@ -12,6 +12,9 @@ function CheckMethodEx(object, prop_name, function_name, length) { ...@@ -12,6 +12,9 @@ function CheckMethodEx(object, prop_name, function_name, length) {
assertTrue(desc.configurable); assertTrue(desc.configurable);
assertTrue(desc.writable); assertTrue(desc.writable);
assertThrows(() => new desc.value()); assertThrows(() => new desc.value());
// Check that built-in function is strict.
assertThrows(() => desc.value.arguments);
assertThrows(() => desc.value.caller);
} }
function CheckMethod(object, name, length) { function CheckMethod(object, name, length) {
...@@ -32,6 +35,9 @@ function CheckGetter(object, name) { ...@@ -32,6 +35,9 @@ function CheckGetter(object, name) {
assertEquals(0, desc.get.length); assertEquals(0, desc.get.length);
assertFalse(desc.enumerable); assertFalse(desc.enumerable);
assertTrue(desc.configurable); assertTrue(desc.configurable);
// Check that built-in function is strict.
assertThrows(() => desc.get.arguments);
assertThrows(() => desc.get.caller);
} }
......
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