OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <vector> | 5 #include <vector> |
6 | 6 |
7 #include "src/hydrogen-types.h" | 7 #include "src/hydrogen-types.h" |
8 #include "src/isolate-inl.h" | 8 #include "src/isolate-inl.h" |
9 #include "src/types.h" | 9 #include "src/types.h" |
10 #include "test/cctest/cctest.h" | 10 #include "test/cctest/cctest.h" |
11 | 11 |
12 using namespace v8::internal; | 12 using namespace v8::internal; |
13 | 13 |
14 // Testing auxiliaries (breaking the Type abstraction). | 14 // Testing auxiliaries (breaking the Type abstraction). |
15 struct ZoneRep { | 15 struct ZoneRep { |
16 typedef void* Struct; | 16 typedef void* Struct; |
17 | 17 |
18 static bool IsStruct(Type* t, int tag) { | 18 static bool IsStruct(Type* t, int tag) { |
19 return !IsBitset(t) && reinterpret_cast<intptr_t>(AsStruct(t)[0]) == tag; | 19 return !IsBitset(t) && reinterpret_cast<intptr_t>(AsStruct(t)[0]) == tag; |
20 } | 20 } |
21 static bool IsBitset(Type* t) { return reinterpret_cast<intptr_t>(t) & 1; } | 21 static bool IsBitset(Type* t) { return reinterpret_cast<intptr_t>(t) & 1; } |
22 static bool IsClass(Type* t) { return IsStruct(t, 0); } | 22 static bool IsClass(Type* t) { return IsStruct(t, 0); } |
23 static bool IsConstant(Type* t) { return IsStruct(t, 1); } | 23 static bool IsConstant(Type* t) { return IsStruct(t, 1); } |
24 static bool IsContext(Type* t) { return IsStruct(t, 2); } | 24 static bool IsRange(Type* t) { return IsStruct(t, 2); } |
25 static bool IsArray(Type* t) { return IsStruct(t, 3); } | 25 static bool IsContext(Type* t) { return IsStruct(t, 3); } |
26 static bool IsFunction(Type* t) { return IsStruct(t, 4); } | 26 static bool IsArray(Type* t) { return IsStruct(t, 4); } |
27 static bool IsUnion(Type* t) { return IsStruct(t, 5); } | 27 static bool IsFunction(Type* t) { return IsStruct(t, 5); } |
| 28 static bool IsUnion(Type* t) { return IsStruct(t, 6); } |
28 | 29 |
29 static Struct* AsStruct(Type* t) { | 30 static Struct* AsStruct(Type* t) { |
30 return reinterpret_cast<Struct*>(t); | 31 return reinterpret_cast<Struct*>(t); |
31 } | 32 } |
32 static int AsBitset(Type* t) { | 33 static int AsBitset(Type* t) { |
33 return static_cast<int>(reinterpret_cast<intptr_t>(t) >> 1); | 34 return static_cast<int>(reinterpret_cast<intptr_t>(t) >> 1); |
34 } | 35 } |
35 static Map* AsClass(Type* t) { | 36 static Map* AsClass(Type* t) { |
36 return *static_cast<Map**>(AsStruct(t)[3]); | 37 return *static_cast<Map**>(AsStruct(t)[3]); |
37 } | 38 } |
(...skipping 25 matching lines...) Expand all Loading... |
63 typedef FixedArray Struct; | 64 typedef FixedArray Struct; |
64 | 65 |
65 static bool IsStruct(Handle<HeapType> t, int tag) { | 66 static bool IsStruct(Handle<HeapType> t, int tag) { |
66 return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag; | 67 return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag; |
67 } | 68 } |
68 static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); } | 69 static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); } |
69 static bool IsClass(Handle<HeapType> t) { | 70 static bool IsClass(Handle<HeapType> t) { |
70 return t->IsMap() || IsStruct(t, 0); | 71 return t->IsMap() || IsStruct(t, 0); |
71 } | 72 } |
72 static bool IsConstant(Handle<HeapType> t) { return IsStruct(t, 1); } | 73 static bool IsConstant(Handle<HeapType> t) { return IsStruct(t, 1); } |
73 static bool IsContext(Handle<HeapType> t) { return IsStruct(t, 2); } | 74 static bool IsRange(Handle<HeapType> t) { return IsStruct(t, 2); } |
74 static bool IsArray(Handle<HeapType> t) { return IsStruct(t, 3); } | 75 static bool IsContext(Handle<HeapType> t) { return IsStruct(t, 3); } |
75 static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 4); } | 76 static bool IsArray(Handle<HeapType> t) { return IsStruct(t, 4); } |
76 static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 5); } | 77 static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 5); } |
| 78 static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 6); } |
77 | 79 |
78 static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); } | 80 static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); } |
79 static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); } | 81 static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); } |
80 static Map* AsClass(Handle<HeapType> t) { | 82 static Map* AsClass(Handle<HeapType> t) { |
81 return t->IsMap() ? Map::cast(*t) : Map::cast(AsStruct(t)->get(2)); | 83 return t->IsMap() ? Map::cast(*t) : Map::cast(AsStruct(t)->get(2)); |
82 } | 84 } |
83 static Object* AsConstant(Handle<HeapType> t) { return AsStruct(t)->get(2); } | 85 static Object* AsConstant(Handle<HeapType> t) { return AsStruct(t)->get(2); } |
84 static HeapType* AsContext(Handle<HeapType> t) { | 86 static HeapType* AsContext(Handle<HeapType> t) { |
85 return HeapType::cast(AsStruct(t)->get(1)); | 87 return HeapType::cast(AsStruct(t)->get(1)); |
86 } | 88 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 values.push_back(smi); | 144 values.push_back(smi); |
143 values.push_back(signed32); | 145 values.push_back(signed32); |
144 values.push_back(object1); | 146 values.push_back(object1); |
145 values.push_back(object2); | 147 values.push_back(object2); |
146 values.push_back(array); | 148 values.push_back(array); |
147 values.push_back(uninitialized); | 149 values.push_back(uninitialized); |
148 for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { | 150 for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { |
149 types.push_back(Type::Constant(*it, region)); | 151 types.push_back(Type::Constant(*it, region)); |
150 } | 152 } |
151 | 153 |
| 154 doubles.push_back(-0.0); |
| 155 doubles.push_back(+0.0); |
| 156 doubles.push_back(-std::numeric_limits<double>::infinity()); |
| 157 doubles.push_back(+std::numeric_limits<double>::infinity()); |
| 158 for (int i = 0; i < 10; ++i) { |
| 159 doubles.push_back(rng_->NextInt()); |
| 160 doubles.push_back(rng_->NextDouble() * rng_->NextInt()); |
| 161 } |
| 162 |
152 NumberArray = Type::Array(Number, region); | 163 NumberArray = Type::Array(Number, region); |
153 StringArray = Type::Array(String, region); | 164 StringArray = Type::Array(String, region); |
154 AnyArray = Type::Array(Any, region); | 165 AnyArray = Type::Array(Any, region); |
155 | 166 |
156 SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region); | 167 SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region); |
157 NumberFunction1 = Type::Function(Number, Number, region); | 168 NumberFunction1 = Type::Function(Number, Number, region); |
158 NumberFunction2 = Type::Function(Number, Number, Number, region); | 169 NumberFunction2 = Type::Function(Number, Number, Number, region); |
159 MethodFunction = Type::Function(String, Object, 0, region); | 170 MethodFunction = Type::Function(String, Object, 0, region); |
160 | 171 |
161 for (int i = 0; i < 40; ++i) { | 172 for (int i = 0; i < 40; ++i) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 TypeHandle AnyArray; | 205 TypeHandle AnyArray; |
195 | 206 |
196 TypeHandle SignedFunction1; | 207 TypeHandle SignedFunction1; |
197 TypeHandle NumberFunction1; | 208 TypeHandle NumberFunction1; |
198 TypeHandle NumberFunction2; | 209 TypeHandle NumberFunction2; |
199 TypeHandle MethodFunction; | 210 TypeHandle MethodFunction; |
200 | 211 |
201 typedef std::vector<TypeHandle> TypeVector; | 212 typedef std::vector<TypeHandle> TypeVector; |
202 typedef std::vector<Handle<i::Map> > MapVector; | 213 typedef std::vector<Handle<i::Map> > MapVector; |
203 typedef std::vector<Handle<i::Object> > ValueVector; | 214 typedef std::vector<Handle<i::Object> > ValueVector; |
| 215 typedef std::vector<double> DoubleVector; |
| 216 |
204 TypeVector types; | 217 TypeVector types; |
205 MapVector maps; | 218 MapVector maps; |
206 ValueVector values; | 219 ValueVector values; |
| 220 DoubleVector doubles; |
207 | 221 |
208 TypeHandle Of(Handle<i::Object> value) { | 222 TypeHandle Of(Handle<i::Object> value) { |
209 return Type::Of(value, region_); | 223 return Type::Of(value, region_); |
210 } | 224 } |
211 | 225 |
212 TypeHandle NowOf(Handle<i::Object> value) { | 226 TypeHandle NowOf(Handle<i::Object> value) { |
213 return Type::NowOf(value, region_); | 227 return Type::NowOf(value, region_); |
214 } | 228 } |
215 | 229 |
216 TypeHandle Constant(Handle<i::Object> value) { | 230 TypeHandle Constant(Handle<i::Object> value) { |
217 return Type::Constant(value, region_); | 231 return Type::Constant(value, region_); |
218 } | 232 } |
219 | 233 |
| 234 TypeHandle Range(double min, double max) { |
| 235 return Type::Range(min, max, region_); |
| 236 } |
| 237 |
220 TypeHandle Class(Handle<i::Map> map) { | 238 TypeHandle Class(Handle<i::Map> map) { |
221 return Type::Class(map, region_); | 239 return Type::Class(map, region_); |
222 } | 240 } |
223 | 241 |
224 TypeHandle Array1(TypeHandle element) { | 242 TypeHandle Array1(TypeHandle element) { |
225 return Type::Array(element, region_); | 243 return Type::Array(element, region_); |
226 } | 244 } |
227 | 245 |
228 TypeHandle Function0(TypeHandle result, TypeHandle receiver) { | 246 TypeHandle Function0(TypeHandle result, TypeHandle receiver) { |
229 return Type::Function(result, receiver, 0, region_); | 247 return Type::Function(result, receiver, 0, region_); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 v8::base::RandomNumberGenerator* rng_; | 338 v8::base::RandomNumberGenerator* rng_; |
321 }; | 339 }; |
322 | 340 |
323 | 341 |
324 template<class Type, class TypeHandle, class Region, class Rep> | 342 template<class Type, class TypeHandle, class Region, class Rep> |
325 struct Tests : Rep { | 343 struct Tests : Rep { |
326 typedef Types<Type, TypeHandle, Region> TypesInstance; | 344 typedef Types<Type, TypeHandle, Region> TypesInstance; |
327 typedef typename TypesInstance::TypeVector::iterator TypeIterator; | 345 typedef typename TypesInstance::TypeVector::iterator TypeIterator; |
328 typedef typename TypesInstance::MapVector::iterator MapIterator; | 346 typedef typename TypesInstance::MapVector::iterator MapIterator; |
329 typedef typename TypesInstance::ValueVector::iterator ValueIterator; | 347 typedef typename TypesInstance::ValueVector::iterator ValueIterator; |
| 348 typedef typename TypesInstance::DoubleVector::iterator DoubleIterator; |
330 | 349 |
331 Isolate* isolate; | 350 Isolate* isolate; |
332 HandleScope scope; | 351 HandleScope scope; |
333 Zone zone; | 352 Zone zone; |
334 TypesInstance T; | 353 TypesInstance T; |
335 | 354 |
336 Tests() : | 355 Tests() : |
337 isolate(CcTest::i_isolate()), | 356 isolate(CcTest::i_isolate()), |
338 scope(isolate), | 357 scope(isolate), |
339 zone(isolate), | 358 zone(isolate), |
340 T(Rep::ToRegion(&zone, isolate), isolate) { | 359 T(Rep::ToRegion(&zone, isolate), isolate) { |
341 } | 360 } |
342 | 361 |
343 bool Equal(TypeHandle type1, TypeHandle type2) { | 362 bool Equal(TypeHandle type1, TypeHandle type2) { |
344 return | 363 return |
345 type1->Is(type2) && type2->Is(type1) && | 364 type1->Is(type2) && type2->Is(type1) && |
346 Rep::IsBitset(type1) == Rep::IsBitset(type2) && | 365 Rep::IsBitset(type1) == Rep::IsBitset(type2) && |
347 Rep::IsClass(type1) == Rep::IsClass(type2) && | 366 Rep::IsClass(type1) == Rep::IsClass(type2) && |
348 Rep::IsConstant(type1) == Rep::IsConstant(type2) && | 367 Rep::IsConstant(type1) == Rep::IsConstant(type2) && |
| 368 Rep::IsRange(type1) == Rep::IsRange(type2) && |
349 Rep::IsContext(type1) == Rep::IsContext(type2) && | 369 Rep::IsContext(type1) == Rep::IsContext(type2) && |
350 Rep::IsArray(type1) == Rep::IsArray(type2) && | 370 Rep::IsArray(type1) == Rep::IsArray(type2) && |
351 Rep::IsFunction(type1) == Rep::IsFunction(type2) && | 371 Rep::IsFunction(type1) == Rep::IsFunction(type2) && |
352 Rep::IsUnion(type1) == Rep::IsUnion(type2) && | 372 Rep::IsUnion(type1) == Rep::IsUnion(type2) && |
353 type1->NumClasses() == type2->NumClasses() && | 373 type1->NumClasses() == type2->NumClasses() && |
354 type1->NumConstants() == type2->NumConstants() && | 374 type1->NumConstants() == type2->NumConstants() && |
355 (!Rep::IsBitset(type1) || | 375 (!Rep::IsBitset(type1) || |
356 Rep::AsBitset(type1) == Rep::AsBitset(type2)) && | 376 Rep::AsBitset(type1) == Rep::AsBitset(type2)) && |
357 (!Rep::IsClass(type1) || | 377 (!Rep::IsClass(type1) || |
358 Rep::AsClass(type1) == Rep::AsClass(type2)) && | 378 Rep::AsClass(type1) == Rep::AsClass(type2)) && |
359 (!Rep::IsConstant(type1) || | 379 (!Rep::IsConstant(type1) || |
360 Rep::AsConstant(type1) == Rep::AsConstant(type2)) && | 380 Rep::AsConstant(type1) == Rep::AsConstant(type2)) && |
| 381 (!Rep::IsRange(type1) || |
| 382 (type1->AsRange()->Min() == type2->AsRange()->Min() && |
| 383 type1->AsRange()->Max() == type2->AsRange()->Max())) && |
361 // TODO(rossberg): Check details of arrays, functions, bounds. | 384 // TODO(rossberg): Check details of arrays, functions, bounds. |
362 (!Rep::IsUnion(type1) || | 385 (!Rep::IsUnion(type1) || |
363 Rep::Length(Rep::AsUnion(type1)) == Rep::Length(Rep::AsUnion(type2))); | 386 Rep::Length(Rep::AsUnion(type1)) == Rep::Length(Rep::AsUnion(type2))); |
364 } | 387 } |
365 | 388 |
366 void CheckEqual(TypeHandle type1, TypeHandle type2) { | 389 void CheckEqual(TypeHandle type1, TypeHandle type2) { |
367 CHECK(Equal(type1, type2)); | 390 CHECK(Equal(type1, type2)); |
368 } | 391 } |
369 | 392 |
370 void CheckSub(TypeHandle type1, TypeHandle type2) { | 393 void CheckSub(TypeHandle type1, TypeHandle type2) { |
371 CHECK(type1->Is(type2)); | 394 CHECK(type1->Is(type2)); |
372 CHECK(!type2->Is(type1)); | 395 CHECK(!type2->Is(type1)); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber)); | 582 CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber)); |
560 CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber)); | 583 CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber)); |
561 CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber)); | 584 CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber)); |
562 CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber)); | 585 CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber)); |
563 CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero)); | 586 CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero)); |
564 CHECK(T.Constant(fac->NewNumber(v8::base::OS::nan_value()))->Is(T.NaN)); | 587 CHECK(T.Constant(fac->NewNumber(v8::base::OS::nan_value()))->Is(T.NaN)); |
565 CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.OtherNumber)); | 588 CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.OtherNumber)); |
566 CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber)); | 589 CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber)); |
567 } | 590 } |
568 | 591 |
| 592 void Range() { |
| 593 // Constructor |
| 594 for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) { |
| 595 for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) { |
| 596 double min = std::min(*i, *j); |
| 597 double max = std::max(*i, *j); |
| 598 TypeHandle type = T.Range(min, max); |
| 599 CHECK(this->IsRange(type)); |
| 600 } |
| 601 } |
| 602 |
| 603 // Range attributes |
| 604 for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) { |
| 605 for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) { |
| 606 double min = std::min(*i, *j); |
| 607 double max = std::max(*i, *j); |
| 608 TypeHandle type = T.Range(min, max); |
| 609 CHECK(min == type->AsRange()->Min()); |
| 610 CHECK(max == type->AsRange()->Max()); |
| 611 } |
| 612 } |
| 613 |
| 614 // TODO(neis): enable once subtyping is updated. |
| 615 // // Functionality & Injectivity: Range(min1, max1) = Range(min2, max2) <=> |
| 616 // // min1 = min2 /\ max1 = max2 |
| 617 // for (DoubleIterator i1 = T.doubles.begin(); i1 != T.doubles.end(); ++i1) { |
| 618 // for (DoubleIterator j1 = T.doubles.begin(); j1 != T.doubles.end(); ++j1) { |
| 619 // for (DoubleIterator i2 = T.doubles.begin(); |
| 620 // i2 != T.doubles.end(); ++i2) { |
| 621 // for (DoubleIterator j2 = T.doubles.begin(); |
| 622 // j2 != T.doubles.end(); ++j2) { |
| 623 // double min1 = std::min(*i1, *j1); |
| 624 // double max1 = std::max(*i1, *j1); |
| 625 // double min2 = std::min(*i2, *j2); |
| 626 // double max2 = std::max(*i2, *j2); |
| 627 // TypeHandle type1 = T.Range(min1, max1); |
| 628 // TypeHandle type2 = T.Range(min2, max2); |
| 629 // CHECK(Equal(type1, type2) == (min1 == min2 && max1 == max2)); |
| 630 // } |
| 631 // } |
| 632 // } |
| 633 // } |
| 634 } |
| 635 |
569 void Array() { | 636 void Array() { |
570 // Constructor | 637 // Constructor |
571 for (int i = 0; i < 20; ++i) { | 638 for (int i = 0; i < 20; ++i) { |
572 TypeHandle type = T.Random(); | 639 TypeHandle type = T.Random(); |
573 TypeHandle array = T.Array1(type); | 640 TypeHandle array = T.Array1(type); |
574 CHECK(this->IsArray(array)); | 641 CHECK(this->IsArray(array)); |
575 } | 642 } |
576 | 643 |
577 // Attributes | 644 // Attributes |
578 for (int i = 0; i < 20; ++i) { | 645 for (int i = 0; i < 20; ++i) { |
(...skipping 1208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1787 } | 1854 } |
1788 | 1855 |
1789 | 1856 |
1790 TEST(ConstantType) { | 1857 TEST(ConstantType) { |
1791 CcTest::InitializeVM(); | 1858 CcTest::InitializeVM(); |
1792 ZoneTests().Constant(); | 1859 ZoneTests().Constant(); |
1793 HeapTests().Constant(); | 1860 HeapTests().Constant(); |
1794 } | 1861 } |
1795 | 1862 |
1796 | 1863 |
| 1864 TEST(RangeType) { |
| 1865 CcTest::InitializeVM(); |
| 1866 ZoneTests().Range(); |
| 1867 HeapTests().Range(); |
| 1868 } |
| 1869 |
| 1870 |
1797 TEST(ArrayType) { | 1871 TEST(ArrayType) { |
1798 CcTest::InitializeVM(); | 1872 CcTest::InitializeVM(); |
1799 ZoneTests().Array(); | 1873 ZoneTests().Array(); |
1800 HeapTests().Array(); | 1874 HeapTests().Array(); |
1801 } | 1875 } |
1802 | 1876 |
1803 | 1877 |
1804 TEST(FunctionType) { | 1878 TEST(FunctionType) { |
1805 CcTest::InitializeVM(); | 1879 CcTest::InitializeVM(); |
1806 ZoneTests().Function(); | 1880 ZoneTests().Function(); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1911 ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>(); | 1985 ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>(); |
1912 HeapTests().Convert<Type, Type*, Zone, ZoneRep>(); | 1986 HeapTests().Convert<Type, Type*, Zone, ZoneRep>(); |
1913 } | 1987 } |
1914 | 1988 |
1915 | 1989 |
1916 TEST(HTypeFromType) { | 1990 TEST(HTypeFromType) { |
1917 CcTest::InitializeVM(); | 1991 CcTest::InitializeVM(); |
1918 ZoneTests().HTypeFromType(); | 1992 ZoneTests().HTypeFromType(); |
1919 HeapTests().HTypeFromType(); | 1993 HeapTests().HTypeFromType(); |
1920 } | 1994 } |
OLD | NEW |