Intrinsic version of Object.runtimeType

BUG=
R=regis@google.com

Review URL: https://codereview.chromium.org//1217323002.
This commit is contained in:
Srdjan Mitrovic 2015-07-01 10:13:14 -07:00
parent 8f9d21b9c7
commit c0b359db6c
20 changed files with 175 additions and 10 deletions

View file

@ -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);
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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.

View file

@ -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()));

View file

@ -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));

View file

@ -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.

View file

@ -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));

View file

@ -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.

View file

@ -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) \

View file

@ -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());

View file

@ -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;
};

View file

@ -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_;

View file

@ -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);
}