mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 14:32:24 +00:00
Intrinsic version of Object.runtimeType
BUG= R=regis@google.com Review URL: https://codereview.chromium.org//1217323002.
This commit is contained in:
parent
8f9d21b9c7
commit
c0b359db6c
20 changed files with 175 additions and 10 deletions
|
@ -1966,13 +1966,18 @@ void Assembler::CompareClassId(Register object,
|
|||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
|
||||
static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
|
||||
|
||||
LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
|
||||
tst(object, Operand(kSmiTagMask));
|
||||
mov(TMP, Operand(object), NE);
|
||||
LoadClassId(result, TMP);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
LoadClassIdMayBeSmi(result, object);
|
||||
SmiTag(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -739,6 +739,7 @@ class Assembler : public ValueObject {
|
|||
void LoadClassById(Register result, Register class_id);
|
||||
void LoadClass(Register result, Register object, Register scratch);
|
||||
void CompareClassId(Register object, intptr_t class_id, Register scratch);
|
||||
void LoadClassIdMayBeSmi(Register result, Register object);
|
||||
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
|
||||
|
||||
void ComputeRange(Register result,
|
||||
|
|
|
@ -1009,7 +1009,7 @@ void Assembler::CompareClassId(
|
|||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
|
||||
// Load up a null object. We only need it so we can use LoadClassId on it in
|
||||
// the case that object is a Smi..
|
||||
LoadObject(TMP, Object::null_object(), PP);
|
||||
|
@ -1024,6 +1024,11 @@ void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
|||
LoadImmediate(TMP, kSmiCid, PP);
|
||||
// If object is a Smi, move the Smi cid into result. o/w leave alone.
|
||||
csel(result, TMP, result, EQ);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
LoadClassIdMayBeSmi(result, object);
|
||||
// Finally, tag the result.
|
||||
SmiTag(result);
|
||||
}
|
||||
|
|
|
@ -1336,6 +1336,7 @@ class Assembler : public ValueObject {
|
|||
void LoadClassById(Register result, Register class_id, Register pp);
|
||||
void LoadClass(Register result, Register object, Register pp);
|
||||
void CompareClassId(Register object, intptr_t class_id, Register pp);
|
||||
void LoadClassIdMayBeSmi(Register result, Register object);
|
||||
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
|
||||
|
||||
void ComputeRange(Register result,
|
||||
|
|
|
@ -3017,7 +3017,7 @@ void Assembler::SmiUntagOrCheckClass(Register object,
|
|||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
|
||||
ASSERT(result != object);
|
||||
static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
|
||||
|
||||
|
@ -3031,7 +3031,11 @@ void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
|||
// Otherwise, the dummy object is used, and the result is kSmiCid.
|
||||
cmovne(result, object);
|
||||
LoadClassId(result, result);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
LoadClassIdMayBeSmi(result, object);
|
||||
// Tag the result.
|
||||
SmiTag(result);
|
||||
}
|
||||
|
|
|
@ -742,8 +742,8 @@ class Assembler : public ValueObject {
|
|||
|
||||
void CompareClassId(Register object, intptr_t class_id, Register scratch);
|
||||
|
||||
void LoadTaggedClassIdMayBeSmi(Register result,
|
||||
Register object);
|
||||
void LoadClassIdMayBeSmi(Register result, Register object);
|
||||
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
|
||||
|
||||
void SmiUntagOrCheckClass(Register object,
|
||||
intptr_t class_id,
|
||||
|
|
|
@ -667,7 +667,7 @@ void Assembler::LoadClass(Register result, Register object) {
|
|||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
|
||||
static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
|
||||
|
||||
LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
|
||||
|
@ -677,6 +677,11 @@ void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
|||
}
|
||||
movz(result, TMP, CMPRES1);
|
||||
LoadClassId(result, result);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
LoadClassIdMayBeSmi(result, object);
|
||||
SmiTag(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -1549,6 +1549,7 @@ class Assembler : public ValueObject {
|
|||
void LoadClassId(Register result, Register object);
|
||||
void LoadClassById(Register result, Register class_id);
|
||||
void LoadClass(Register result, Register object);
|
||||
void LoadClassIdMayBeSmi(Register result, Register object);
|
||||
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
|
||||
|
||||
void ComputeRange(Register result,
|
||||
|
|
|
@ -3786,7 +3786,7 @@ void Assembler::SmiUntagOrCheckClass(Register object,
|
|||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
|
||||
ASSERT(result != object);
|
||||
|
||||
// Load up a null object. We only need it so we can use LoadClassId on it in
|
||||
|
@ -3803,6 +3803,11 @@ void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
|||
movq(object, Immediate(kSmiCid));
|
||||
// If object is a Smi, move the Smi cid into result. o/w leave alone.
|
||||
cmoveq(result, object);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
|
||||
LoadClassIdMayBeSmi(result, object);
|
||||
// Finally, tag the result.
|
||||
SmiTag(result);
|
||||
}
|
||||
|
|
|
@ -859,6 +859,7 @@ class Assembler : public ValueObject {
|
|||
|
||||
void CompareClassId(Register object, intptr_t class_id);
|
||||
|
||||
void LoadClassIdMayBeSmi(Register result, Register object);
|
||||
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
|
||||
|
||||
// CheckClassIs fused with optimistic SmiUntag.
|
||||
|
|
|
@ -1570,6 +1570,35 @@ void Intrinsifier::ObjectEquals(Assembler* assembler) {
|
|||
}
|
||||
|
||||
|
||||
// Return type quickly for simple types (not parameterized and not signature).
|
||||
void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
|
||||
__ ldr(R0, Address(SP, 0 * kWordSize));
|
||||
|
||||
__ LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
|
||||
__ tst(R0, Operand(kSmiTagMask));
|
||||
__ mov(TMP, Operand(R0), NE);
|
||||
__ LoadClassId(R1, TMP);
|
||||
__ LoadClassById(R2, R1);
|
||||
// R2: class of instance (R0).
|
||||
__ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
|
||||
__ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null()));
|
||||
__ b(&fall_through, NE);
|
||||
|
||||
__ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
|
||||
__ CompareImmediate(R3, 0);
|
||||
__ b(&fall_through, NE);
|
||||
|
||||
__ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
|
||||
__ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
|
||||
__ b(&fall_through, EQ);
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&fall_through);
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
__ ldr(R0, Address(SP, 0 * kWordSize));
|
||||
__ ldr(R0, FieldAddress(R0, String::hash_offset()));
|
||||
|
|
|
@ -1646,6 +1646,30 @@ void Intrinsifier::ObjectEquals(Assembler* assembler) {
|
|||
}
|
||||
|
||||
|
||||
// Return type quickly for simple types (not parameterized and not signature).
|
||||
void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ ldr(R0, Address(SP, 0 * kWordSize));
|
||||
__ LoadClassIdMayBeSmi(R1, R0);
|
||||
__ LoadClassById(R2, R1, PP);
|
||||
// R2: class of instance (R0).
|
||||
__ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
|
||||
__ CompareObject(R3, Object::null_object(), PP);
|
||||
__ b(&fall_through, NE);
|
||||
|
||||
__ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
|
||||
__ CompareImmediate(R3, 0, kNoPP);
|
||||
__ b(&fall_through, NE);
|
||||
|
||||
__ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
|
||||
__ CompareObject(R0, Object::null_object(), PP);
|
||||
__ b(&fall_through, EQ);
|
||||
__ ret();
|
||||
|
||||
__ Bind(&fall_through);
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ ldr(R0, Address(SP, 0 * kWordSize));
|
||||
|
|
|
@ -1666,6 +1666,31 @@ void Intrinsifier::ObjectEquals(Assembler* assembler) {
|
|||
}
|
||||
|
||||
|
||||
// Return type quickly for simple types (not parameterized and not signature).
|
||||
void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ movl(EAX, Address(ESP, + 1 * kWordSize));
|
||||
__ LoadClassIdMayBeSmi(EDI, EAX);
|
||||
__ LoadClassById(EBX, EDI);
|
||||
// EBX: class of instance (EAX).
|
||||
const Immediate& raw_null =
|
||||
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
||||
__ movl(EDI, FieldAddress(EBX, Class::signature_function_offset()));
|
||||
__ cmpl(EDI, raw_null);
|
||||
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
|
||||
|
||||
__ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
|
||||
__ cmpl(EDI, Immediate(0));
|
||||
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
|
||||
__ movl(EAX, FieldAddress(EBX, Class::canonical_types_offset()));
|
||||
__ cmpl(EAX, raw_null);
|
||||
__ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set.
|
||||
__ ret();
|
||||
|
||||
__ Bind(&fall_through);
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object.
|
||||
|
@ -2073,7 +2098,7 @@ void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
|
|||
// Registers are now set up for the lazy compile stub. It expects the function
|
||||
// in EAX, the argument descriptor in EDX, and IC-Data in ECX.
|
||||
static const intptr_t arg_count = RegExpMacroAssembler::kParamCount;
|
||||
__ LoadObject(EDX, Array::Handle(ArgumentsDescriptor::New(arg_count)));
|
||||
__ LoadObject(EDX, Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)));
|
||||
__ xorl(ECX, ECX);
|
||||
|
||||
// Tail-call the function.
|
||||
|
|
|
@ -1675,6 +1675,28 @@ void Intrinsifier::ObjectEquals(Assembler* assembler) {
|
|||
}
|
||||
|
||||
|
||||
// Return type quickly for simple types (not parameterized and not signature).
|
||||
void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ lw(T0, Address(SP, 0 * kWordSize));
|
||||
__ LoadClassIdMayBeSmi(T1, T0);
|
||||
__ LoadClassById(T2, T1);
|
||||
// T2: class of instance (T0).
|
||||
|
||||
__ lw(T1, FieldAddress(T2, Class::signature_function_offset()));
|
||||
__ BranchNotEqual(T1, Object::null_object(), &fall_through);
|
||||
|
||||
__ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
|
||||
__ BranchNotEqual(T1, Immediate(0), &fall_through);
|
||||
|
||||
__ lw(V0, FieldAddress(T2, Class::canonical_types_offset()));
|
||||
__ BranchEqual(V0, Object::null_object(), &fall_through);
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&fall_through);
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ lw(T0, Address(SP, 0 * kWordSize));
|
||||
|
|
|
@ -1524,6 +1524,31 @@ void Intrinsifier::ObjectEquals(Assembler* assembler) {
|
|||
}
|
||||
|
||||
|
||||
// Return type quickly for simple types (not parameterized and not signature).
|
||||
void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ movq(RAX, Address(RSP, + 1 * kWordSize));
|
||||
__ LoadClassIdMayBeSmi(RCX, RAX);
|
||||
|
||||
// RCX: untagged cid of instance (RAX).
|
||||
__ LoadClassById(RDI, RCX, PP);
|
||||
// RDI: class of instance (RAX).
|
||||
__ movq(RCX, FieldAddress(RDI, Class::signature_function_offset()));
|
||||
__ CompareObject(RCX, Object::null_object(), PP);
|
||||
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
|
||||
|
||||
__ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
|
||||
__ cmpq(RCX, Immediate(0));
|
||||
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
|
||||
__ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset()));
|
||||
__ CompareObject(RAX, Object::null_object(), PP);
|
||||
__ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set.
|
||||
__ ret();
|
||||
|
||||
__ Bind(&fall_through);
|
||||
}
|
||||
|
||||
|
||||
void Intrinsifier::String_getHashCode(Assembler* assembler) {
|
||||
Label fall_through;
|
||||
__ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object.
|
||||
|
@ -1932,7 +1957,8 @@ void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
|
|||
// Registers are now set up for the lazy compile stub. It expects the function
|
||||
// in RAX, the argument descriptor in R10, and IC-Data in RCX.
|
||||
static const intptr_t arg_count = RegExpMacroAssembler::kParamCount;
|
||||
__ LoadObject(R10, Array::Handle(ArgumentsDescriptor::New(arg_count)), PP);
|
||||
__ LoadObject(R10,
|
||||
Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)), PP);
|
||||
__ xorq(RCX, RCX);
|
||||
|
||||
// Tail-call the function.
|
||||
|
|
|
@ -190,6 +190,7 @@ namespace dart {
|
|||
V(_GrowableList, add, GrowableArray_add, 1675959698) \
|
||||
V(_JSSyntaxRegExp, _ExecuteMatch, JSRegExp_ExecuteMatch, 1711509198) \
|
||||
V(Object, ==, ObjectEquals, 409406570) \
|
||||
V(Object, get:runtimeType, ObjectRuntimeType, 2076963579) \
|
||||
V(_StringBase, get:hashCode, String_getHashCode, 2103025405) \
|
||||
V(_StringBase, get:isEmpty, StringBaseIsEmpty, 780870414) \
|
||||
V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 397735324) \
|
||||
|
|
|
@ -3551,6 +3551,7 @@ RawObject* Class::canonical_types() const {
|
|||
return raw_ptr()->canonical_types_;
|
||||
}
|
||||
|
||||
|
||||
void Class::set_canonical_types(const Object& value) const {
|
||||
ASSERT(!value.IsNull());
|
||||
StorePointer(&raw_ptr()->canonical_types_, value.raw());
|
||||
|
|
|
@ -1049,6 +1049,9 @@ class Class : public Object {
|
|||
}
|
||||
return reinterpret_cast<RawType*>(Object::null());
|
||||
}
|
||||
static intptr_t canonical_types_offset() {
|
||||
return OFFSET_OF(RawClass, canonical_types_);
|
||||
}
|
||||
|
||||
// The super type of this class, Object type if not explicitly specified.
|
||||
// Note that the super type may be bounded, as in this example:
|
||||
|
@ -1442,6 +1445,9 @@ class Class : public Object {
|
|||
return raw_ptr()->num_type_arguments_;
|
||||
}
|
||||
void set_num_type_arguments(intptr_t value) const;
|
||||
static intptr_t num_type_arguments_offset() {
|
||||
return OFFSET_OF(RawClass, num_type_arguments_);
|
||||
}
|
||||
|
||||
int16_t num_own_type_arguments() const {
|
||||
return raw_ptr()->num_own_type_arguments_;
|
||||
|
@ -1484,6 +1490,7 @@ class Class : public Object {
|
|||
friend class Instance;
|
||||
friend class Object;
|
||||
friend class Type;
|
||||
friend class Intrinsifier;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -638,7 +638,7 @@ class RawClass : public RawObject {
|
|||
int32_t type_arguments_field_offset_in_words_; // Offset of type args fld.
|
||||
int32_t next_field_offset_in_words_; // Offset of the next instance field.
|
||||
classid_t id_; // Class Id, also index in the class table.
|
||||
int16_t num_type_arguments_; // Number of type arguments in flatten vector.
|
||||
int16_t num_type_arguments_; // Number of type arguments in flattened vector.
|
||||
int16_t num_own_type_arguments_; // Number of non-overlapping type arguments.
|
||||
uint16_t num_native_fields_; // Number of native fields in class.
|
||||
uint16_t state_bits_;
|
||||
|
|
|
@ -10,4 +10,6 @@ class A {
|
|||
|
||||
main() {
|
||||
Expect.isTrue(new A().className is Type);
|
||||
Expect.isTrue(null.runtimeType is Type);
|
||||
Expect.equals(null.runtimeType, Null);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue