mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 23:31:42 +00:00
Implement InstanceMirror.== in dart2js and InstanceMirror.hashCode in the VM and dart2js.
BUG=http://dartbug.com/12909 BUG=http://dartbug.com/12919 R=ahe@google.com, asiva@google.com Review URL: https://codereview.chromium.org//23460013 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27075 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
f8c8395201
commit
64fd5a5079
|
@ -751,6 +751,18 @@ DEFINE_NATIVE_ENTRY(TypeVariableMirror_upper_bound, 1) {
|
|||
}
|
||||
|
||||
|
||||
DEFINE_NATIVE_ENTRY(InstanceMirror_identityHash, 1) {
|
||||
GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(0));
|
||||
ObjectStore* object_store = isolate->object_store();
|
||||
const Class& cls = Class::Handle(isolate, object_store->object_class());
|
||||
const Function& function =
|
||||
Function::Handle(isolate, cls.LookupDynamicFunction(Symbols::hashCode()));
|
||||
const Array& args = Array::Handle(isolate, Array::New(1));
|
||||
args.SetAt(0, reflectee);
|
||||
return DartEntry::InvokeFunction(function, args);
|
||||
}
|
||||
|
||||
|
||||
// Invoke the function, or noSuchMethod if it is null. Propagate any unhandled
|
||||
// exceptions. Wrap and propagate any compilation errors.
|
||||
static RawObject* ReflectivelyInvokeDynamicFunction(const Instance& receiver,
|
||||
|
|
|
@ -283,8 +283,21 @@ class _LocalInstanceMirrorImpl extends _LocalObjectMirrorImpl
|
|||
identical(_reflectee, other._reflectee);
|
||||
}
|
||||
|
||||
// TODO(12909): Use the reflectee's identity hash.
|
||||
int get hashCode => _reflectee.hashCode;
|
||||
int get hashCode {
|
||||
// If the reflectee is a double or bignum, use the base hashCode to preserve
|
||||
// the illusion that boxed numbers with the same value are identical. If the
|
||||
// reflectee is a Smi, use the base hashCode because Object.hashCode does
|
||||
// not work for non-heap objects. Otherwise, use Object.hashCode to maintain
|
||||
// correctness even if a user-defined hashCode returns different values for
|
||||
// successive invocations.
|
||||
var h = _reflectee is num ? _reflectee.hashCode : _identityHash(_reflectee);
|
||||
// Avoid hash collisions with the reflectee. This constant is in Smi range
|
||||
// and happens to be the inner padding from RFC 2104.
|
||||
return h ^ 0x36363636;
|
||||
}
|
||||
|
||||
static _identityHash(reflectee)
|
||||
native "InstanceMirror_identityHash";
|
||||
|
||||
_invoke(reflectee, functionName, positionalArguments)
|
||||
native 'InstanceMirror_invoke';
|
||||
|
|
|
@ -253,6 +253,7 @@ namespace dart {
|
|||
V(Mirrors_makeLocalTypeMirror, 1) \
|
||||
V(Mirrors_makeLocalMirrorSystem, 0) \
|
||||
V(MirrorReference_equals, 2) \
|
||||
V(InstanceMirror_identityHash, 1) \
|
||||
V(InstanceMirror_invoke, 4) \
|
||||
V(InstanceMirror_invokeGetter, 3) \
|
||||
V(InstanceMirror_invokeSetter, 4) \
|
||||
|
|
|
@ -284,6 +284,7 @@ class ObjectPointerVisitor;
|
|||
V(_LocalMirrorSystemImpl, "_LocalMirrorSystemImpl") \
|
||||
V(_LocalTypedefMirrorImpl, "_LocalTypedefMirrorImpl") \
|
||||
V(_LocalTypeVariableMirrorImpl, "_LocalTypeVariableMirrorImpl") \
|
||||
V(hashCode, "get:hashCode") \
|
||||
V(_leftShiftWithMask32, "_leftShiftWithMask32") \
|
||||
|
||||
|
||||
|
|
|
@ -677,6 +677,26 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
|
|||
return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
|
||||
}
|
||||
|
||||
operator ==(other) {
|
||||
return other is JsInstanceMirror &&
|
||||
identical(reflectee, other.reflectee);
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
// If the reflectee is a built-in type, use the base-level hashCode to
|
||||
// preserve the illusion that, e.g. doubles, with the same value are
|
||||
// identical. Otherwise, use the primitive identity hash to maintain
|
||||
// correctness even if a user-defined hashCode returns different values for
|
||||
// successive invocations.
|
||||
var h = ((JS('bool', 'typeof # != "object"', reflectee)) ||
|
||||
(reflectee == null))
|
||||
? reflectee.hashCode
|
||||
: Primitives.objectHashCode(reflectee);
|
||||
// Avoid hash collisions with the reflectee. This constant is in Smi range
|
||||
// and happens to be the inner padding from RFC 2104.
|
||||
return h ^ 0x36363636;
|
||||
}
|
||||
|
||||
String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}';
|
||||
|
||||
// TODO(ahe): Remove this method from the API.
|
||||
|
|
|
@ -13,7 +13,7 @@ math/random_test: Fail
|
|||
mirrors/invoke_test: Fail # Issue 11954
|
||||
mirrors/class_mirror_type_variables_test: Fail # Issue 12087
|
||||
mirrors/invoke_private_test: Fail # Issue 12164
|
||||
mirrors/equality_test: Fail # Issue 12333, 12919
|
||||
mirrors/equality_test: Fail # Issue 12333
|
||||
mirrors/function_type_mirror_test: Fail # Issue 12166
|
||||
mirrors/generics_test: Fail # Issue 12333
|
||||
mirrors/hierarchy_invariants_test: Fail # Issue 11863
|
||||
|
|
112
tests/lib/mirrors/equality_dart2js_test.dart
Normal file
112
tests/lib/mirrors/equality_dart2js_test.dart
Normal file
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library test.class_equality_test;
|
||||
|
||||
import 'dart:mirrors';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class A<T> {}
|
||||
class B extends A<int> {}
|
||||
|
||||
class BadEqualityHash {
|
||||
int count = 0;
|
||||
bool operator ==(other) => true;
|
||||
int get hashCode => count++;
|
||||
}
|
||||
|
||||
checkEquality(List<Map> equivalenceClasses) {
|
||||
for (var equivalenceClass in equivalenceClasses) {
|
||||
equivalenceClass.forEach((name, member) {
|
||||
equivalenceClass.forEach((otherName, otherMember) {
|
||||
// Reflexivity, symmetry and transitivity.
|
||||
Expect.equals(member,
|
||||
otherMember,
|
||||
"$name == $otherName");
|
||||
Expect.equals(member.hashCode,
|
||||
otherMember.hashCode,
|
||||
"$name.hashCode == $otherName.hashCode");
|
||||
});
|
||||
for (var otherEquivalenceClass in equivalenceClasses) {
|
||||
if (otherEquivalenceClass == equivalenceClass) continue;
|
||||
otherEquivalenceClass.forEach((otherName, otherMember) {
|
||||
Expect.notEquals(member,
|
||||
otherMember,
|
||||
"$name != $otherName"); // Exclusion.
|
||||
// Hash codes may or may not be equal.
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void subroutine() {
|
||||
}
|
||||
|
||||
main() {
|
||||
LibraryMirror thisLibrary =
|
||||
currentMirrorSystem()
|
||||
.findLibrary(const Symbol('test.class_equality_test'))
|
||||
.single;
|
||||
|
||||
var o1 = new Object();
|
||||
var o2 = new Object();
|
||||
|
||||
var badEqualityHash1 = new BadEqualityHash();
|
||||
var badEqualityHash2 = new BadEqualityHash();
|
||||
|
||||
checkEquality([
|
||||
{'reflect(o1)' : reflect(o1),
|
||||
'reflect(o1), again' : reflect(o1)},
|
||||
|
||||
{'reflect(o2)' : reflect(o2),
|
||||
'reflect(o2), again' : reflect(o2)},
|
||||
|
||||
{'reflect(badEqualityHash1)' : reflect(badEqualityHash1),
|
||||
'reflect(badEqualityHash1), again' : reflect(badEqualityHash1)},
|
||||
|
||||
{'reflect(badEqualityHash2)' : reflect(badEqualityHash2),
|
||||
'reflect(badEqualityHash2), again' : reflect(badEqualityHash2)},
|
||||
|
||||
{'reflect(true)' : reflect(true),
|
||||
'reflect(true), again' : reflect(true)},
|
||||
|
||||
{'reflect(false)' : reflect(false),
|
||||
'reflect(false), again' : reflect(false)},
|
||||
|
||||
{'reflect(null)' : reflect(null),
|
||||
'reflect(null), again' : reflect(null)},
|
||||
|
||||
{'reflect(3.5+4.5)' : reflect(3.5+4.5),
|
||||
'reflect(6.5+1.5)' : reflect(6.5+1.5)},
|
||||
|
||||
{'reflect(3+4)' : reflect(3+4),
|
||||
'reflect(6+1)' : reflect(6+1)},
|
||||
|
||||
{'reflect("foo")' : reflect("foo"),
|
||||
'reflect("foo"), again' : reflect("foo")},
|
||||
|
||||
{'currentMirrorSystem().voidType' : currentMirrorSystem().voidType},
|
||||
|
||||
{'currentMirrorSystem().dynamicType' : currentMirrorSystem().dynamicType,
|
||||
'thisLibrary.functions[#main].returnType' :
|
||||
thisLibrary.functions[const Symbol('main')].returnType},
|
||||
|
||||
{'reflectClass(A)' : reflectClass(A),
|
||||
'thisLibrary.classes[#A]' : thisLibrary.classes[const Symbol('A')],
|
||||
'reflect(new A<int>()).type.originalDeclaration' :
|
||||
reflect(new A<int>()).type.originalDeclaration},
|
||||
|
||||
{'reflectClass(B)' : reflectClass(B),
|
||||
'thisLibrary.classes[#B]' : thisLibrary.classes[const Symbol('B')],
|
||||
'reflect(new B()).type' : reflect(new B()).type},
|
||||
|
||||
{'thisLibrary' : thisLibrary,
|
||||
'reflectClass(A).owner' : reflectClass(A).owner,
|
||||
'reflectClass(B).owner' : reflectClass(B).owner,
|
||||
'reflect(new A()).type.owner' : reflect(new A()).type.owner,
|
||||
'reflect(new A()).type.owner' : reflect(new A()).type.owner},
|
||||
]);
|
||||
}
|
|
@ -11,6 +11,12 @@ import 'package:expect/expect.dart';
|
|||
class A<T> {}
|
||||
class B extends A<int> {}
|
||||
|
||||
class BadEqualityHash {
|
||||
int count = 0;
|
||||
bool operator ==(other) => true;
|
||||
int get hashCode => count++;
|
||||
}
|
||||
|
||||
checkEquality(List<Map> equivalenceClasses) {
|
||||
for (var equivalenceClass in equivalenceClasses) {
|
||||
equivalenceClass.forEach((name, member) {
|
||||
|
@ -45,8 +51,11 @@ main() {
|
|||
.findLibrary(const Symbol('test.class_equality_test'))
|
||||
.single;
|
||||
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
var o1 = new Object();
|
||||
var o2 = new Object();
|
||||
|
||||
var badEqualityHash1 = new BadEqualityHash();
|
||||
var badEqualityHash2 = new BadEqualityHash();
|
||||
|
||||
checkEquality([
|
||||
{'reflect(o1)' : reflect(o1),
|
||||
|
@ -55,9 +64,30 @@ main() {
|
|||
{'reflect(o2)' : reflect(o2),
|
||||
'reflect(o2), again' : reflect(o2)},
|
||||
|
||||
{'reflect(badEqualityHash1)' : reflect(badEqualityHash1),
|
||||
'reflect(badEqualityHash1), again' : reflect(badEqualityHash1)},
|
||||
|
||||
{'reflect(badEqualityHash2)' : reflect(badEqualityHash2),
|
||||
'reflect(badEqualityHash2), again' : reflect(badEqualityHash2)},
|
||||
|
||||
{'reflect(true)' : reflect(true),
|
||||
'reflect(true), again' : reflect(true)},
|
||||
|
||||
{'reflect(false)' : reflect(false),
|
||||
'reflect(false), again' : reflect(false)},
|
||||
|
||||
{'reflect(null)' : reflect(null),
|
||||
'reflect(null), again' : reflect(null)},
|
||||
|
||||
{'reflect(3.5+4.5)' : reflect(3.5+4.5),
|
||||
'reflect(6.5+1.5)' : reflect(6.5+1.5)},
|
||||
|
||||
{'reflect(3+4)' : reflect(3+4),
|
||||
'reflect(6+1)' : reflect(6+1)},
|
||||
|
||||
{'reflect("foo")' : reflect("foo"),
|
||||
'reflect("foo"), again' : reflect("foo")},
|
||||
|
||||
{'currentMirrorSystem().voidType' : currentMirrorSystem().voidType,
|
||||
'thisLibrary.functions[#subroutine].returnType' :
|
||||
thisLibrary.functions[const Symbol('subroutine')].returnType},
|
||||
|
|
Loading…
Reference in a new issue