Commit 888acb2f authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[runtime] Properly deal with prototype setup mode during class literal instantiation.

1) Make sure we don't enable prototype setup mode for parent class and its prototype
objects.
2) Make sure we create builtins and their prototypes with completed setup mode.
3) Drive-by-fix: setup typed array classes in bootstrapper.cc instead of typedarray.js,
and drop %FunctionSetPrototype().

Bug: v8:7115, v8:5902
Change-Id: I58ac091d85647abc3307bd47baf48e378e3695c5
Reviewed-on: https://chromium-review.googlesource.com/790992
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49655}
parent 904c3a1f
...@@ -223,8 +223,8 @@ class Genesis BASE_EMBEDDED { ...@@ -223,8 +223,8 @@ class Genesis BASE_EMBEDDED {
ElementsKind elements_kind); ElementsKind elements_kind);
bool InstallNatives(GlobalContextType context_type); bool InstallNatives(GlobalContextType context_type);
void InstallTypedArray(const char* name, ElementsKind elements_kind, Handle<JSFunction> InstallTypedArray(const char* name,
Handle<JSFunction>* fun); ElementsKind elements_kind);
bool InstallExtraNatives(); bool InstallExtraNatives();
bool InstallExperimentalExtraNatives(); bool InstallExperimentalExtraNatives();
bool InstallDebuggerNatives(); bool InstallDebuggerNatives();
...@@ -403,12 +403,17 @@ V8_NOINLINE Handle<JSFunction> CreateFunction( ...@@ -403,12 +403,17 @@ V8_NOINLINE Handle<JSFunction> CreateFunction(
builtin_id, IMMUTABLE); builtin_id, IMMUTABLE);
result = isolate->factory()->NewFunction(args); result = isolate->factory()->NewFunction(args);
// Make the JSFunction's prototype object fast.
JSObject::MakePrototypesFast(handle(result->prototype(), isolate),
kStartAtReceiver, isolate);
} else { } else {
NewFunctionArgs args = NewFunctionArgs::ForBuiltinWithoutPrototype( NewFunctionArgs args = NewFunctionArgs::ForBuiltinWithoutPrototype(
name, code, builtin_id, LanguageMode::kStrict); name, code, builtin_id, LanguageMode::kStrict);
result = isolate->factory()->NewFunction(args); result = isolate->factory()->NewFunction(args);
} }
// Make the resulting JSFunction object fast.
JSObject::MakePrototypesFast(result, kStartAtReceiver, isolate);
result->shared()->set_native(true); result->shared()->set_native(true);
return result; return result;
} }
...@@ -3043,8 +3048,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3043,8 +3048,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
{ // -- T y p e d A r r a y s { // -- T y p e d A r r a y s
#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ #define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
{ \ { \
Handle<JSFunction> fun; \ Handle<JSFunction> fun = \
InstallTypedArray(#Type "Array", TYPE##_ELEMENTS, &fun); \ InstallTypedArray(#Type "Array", TYPE##_ELEMENTS); \
InstallWithIntrinsicDefaultProto(isolate, fun, \ InstallWithIntrinsicDefaultProto(isolate, fun, \
Context::TYPE##_ARRAY_FUN_INDEX); \ Context::TYPE##_ARRAY_FUN_INDEX); \
} }
...@@ -3598,8 +3603,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3598,8 +3603,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
} }
} // NOLINT(readability/fn_size) } // NOLINT(readability/fn_size)
void Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind, Handle<JSFunction> Genesis::InstallTypedArray(const char* name,
Handle<JSFunction>* fun) { ElementsKind elements_kind) {
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object()); Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
Handle<JSObject> typed_array_prototype = Handle<JSObject> typed_array_prototype =
...@@ -3607,20 +3612,29 @@ void Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind, ...@@ -3607,20 +3612,29 @@ void Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind,
Handle<JSFunction> typed_array_function = Handle<JSFunction> typed_array_function =
Handle<JSFunction>(isolate()->typed_array_function()); Handle<JSFunction>(isolate()->typed_array_function());
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
Handle<JSFunction> result = InstallFunction( Handle<JSFunction> result = InstallFunction(
global, name, JS_TYPED_ARRAY_TYPE, JSTypedArray::kSizeWithEmbedderFields, global, name, JS_TYPED_ARRAY_TYPE, JSTypedArray::kSizeWithEmbedderFields,
0, prototype, Builtins::kIllegal); 0, factory()->the_hole_value(), Builtins::kIllegal);
result->initial_map()->set_elements_kind(elements_kind); result->initial_map()->set_elements_kind(elements_kind);
CHECK(JSObject::SetPrototype(result, typed_array_function, false, kDontThrow) CHECK(JSObject::SetPrototype(result, typed_array_function, false, kDontThrow)
.FromJust()); .FromJust());
Handle<Smi> bytes_per_element(
Smi::FromInt(1 << ElementsKindToShiftSize(elements_kind)), isolate());
InstallConstant(isolate(), result, "BYTES_PER_ELEMENT", bytes_per_element);
// Setup prototype object.
DCHECK(result->prototype()->IsJSObject());
Handle<JSObject> prototype(JSObject::cast(result->prototype()), isolate());
CHECK(JSObject::SetPrototype(prototype, typed_array_prototype, false, CHECK(JSObject::SetPrototype(prototype, typed_array_prototype, false,
kDontThrow) kDontThrow)
.FromJust()); .FromJust());
*fun = result;
InstallConstant(isolate(), prototype, "BYTES_PER_ELEMENT", bytes_per_element);
return result;
} }
......
...@@ -453,18 +453,6 @@ function TypedArrayConstructor() { ...@@ -453,18 +453,6 @@ function TypedArrayConstructor() {
macro SETUP_TYPED_ARRAY(NAME, ELEMENT_SIZE) macro SETUP_TYPED_ARRAY(NAME, ELEMENT_SIZE)
%SetCode(GlobalNAME, NAMEConstructor); %SetCode(GlobalNAME, NAMEConstructor);
%FunctionSetPrototype(GlobalNAME, new GlobalObject());
%InternalSetPrototype(GlobalNAME, GlobalTypedArray);
%InternalSetPrototype(GlobalNAME.prototype, GlobalTypedArray.prototype);
%AddNamedProperty(GlobalNAME, "BYTES_PER_ELEMENT", ELEMENT_SIZE,
READ_ONLY | DONT_ENUM | DONT_DELETE);
%AddNamedProperty(GlobalNAME.prototype,
"constructor", global.NAME, DONT_ENUM);
%AddNamedProperty(GlobalNAME.prototype,
"BYTES_PER_ELEMENT", ELEMENT_SIZE,
READ_ONLY | DONT_ENUM | DONT_DELETE);
endmacro endmacro
TYPED_ARRAYS(SETUP_TYPED_ARRAY) TYPED_ARRAYS(SETUP_TYPED_ARRAY)
......
...@@ -1411,6 +1411,7 @@ void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT ...@@ -1411,6 +1411,7 @@ void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT
os << "\n - registry slot: " << registry_slot(); os << "\n - registry slot: " << registry_slot();
os << "\n - validity cell: " << Brief(validity_cell()); os << "\n - validity cell: " << Brief(validity_cell());
os << "\n - object create map: " << Brief(object_create_map()); os << "\n - object create map: " << Brief(object_create_map());
os << "\n - should_be_fast_map: " << should_be_fast_map();
os << "\n"; os << "\n";
} }
......
...@@ -12401,9 +12401,10 @@ void JSObject::MakePrototypesFast(Handle<Object> receiver, ...@@ -12401,9 +12401,10 @@ void JSObject::MakePrototypesFast(Handle<Object> receiver,
} }
// static // static
void JSObject::OptimizeAsPrototype(Handle<JSObject> object) { void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
bool enable_setup_mode) {
if (object->IsJSGlobalObject()) return; if (object->IsJSGlobalObject()) return;
if (PrototypeBenefitsFromNormalization(object)) { if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
// First normalize to ensure all JSFunctions are DATA_CONSTANT. // First normalize to ensure all JSFunctions are DATA_CONSTANT.
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
"NormalizeAsPrototype"); "NormalizeAsPrototype");
...@@ -12657,13 +12658,14 @@ Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype, ...@@ -12657,13 +12658,14 @@ Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype,
} }
// static // static
void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype) { void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
bool enable_prototype_setup_mode) {
RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype); RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
bool is_hidden = false; bool is_hidden = false;
if (prototype->IsJSObject()) { if (prototype->IsJSObject()) {
Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
JSObject::OptimizeAsPrototype(prototype_jsobj); JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
Object* maybe_constructor = prototype_jsobj->map()->GetConstructor(); Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
if (maybe_constructor->IsJSFunction()) { if (maybe_constructor->IsJSFunction()) {
......
...@@ -2380,7 +2380,8 @@ class JSObject: public JSReceiver { ...@@ -2380,7 +2380,8 @@ class JSObject: public JSReceiver {
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes); PropertyAttributes attributes);
static void OptimizeAsPrototype(Handle<JSObject> object); static void OptimizeAsPrototype(Handle<JSObject> object,
bool enable_setup_mode = true);
static void ReoptimizeIfPrototype(Handle<JSObject> object); static void ReoptimizeIfPrototype(Handle<JSObject> object);
static void MakePrototypesFast(Handle<Object> receiver, static void MakePrototypesFast(Handle<Object> receiver,
WhereToStart where_to_start, Isolate* isolate); WhereToStart where_to_start, Isolate* isolate);
......
...@@ -498,7 +498,8 @@ class Map : public HeapObject { ...@@ -498,7 +498,8 @@ class Map : public HeapObject {
// [prototype]: implicit prototype object. // [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object) DECL_ACCESSORS(prototype, Object)
// TODO(jkummerow): make set_prototype private. // TODO(jkummerow): make set_prototype private.
static void SetPrototype(Handle<Map> map, Handle<Object> prototype); static void SetPrototype(Handle<Map> map, Handle<Object> prototype,
bool enable_prototype_setup_mode = true);
// [constructor]: points back to the function or FunctionTemplateInfo // [constructor]: points back to the function or FunctionTemplateInfo
// responsible for this map. // responsible for this map.
......
...@@ -450,7 +450,6 @@ bool InitClassPrototype(Isolate* isolate, ...@@ -450,7 +450,6 @@ bool InitClassPrototype(Isolate* isolate,
Map::SetPrototype(map, prototype_parent); Map::SetPrototype(map, prototype_parent);
constructor->set_prototype_or_initial_map(*prototype); constructor->set_prototype_or_initial_map(*prototype);
map->SetConstructor(*constructor); map->SetConstructor(*constructor);
Map::SetShouldBeFastPrototypeMap(map, true, isolate);
Handle<FixedArray> computed_properties( Handle<FixedArray> computed_properties(
class_boilerplate->instance_computed_properties(), isolate); class_boilerplate->instance_computed_properties(), isolate);
...@@ -467,7 +466,7 @@ bool InitClassPrototype(Isolate* isolate, ...@@ -467,7 +466,7 @@ bool InitClassPrototype(Isolate* isolate,
map->set_dictionary_map(true); map->set_dictionary_map(true);
map->set_migration_target(false); map->set_migration_target(false);
map->set_may_have_interesting_symbols(true); map->set_may_have_interesting_symbols(true);
// map->set_construction_counter(Map::kNoSlackTracking); map->set_construction_counter(Map::kNoSlackTracking);
// We care about name property only for class constructor. // We care about name property only for class constructor.
const bool install_name_accessor = false; const bool install_name_accessor = false;
...@@ -496,13 +495,11 @@ bool InitClassConstructor(Isolate* isolate, ...@@ -496,13 +495,11 @@ bool InitClassConstructor(Isolate* isolate,
Handle<Map> map(constructor->map(), isolate); Handle<Map> map(constructor->map(), isolate);
map = Map::CopyDropDescriptors(map); map = Map::CopyDropDescriptors(map);
DCHECK(map->is_prototype_map()); DCHECK(map->is_prototype_map());
Map::SetShouldBeFastPrototypeMap(map, true, isolate);
if (!constructor_parent.is_null()) { if (!constructor_parent.is_null()) {
// Set map's prototype without triggering JSObject::OptimizeAsPrototype() // Set map's prototype without enabling prototype setup mode for superclass
// for parent class. // because it does not make sense.
// map->set_prototype(*constructor_parent); Map::SetPrototype(map, constructor_parent, false);
Map::SetPrototype(map, constructor_parent);
} }
Handle<NumberDictionary> elements_dictionary_template( Handle<NumberDictionary> elements_dictionary_template(
......
...@@ -97,18 +97,6 @@ RUNTIME_FUNCTION(Runtime_FunctionSetLength) { ...@@ -97,18 +97,6 @@ RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
} }
RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
CHECK(fun->IsConstructor());
JSFunction::SetPrototype(fun, value);
return args[0]; // return TOS
}
RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) { RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
......
...@@ -232,7 +232,6 @@ namespace internal { ...@@ -232,7 +232,6 @@ namespace internal {
F(FunctionGetScriptSourcePosition, 1, 1) \ F(FunctionGetScriptSourcePosition, 1, 1) \
F(FunctionGetContextData, 1, 1) \ F(FunctionGetContextData, 1, 1) \
F(FunctionSetLength, 2, 1) \ F(FunctionSetLength, 2, 1) \
F(FunctionSetPrototype, 2, 1) \
F(FunctionIsAPIFunction, 1, 1) \ F(FunctionIsAPIFunction, 1, 1) \
F(SetCode, 2, 1) \ F(SetCode, 2, 1) \
F(SetNativeFlag, 1, 1) \ F(SetNativeFlag, 1, 1) \
......
...@@ -243,10 +243,6 @@ var migrations = [ ...@@ -243,10 +243,6 @@ var migrations = [
name: "set prototype {}", name: "set prototype {}",
migr: function(o, i) { o.__proto__ = {}; }, migr: function(o, i) { o.__proto__ = {}; },
}, },
{
name: "%FunctionSetPrototype",
migr: function(o, i) { %FunctionSetPrototype(o, null); },
},
{ {
name: "modify prototype", name: "modify prototype",
migr: function(o, i) { if (i == 0) o.__proto__.__proto1__ = [,,,5,,,]; }, migr: function(o, i) { if (i == 0) o.__proto__.__proto1__ = [,,,5,,,]; },
......
...@@ -51,12 +51,5 @@ Object.getOwnPropertyNames(global).forEach(function(name) { ...@@ -51,12 +51,5 @@ Object.getOwnPropertyNames(global).forEach(function(name) {
`${name}.prototype.constructor`); `${name}.prototype.constructor`);
}); });
// This is the current set of dictionary mode objects. // There should be no dictionary mode builtin objects.
// Remove items as we fix them. See issue 5902. assertEquals([], log);
assertEquals(
[
'Error.prototype',
'EvalError.prototype', 'RangeError.prototype', 'ReferenceError.prototype',
'SyntaxError.prototype', 'TypeError.prototype', 'URIError.prototype'
],
log);
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function TestBuiltinSubclassing(Builtin) {
assertTrue(%HasFastProperties(Builtin));
assertTrue(%HasFastProperties(Builtin.prototype));
assertTrue(%HasFastProperties(Builtin.prototype.__proto__));
class SubClass extends Builtin {}
assertTrue(%HasFastProperties(Builtin));
assertTrue(%HasFastProperties(Builtin.prototype));
assertTrue(%HasFastProperties(Builtin.prototype.__proto__));
}
let TypedArray = Uint8Array.__proto__;
TestBuiltinSubclassing(RegExp);
TestBuiltinSubclassing(Promise);
TestBuiltinSubclassing(Array);
TestBuiltinSubclassing(TypedArray);
TestBuiltinSubclassing(Uint8Array);
TestBuiltinSubclassing(Int8Array);
TestBuiltinSubclassing(Uint16Array);
TestBuiltinSubclassing(Int16Array);
TestBuiltinSubclassing(Uint32Array);
TestBuiltinSubclassing(Int32Array);
TestBuiltinSubclassing(Float32Array);
TestBuiltinSubclassing(Float64Array);
TestBuiltinSubclassing(Uint8ClampedArray);
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