Commit 24ec2a0b authored by conradw's avatar conradw Committed by Commit bot

[strong] Implement revised strong class semantics

Weak classes can inherit from strong ones again, a strong base class makes
instances strong.

BUG=v8:3956
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30867}
parent 191a0cb6
......@@ -226,7 +226,6 @@ class CallSite {
"to be non-writable is deprecated") \
T(StrongSetProto, \
"On strong object %, redefining the internal prototype is deprecated") \
T(StrongWeakExtend, "Non-strong class % cannot extend a strong object") \
T(SymbolKeyFor, "% is not a symbol") \
T(SymbolToNumber, "Cannot convert a Symbol value to a number") \
T(SymbolToString, "Cannot convert a Symbol value to a string") \
......
......@@ -10627,6 +10627,9 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
function->set_prototype_or_initial_map(*value);
} else {
Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
if (function->map()->is_strong()) {
new_map->set_is_strong();
}
JSFunction::SetInitialMap(function, new_map, value);
// If the function is used as the global Array function, cache the
......@@ -10751,6 +10754,9 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
in_object_properties = function->shared()->CalculateInObjectProperties();
}
Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
if (function->map()->is_strong()) {
map->set_is_strong();
}
// Fetch or allocate prototype.
Handle<Object> prototype;
......@@ -10764,7 +10770,8 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
DCHECK(map->has_fast_object_elements());
// Finally link initial map and constructor function.
JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype));
DCHECK(prototype->IsJSReceiver());
JSFunction::SetInitialMap(function, map, prototype);
if (!function->shared()->is_generator()) {
function->StartInobjectSlackTracking();
......
......@@ -142,13 +142,6 @@ static MaybeHandle<Object> DefineClass(Isolate* isolate, Handle<Object> name,
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongExtendNull),
Object);
}
} else {
if (Handle<HeapObject>::cast(super_class)->map()->is_strong()) {
// Weak class is not permitted to extend strong class.
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kStrongWeakExtend, name),
Object);
}
}
Map::SetPrototype(map, prototype_parent);
map->SetConstructor(*constructor);
......
// Copyright 2015 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: --strong-mode --allow-natives-syntax
'use strict';
function assertWeakClassWeakInstances(x) {
assertFalse(%IsStrong(x));
assertFalse(%IsStrong(x.prototype));
assertFalse(%IsStrong(new x));
}
function assertWeakClassStrongInstances(x) {
assertFalse(%IsStrong(x));
assertFalse(%IsStrong(x.prototype));
assertTrue(%IsStrong(new x));
}
function assertStrongClassWeakInstances(x) {
assertTrue(%IsStrong(x));
assertTrue(%IsStrong(x.prototype));
assertFalse(%IsStrong(new x));
}
function assertStrongClassStrongInstances(x) {
assertTrue(%IsStrong(x));
assertTrue(%IsStrong(x.prototype));
assertTrue(%IsStrong(new x));
}
function getWeakClass() {
return (class {});
}
function getWeakClassExtends(x) {
return (class extends x {});
}
function getStrongClass() {
"use strong";
return (class {});
}
function getStrongClassExtends(x) {
"use strong";
return (class extends x {});
}
(function SimpleWeakClassLiterals() {
class C {};
class D extends C {};
class E extends Object {};
assertWeakClassWeakInstances(C);
assertWeakClassWeakInstances(D);
assertWeakClassWeakInstances(E);
assertWeakClassWeakInstances(class {});
assertWeakClassWeakInstances(class extends Object {});
assertWeakClassWeakInstances(class extends C {});
assertWeakClassWeakInstances(class extends class {} {});
})();
(function SimpleStrongClassLiterals() {
'use strong';
class C {};
class D extends C {};
assertStrongClassStrongInstances(C);
assertStrongClassStrongInstances(D);
assertStrongClassStrongInstances(class {});
assertStrongClassStrongInstances(class extends C {});
assertStrongClassStrongInstances(class extends class {} {});
})();
(function MixedWeakClassLiterals() {
class C extends getStrongClass() {};
class D extends getStrongClassExtends((class {})) {};
class E extends getStrongClassExtends(C) {};
assertWeakClassStrongInstances(C);
assertWeakClassStrongInstances(class extends getStrongClass() {});
assertWeakClassWeakInstances(D);
assertWeakClassWeakInstances(
class extends getStrongClassExtends((class {})) {});
assertWeakClassStrongInstances(E);
assertWeakClassStrongInstances(
class extends getStrongClassExtends(class extends getStrongClass() {}) {});
})();
(function MixedStrongClassLiterals() {
'use strong';
class C extends getWeakClass() {};
class D extends getWeakClassExtends((class {})) {};
class E extends getWeakClassExtends(C) {};
class F extends Object {};
assertStrongClassWeakInstances(C);
assertStrongClassWeakInstances(class extends getWeakClass() {});
assertStrongClassStrongInstances(D);
assertStrongClassStrongInstances(
class extends getWeakClassExtends((class {})) {});
assertStrongClassWeakInstances(E);
assertStrongClassWeakInstances(
class extends getWeakClassExtends(class extends getWeakClass() {}) {});
assertStrongClassWeakInstances(F);
assertStrongClassWeakInstances(class extends Object {});
})();
(function WeakMonkeyPatchedClassLiterals() {
class C {};
assertWeakClassWeakInstances(C);
C.__proto__ = getStrongClass();
// C's default constructor doesn't call super.
assertWeakClassWeakInstances(C);
class D extends Object {};
assertWeakClassWeakInstances(D);
D.__proto__ = getStrongClass();
// D is a derived class, so its default constructor calls super.
assertWeakClassStrongInstances(D);
class E extends (class {}) {};
E.__proto__ = C;
assertWeakClassWeakInstances(E);
class F extends (class {}) {};
F.__proto__ = D;
assertWeakClassStrongInstances(F);
class G extends getStrongClass() {};
G.__proto__ = getWeakClass();
assertWeakClassWeakInstances(G);
})();
(function StrongMonkeyPatchedClassLiterals() {
let C = getStrongClassExtends(getWeakClassExtends(getStrongClass()));
let D = getStrongClassExtends(getWeakClassExtends(getWeakClass()));
assertStrongClassStrongInstances(C);
C.__proto__.__proto__ = getWeakClass();
assertStrongClassWeakInstances(C);
C.__proto__.__proto__ = getStrongClass();
assertStrongClassStrongInstances(C);
assertStrongClassWeakInstances(D);
D.__proto__.__proto__ = getStrongClass();
assertStrongClassStrongInstances(D);
D.__proto__.__proto__ = getWeakClass();
assertStrongClassWeakInstances(D);
})();
......@@ -79,3 +79,20 @@ testStrongClass(getClassExprStrong);
assertDoesNotThrow(function(){addProperty(parent)});
assertDoesNotThrow(function(){convertPropertyToData(parent)});
})();
// Check strong classes don't freeze their children.
(function() {
let parent = getClassStrong();
let classFunc = function() {
class Foo extends parent {
static get bar() { return 0 }
get bar() { return 0 }
}
return Foo;
}
assertThrows(function(){addProperty(parent)}, TypeError);
assertThrows(function(){convertPropertyToData(parent)}, TypeError);
testWeakClass(classFunc);
})();
// Copyright 2015 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: --strong-mode --allow-natives-syntax
function getStrongClass() {
"use strong";
return (class {});
}
function weakClass() {
"use strict";
class Weak extends getStrongClass() {}
}
function strongClass() {
"use strong";
class Strong extends getStrongClass() {}
}
assertThrows(weakClass, TypeError);
%OptimizeFunctionOnNextCall(weakClass);
assertThrows(weakClass, TypeError);
assertDoesNotThrow(strongClass);
%OptimizeFunctionOnNextCall(strongClass);
assertDoesNotThrow(strongClass);
......@@ -275,61 +275,6 @@ let GeneratorPrototype = (function*(){}).__proto__;
assertStrongGenerator((new class {*m(){'use strong'}}).m);
})();
(function WeakClassLiterals() {
function assertWeakClass(x) {
assertFalse(%IsStrong(x));
assertFalse(%IsStrong(x.prototype));
assertFalse(%IsStrong(new x));
}
class C {};
class D extends C {};
class E extends Object {};
// class F extends null {};
assertWeakClass(C);
assertWeakClass(D);
assertWeakClass(E);
// assertWeakClass(F);
assertWeakClass(class {});
assertWeakClass(class extends Object {});
// assertWeakClass(class extends null {});
assertWeakClass(class extends C {});
assertWeakClass(class extends class {} {});
assertWeakClass(class C {});
assertWeakClass(class D extends Object {});
// assertWeakClass(class D extends null {});
assertWeakClass(class D extends C {});
assertWeakClass(class D extends class {} {});
})();
(function StrongClassLiterals() {
'use strong';
function assertStrongClass(x) {
assertTrue(%IsStrong(x));
assertTrue(%IsStrong(x.prototype));
// TODO(rossberg): strongify class instance
// assertTrue(%IsStrong(new x));
}
class C {};
class D extends C {};
class E extends Object {};
const W = (1, eval)(() => {'use strict'; return class {}})();
class G extends W {};
assertStrongClass(C);
assertStrongClass(D);
assertStrongClass(E);
assertStrongClass(G);
assertStrongClass(class {});
assertStrongClass(class extends Object {});
assertStrongClass(class extends C {});
assertStrongClass(class extends W {});
assertStrongClass(class extends class {} {});
assertStrongClass(class C {});
assertStrongClass(class D extends Object {});
assertStrongClass(class D extends C {});
assertStrongClass(class D extends W {});
assertStrongClass(class D extends class {} {});
})();
(function WeakRegExpLiterals() {
function assertWeakRegExp(x) {
assertFalse(%IsStrong(x));
......
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