[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:
parent
3568e4441c
commit
1b04772f7f
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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 + "()";
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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>';
|
||||
|
Loading…
Reference in New Issue
Block a user