[torque] weak pointer type Weak<T> + port CreateObjectWithoutProperties

Overview:
- Change basic type hierarchy to split Tagged into StrongTagged (= Object) and
  and WeakHeapObject. This enables to emit the right CSA types (Object, MaybeObject).
- The new Weak<T> type encodes a possibly cleared weak bit pattern that
  points to type T if it's not cleared.
- Make TNode<Object> a subtype of TNode<MaybeObject> so that the generated code
  compiles on the C++ side. Drive-by change: simplify a few CSA helpers by using
  MaybeObject as a common supertype of MaybeObject and Object.
- Port CreateObjectWithoutProperties and LoadMapPrototypeInfo.

Bug: v8:7793
Change-Id: I895a6501ce3e287ea8cf4065aaff3a5535245ab4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1889870
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64876}
This commit is contained in:
Tobias Tebbi 2019-11-08 19:53:48 +01:00 committed by Commit Bot
parent 3568e4441c
commit 1b04772f7f
14 changed files with 197 additions and 171 deletions

View File

@ -24,8 +24,22 @@
type void;
type never;
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
type StrongTagged extends Tagged
generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends StrongTagged generates 'TNode<Smi>' constexpr 'Smi';
// A possibly cleared weak pointer with a bit pattern that distinguishes it from
// strong HeapObject pointers and Smi values.
type WeakHeapObject extends Tagged;
type Weak<T : type extends HeapObject> extends WeakHeapObject;
type Object = Smi|HeapObject;
type MaybeObject = Smi|HeapObject|WeakHeapObject;
@abstract
extern class HeapObject extends StrongTagged {
map: Map;
}
// A Smi that is greater than or equal to 0. See TaggedIsPositiveSmi.
type PositiveSmi extends Smi;
@ -36,12 +50,18 @@ type Zero extends PositiveSmi;
// A value with the size of Tagged which may contain arbitrary data.
type Uninitialized extends Tagged;
@abstract
extern class HeapObject extends Tagged {
map: Map;
}
extern macro MakeWeak(HeapObject): WeakHeapObject;
extern macro GetHeapObjectAssumeWeak(WeakHeapObject):
HeapObject labels ClearedWeakPointer;
extern macro IsWeakOrCleared(MaybeObject): bool;
type Object = Smi|HeapObject;
macro StrongToWeak<T: type>(x: T): Weak<T> {
return %RawDownCast<Weak<T>>(MakeWeak(x));
}
macro WeakToStrong<T: type>(x: Weak<T>): T labels ClearedWeakPointer {
const x = GetHeapObjectAssumeWeak(x) otherwise ClearedWeakPointer;
return %RawDownCast<T>(x);
}
// Defined to coincide with https://tc39.es/ecma262/#sec-ispropertykey
// Doesn't include PrivateSymbol.
@ -260,6 +280,8 @@ extern class FixedArray extends FixedArrayBase {
objects[length]: Object;
}
type EmptyFixedArray extends FixedArray;
extern class FixedDoubleArray extends FixedArrayBase {
floats[length]: float64;
}
@ -287,6 +309,23 @@ extern class TransitionArray extends WeakFixedArray;
type InstanceType extends uint16 constexpr 'v8::internal::InstanceType';
extern class Map extends HeapObject {
PrototypeInfo(): PrototypeInfo labels HasNoPrototypeInfo {
typeswitch (this.transitions_or_prototype_info) {
case (Weak<Map>): {
goto HasNoPrototypeInfo;
}
case (Smi): {
goto HasNoPrototypeInfo;
}
case (info: PrototypeInfo): {
return info;
}
case (Map | TransitionArray): {
goto HasNoPrototypeInfo;
}
}
}
instance_size_in_words: uint8;
in_object_properties_start_or_constructor_function_index: uint8;
used_or_unused_instance_size_in_words: uint8;
@ -299,16 +338,20 @@ extern class Map extends HeapObject {
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
prototype: HeapObject;
prototype: JSReceiver|Null;
constructor_or_back_pointer_or_native_context: Object;
instance_descriptors: DescriptorArray;
@if(V8_DOUBLE_FIELDS_UNBOXING) layout_descriptor: LayoutDescriptor;
@ifnot(V8_DOUBLE_FIELDS_UNBOXING) layout_descriptor: void;
dependent_code: DependentCode;
prototype_validity_cell: Smi|Cell;
// TODO(v8:9108): Misusing "weak" keyword; type should be
// Map | Weak<Map> | TransitionArray | PrototypeInfo | Smi.
weak transitions_or_prototype_info: Map|TransitionArray|PrototypeInfo|Smi;
weak transitions_or_prototype_info: Map|Weak<Map>|TransitionArray|
PrototypeInfo|Smi;
}
@export
macro LoadMapPrototypeInfo(m: Map): PrototypeInfo labels HasNoPrototypeInfo {
return m.PrototypeInfo() otherwise HasNoPrototypeInfo;
}
@generatePrint
@ -457,7 +500,7 @@ macro GetDerivedMap(implicit context: Context)(
macro AllocateFastOrSlowJSObjectFromMap(implicit context: Context)(map: Map):
JSObject {
let properties = kEmptyFixedArray;
let properties: EmptyFixedArray|NameDictionary = kEmptyFixedArray;
if (IsDictionaryMap(map)) {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
@ -714,8 +757,7 @@ extern class JSMessageObject extends JSObject {
extern class WeakArrayList extends HeapObject {
capacity: Smi;
length: Smi;
// TODO(v8:8983): declare variable-sized region for contained MaybeObject's
// objects[length]: MaybeObject;
objects[length]: MaybeObject;
}
extern class PrototypeInfo extends Struct {
@ -723,11 +765,18 @@ extern class PrototypeInfo extends Struct {
prototype_users: WeakArrayList|Zero;
registry_slot: Smi;
validity_cell: Object;
// TODO(v8:9108): Should be Weak<Map> | Undefined.
@noVerifier object_create_map: Map|Undefined;
object_create_map: Weak<Map>|Undefined;
bit_field: Smi;
}
extern macro PrototypeInfoMapConstant(): Map;
const kPrototypeInfoMap: Map = PrototypeInfoMapConstant();
Cast<PrototypeInfo>(o: HeapObject): PrototypeInfo labels CastError {
if (o.map != kPrototypeInfoMap) goto CastError;
return %RawDownCast<PrototypeInfo>(o);
}
extern class Script extends Struct {
source: Object;
name: Object;
@ -872,6 +921,8 @@ const REGEXP_LAST_MATCH_INFO_INDEX: constexpr NativeContextSlot
generates 'Context::REGEXP_LAST_MATCH_INFO_INDEX';
const INITIAL_STRING_ITERATOR_MAP_INDEX: constexpr NativeContextSlot
generates 'Context::INITIAL_STRING_ITERATOR_MAP_INDEX';
const SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP: constexpr NativeContextSlot
generates 'Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP';
extern operator '[]' macro LoadContextElement(
NativeContext, NativeContextSlot): Object;
extern operator '[]=' macro StoreContextElement(
@ -1102,10 +1153,9 @@ extern class DataHandler extends Struct {
validity_cell: Smi|Cell;
// Space for the following fields may or may not be allocated.
// TODO(v8:9108): Misusing "weak" keyword; should be MaybeObject.
@noVerifier weak data_1: Object;
@noVerifier weak data_2: Object;
@noVerifier weak data_3: Object;
@noVerifier data_1: MaybeObject;
@noVerifier data_2: MaybeObject;
@noVerifier data_3: MaybeObject;
}
extern class LoadHandler extends DataHandler;
@ -1741,8 +1791,7 @@ extern class DebugInfo extends Struct {
extern class FeedbackVector extends HeapObject {
shared_function_info: SharedFunctionInfo;
// TODO(v8:9108): currently no support for MaybeObject in Torque
@noVerifier optimized_code_weak_or_smi: Object;
optimized_code_weak_or_smi: Weak<Code>|Smi;
closure_feedback_cell_array: FixedArray;
length: int32;
invocation_count: int32;
@ -2122,14 +2171,16 @@ extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool;
extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool;
extern operator '==' macro TaggedEqual(
TaggedWithIdentity, TaggedWithIdentity): bool;
extern operator '==' macro TaggedEqual(WeakHeapObject, WeakHeapObject): bool;
extern operator '!=' macro TaggedNotEqual(TaggedWithIdentity, Object): bool;
extern operator '!=' macro TaggedNotEqual(Object, TaggedWithIdentity): bool;
extern operator '!=' macro TaggedNotEqual(
TaggedWithIdentity, TaggedWithIdentity): bool;
extern operator '!=' macro TaggedNotEqual(WeakHeapObject, WeakHeapObject): bool;
// Do not overload == and != if it is unclear if object identity is the right
// equality.
extern macro TaggedEqual(Object, Object): bool;
extern macro TaggedNotEqual(Object, Object): bool;
extern macro TaggedEqual(MaybeObject, MaybeObject): bool;
extern macro TaggedNotEqual(MaybeObject, MaybeObject): bool;
extern operator '+' macro SmiAdd(Smi, Smi): Smi;
extern operator '-' macro SmiSub(Smi, Smi): Smi;
@ -2305,6 +2356,18 @@ extern macro HeapObjectToRegExpMatchInfo(HeapObject):
extern macro TaggedToNumber(Object): Number
labels CastError;
macro Cast<A : type extends WeakHeapObject>(o: A|Object): A labels CastError {
if (!IsWeakOrCleared(o)) goto CastError;
return %RawDownCast<A>(o);
}
macro Cast<A: type>(o: MaybeObject): A labels CastError;
Cast<Undefined>(o: MaybeObject): Undefined labels CastError {
if (TaggedNotEqual(o, Undefined)) goto CastError;
return %RawDownCast<Undefined>(o);
}
macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
labels CastError {
return Cast<A>(TaggedToHeapObject(o) otherwise CastError)
@ -2333,8 +2396,8 @@ Cast<Number>(o: Object): Number
Cast<Undefined>(o: Object): Undefined
labels CastError {
if (o != Undefined) goto CastError;
return %RawDownCast<Undefined>(o);
const o: MaybeObject = o;
return Cast<Undefined>(o) otherwise CastError;
}
Cast<Numeric>(o: Object): Numeric labels CastError {
@ -2487,7 +2550,7 @@ Cast<Null>(o: HeapObject): Null
Cast<Undefined>(o: HeapObject): Undefined
labels CastError {
const o: Object = o;
const o: MaybeObject = o;
return Cast<Undefined>(o) otherwise CastError;
}
@ -3199,13 +3262,13 @@ macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object):
extern macro FixedArrayMapConstant(): Map;
extern macro FixedCOWArrayMapConstant(): Map;
extern macro EmptyByteArrayConstant(): ByteArray;
extern macro EmptyFixedArrayConstant(): FixedArray;
extern macro EmptyFixedArrayConstant(): EmptyFixedArray;
extern macro PromiseCapabilityMapConstant(): Map;
const kFixedArrayMap: Map = FixedArrayMapConstant();
const kCOWMap: Map = FixedCOWArrayMapConstant();
const kEmptyByteArray: ByteArray = EmptyByteArrayConstant();
const kEmptyFixedArray: FixedArray = EmptyFixedArrayConstant();
const kEmptyFixedArray: EmptyFixedArray = EmptyFixedArrayConstant();
const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant();
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
@ -3347,8 +3410,10 @@ extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
extern macro AllocateJSArray(Map, FixedArrayBase, Smi): JSArray;
extern macro AllocateJSObjectFromMap(Map): JSObject;
extern macro AllocateJSObjectFromMap(
Map, FixedArray | PropertyArray, FixedArray, constexpr AllocationFlags,
constexpr SlackTrackingMode): JSObject;
Map, NameDictionary | EmptyFixedArray | PropertyArray): JSObject;
extern macro AllocateJSObjectFromMap(
Map, NameDictionary | EmptyFixedArray | PropertyArray, FixedArray,
constexpr AllocationFlags, constexpr SlackTrackingMode): JSObject;
extern macro LoadDoubleWithHoleCheck(FixedDoubleArray, Smi): float64
labels IfHole;

View File

@ -703,7 +703,6 @@ namespace internal {
TFJ(ObjectAssign, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES #sec-object.create */ \
TFJ(ObjectCreate, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
TFS(CreateObjectWithoutProperties, kPrototypeArg) \
CPP(ObjectDefineGetter) \
CPP(ObjectDefineProperties) \
CPP(ObjectDefineProperty) \

View File

@ -1060,70 +1060,6 @@ TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
Return(ToObject_Inline(context, receiver));
}
// ES #sec-object.create
TF_BUILTIN(CreateObjectWithoutProperties, ObjectBuiltinsAssembler) {
const TNode<Object> prototype = CAST(Parameter(Descriptor::kPrototypeArg));
const TNode<Context> context = CAST(Parameter(Descriptor::kContext));
const TNode<NativeContext> native_context = LoadNativeContext(context);
Label call_runtime(this, Label::kDeferred), prototype_null(this),
prototype_jsreceiver(this);
{
Comment("Argument check: prototype");
GotoIf(IsNull(prototype), &prototype_null);
BranchIfJSReceiver(prototype, &prototype_jsreceiver, &call_runtime);
}
TVARIABLE(Map, map);
TVARIABLE(HeapObject, properties);
Label instantiate_map(this);
BIND(&prototype_null);
{
Comment("Prototype is null");
map = CAST(LoadContextElement(
native_context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
properties = AllocateNameDictionary(NameDictionary::kInitialCapacity);
Goto(&instantiate_map);
}
BIND(&prototype_jsreceiver);
{
Comment("Prototype is JSReceiver");
properties = EmptyFixedArrayConstant();
TNode<HeapObject> object_function = CAST(
LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
TNode<Map> object_function_map = LoadObjectField<Map>(
object_function, JSFunction::kPrototypeOrInitialMapOffset);
map = object_function_map;
GotoIf(TaggedEqual(prototype, LoadMapPrototype(map.value())),
&instantiate_map);
Comment("Try loading the prototype info");
TNode<PrototypeInfo> prototype_info =
LoadMapPrototypeInfo(LoadMap(CAST(prototype)), &call_runtime);
TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
prototype_info, PrototypeInfo::kObjectCreateMapOffset);
GotoIf(TaggedEqual(maybe_map, UndefinedConstant()), &call_runtime);
map = CAST(GetHeapObjectAssumeWeak(maybe_map, &call_runtime));
Goto(&instantiate_map);
}
BIND(&instantiate_map);
{
Comment("Instantiate map");
TNode<JSObject> instance =
AllocateJSObjectFromMap(map.value(), properties.value());
Return(instance);
}
BIND(&call_runtime);
{
Comment("Call Runtime (prototype is not null/jsreceiver)");
TNode<Object> result = CallRuntime(Runtime::kObjectCreate, context,
prototype, UndefinedConstant());
Return(result);
}
}
// ES #sec-object.create
TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
int const kPrototypeArg = 0;

View File

@ -105,7 +105,8 @@ operator '==' macro FrameTypeEquals(f1: FrameType, f2: FrameType): bool {
return TaggedEqual(f1, f2);
}
macro Cast<A: type>(implicit context: Context)(o: Frame): A labels CastError;
macro Cast<A : type extends Frame>(implicit context: Context)(o: Frame):
A labels CastError;
Cast<StandardFrame>(implicit context: Context)(f: Frame):
StandardFrame labels CastError {
const o: HeapObject =

View File

@ -24,6 +24,9 @@ namespace runtime {
extern transitioning runtime
JSReceiverSetPrototypeOfDontThrow(implicit context:
Context)(JSReceiver, JSAny): JSAny;
extern transitioning runtime ObjectCreate(implicit context:
Context)(JSAny, JSAny): JSAny;
} // namespace runtime
namespace object {
@ -91,6 +94,48 @@ namespace object {
return proxy::ProxySetPrototypeOf(objectJSProxy, proto, False);
}
transitioning builtin CreateObjectWithoutProperties(
implicit context: Context)(prototype: JSAny): JSAny {
const nativeContext = LoadNativeContext(context);
try {
let map: Map;
let properties: NameDictionary|EmptyFixedArray;
typeswitch (prototype) {
case (Null): {
map = UnsafeCast<Map>(
nativeContext[SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP]);
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
case (prototype: JSReceiver): {
properties = kEmptyFixedArray;
const objectFunction =
UnsafeCast<JSFunction>(nativeContext[OBJECT_FUNCTION_INDEX]);
map = UnsafeCast<Map>(objectFunction.prototype_or_initial_map);
if (prototype != map.prototype) {
const prototypeInfo =
prototype.map.PrototypeInfo() otherwise Runtime;
typeswitch (prototypeInfo.object_create_map) {
case (Undefined): {
goto Runtime;
}
case (weak_map: Weak<Map>): {
map = WeakToStrong(weak_map) otherwise Runtime;
}
}
}
}
case (JSAny): {
goto Runtime;
}
}
return AllocateJSObjectFromMap(map, properties);
}
label Runtime deferred {
return runtime::ObjectCreate(prototype, Undefined);
}
}
// ES6 section 19.1.2.11 Object.isExtensible ( O )
transitioning javascript builtin
ObjectIsExtensible(js-implicit context: Context)(object: JSAny): JSAny {

View File

@ -1130,7 +1130,7 @@ TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32(
return ReinterpretCast<Int32T>(value);
}
TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) {
TNode<BoolT> CodeStubAssembler::TaggedIsSmi(SloppyTNode<MaybeObject> a) {
STATIC_ASSERT(kSmiTagMask < kMaxUInt32);
return Word32Equal(
Word32And(TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)),
@ -1138,7 +1138,7 @@ TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) {
Int32Constant(0));
}
TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(TNode<MaybeObject> a) {
TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(SloppyTNode<MaybeObject> a) {
return Word32BinaryNot(TaggedIsSmi(a));
}
@ -1749,24 +1749,6 @@ TNode<HeapObject> CodeStubAssembler::LoadMapPrototype(SloppyTNode<Map> map) {
return LoadObjectField<HeapObject>(map, Map::kPrototypeOffset);
}
TNode<PrototypeInfo> CodeStubAssembler::LoadMapPrototypeInfo(
SloppyTNode<Map> map, Label* if_no_proto_info) {
Label if_strong_heap_object(this);
CSA_ASSERT(this, IsMap(map));
TNode<MaybeObject> maybe_prototype_info =
LoadMaybeWeakObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
TVARIABLE(Object, prototype_info);
DispatchMaybeObject(maybe_prototype_info, if_no_proto_info, if_no_proto_info,
if_no_proto_info, &if_strong_heap_object,
&prototype_info);
BIND(&if_strong_heap_object);
GotoIfNot(TaggedEqual(LoadMap(CAST(prototype_info.value())),
PrototypeInfoMapConstant()),
if_no_proto_info);
return CAST(prototype_info.value());
}
TNode<IntPtrT> CodeStubAssembler::LoadMapInstanceSizeInWords(
SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map));

View File

@ -915,14 +915,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Int32T> TruncateIntPtrToInt32(SloppyTNode<IntPtrT> value);
// Check a value for smi-ness
TNode<BoolT> TaggedIsSmi(TNode<MaybeObject> a);
TNode<BoolT> TaggedIsSmi(SloppyTNode<Object> a) {
return TaggedIsSmi(UncheckedCast<MaybeObject>(a));
}
TNode<BoolT> TaggedIsNotSmi(TNode<MaybeObject> a);
TNode<BoolT> TaggedIsNotSmi(SloppyTNode<Object> a) {
return TaggedIsNotSmi(UncheckedCast<MaybeObject>(a));
}
TNode<BoolT> TaggedIsSmi(SloppyTNode<MaybeObject> a);
TNode<BoolT> TaggedIsNotSmi(SloppyTNode<MaybeObject> a);
// Check that the value is a non-negative smi.
TNode<BoolT> TaggedIsPositiveSmi(SloppyTNode<Object> a);
// Check that a word has a word-aligned address.
@ -1071,9 +1066,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return CAST(
LoadFromObject(MachineTypeOf<T>::value, reference.object, offset));
}
template <class T, typename std::enable_if<
std::is_convertible<TNode<T>, TNode<UntaggedT>>::value,
int>::type = 0>
template <class T,
typename std::enable_if<
std::is_convertible<TNode<T>, TNode<UntaggedT>>::value ||
std::is_same<T, MaybeObject>::value,
int>::type = 0>
TNode<T> LoadReference(Reference reference) {
TNode<IntPtrT> offset =
IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag));
@ -1081,7 +1078,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
LoadFromObject(MachineTypeOf<T>::value, reference.object, offset));
}
template <class T, typename std::enable_if<
std::is_convertible<TNode<T>, TNode<Object>>::value,
std::is_convertible<TNode<T>, TNode<Object>>::value ||
std::is_same<T, MaybeObject>::value,
int>::type = 0>
void StoreReference(Reference reference, TNode<T> value) {
MachineRepresentation rep = MachineRepresentationOf<T>::value;
@ -1162,10 +1160,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<DescriptorArray> LoadMapDescriptors(SloppyTNode<Map> map);
// Load the prototype of a map.
TNode<HeapObject> LoadMapPrototype(SloppyTNode<Map> map);
// Load the prototype info of a map. The result has to be checked if it is a
// prototype info object or not.
TNode<PrototypeInfo> LoadMapPrototypeInfo(SloppyTNode<Map> map,
Label* if_has_no_proto_info);
// Load the instance size of a Map.
TNode<IntPtrT> LoadMapInstanceSizeInWords(SloppyTNode<Map> map);
// Load the inobject properties start of a Map (valid only for JSObjects).
@ -1224,10 +1218,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TVariable<Object>* extracted);
// See MaybeObject for semantics of these functions.
TNode<BoolT> IsStrong(TNode<MaybeObject> value);
// This variant is for overzealous checking.
TNode<BoolT> IsStrong(TNode<Object> value) {
return IsStrong(ReinterpretCast<MaybeObject>(value));
}
TNode<HeapObject> GetHeapObjectIfStrong(TNode<MaybeObject> value,
Label* if_not_strong);
@ -3513,10 +3503,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Support for printf-style debugging
void Print(const char* s);
void Print(const char* prefix, Node* tagged_value);
inline void Print(SloppyTNode<Object> tagged_value) {
return Print(nullptr, tagged_value);
}
inline void Print(TNode<MaybeObject> tagged_value) {
void Print(SloppyTNode<MaybeObject> tagged_value) {
return Print(nullptr, tagged_value);
}

View File

@ -231,7 +231,9 @@ class int31_t {
template <class T, class U>
struct is_subtype {
static const bool value = std::is_base_of<U, T>::value;
static const bool value =
std::is_base_of<U, T>::value || (std::is_same<U, MaybeObject>::value &&
std::is_convertible<T, Object>::value);
};
template <class T1, class T2, class U>
struct is_subtype<UnionT<T1, T2>, U> {
@ -301,19 +303,11 @@ struct types_have_common_values<UnionT<T1, T2>, UnionT<U1, U2>> {
types_have_common_values<T2, U2>::value;
};
template <class T>
struct types_have_common_values<T, MaybeObject> {
static const bool value = types_have_common_values<T, Object>::value;
};
template <class T>
struct types_have_common_values<MaybeObject, T> {
static const bool value = types_have_common_values<Object, T>::value;
};
// TNode<T> is an SSA value with the static type tag T, which is one of the
// following:
// - a subclass of internal::Object represents a tagged type
// - MaybeObject represents the type of all tagged values, including weak
// pointers.
// - a subclass of internal::Object represents a non-weak tagged type.
// - a subclass of internal::UntaggedT represents an untagged type
// - ExternalReference
// - PairT<T1, T2> for an operation returning two values, with types T1

View File

@ -32,6 +32,7 @@ static const char* const JSANY_TYPE_STRING = "JSAny";
static const char* const JSOBJECT_TYPE_STRING = "JSObject";
static const char* const SMI_TYPE_STRING = "Smi";
static const char* const TAGGED_TYPE_STRING = "Tagged";
static const char* const STRONG_TAGGED_TYPE_STRING = "StrongTagged";
static const char* const UNINITIALIZED_TYPE_STRING = "Uninitialized";
static const char* const RAWPTR_TYPE_STRING = "RawPtr";
static const char* const CONST_STRING_TYPE_STRING = "constexpr string";

View File

@ -3444,14 +3444,16 @@ void GenerateClassFieldVerifier(const std::string& class_name,
if (!f.generate_verify) return;
const Type* field_type = f.name_and_type.type;
// We only verify tagged types, not raw numbers or pointers. Note that this
// must check against GetObjectType not GetTaggedType, because Uninitialized
// is a Tagged but should not be verified.
if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType())) return;
// We only verify tagged types, not raw numbers or pointers.
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) return;
// Do not verify if the field may be uninitialized.
if (TypeOracle::GetUninitializedType()->IsSubtypeOf(field_type)) return;
if (f.index) {
if (f.index->type != TypeOracle::GetSmiType()) {
ReportError("Non-SMI values are not (yet) supported as indexes.");
const Type* index_type = f.index->type;
if (index_type != TypeOracle::GetSmiType()) {
Error("Expected type Smi for indexed field but found type ", *index_type)
.Position(f.pos);
}
// We already verified the index field because it was listed earlier, so we
// can assume it's safe to read here.
@ -3462,9 +3464,11 @@ void GenerateClassFieldVerifier(const std::string& class_name,
cc_contents << " {\n";
}
const char* object_type = f.is_weak ? "MaybeObject" : "Object";
bool maybe_object =
!f.name_and_type.type->IsSubtypeOf(TypeOracle::GetStrongTaggedType());
const char* object_type = maybe_object ? "MaybeObject" : "Object";
const char* verify_fn =
f.is_weak ? "VerifyMaybeObjectPointer" : "VerifyPointer";
maybe_object ? "VerifyMaybeObjectPointer" : "VerifyPointer";
const char* index_offset = f.index ? "i * kTaggedSize" : "0";
// Name the local var based on the field name for nicer CHECK output.
const std::string value = f.name_and_type.name + "__value";
@ -3483,10 +3487,11 @@ void GenerateClassFieldVerifier(const std::string& class_name,
// the Object type because it would not check anything beyond what we already
// checked with VerifyPointer.
if (f.name_and_type.type != TypeOracle::GetObjectType()) {
std::string type_check = f.is_weak ? value + ".IsWeakOrCleared()" : "";
std::string type_check = maybe_object ? value + ".IsWeakOrCleared()" : "";
std::string strong_value =
value + (f.is_weak ? ".GetHeapObjectOrSmi()" : "");
value + (maybe_object ? ".GetHeapObjectOrSmi()" : "");
for (const std::string& runtime_type : field_type->GetRuntimeTypes()) {
if (runtime_type == "MaybeObject") continue;
if (!type_check.empty()) type_check += " || ";
type_check += strong_value + ".Is" + runtime_type + "()";
}

View File

@ -169,6 +169,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Get().GetBuiltinType(TAGGED_TYPE_STRING);
}
static const Type* GetStrongTaggedType() {
return Get().GetBuiltinType(STRONG_TAGGED_TYPE_STRING);
}
static const Type* GetUninitializedType() {
return Get().GetBuiltinType(UNINITIALIZED_TYPE_STRING);
}

View File

@ -167,12 +167,12 @@ const ClassType* TypeVisitor::ComputeType(
ReportError("Extern class must extend another type.");
}
const Type* super_type = TypeVisitor::ComputeType(*decl->super);
if (super_type != TypeOracle::GetTaggedType()) {
if (super_type != TypeOracle::GetStrongTaggedType()) {
const ClassType* super_class = ClassType::DynamicCast(super_type);
if (!super_class) {
ReportError(
"class \"", decl->name->value,
"\" must extend either Tagged or an already declared class");
"\" must extend either StrongTagged or an already declared class");
}
if (super_class->HasUndefinedLayout() &&
!(decl->flags & ClassFlag::kUndefinedLayout)) {
@ -283,8 +283,11 @@ void TypeVisitor::VisitClassFieldsAndMethods(
field_expression.name_and_type.type->pos);
const Type* field_type = ComputeType(field_expression.name_and_type.type);
if (!(class_declaration->flags & ClassFlag::kExtern)) {
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
ReportError("non-extern classes do not support untagged fields");
if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType())) {
ReportError(
"non-extern classes only support subtypes of type Object, but "
"found type ",
*field_type);
}
if (field_expression.weak) {
ReportError("non-extern classes do not support weak fields");

View File

@ -241,7 +241,9 @@ class AbstractType final : public Type {
return nullptr;
}
std::vector<std::string> GetRuntimeTypes() const override { return {name()}; }
std::vector<std::string> GetRuntimeTypes() const override {
return {GetGeneratedTNodeTypeName()};
}
private:
friend class TypeOracle;

View File

@ -27,11 +27,13 @@ namespace torque_internal {
}
}
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
type StrongTagged extends Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends StrongTagged generates 'TNode<Smi>' constexpr 'Smi';
type Uninitialized extends Tagged;
@abstract
extern class HeapObject extends Tagged {
extern class HeapObject extends StrongTagged {
map: Map;
}
type Map extends HeapObject generates 'TNode<Map>';