Commit 1b04772f authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[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/+/1889870Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64876}
parent 3568e444
...@@ -24,8 +24,22 @@ ...@@ -24,8 +24,22 @@
type void; type void;
type never; type never;
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr'; type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi'; 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. // A Smi that is greater than or equal to 0. See TaggedIsPositiveSmi.
type PositiveSmi extends Smi; type PositiveSmi extends Smi;
...@@ -36,12 +50,18 @@ type Zero extends PositiveSmi; ...@@ -36,12 +50,18 @@ type Zero extends PositiveSmi;
// A value with the size of Tagged which may contain arbitrary data. // A value with the size of Tagged which may contain arbitrary data.
type Uninitialized extends Tagged; type Uninitialized extends Tagged;
@abstract extern macro MakeWeak(HeapObject): WeakHeapObject;
extern class HeapObject extends Tagged { extern macro GetHeapObjectAssumeWeak(WeakHeapObject):
map: Map; 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 // Defined to coincide with https://tc39.es/ecma262/#sec-ispropertykey
// Doesn't include PrivateSymbol. // Doesn't include PrivateSymbol.
...@@ -260,6 +280,8 @@ extern class FixedArray extends FixedArrayBase { ...@@ -260,6 +280,8 @@ extern class FixedArray extends FixedArrayBase {
objects[length]: Object; objects[length]: Object;
} }
type EmptyFixedArray extends FixedArray;
extern class FixedDoubleArray extends FixedArrayBase { extern class FixedDoubleArray extends FixedArrayBase {
floats[length]: float64; floats[length]: float64;
} }
...@@ -287,6 +309,23 @@ extern class TransitionArray extends WeakFixedArray; ...@@ -287,6 +309,23 @@ extern class TransitionArray extends WeakFixedArray;
type InstanceType extends uint16 constexpr 'v8::internal::InstanceType'; type InstanceType extends uint16 constexpr 'v8::internal::InstanceType';
extern class Map extends HeapObject { 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; instance_size_in_words: uint8;
in_object_properties_start_or_constructor_function_index: uint8; in_object_properties_start_or_constructor_function_index: uint8;
used_or_unused_instance_size_in_words: uint8; used_or_unused_instance_size_in_words: uint8;
...@@ -299,16 +338,20 @@ extern class Map extends HeapObject { ...@@ -299,16 +338,20 @@ extern class Map extends HeapObject {
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void; @ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
prototype: HeapObject; prototype: JSReceiver|Null;
constructor_or_back_pointer_or_native_context: Object; constructor_or_back_pointer_or_native_context: Object;
instance_descriptors: DescriptorArray; instance_descriptors: DescriptorArray;
@if(V8_DOUBLE_FIELDS_UNBOXING) layout_descriptor: LayoutDescriptor; @if(V8_DOUBLE_FIELDS_UNBOXING) layout_descriptor: LayoutDescriptor;
@ifnot(V8_DOUBLE_FIELDS_UNBOXING) layout_descriptor: void; @ifnot(V8_DOUBLE_FIELDS_UNBOXING) layout_descriptor: void;
dependent_code: DependentCode; dependent_code: DependentCode;
prototype_validity_cell: Smi|Cell; prototype_validity_cell: Smi|Cell;
// TODO(v8:9108): Misusing "weak" keyword; type should be weak transitions_or_prototype_info: Map|Weak<Map>|TransitionArray|
// Map | Weak<Map> | TransitionArray | PrototypeInfo | Smi. PrototypeInfo|Smi;
weak transitions_or_prototype_info: Map|TransitionArray|PrototypeInfo|Smi; }
@export
macro LoadMapPrototypeInfo(m: Map): PrototypeInfo labels HasNoPrototypeInfo {
return m.PrototypeInfo() otherwise HasNoPrototypeInfo;
} }
@generatePrint @generatePrint
...@@ -457,7 +500,7 @@ macro GetDerivedMap(implicit context: Context)( ...@@ -457,7 +500,7 @@ macro GetDerivedMap(implicit context: Context)(
macro AllocateFastOrSlowJSObjectFromMap(implicit context: Context)(map: Map): macro AllocateFastOrSlowJSObjectFromMap(implicit context: Context)(map: Map):
JSObject { JSObject {
let properties = kEmptyFixedArray; let properties: EmptyFixedArray|NameDictionary = kEmptyFixedArray;
if (IsDictionaryMap(map)) { if (IsDictionaryMap(map)) {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity); properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
} }
...@@ -714,8 +757,7 @@ extern class JSMessageObject extends JSObject { ...@@ -714,8 +757,7 @@ extern class JSMessageObject extends JSObject {
extern class WeakArrayList extends HeapObject { extern class WeakArrayList extends HeapObject {
capacity: Smi; capacity: Smi;
length: 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 { extern class PrototypeInfo extends Struct {
...@@ -723,11 +765,18 @@ extern class PrototypeInfo extends Struct { ...@@ -723,11 +765,18 @@ extern class PrototypeInfo extends Struct {
prototype_users: WeakArrayList|Zero; prototype_users: WeakArrayList|Zero;
registry_slot: Smi; registry_slot: Smi;
validity_cell: Object; validity_cell: Object;
// TODO(v8:9108): Should be Weak<Map> | Undefined. object_create_map: Weak<Map>|Undefined;
@noVerifier object_create_map: Map|Undefined;
bit_field: Smi; 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 { extern class Script extends Struct {
source: Object; source: Object;
name: Object; name: Object;
...@@ -872,6 +921,8 @@ const REGEXP_LAST_MATCH_INFO_INDEX: constexpr NativeContextSlot ...@@ -872,6 +921,8 @@ const REGEXP_LAST_MATCH_INFO_INDEX: constexpr NativeContextSlot
generates 'Context::REGEXP_LAST_MATCH_INFO_INDEX'; generates 'Context::REGEXP_LAST_MATCH_INFO_INDEX';
const INITIAL_STRING_ITERATOR_MAP_INDEX: constexpr NativeContextSlot const INITIAL_STRING_ITERATOR_MAP_INDEX: constexpr NativeContextSlot
generates 'Context::INITIAL_STRING_ITERATOR_MAP_INDEX'; 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( extern operator '[]' macro LoadContextElement(
NativeContext, NativeContextSlot): Object; NativeContext, NativeContextSlot): Object;
extern operator '[]=' macro StoreContextElement( extern operator '[]=' macro StoreContextElement(
...@@ -1102,10 +1153,9 @@ extern class DataHandler extends Struct { ...@@ -1102,10 +1153,9 @@ extern class DataHandler extends Struct {
validity_cell: Smi|Cell; validity_cell: Smi|Cell;
// Space for the following fields may or may not be allocated. // Space for the following fields may or may not be allocated.
// TODO(v8:9108): Misusing "weak" keyword; should be MaybeObject. @noVerifier data_1: MaybeObject;
@noVerifier weak data_1: Object; @noVerifier data_2: MaybeObject;
@noVerifier weak data_2: Object; @noVerifier data_3: MaybeObject;
@noVerifier weak data_3: Object;
} }
extern class LoadHandler extends DataHandler; extern class LoadHandler extends DataHandler;
...@@ -1741,8 +1791,7 @@ extern class DebugInfo extends Struct { ...@@ -1741,8 +1791,7 @@ extern class DebugInfo extends Struct {
extern class FeedbackVector extends HeapObject { extern class FeedbackVector extends HeapObject {
shared_function_info: SharedFunctionInfo; shared_function_info: SharedFunctionInfo;
// TODO(v8:9108): currently no support for MaybeObject in Torque optimized_code_weak_or_smi: Weak<Code>|Smi;
@noVerifier optimized_code_weak_or_smi: Object;
closure_feedback_cell_array: FixedArray; closure_feedback_cell_array: FixedArray;
length: int32; length: int32;
invocation_count: int32; invocation_count: int32;
...@@ -2122,14 +2171,16 @@ extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool; ...@@ -2122,14 +2171,16 @@ extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool;
extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool; extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool;
extern operator '==' macro TaggedEqual( extern operator '==' macro TaggedEqual(
TaggedWithIdentity, TaggedWithIdentity): bool; TaggedWithIdentity, TaggedWithIdentity): bool;
extern operator '==' macro TaggedEqual(WeakHeapObject, WeakHeapObject): bool;
extern operator '!=' macro TaggedNotEqual(TaggedWithIdentity, Object): bool; extern operator '!=' macro TaggedNotEqual(TaggedWithIdentity, Object): bool;
extern operator '!=' macro TaggedNotEqual(Object, TaggedWithIdentity): bool; extern operator '!=' macro TaggedNotEqual(Object, TaggedWithIdentity): bool;
extern operator '!=' macro TaggedNotEqual( extern operator '!=' macro TaggedNotEqual(
TaggedWithIdentity, TaggedWithIdentity): bool; TaggedWithIdentity, TaggedWithIdentity): bool;
extern operator '!=' macro TaggedNotEqual(WeakHeapObject, WeakHeapObject): bool;
// Do not overload == and != if it is unclear if object identity is the right // Do not overload == and != if it is unclear if object identity is the right
// equality. // equality.
extern macro TaggedEqual(Object, Object): bool; extern macro TaggedEqual(MaybeObject, MaybeObject): bool;
extern macro TaggedNotEqual(Object, Object): bool; extern macro TaggedNotEqual(MaybeObject, MaybeObject): bool;
extern operator '+' macro SmiAdd(Smi, Smi): Smi; extern operator '+' macro SmiAdd(Smi, Smi): Smi;
extern operator '-' macro SmiSub(Smi, Smi): Smi; extern operator '-' macro SmiSub(Smi, Smi): Smi;
...@@ -2305,6 +2356,18 @@ extern macro HeapObjectToRegExpMatchInfo(HeapObject): ...@@ -2305,6 +2356,18 @@ extern macro HeapObjectToRegExpMatchInfo(HeapObject):
extern macro TaggedToNumber(Object): Number extern macro TaggedToNumber(Object): Number
labels CastError; 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 macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
labels CastError { labels CastError {
return Cast<A>(TaggedToHeapObject(o) otherwise CastError) return Cast<A>(TaggedToHeapObject(o) otherwise CastError)
...@@ -2333,8 +2396,8 @@ Cast<Number>(o: Object): Number ...@@ -2333,8 +2396,8 @@ Cast<Number>(o: Object): Number
Cast<Undefined>(o: Object): Undefined Cast<Undefined>(o: Object): Undefined
labels CastError { labels CastError {
if (o != Undefined) goto CastError; const o: MaybeObject = o;
return %RawDownCast<Undefined>(o); return Cast<Undefined>(o) otherwise CastError;
} }
Cast<Numeric>(o: Object): Numeric labels CastError { Cast<Numeric>(o: Object): Numeric labels CastError {
...@@ -2487,7 +2550,7 @@ Cast<Null>(o: HeapObject): Null ...@@ -2487,7 +2550,7 @@ Cast<Null>(o: HeapObject): Null
Cast<Undefined>(o: HeapObject): Undefined Cast<Undefined>(o: HeapObject): Undefined
labels CastError { labels CastError {
const o: Object = o; const o: MaybeObject = o;
return Cast<Undefined>(o) otherwise CastError; return Cast<Undefined>(o) otherwise CastError;
} }
...@@ -3199,13 +3262,13 @@ macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object): ...@@ -3199,13 +3262,13 @@ macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object):
extern macro FixedArrayMapConstant(): Map; extern macro FixedArrayMapConstant(): Map;
extern macro FixedCOWArrayMapConstant(): Map; extern macro FixedCOWArrayMapConstant(): Map;
extern macro EmptyByteArrayConstant(): ByteArray; extern macro EmptyByteArrayConstant(): ByteArray;
extern macro EmptyFixedArrayConstant(): FixedArray; extern macro EmptyFixedArrayConstant(): EmptyFixedArray;
extern macro PromiseCapabilityMapConstant(): Map; extern macro PromiseCapabilityMapConstant(): Map;
const kFixedArrayMap: Map = FixedArrayMapConstant(); const kFixedArrayMap: Map = FixedArrayMapConstant();
const kCOWMap: Map = FixedCOWArrayMapConstant(); const kCOWMap: Map = FixedCOWArrayMapConstant();
const kEmptyByteArray: ByteArray = EmptyByteArrayConstant(); const kEmptyByteArray: ByteArray = EmptyByteArrayConstant();
const kEmptyFixedArray: FixedArray = EmptyFixedArrayConstant(); const kEmptyFixedArray: EmptyFixedArray = EmptyFixedArrayConstant();
const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant(); const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant();
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map): extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
...@@ -3347,8 +3410,10 @@ extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray; ...@@ -3347,8 +3410,10 @@ extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
extern macro AllocateJSArray(Map, FixedArrayBase, Smi): JSArray; extern macro AllocateJSArray(Map, FixedArrayBase, Smi): JSArray;
extern macro AllocateJSObjectFromMap(Map): JSObject; extern macro AllocateJSObjectFromMap(Map): JSObject;
extern macro AllocateJSObjectFromMap( extern macro AllocateJSObjectFromMap(
Map, FixedArray | PropertyArray, FixedArray, constexpr AllocationFlags, Map, NameDictionary | EmptyFixedArray | PropertyArray): JSObject;
constexpr SlackTrackingMode): JSObject; extern macro AllocateJSObjectFromMap(
Map, NameDictionary | EmptyFixedArray | PropertyArray, FixedArray,
constexpr AllocationFlags, constexpr SlackTrackingMode): JSObject;
extern macro LoadDoubleWithHoleCheck(FixedDoubleArray, Smi): float64 extern macro LoadDoubleWithHoleCheck(FixedDoubleArray, Smi): float64
labels IfHole; labels IfHole;
......
...@@ -703,7 +703,6 @@ namespace internal { ...@@ -703,7 +703,6 @@ namespace internal {
TFJ(ObjectAssign, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ TFJ(ObjectAssign, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES #sec-object.create */ \ /* ES #sec-object.create */ \
TFJ(ObjectCreate, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ TFJ(ObjectCreate, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
TFS(CreateObjectWithoutProperties, kPrototypeArg) \
CPP(ObjectDefineGetter) \ CPP(ObjectDefineGetter) \
CPP(ObjectDefineProperties) \ CPP(ObjectDefineProperties) \
CPP(ObjectDefineProperty) \ CPP(ObjectDefineProperty) \
......
...@@ -1060,70 +1060,6 @@ TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) { ...@@ -1060,70 +1060,6 @@ TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
Return(ToObject_Inline(context, receiver)); 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 // ES #sec-object.create
TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) { TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
int const kPrototypeArg = 0; int const kPrototypeArg = 0;
......
...@@ -105,7 +105,8 @@ operator '==' macro FrameTypeEquals(f1: FrameType, f2: FrameType): bool { ...@@ -105,7 +105,8 @@ operator '==' macro FrameTypeEquals(f1: FrameType, f2: FrameType): bool {
return TaggedEqual(f1, f2); 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): Cast<StandardFrame>(implicit context: Context)(f: Frame):
StandardFrame labels CastError { StandardFrame labels CastError {
const o: HeapObject = const o: HeapObject =
......
...@@ -24,6 +24,9 @@ namespace runtime { ...@@ -24,6 +24,9 @@ namespace runtime {
extern transitioning runtime extern transitioning runtime
JSReceiverSetPrototypeOfDontThrow(implicit context: JSReceiverSetPrototypeOfDontThrow(implicit context:
Context)(JSReceiver, JSAny): JSAny; Context)(JSReceiver, JSAny): JSAny;
extern transitioning runtime ObjectCreate(implicit context:
Context)(JSAny, JSAny): JSAny;
} // namespace runtime } // namespace runtime
namespace object { namespace object {
...@@ -91,6 +94,48 @@ namespace object { ...@@ -91,6 +94,48 @@ namespace object {
return proxy::ProxySetPrototypeOf(objectJSProxy, proto, False); 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 ) // ES6 section 19.1.2.11 Object.isExtensible ( O )
transitioning javascript builtin transitioning javascript builtin
ObjectIsExtensible(js-implicit context: Context)(object: JSAny): JSAny { ObjectIsExtensible(js-implicit context: Context)(object: JSAny): JSAny {
......
...@@ -1130,7 +1130,7 @@ TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32( ...@@ -1130,7 +1130,7 @@ TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32(
return ReinterpretCast<Int32T>(value); return ReinterpretCast<Int32T>(value);
} }
TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) { TNode<BoolT> CodeStubAssembler::TaggedIsSmi(SloppyTNode<MaybeObject> a) {
STATIC_ASSERT(kSmiTagMask < kMaxUInt32); STATIC_ASSERT(kSmiTagMask < kMaxUInt32);
return Word32Equal( return Word32Equal(
Word32And(TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), Word32And(TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)),
...@@ -1138,7 +1138,7 @@ TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) { ...@@ -1138,7 +1138,7 @@ TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) {
Int32Constant(0)); Int32Constant(0));
} }
TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(TNode<MaybeObject> a) { TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(SloppyTNode<MaybeObject> a) {
return Word32BinaryNot(TaggedIsSmi(a)); return Word32BinaryNot(TaggedIsSmi(a));
} }
...@@ -1749,24 +1749,6 @@ TNode<HeapObject> CodeStubAssembler::LoadMapPrototype(SloppyTNode<Map> map) { ...@@ -1749,24 +1749,6 @@ TNode<HeapObject> CodeStubAssembler::LoadMapPrototype(SloppyTNode<Map> map) {
return LoadObjectField<HeapObject>(map, Map::kPrototypeOffset); 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( TNode<IntPtrT> CodeStubAssembler::LoadMapInstanceSizeInWords(
SloppyTNode<Map> map) { SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map)); CSA_SLOW_ASSERT(this, IsMap(map));
......
...@@ -915,14 +915,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -915,14 +915,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Int32T> TruncateIntPtrToInt32(SloppyTNode<IntPtrT> value); TNode<Int32T> TruncateIntPtrToInt32(SloppyTNode<IntPtrT> value);
// Check a value for smi-ness // Check a value for smi-ness
TNode<BoolT> TaggedIsSmi(TNode<MaybeObject> a); TNode<BoolT> TaggedIsSmi(SloppyTNode<MaybeObject> a);
TNode<BoolT> TaggedIsSmi(SloppyTNode<Object> a) { TNode<BoolT> TaggedIsNotSmi(SloppyTNode<MaybeObject> a);
return TaggedIsSmi(UncheckedCast<MaybeObject>(a));
}
TNode<BoolT> TaggedIsNotSmi(TNode<MaybeObject> a);
TNode<BoolT> TaggedIsNotSmi(SloppyTNode<Object> a) {
return TaggedIsNotSmi(UncheckedCast<MaybeObject>(a));
}
// Check that the value is a non-negative smi. // Check that the value is a non-negative smi.
TNode<BoolT> TaggedIsPositiveSmi(SloppyTNode<Object> a); TNode<BoolT> TaggedIsPositiveSmi(SloppyTNode<Object> a);
// Check that a word has a word-aligned address. // Check that a word has a word-aligned address.
...@@ -1071,9 +1066,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -1071,9 +1066,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return CAST( return CAST(
LoadFromObject(MachineTypeOf<T>::value, reference.object, offset)); LoadFromObject(MachineTypeOf<T>::value, reference.object, offset));
} }
template <class T, typename std::enable_if< template <class T,
std::is_convertible<TNode<T>, TNode<UntaggedT>>::value, typename std::enable_if<
int>::type = 0> std::is_convertible<TNode<T>, TNode<UntaggedT>>::value ||
std::is_same<T, MaybeObject>::value,
int>::type = 0>
TNode<T> LoadReference(Reference reference) { TNode<T> LoadReference(Reference reference) {
TNode<IntPtrT> offset = TNode<IntPtrT> offset =
IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag)); IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag));
...@@ -1081,7 +1078,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -1081,7 +1078,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
LoadFromObject(MachineTypeOf<T>::value, reference.object, offset)); LoadFromObject(MachineTypeOf<T>::value, reference.object, offset));
} }
template <class T, typename std::enable_if< 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> int>::type = 0>
void StoreReference(Reference reference, TNode<T> value) { void StoreReference(Reference reference, TNode<T> value) {
MachineRepresentation rep = MachineRepresentationOf<T>::value; MachineRepresentation rep = MachineRepresentationOf<T>::value;
...@@ -1162,10 +1160,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -1162,10 +1160,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<DescriptorArray> LoadMapDescriptors(SloppyTNode<Map> map); TNode<DescriptorArray> LoadMapDescriptors(SloppyTNode<Map> map);
// Load the prototype of a map. // Load the prototype of a map.
TNode<HeapObject> LoadMapPrototype(SloppyTNode<Map> 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. // Load the instance size of a Map.
TNode<IntPtrT> LoadMapInstanceSizeInWords(SloppyTNode<Map> map); TNode<IntPtrT> LoadMapInstanceSizeInWords(SloppyTNode<Map> map);
// Load the inobject properties start of a Map (valid only for JSObjects). // Load the inobject properties start of a Map (valid only for JSObjects).
...@@ -1224,10 +1218,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -1224,10 +1218,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TVariable<Object>* extracted); TVariable<Object>* extracted);
// See MaybeObject for semantics of these functions. // See MaybeObject for semantics of these functions.
TNode<BoolT> IsStrong(TNode<MaybeObject> value); 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, TNode<HeapObject> GetHeapObjectIfStrong(TNode<MaybeObject> value,
Label* if_not_strong); Label* if_not_strong);
...@@ -3513,10 +3503,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -3513,10 +3503,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Support for printf-style debugging // Support for printf-style debugging
void Print(const char* s); void Print(const char* s);
void Print(const char* prefix, Node* tagged_value); void Print(const char* prefix, Node* tagged_value);
inline void Print(SloppyTNode<Object> tagged_value) { void Print(SloppyTNode<MaybeObject> tagged_value) {
return Print(nullptr, tagged_value);
}
inline void Print(TNode<MaybeObject> tagged_value) {
return Print(nullptr, tagged_value); return Print(nullptr, tagged_value);
} }
......
...@@ -231,7 +231,9 @@ class int31_t { ...@@ -231,7 +231,9 @@ class int31_t {
template <class T, class U> template <class T, class U>
struct is_subtype { 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> template <class T1, class T2, class U>
struct is_subtype<UnionT<T1, T2>, U> { struct is_subtype<UnionT<T1, T2>, U> {
...@@ -301,19 +303,11 @@ struct types_have_common_values<UnionT<T1, T2>, UnionT<U1, U2>> { ...@@ -301,19 +303,11 @@ struct types_have_common_values<UnionT<T1, T2>, UnionT<U1, U2>> {
types_have_common_values<T2, U2>::value; 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 // TNode<T> is an SSA value with the static type tag T, which is one of the
// following: // 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 // - a subclass of internal::UntaggedT represents an untagged type
// - ExternalReference // - ExternalReference
// - PairT<T1, T2> for an operation returning two values, with types T1 // - PairT<T1, T2> for an operation returning two values, with types T1
......
...@@ -32,6 +32,7 @@ static const char* const JSANY_TYPE_STRING = "JSAny"; ...@@ -32,6 +32,7 @@ static const char* const JSANY_TYPE_STRING = "JSAny";
static const char* const JSOBJECT_TYPE_STRING = "JSObject"; static const char* const JSOBJECT_TYPE_STRING = "JSObject";
static const char* const SMI_TYPE_STRING = "Smi"; static const char* const SMI_TYPE_STRING = "Smi";
static const char* const TAGGED_TYPE_STRING = "Tagged"; 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 UNINITIALIZED_TYPE_STRING = "Uninitialized";
static const char* const RAWPTR_TYPE_STRING = "RawPtr"; static const char* const RAWPTR_TYPE_STRING = "RawPtr";
static const char* const CONST_STRING_TYPE_STRING = "constexpr string"; static const char* const CONST_STRING_TYPE_STRING = "constexpr string";
......
...@@ -3444,14 +3444,16 @@ void GenerateClassFieldVerifier(const std::string& class_name, ...@@ -3444,14 +3444,16 @@ void GenerateClassFieldVerifier(const std::string& class_name,
if (!f.generate_verify) return; if (!f.generate_verify) return;
const Type* field_type = f.name_and_type.type; const Type* field_type = f.name_and_type.type;
// We only verify tagged types, not raw numbers or pointers. Note that this // We only verify tagged types, not raw numbers or pointers.
// must check against GetObjectType not GetTaggedType, because Uninitialized if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) return;
// is a Tagged but should not be verified. // Do not verify if the field may be uninitialized.
if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType())) return; if (TypeOracle::GetUninitializedType()->IsSubtypeOf(field_type)) return;
if (f.index) { if (f.index) {
if (f.index->type != TypeOracle::GetSmiType()) { const Type* index_type = f.index->type;
ReportError("Non-SMI values are not (yet) supported as indexes."); 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 // We already verified the index field because it was listed earlier, so we
// can assume it's safe to read here. // can assume it's safe to read here.
...@@ -3462,9 +3464,11 @@ void GenerateClassFieldVerifier(const std::string& class_name, ...@@ -3462,9 +3464,11 @@ void GenerateClassFieldVerifier(const std::string& class_name,
cc_contents << " {\n"; 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 = const char* verify_fn =
f.is_weak ? "VerifyMaybeObjectPointer" : "VerifyPointer"; maybe_object ? "VerifyMaybeObjectPointer" : "VerifyPointer";
const char* index_offset = f.index ? "i * kTaggedSize" : "0"; const char* index_offset = f.index ? "i * kTaggedSize" : "0";
// Name the local var based on the field name for nicer CHECK output. // Name the local var based on the field name for nicer CHECK output.
const std::string value = f.name_and_type.name + "__value"; const std::string value = f.name_and_type.name + "__value";
...@@ -3483,10 +3487,11 @@ void GenerateClassFieldVerifier(const std::string& class_name, ...@@ -3483,10 +3487,11 @@ void GenerateClassFieldVerifier(const std::string& class_name,
// the Object type because it would not check anything beyond what we already // the Object type because it would not check anything beyond what we already
// checked with VerifyPointer. // checked with VerifyPointer.
if (f.name_and_type.type != TypeOracle::GetObjectType()) { 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 = std::string strong_value =
value + (f.is_weak ? ".GetHeapObjectOrSmi()" : ""); value + (maybe_object ? ".GetHeapObjectOrSmi()" : "");
for (const std::string& runtime_type : field_type->GetRuntimeTypes()) { for (const std::string& runtime_type : field_type->GetRuntimeTypes()) {
if (runtime_type == "MaybeObject") continue;
if (!type_check.empty()) type_check += " || "; if (!type_check.empty()) type_check += " || ";
type_check += strong_value + ".Is" + runtime_type + "()"; type_check += strong_value + ".Is" + runtime_type + "()";
} }
......
...@@ -169,6 +169,10 @@ class TypeOracle : public ContextualClass<TypeOracle> { ...@@ -169,6 +169,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Get().GetBuiltinType(TAGGED_TYPE_STRING); return Get().GetBuiltinType(TAGGED_TYPE_STRING);
} }
static const Type* GetStrongTaggedType() {
return Get().GetBuiltinType(STRONG_TAGGED_TYPE_STRING);
}
static const Type* GetUninitializedType() { static const Type* GetUninitializedType() {
return Get().GetBuiltinType(UNINITIALIZED_TYPE_STRING); return Get().GetBuiltinType(UNINITIALIZED_TYPE_STRING);
} }
......
...@@ -167,12 +167,12 @@ const ClassType* TypeVisitor::ComputeType( ...@@ -167,12 +167,12 @@ const ClassType* TypeVisitor::ComputeType(
ReportError("Extern class must extend another type."); ReportError("Extern class must extend another type.");
} }
const Type* super_type = TypeVisitor::ComputeType(*decl->super); 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); const ClassType* super_class = ClassType::DynamicCast(super_type);
if (!super_class) { if (!super_class) {
ReportError( ReportError(
"class \"", decl->name->value, "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() && if (super_class->HasUndefinedLayout() &&
!(decl->flags & ClassFlag::kUndefinedLayout)) { !(decl->flags & ClassFlag::kUndefinedLayout)) {
...@@ -283,8 +283,11 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -283,8 +283,11 @@ void TypeVisitor::VisitClassFieldsAndMethods(
field_expression.name_and_type.type->pos); field_expression.name_and_type.type->pos);
const Type* field_type = ComputeType(field_expression.name_and_type.type); const Type* field_type = ComputeType(field_expression.name_and_type.type);
if (!(class_declaration->flags & ClassFlag::kExtern)) { if (!(class_declaration->flags & ClassFlag::kExtern)) {
if (!field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) { if (!field_type->IsSubtypeOf(TypeOracle::GetObjectType())) {
ReportError("non-extern classes do not support untagged fields"); ReportError(
"non-extern classes only support subtypes of type Object, but "
"found type ",
*field_type);
} }
if (field_expression.weak) { if (field_expression.weak) {
ReportError("non-extern classes do not support weak fields"); ReportError("non-extern classes do not support weak fields");
......
...@@ -241,7 +241,9 @@ class AbstractType final : public Type { ...@@ -241,7 +241,9 @@ class AbstractType final : public Type {
return nullptr; return nullptr;
} }
std::vector<std::string> GetRuntimeTypes() const override { return {name()}; } std::vector<std::string> GetRuntimeTypes() const override {
return {GetGeneratedTNodeTypeName()};
}
private: private:
friend class TypeOracle; friend class TypeOracle;
......
...@@ -27,11 +27,13 @@ namespace torque_internal { ...@@ -27,11 +27,13 @@ namespace torque_internal {
} }
} }
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr'; type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi'; type StrongTagged extends Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends StrongTagged generates 'TNode<Smi>' constexpr 'Smi';
type Uninitialized extends Tagged;
@abstract @abstract
extern class HeapObject extends Tagged { extern class HeapObject extends StrongTagged {
map: Map; map: Map;
} }
type Map extends HeapObject generates 'TNode<Map>'; type Map extends HeapObject generates 'TNode<Map>';
......
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