Commit 1052dfb3 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque] generate Cast<> macros from Torque-defined classes

This change enables automatic generation of Cast<> operators for
classes that are defined in Torque.

* Cast<> macros are generated for all classes that are defined in
  Torque code that are neither shapes nor marked with a new
  @doNotGenerateCast annotation.

* Implicitly generated Cast macros simply call through to an
  internally-defined "DownCastForTorqueClass" macro that implements
  the cast using one of three strategies for efficiency. If the class
  has subclasses (i.e. a range of instance types including subtypes),
  the DownCastForTorqueClass checks for inclusion in the instance type
  range. If the class has a single instance type (i.e. no subclasses),
  then either 1) a map check is used if the class has a globally-
  defined map constant or 2) an equality check for the instance type
  is used.

* Added new intrinsics to introspect class information, e.g. fetching
  instance type ranges for a class, accessing the globally-defined map
  for a class.

* Removed a whole pile of existing explicit Cast<> operators that are
  no longer needed because of the implicitly generated Cast<> macros.

* Added tests for the new Cast<> implementations.

Bug: v8:7793
Change-Id: I3aadb0c62b720e9de4e7978b9ec4f05075771b8b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2250239
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68478}
parent 443e37ac
......@@ -418,7 +418,7 @@ macro LoadJoinStack(implicit context: Context)(): FixedArray
const stack: HeapObject = UnsafeCast<HeapObject>(
nativeContext[NativeContextSlot::ARRAY_JOIN_STACK_INDEX]);
if (stack == Undefined) goto IfUninitialized;
assert(IsFixedArray(stack));
assert(Is<FixedArray>(stack));
return UnsafeCast<FixedArray>(stack);
}
......
......@@ -135,6 +135,7 @@ const kDoubleHole: float64_or_hole = float64_or_hole{is_hole: true, value: 0};
// The HashTable inheritance hierarchy doesn't actually look like this in C++
// because it uses some class templates that we can't yet (and may never)
// express in Torque, but this is the expected organization of instance types.
@doNotGenerateCast
extern class HashTable extends FixedArray generates 'TNode<FixedArray>';
extern class OrderedHashMap extends HashTable;
extern class OrderedHashSet extends HashTable;
......@@ -805,6 +806,8 @@ extern operator '+' macro ConstexprInt31Add(
constexpr int31, constexpr int31): constexpr int31;
extern operator '*' macro ConstexprInt31Mul(
constexpr int31, constexpr int31): constexpr int31;
extern operator '-' macro Int32Sub(int16, int16): int32;
extern operator '-' macro Int32Sub(uint16, uint16): int32;
extern operator '-' macro Int32Sub(int32, int32): int32;
extern operator '*' macro Int32Mul(int32, int32): int32;
extern operator '/' macro Int32Div(int32, int32): int32;
......@@ -878,6 +881,12 @@ extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool;
extern operator '!' macro Word32BinaryNot(bool): bool;
extern operator '!' macro IsFalse(Boolean): bool;
extern operator '==' macro
ConstexprInt31Equal(
constexpr InstanceType, constexpr InstanceType): constexpr bool;
extern operator '-' macro ConstexprUint32Sub(
constexpr InstanceType, constexpr InstanceType): constexpr int32;
extern operator '.instanceType' macro LoadInstanceType(HeapObject):
InstanceType;
......@@ -969,6 +978,7 @@ extern macro NumberConstant(constexpr int32): Number;
extern macro NumberConstant(constexpr uint32): Number;
extern macro IntPtrConstant(constexpr int31): intptr;
extern macro IntPtrConstant(constexpr int32): intptr;
extern macro Uint16Constant(constexpr uint16): uint16;
extern macro Int32Constant(constexpr int31): int31;
extern macro Int32Constant(constexpr int32): int32;
extern macro Float64Constant(constexpr int31): float64;
......@@ -993,22 +1003,6 @@ extern macro BitcastWordToTagged(uintptr): Object;
extern macro BitcastTaggedToWord(Tagged): intptr;
extern macro BitcastTaggedToWordForTagAndSmiBits(Tagged): intptr;
macro Is<A : type extends Object, B : type extends Object>(
implicit context: Context)(o: B): bool {
Cast<A>(o) otherwise return false;
return true;
}
macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object):
A {
assert(Is<A>(o));
return %RawDownCast<A>(o);
}
macro UnsafeConstCast<T: type>(r: const &T):&T {
return %RawDownCast<&T>(r);
}
extern macro FixedArrayMapConstant(): Map;
extern macro FixedDoubleArrayMapConstant(): Map;
extern macro FixedCOWArrayMapConstant(): Map;
......
......@@ -13,6 +13,7 @@ type BigInt extends BigIntBase;
@noVerifier
@hasSameInstanceTypeAsParent
@doNotGenerateCast
extern class MutableBigInt extends BigIntBase generates 'TNode<BigInt>' {
}
......
This diff is collapsed.
......@@ -94,6 +94,10 @@ FromConstexpr<PromiseState, constexpr PromiseState>(c: constexpr PromiseState):
PromiseState {
return %RawDownCast<PromiseState>(Int32Constant(c));
}
FromConstexpr<InstanceType, constexpr InstanceType>(c: constexpr InstanceType):
InstanceType {
return %RawDownCast<InstanceType>(Uint16Constant(c));
}
FromConstexpr<IterationKind, constexpr IterationKind>(
c: constexpr IterationKind): IterationKind {
......
......@@ -186,6 +186,28 @@ macro StoreFloat64OrHole(r:&float64_or_hole, value: float64_or_hole) {
* unsafe::NewReference<float64>(r.object, r.offset) = value.value;
}
}
macro DownCastForTorqueClass<T : type extends HeapObject>(o: HeapObject):
T labels CastError {
const map = o.map;
const minInstanceType = %MinInstanceType<T>();
const maxInstanceType = %MaxInstanceType<T>();
if constexpr (minInstanceType == maxInstanceType) {
if constexpr (%ClassHasMapConstant<T>()) {
if (map != %GetClassMapConstant<T>()) goto CastError;
} else {
if (map.instance_type != minInstanceType) goto CastError;
}
} else {
const diff: int32 = maxInstanceType - minInstanceType;
const offset = Convert<int32>(Convert<uint16>(map.instance_type)) -
Convert<int32>(Convert<uint16>(
FromConstexpr<InstanceType>(minInstanceType)));
if (Unsigned(offset) > Unsigned(diff)) goto CastError;
}
return %RawDownCast<T>(o);
}
} // namespace torque_internal
// Indicates that an array-field should not be initialized.
......@@ -198,6 +220,12 @@ struct UninitializedIterator {}
intrinsic %RawDownCast<To: type, From: type>(x: From): To;
intrinsic %RawConstexprCast<To: type, From: type>(f: From): To;
intrinsic %MinInstanceType<T: type>(): constexpr InstanceType;
intrinsic %MaxInstanceType<T: type>(): constexpr InstanceType;
intrinsic %ClassHasMapConstant<T: type>(): constexpr bool;
intrinsic %GetClassMapConstant<T: type>(): Map;
struct IteratorSequence<T: type, FirstIterator: type, SecondIterator: type> {
macro Empty(): bool {
return this.first.Empty() && this.second.Empty();
......
......@@ -6111,11 +6111,6 @@ TNode<BoolT> CodeStubAssembler::IsAccessorPair(SloppyTNode<HeapObject> object) {
return IsAccessorPairMap(LoadMap(object));
}
TNode<BoolT> CodeStubAssembler::IsAllocationSite(
SloppyTNode<HeapObject> object) {
return IsAllocationSiteInstanceType(LoadInstanceType(object));
}
TNode<BoolT> CodeStubAssembler::IsHeapNumber(SloppyTNode<HeapObject> object) {
return IsHeapNumberMap(LoadMap(object));
}
......@@ -6296,11 +6291,6 @@ TNode<BoolT> CodeStubAssembler::IsJSFunctionInstanceType(
return InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsAllocationSiteInstanceType(
SloppyTNode<Int32T> instance_type) {
return InstanceTypeEqual(instance_type, ALLOCATION_SITE_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsJSFunction(SloppyTNode<HeapObject> object) {
return IsJSFunctionMap(LoadMap(object));
}
......
......@@ -107,6 +107,10 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(TypedArraySpeciesProtector, typed_array_species_protector, \
TypedArraySpeciesProtector)
#define UNIQUE_INSTANCE_TYPE_IMMUTABLE_IMMOVABLE_MAP_ADAPTER( \
V, rootIndexName, rootAccessorName, class_name) \
V(rootIndexName, rootAccessorName, class_name##Map)
#define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
......@@ -232,7 +236,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(valueOf_string, valueOf_string, ValueOfString) \
V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap) \
V(zero_string, zero_string, ZeroString) \
TORQUE_INTERNAL_MAP_CSA_LIST(V)
UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR( \
UNIQUE_INSTANCE_TYPE_IMMUTABLE_IMMOVABLE_MAP_ADAPTER, V)
#define HEAP_IMMOVABLE_OBJECT_LIST(V) \
HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \
......@@ -470,16 +475,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return UncheckedCast<HeapObject>(value);
}
TNode<JSArray> HeapObjectToJSArray(TNode<HeapObject> heap_object,
Label* fail) {
GotoIfNot(IsJSArray(heap_object), fail);
return UncheckedCast<JSArray>(heap_object);
}
TNode<JSArrayBuffer> HeapObjectToJSArrayBuffer(TNode<HeapObject> heap_object,
Label* fail) {
GotoIfNot(IsJSArrayBuffer(heap_object), fail);
return UncheckedCast<JSArrayBuffer>(heap_object);
TNode<Uint16T> Uint16Constant(uint16_t t) {
return UncheckedCast<Uint16T>(Int32Constant(t));
}
TNode<JSArray> TaggedToFastJSArray(TNode<Context> context,
......@@ -2178,17 +2175,21 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return UncheckedCast<FixedDoubleArray>(base);
}
TNode<SloppyArgumentsElements> HeapObjectToSloppyArgumentsElements(
TNode<HeapObject> base, Label* cast_fail) {
GotoIf(TaggedNotEqual(LoadMap(base), SloppyArgumentsElementsMapConstant()),
cast_fail);
return UncheckedCast<SloppyArgumentsElements>(base);
}
TNode<Int32T> ConvertElementsKindToInt(TNode<Int32T> elements_kind) {
return UncheckedCast<Int32T>(elements_kind);
}
template <typename T>
bool ClassHasMapConstant() {
return false;
}
template <typename T>
TNode<Map> GetClassMapConstant() {
UNREACHABLE();
return TNode<Map>();
}
enum class ExtractFixedArrayFlag {
kFixedArrays = 1,
kFixedDoubleArrays = 2,
......@@ -2525,7 +2526,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> InstanceTypeEqual(SloppyTNode<Int32T> instance_type, int type);
TNode<BoolT> IsAccessorInfo(SloppyTNode<HeapObject> object);
TNode<BoolT> IsAccessorPair(SloppyTNode<HeapObject> object);
TNode<BoolT> IsAllocationSite(SloppyTNode<HeapObject> object);
TNode<BoolT> IsNoElementsProtectorCellInvalid();
TNode<BoolT> IsArrayIteratorProtectorCellInvalid();
TNode<BoolT> IsBigIntInstanceType(SloppyTNode<Int32T> instance_type);
......@@ -2573,7 +2573,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsJSArrayIterator(SloppyTNode<HeapObject> object);
TNode<BoolT> IsJSAsyncGeneratorObject(SloppyTNode<HeapObject> object);
TNode<BoolT> IsJSFunctionInstanceType(SloppyTNode<Int32T> instance_type);
TNode<BoolT> IsAllocationSiteInstanceType(SloppyTNode<Int32T> instance_type);
TNode<BoolT> IsJSFunctionMap(SloppyTNode<Map> map);
TNode<BoolT> IsJSFunction(SloppyTNode<HeapObject> object);
TNode<BoolT> IsJSBoundFunction(SloppyTNode<HeapObject> object);
......@@ -3720,6 +3719,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
bool ConstexprInt32NotEqual(int32_t a, int32_t b) { return a != b; }
bool ConstexprInt32GreaterThanEqual(int32_t a, int32_t b) { return a >= b; }
uint32_t ConstexprUint32Add(uint32_t a, uint32_t b) { return a + b; }
int32_t ConstexprUint32Sub(uint32_t a, uint32_t b) { return a - b; }
int31_t ConstexprInt31Add(int31_t a, int31_t b) {
int32_t val;
CHECK(!base::bits::SignedAddOverflow32(a, b, &val));
......@@ -4131,6 +4131,19 @@ class PrototypeCheckAssembler : public CodeStubAssembler {
DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags)
#define CLASS_MAP_CONSTANT_ADAPTER(V, rootIndexName, rootAccessorName, \
class_name) \
template <> \
inline bool CodeStubAssembler::ClassHasMapConstant<class_name>() { \
return true; \
} \
template <> \
inline TNode<Map> CodeStubAssembler::GetClassMapConstant<class_name>() { \
return class_name##MapConstant(); \
}
UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(CLASS_MAP_CONSTANT_ADAPTER, _)
} // namespace internal
} // namespace v8
#endif // V8_CODEGEN_CODE_STUB_ASSEMBLER_H_
......@@ -75,7 +75,7 @@ class PromiseReactionJobTask;
class PromiseRejectReactionJobTask;
class Zone;
#define MAKE_FORWARD_DECLARATION(Name) class Name;
TORQUE_INTERNAL_CLASS_LIST(MAKE_FORWARD_DECLARATION)
TORQUE_DEFINED_CLASS_LIST(MAKE_FORWARD_DECLARATION)
#undef MAKE_FORWARD_DECLARATION
template <typename T>
......
......@@ -370,7 +370,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case PROMISE_REJECT_REACTION_JOB_TASK_TYPE:
case PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE:
#define MAKE_TORQUE_CLASS_TYPE(INSTANCE_TYPE, Name, name) case INSTANCE_TYPE:
TORQUE_INTERNAL_INSTANCE_TYPE_LIST(MAKE_TORQUE_CLASS_TYPE)
TORQUE_DEFINED_INSTANCE_TYPE_LIST(MAKE_TORQUE_CLASS_TYPE)
#undef MAKE_TORQUE_CLASS_TYPE
UNREACHABLE();
}
......
......@@ -421,12 +421,12 @@ bool Heap::CreateInitialMaps() {
#define TORQUE_ALLOCATE_MAP(NAME, Name, name) \
ALLOCATE_MAP(NAME, Name::kSize, name)
TORQUE_INTERNAL_FIXED_INSTANCE_TYPE_LIST(TORQUE_ALLOCATE_MAP);
TORQUE_DEFINED_FIXED_INSTANCE_TYPE_LIST(TORQUE_ALLOCATE_MAP);
#undef TORQUE_ALLOCATE_MAP
#define TORQUE_ALLOCATE_VARSIZE_MAP(NAME, Name, name) \
ALLOCATE_VARSIZE_MAP(NAME, name)
TORQUE_INTERNAL_VARSIZE_INSTANCE_TYPE_LIST(TORQUE_ALLOCATE_VARSIZE_MAP);
TORQUE_DEFINED_VARSIZE_INSTANCE_TYPE_LIST(TORQUE_ALLOCATE_VARSIZE_MAP);
#undef TORQUE_ALLOCATE_VARSIZE_MAP
ALLOCATE_VARSIZE_MAP(CODE_TYPE, code)
......
......@@ -36,11 +36,13 @@ extern class ByteArray extends FixedArrayBase {
@hasSameInstanceTypeAsParent
@generateCppClass
@doNotGenerateCast
extern class ArrayList extends FixedArray {
}
@hasSameInstanceTypeAsParent
@generateCppClass
@doNotGenerateCast
extern class TemplateList extends FixedArray {
}
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
@abstract
@doNotGenerateCast
extern class HeapObject extends StrongTagged {
const map: Map;
}
......@@ -243,6 +243,11 @@ TYPED_ARRAYS(TYPED_ARRAY_IS_TYPE_FUNCTION_DECL)
#undef IS_TYPE_FUNCTION_DECL
} // namespace InstanceTypeChecker
// This list must contain only maps that are shared by all objects of their
// instance type.
#define UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(V, _) \
TORQUE_DEFINED_MAP_CSA_LIST_GENERATOR(V, _)
} // namespace internal
} // namespace v8
......
......@@ -91,7 +91,7 @@ Map Map::GetInstanceTypeMap(ReadOnlyRoots roots, InstanceType type) {
case TYPE: \
map = roots.name##_map(); \
break;
TORQUE_INTERNAL_INSTANCE_TYPE_LIST(MAKE_CASE)
TORQUE_DEFINED_INSTANCE_TYPE_LIST(MAKE_CASE)
#undef MAKE_CASE
default:
UNREACHABLE();
......
......@@ -236,7 +236,7 @@ class ZoneForwardList;
V(WeakFixedArray) \
V(WeakArrayList) \
V(WeakCell) \
TORQUE_INTERNAL_CLASS_LIST(V)
TORQUE_DEFINED_CLASS_LIST(V)
#ifdef V8_INTL_SUPPORT
#define HEAP_OBJECT_ORDINARY_TYPE_LIST(V) \
......
......@@ -29,11 +29,3 @@ extern class PrototypeInfo extends Struct {
bit_field: SmiTagged<PrototypeInfoFlags>;
}
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);
}
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
@hasSameInstanceTypeAsParent
@doNotGenerateCast
extern class RegExpMatchInfo extends FixedArray {
macro GetStartOfCapture(implicit context: Context)(captureIndex:
constexpr int31): Smi {
......
......@@ -11,6 +11,7 @@ extern class String extends Name {
@generateCppClass
@generateBodyDescriptor
@doNotGenerateCast
extern class ConsString extends String {
first: String;
second: String;
......@@ -18,35 +19,46 @@ extern class ConsString extends String {
@abstract
@generateBodyDescriptor
@doNotGenerateCast
extern class ExternalString extends String {
resource: ExternalPointer;
resource_data: ExternalPointer;
}
extern class ExternalOneByteString extends ExternalString {}
extern class ExternalTwoByteString extends ExternalString {}
@doNotGenerateCast
extern class ExternalOneByteString extends ExternalString {
}
@doNotGenerateCast
extern class ExternalTwoByteString extends ExternalString {
}
@generateCppClass
@doNotGenerateCast
extern class InternalizedString extends String {
}
@abstract
@generateCppClass
@doNotGenerateCast
extern class SeqString extends String {
}
@generateCppClass
@generateBodyDescriptor
@doNotGenerateCast
extern class SeqOneByteString extends SeqString {
chars[length]: char8;
}
@generateCppClass
@generateBodyDescriptor
@doNotGenerateCast
extern class SeqTwoByteString extends SeqString {
chars[length]: char16;
}
@generateCppClass
@generateBodyDescriptor
@doNotGenerateCast
extern class SlicedString extends String {
parent: String;
offset: Smi;
......@@ -54,6 +66,7 @@ extern class SlicedString extends String {
@generateCppClass
@generateBodyDescriptor
@doNotGenerateCast
extern class ThinString extends String {
actual: String;
}
......
......@@ -356,7 +356,7 @@ class Symbol;
PUBLIC_SYMBOL_ROOT_LIST(V) \
WELL_KNOWN_SYMBOL_ROOT_LIST(V) \
STRUCT_MAPS_LIST(V) \
TORQUE_INTERNAL_MAP_ROOT_LIST(V) \
TORQUE_DEFINED_MAP_ROOT_LIST(V) \
ALLOCATION_SITE_MAPS_LIST(V) \
DATA_HANDLER_MAPS_LIST(V)
......
......@@ -95,6 +95,7 @@ static const char* const ANNOTATION_IFNOT = "@ifnot";
static const char* const ANNOTATION_GENERATE_BODY_DESCRIPTOR =
"@generateBodyDescriptor";
static const char* const ANNOTATION_EXPORT_CPP_CLASS = "@export";
static const char* const ANNOTATION_DO_NOT_GENERATE_CAST = "@doNotGenerateCast";
inline bool IsConstexprName(const std::string& name) {
return name.substr(0, std::strlen(CONSTEXPR_TYPE_PREFIX)) ==
......@@ -133,6 +134,7 @@ enum class ClassFlag {
kUndefinedLayout = 1 << 11,
kGenerateBodyDescriptor = 1 << 12,
kExport = 1 << 13,
kDoNotGenerateCast = 1 << 14
};
using ClassFlags = base::Flags<ClassFlag>;
......
......@@ -274,6 +274,31 @@ void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
<< return_type->GetGeneratedTNodeTypeName() << ">";
}
}
} else if (instruction.intrinsic->ExternalName() == "%GetClassMapConstant") {
if (parameter_types.size() != 0) {
ReportError("%GetClassMapConstant must not take parameters");
}
if (instruction.specialization_types.size() != 1) {
ReportError(
"%GetClassMapConstant must take a single class as specialization "
"parameter");
}
const ClassType* class_type =
ClassType::DynamicCast(instruction.specialization_types[0]);
if (!class_type) {
ReportError("%GetClassMapConstant must take a class type parameter");
}
// If the class isn't actually used as the parameter to a TNode,
// then we can't rely on the class existing in C++ or being of the same
// type (e.g. it could be a template), so don't use the template CSA
// machinery for accessing the class' map.
std::string class_name =
class_type->name() != class_type->GetGeneratedTNodeTypeName()
? std::string("void")
: class_type->name();
out() << std::string("CodeStubAssembler(state_).GetClassMapConstant<") +
class_name + ">";
} else if (instruction.intrinsic->ExternalName() == "%FromConstexpr") {
if (parameter_types.size() != 1 || !parameter_types[0]->IsConstexpr()) {
ReportError(
......
......@@ -2403,6 +2403,29 @@ void ImplementationVisitor::AddCallParameter(
}
}
namespace {
std::pair<std::string, std::string> GetClassInstanceTypeRange(
const ClassType* class_type) {
std::pair<std::string, std::string> result;
if (class_type->InstanceTypeRange()) {
auto instance_type_range = *class_type->InstanceTypeRange();
std::string instance_type_string_first =
"static_cast<InstanceType>(" +
std::to_string(instance_type_range.first) + ")";
std::string instance_type_string_second =
"static_cast<InstanceType>(" +
std::to_string(instance_type_range.second) + ")";
result =
std::make_pair(instance_type_string_first, instance_type_string_second);
} else {
ReportError(
"%Min/MaxInstanceType must take a class type that is either a string "
"or has a generated instance type range");
}
return result;
}
} // namespace
VisitResult ImplementationVisitor::GenerateCall(
Callable* callable, base::Optional<LocationReference> this_reference,
Arguments arguments, const TypeVector& specialization_types,
......@@ -2633,6 +2656,48 @@ VisitResult ImplementationVisitor::GenerateCall(
Error("size of ", *type, " is not known.");
}
return VisitResult(return_type, size_string);
} else if (intrinsic->ExternalName() == "%ClassHasMapConstant") {
const Type* type = specialization_types[0];
const ClassType* class_type = ClassType::DynamicCast(type);
if (!class_type) {
ReportError("%ClassHasMapConstant must take a class type parameter");
}
// If the class isn't actually used as the parameter to a TNode,
// then we can't rely on the class existing in C++ or being of the same
// type (e.g. it could be a template), so don't use the template CSA
// machinery for accessing the class' map.
if (class_type->name() != class_type->GetGeneratedTNodeTypeName()) {
return VisitResult(return_type, std::string("false"));
} else {
return VisitResult(
return_type,
std::string("CodeStubAssembler(state_).ClassHasMapConstant<") +
class_type->name() + ">()");
}
} else if (intrinsic->ExternalName() == "%MinInstanceType") {
if (specialization_types.size() != 1) {
ReportError("%MinInstanceType must take a single type parameter");
}
const Type* type = specialization_types[0];
const ClassType* class_type = ClassType::DynamicCast(type);
if (!class_type) {
ReportError("%MinInstanceType must take a class type parameter");
}
std::pair<std::string, std::string> instance_types =
GetClassInstanceTypeRange(class_type);
return VisitResult(return_type, instance_types.first);
} else if (intrinsic->ExternalName() == "%MaxInstanceType") {
if (specialization_types.size() != 1) {
ReportError("%MaxInstanceType must take a single type parameter");
}
const Type* type = specialization_types[0];
const ClassType* class_type = ClassType::DynamicCast(type);
if (!class_type) {
ReportError("%MaxInstanceType must take a class type parameter");
}
std::pair<std::string, std::string> instance_types =
GetClassInstanceTypeRange(class_type);
return VisitResult(return_type, instance_types.second);
} else if (intrinsic->ExternalName() == "%RawConstexprCast") {
if (intrinsic->signature().parameter_types.types.size() != 1 ||
constexpr_arguments.size() != 1) {
......@@ -4080,7 +4145,7 @@ void ImplementationVisitor::GenerateClassDefinitions(
structs_used_in_classes.insert(*field_as_struct);
}
}
if (type->ShouldExport()) {
if (type->ShouldExport() && !type->IsAbstract()) {
factory_header << type->HandlifiedCppTypeName() << " New"
<< type->name() << "(";
factory_impl << type->HandlifiedCppTypeName() << " Factory::New"
......
......@@ -436,11 +436,11 @@ void ImplementationVisitor::GenerateInstanceTypes(
header << only_declared_range_instance_types.str();
header << "\n";
std::stringstream torque_internal_class_list;
std::stringstream torque_internal_varsize_instance_type_list;
std::stringstream torque_internal_fixed_instance_type_list;
std::stringstream torque_internal_map_csa_list;
std::stringstream torque_internal_map_root_list;
std::stringstream torque_defined_class_list;
std::stringstream torque_defined_varsize_instance_type_list;
std::stringstream torque_defined_fixed_instance_type_list;
std::stringstream torque_defined_map_csa_list;
std::stringstream torque_defined_map_root_list;
for (const ClassType* type : TypeOracle::GetClasses()) {
std::string upper_case_name = type->name();
......@@ -449,41 +449,40 @@ void ImplementationVisitor::GenerateInstanceTypes(
CapifyStringWithUnderscores(type->name()) + "_TYPE";
if (type->IsExtern()) continue;
torque_internal_class_list << " V(" << upper_case_name << ") \\\n";
torque_defined_class_list << " V(" << upper_case_name << ") \\\n";
if (type->IsAbstract()) continue;
torque_internal_map_csa_list << " V(" << upper_case_name << "Map, "
<< lower_case_name << "_map, "
torque_defined_map_csa_list << " V(_, " << upper_case_name << "Map, "
<< lower_case_name << "_map, "
<< upper_case_name << ") \\\n";
torque_defined_map_root_list << " V(Map, " << lower_case_name << "_map, "
<< upper_case_name << "Map) \\\n";
torque_internal_map_root_list << " V(Map, " << lower_case_name
<< "_map, " << upper_case_name
<< "Map) \\\n";
std::stringstream& list =
type->HasStaticSize() ? torque_internal_fixed_instance_type_list
: torque_internal_varsize_instance_type_list;
std::stringstream& list = type->HasStaticSize()
? torque_defined_fixed_instance_type_list
: torque_defined_varsize_instance_type_list;
list << " V(" << instance_type_name << ", " << upper_case_name << ", "
<< lower_case_name << ") \\\n";
}
header << "// Non-extern Torque classes.\n";
header << "#define TORQUE_INTERNAL_CLASS_LIST(V) \\\n";
header << torque_internal_class_list.str();
header << "// Fully Torque-defined classes (both internal and exported).\n";
header << "#define TORQUE_DEFINED_CLASS_LIST(V) \\\n";
header << torque_defined_class_list.str();
header << "\n";
header << "#define TORQUE_INTERNAL_VARSIZE_INSTANCE_TYPE_LIST(V) \\\n";
header << torque_internal_varsize_instance_type_list.str();
header << "#define TORQUE_DEFINED_VARSIZE_INSTANCE_TYPE_LIST(V) \\\n";
header << torque_defined_varsize_instance_type_list.str();
header << "\n";
header << "#define TORQUE_INTERNAL_FIXED_INSTANCE_TYPE_LIST(V) \\\n";
header << torque_internal_fixed_instance_type_list.str();
header << "#define TORQUE_DEFINED_FIXED_INSTANCE_TYPE_LIST(V) \\\n";
header << torque_defined_fixed_instance_type_list.str();
header << "\n";
header << "#define TORQUE_INTERNAL_INSTANCE_TYPE_LIST(V) \\\n";
header << " TORQUE_INTERNAL_VARSIZE_INSTANCE_TYPE_LIST(V) \\\n";
header << " TORQUE_INTERNAL_FIXED_INSTANCE_TYPE_LIST(V) \\\n";
header << "#define TORQUE_DEFINED_INSTANCE_TYPE_LIST(V) \\\n";
header << " TORQUE_DEFINED_VARSIZE_INSTANCE_TYPE_LIST(V) \\\n";
header << " TORQUE_DEFINED_FIXED_INSTANCE_TYPE_LIST(V) \\\n";
header << "\n";
header << "#define TORQUE_INTERNAL_MAP_CSA_LIST(V) \\\n";
header << torque_internal_map_csa_list.str();
header << "#define TORQUE_DEFINED_MAP_CSA_LIST_GENERATOR(V, _) \\\n";
header << torque_defined_map_csa_list.str();
header << "\n";
header << "#define TORQUE_INTERNAL_MAP_ROOT_LIST(V) \\\n";
header << torque_internal_map_root_list.str();
header << "#define TORQUE_DEFINED_MAP_ROOT_LIST(V) \\\n";
header << torque_defined_map_root_list.str();
header << "\n";
}
std::string output_header_path = output_directory + "/" + file_name;
......
......@@ -855,7 +855,7 @@ base::Optional<ParseResult> MakeClassDeclaration(
{ANNOTATION_GENERATE_PRINT, ANNOTATION_NO_VERIFIER, ANNOTATION_ABSTRACT,
ANNOTATION_HAS_SAME_INSTANCE_TYPE_AS_PARENT,
ANNOTATION_GENERATE_CPP_CLASS, ANNOTATION_GENERATE_BODY_DESCRIPTOR,
ANNOTATION_EXPORT_CPP_CLASS,
ANNOTATION_EXPORT_CPP_CLASS, ANNOTATION_DO_NOT_GENERATE_CAST,
ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT,
ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT},
{ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE,
......@@ -874,6 +874,9 @@ base::Optional<ParseResult> MakeClassDeclaration(
if (annotations.Contains(ANNOTATION_GENERATE_CPP_CLASS)) {
flags |= ClassFlag::kGenerateCppClassDefinitions;
}
if (annotations.Contains(ANNOTATION_DO_NOT_GENERATE_CAST)) {
flags |= ClassFlag::kDoNotGenerateCast;
}
if (annotations.Contains(ANNOTATION_GENERATE_BODY_DESCRIPTOR)) {
flags |= ClassFlag::kGenerateBodyDescriptor;
}
......@@ -896,6 +899,7 @@ base::Optional<ParseResult> MakeClassDeclaration(
flags |= ClassFlag::kIsShape;
flags |= ClassFlag::kTransient;
flags |= ClassFlag::kHasSameInstanceTypeAsParent;
flags |= ClassFlag::kDoNotGenerateCast;
} else {
DCHECK_EQ(kind, "class");
}
......@@ -934,9 +938,60 @@ base::Optional<ParseResult> MakeClassDeclaration(
return true;
});
Declaration* result = MakeNode<ClassDeclaration>(
std::vector<Declaration*> result;
result.push_back(MakeNode<ClassDeclaration>(
name, flags, std::move(extends), std::move(generates), std::move(methods),
fields, MakeInstanceTypeConstraints(annotations));
fields, MakeInstanceTypeConstraints(annotations)));
if ((flags & ClassFlag::kDoNotGenerateCast) == 0 &&
(flags & ClassFlag::kIsShape) == 0) {
ParameterList parameters;
parameters.names.push_back(MakeNode<Identifier>("obj"));
parameters.types.push_back(
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, "HeapObject",
std::vector<TypeExpression*>{}));
LabelAndTypesVector labels;
labels.push_back(LabelAndTypes{MakeNode<Identifier>("CastError"),
std::vector<TypeExpression*>{}});
TypeExpression* class_type =
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, name->value,
std::vector<TypeExpression*>{});
std::vector<std::string> namespace_qualification{
TORQUE_INTERNAL_NAMESPACE_STRING};
IdentifierExpression* internal_downcast_target =
MakeNode<IdentifierExpression>(
namespace_qualification,
MakeNode<Identifier>("DownCastForTorqueClass"),
std::vector<TypeExpression*>{class_type});
IdentifierExpression* internal_downcast_otherwise =
MakeNode<IdentifierExpression>(std::vector<std::string>{},
MakeNode<Identifier>("CastError"));
Expression* argument = MakeNode<IdentifierExpression>(
std::vector<std::string>{}, MakeNode<Identifier>("obj"));
auto value = MakeCall(internal_downcast_target, base::nullopt,
std::vector<Expression*>{argument},
std::vector<Statement*>{MakeNode<ExpressionStatement>(
internal_downcast_otherwise)});
auto cast_body = MakeNode<ReturnStatement>(value);
std::vector<TypeExpression*> generic_parameters;
generic_parameters.push_back(
MakeNode<BasicTypeExpression>(std::vector<std::string>{}, name->value,
std::vector<TypeExpression*>{}));
Declaration* specialization = MakeNode<SpecializationDeclaration>(
false, MakeNode<Identifier>("Cast"), generic_parameters,
std::move(parameters), class_type, std::move(labels), cast_body);
result.push_back(specialization);
}
return ParseResult{result};
}
......@@ -2385,7 +2440,7 @@ struct TorqueGrammar : Grammar {
Optional<std::string>(
Sequence({Token("generates"), &externalString})),
&optionalClassBody},
AsSingletonVector<Declaration*, MakeClassDeclaration>()),
MakeClassDeclaration),
Rule({annotations, Token("struct"), &name,
TryOrDefault<GenericParameters>(&genericParameters), Token("{"),
List<Declaration*>(&method),
......
......@@ -311,6 +311,16 @@ const ClassType* TypeVisitor::ComputeType(
flags = flags | ClassFlag::kGeneratePrint | ClassFlag::kGenerateVerify |
ClassFlag::kGenerateBodyDescriptor;
}
if (!(flags & ClassFlag::kExtern) &&
(flags & ClassFlag::kHasSameInstanceTypeAsParent)) {
Error("non-extern Torque-defined classes must have unique instance types");
}
if ((flags & ClassFlag::kHasSameInstanceTypeAsParent) &&
!(flags & ClassFlag::kDoNotGenerateCast || flags & ClassFlag::kIsShape)) {
Error(
"classes that inherit their instance type must be annotated with "
"@doNotGenerateCast");
}
return TypeOracle::GetClassType(super_type, decl->name->value, flags,
generates, decl, alias);
......
......@@ -660,6 +660,9 @@ class ClassType final : public AggregateType {
if (IsAbstract()) return false;
return flags_ & ClassFlag::kGenerateBodyDescriptor || !IsExtern();
}
bool DoNotGenerateCast() const {
return flags_ & ClassFlag::kDoNotGenerateCast;
}
bool IsTransient() const override { return flags_ & ClassFlag::kTransient; }
bool IsAbstract() const { return flags_ & ClassFlag::kAbstract; }
bool HasSameInstanceTypeAsParent() const {
......
......@@ -821,6 +821,23 @@ TEST(TestFullyGeneratedClassWithElements) {
ft.Call();
}
TEST(TestGeneratedCastOperators) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
i::HandleScope scope(isolate);
CodeAssemblerTester asm_tester(isolate, 1);
TestTorqueAssembler m(asm_tester.state());
{
Handle<Context> context =
Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
m.TestGeneratedCastOperators(
m.UncheckedCast<Context>(m.HeapConstant(context)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -1265,4 +1265,43 @@ macro TestFullyGeneratedClassFromCpp(): ExportedSubClass {
return new
ExportedSubClass{a: Null, b: Null, c_field: 7, d_field: 8, e_field: 9};
}
@export
class ExportedSubClass2 extends ExportedSubClassBase {
x_field: int32;
y_field: int32;
z_field: Smi;
}
@export
macro TestGeneratedCastOperators(implicit context: Context)() {
const a = new
ExportedSubClass{a: Null, b: Null, c_field: 3, d_field: 4, e_field: 5};
const b = new ExportedSubClassBase{a: Undefined, b: Null};
const c = new
ExportedSubClass2{a: Null, b: Null, x_field: 3, y_field: 4, z_field: 5};
const aO: Object = a;
const bO: Object = b;
const cO: Object = c;
assert(Is<ExportedSubClassBase>(aO));
assert(Is<ExportedSubClass>(aO));
assert(!Is<ExportedSubClass2>(aO));
assert(Is<ExportedSubClassBase>(bO));
assert(!Is<ExportedSubClass>(bO));
assert(Is<ExportedSubClassBase>(cO));
assert(!Is<ExportedSubClass>(cO));
assert(Is<ExportedSubClass2>(cO));
const nativeContext = LoadNativeContext(context);
const jsf: JSFunction = UnsafeCast<JSFunction>(
nativeContext[NativeContextSlot::REGEXP_FUNCTION_INDEX]);
assert(!Is<JSSloppyArgumentsObject>(jsf));
const parameterValues = NewFixedArray(0, ConstantIterator(TheHole));
const elements = NewSloppyArgumentsElements(
0, context, parameterValues, ConstantIterator(TheHole));
const fastArgs = arguments::NewJSFastAliasedArgumentsObject(
elements, Convert<Smi>(0), jsf);
assert(Is<JSArgumentsObject>(fastArgs));
}
}
......@@ -29,6 +29,13 @@ namespace torque_internal {
type MutableReference<T : type> extends ConstReference<T>;
type UninitializedHeapObject extends HeapObject;
macro DownCastForTorqueClass<T : type extends HeapObject>(o: HeapObject):
T labels _CastError {
return %RawDownCast<T>(o);
}
macro IsWithContext<T : type extends HeapObject>(o: HeapObject): bool {
return false;
}
}
type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject';
......@@ -128,6 +135,8 @@ macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
return Cast<A>(TaggedToHeapObject(o) otherwise CastError)
otherwise CastError;
}
macro Cast<A : type extends HeapObject>(o: HeapObject): A
labels CastError;
Cast<Smi>(o: Object): Smi
labels CastError {
return TaggedToSmi(o) otherwise CastError;
......
This diff is collapsed.
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