Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: test/unittests/compiler/typer-unittest.cc

Issue 863283002: Convert compiler cctest to unittests: TyperTest (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Tweaks Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « test/cctest/types-fuzz.h ('k') | test/unittests/unittests.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <functional>
6
7 #include "src/codegen.h"
8 #include "src/compiler/js-operator.h"
9 #include "src/compiler/node-properties-inl.h"
10 #include "src/compiler/typer.h"
11 #include "src/isolate-inl.h"
12 #include "test/unittests/compiler/graph-unittest.h"
13 #include "testing/gmock-support.h"
14
15 using namespace v8::internal;
16 using namespace v8::internal::compiler;
17
18 namespace {
19
20 template <class Type, class TypeHandle, class Region>
21 class Types {
22 public:
23 Types(Region* region, Isolate* isolate)
24 : region_(region), rng_(isolate->random_number_generator()) {
25 #define DECLARE_TYPE(name, value) \
26 name = Type::name(region); \
27 types.push_back(name);
28 PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
29 #undef DECLARE_TYPE
30
31 object_map =
32 isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
33 array_map = isolate->factory()->NewMap(JS_ARRAY_TYPE, JSArray::kSize);
34 number_map =
35 isolate->factory()->NewMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
36 uninitialized_map = isolate->factory()->uninitialized_map();
37 ObjectClass = Type::Class(object_map, region);
38 ArrayClass = Type::Class(array_map, region);
39 NumberClass = Type::Class(number_map, region);
40 UninitializedClass = Type::Class(uninitialized_map, region);
41
42 maps.push_back(object_map);
43 maps.push_back(array_map);
44 maps.push_back(uninitialized_map);
45 for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
46 types.push_back(Type::Class(*it, region));
47 }
48
49 smi = handle(Smi::FromInt(666), isolate);
50 signed32 = isolate->factory()->NewHeapNumber(0x40000000);
51 object1 = isolate->factory()->NewJSObjectFromMap(object_map);
52 object2 = isolate->factory()->NewJSObjectFromMap(object_map);
53 array = isolate->factory()->NewJSArray(20);
54 uninitialized = isolate->factory()->uninitialized_value();
55 SmiConstant = Type::Constant(smi, region);
56 Signed32Constant = Type::Constant(signed32, region);
57 ObjectConstant1 = Type::Constant(object1, region);
58 ObjectConstant2 = Type::Constant(object2, region);
59 ArrayConstant = Type::Constant(array, region);
60 UninitializedConstant = Type::Constant(uninitialized, region);
61
62 values.push_back(smi);
63 values.push_back(signed32);
64 values.push_back(object1);
65 values.push_back(object2);
66 values.push_back(array);
67 values.push_back(uninitialized);
68 for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
69 types.push_back(Type::Constant(*it, region));
70 }
71
72 integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
73 integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
74 integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
75 integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
76 for (int i = 0; i < 10; ++i) {
77 double x = rng_->NextInt();
78 integers.push_back(isolate->factory()->NewNumber(x));
79 x *= rng_->NextInt();
80 if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
81 }
82
83 Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY),
84 isolate->factory()->NewNumber(+V8_INFINITY), region);
85
86 NumberArray = Type::Array(Number, region);
87 StringArray = Type::Array(String, region);
88 AnyArray = Type::Array(Any, region);
89
90 SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
91 NumberFunction1 = Type::Function(Number, Number, region);
92 NumberFunction2 = Type::Function(Number, Number, Number, region);
93 MethodFunction = Type::Function(String, Object, 0, region);
94
95 for (int i = 0; i < 30; ++i) {
96 types.push_back(Fuzz());
97 }
98 }
99
100 Handle<i::Map> object_map;
101 Handle<i::Map> array_map;
102 Handle<i::Map> number_map;
103 Handle<i::Map> uninitialized_map;
104
105 Handle<i::Smi> smi;
106 Handle<i::HeapNumber> signed32;
107 Handle<i::JSObject> object1;
108 Handle<i::JSObject> object2;
109 Handle<i::JSArray> array;
110 Handle<i::Oddball> uninitialized;
111
112 #define DECLARE_TYPE(name, value) TypeHandle name;
113 PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
114 #undef DECLARE_TYPE
115
116 TypeHandle ObjectClass;
117 TypeHandle ArrayClass;
118 TypeHandle NumberClass;
119 TypeHandle UninitializedClass;
120
121 TypeHandle SmiConstant;
122 TypeHandle Signed32Constant;
123 TypeHandle ObjectConstant1;
124 TypeHandle ObjectConstant2;
125 TypeHandle ArrayConstant;
126 TypeHandle UninitializedConstant;
127
128 TypeHandle Integer;
129
130 TypeHandle NumberArray;
131 TypeHandle StringArray;
132 TypeHandle AnyArray;
133
134 TypeHandle SignedFunction1;
135 TypeHandle NumberFunction1;
136 TypeHandle NumberFunction2;
137 TypeHandle MethodFunction;
138
139 typedef std::vector<TypeHandle> TypeVector;
140 typedef std::vector<Handle<i::Map> > MapVector;
141 typedef std::vector<Handle<i::Object> > ValueVector;
142
143 TypeVector types;
144 MapVector maps;
145 ValueVector values;
146 ValueVector integers; // "Integer" values used for range limits.
147
148 TypeHandle Of(Handle<i::Object> value) { return Type::Of(value, region_); }
149
150 TypeHandle NowOf(Handle<i::Object> value) {
151 return Type::NowOf(value, region_);
152 }
153
154 TypeHandle Class(Handle<i::Map> map) { return Type::Class(map, region_); }
155
156 TypeHandle Constant(Handle<i::Object> value) {
157 return Type::Constant(value, region_);
158 }
159
160 TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
161 return Type::Range(min, max, region_);
162 }
163
164 TypeHandle Context(TypeHandle outer) { return Type::Context(outer, region_); }
165
166 TypeHandle Array1(TypeHandle element) {
167 return Type::Array(element, region_);
168 }
169
170 TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
171 return Type::Function(result, receiver, 0, region_);
172 }
173
174 TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
175 TypeHandle type = Type::Function(result, receiver, 1, region_);
176 type->AsFunction()->InitParameter(0, arg);
177 return type;
178 }
179
180 TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
181 return Type::Function(result, arg1, arg2, region_);
182 }
183
184 TypeHandle Union(TypeHandle t1, TypeHandle t2) {
185 return Type::Union(t1, t2, region_);
186 }
187 TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
188 return Type::Intersect(t1, t2, region_);
189 }
190
191 template <class Type2, class TypeHandle2>
192 TypeHandle Convert(TypeHandle2 t) {
193 return Type::template Convert<Type2>(t, region_);
194 }
195
196 TypeHandle Random() {
197 return types[rng_->NextInt(static_cast<int>(types.size()))];
198 }
199
200 TypeHandle Fuzz(int depth = 4) {
201 switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
202 case 0: { // bitset
203 #define COUNT_BITSET_TYPES(type, value) +1
204 int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES);
205 #undef COUNT_BITSET_TYPES
206 // Pick a bunch of named bitsets and return their intersection.
207 TypeHandle result = Type::Any(region_);
208 for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) {
209 int j = rng_->NextInt(n);
210 #define PICK_BITSET_TYPE(type, value) \
211 if (j-- == 0) { \
212 TypeHandle tmp = Type::Intersect(result, Type::type(region_), region_); \
213 if (tmp->Is(Type::None()) && i != 0) { \
214 break; \
215 } else { \
216 result = tmp; \
217 continue; \
218 } \
219 }
220 PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
221 #undef PICK_BITSET_TYPE
222 }
223 return result;
224 }
225 case 1: { // class
226 int i = rng_->NextInt(static_cast<int>(maps.size()));
227 return Type::Class(maps[i], region_);
228 }
229 case 2: { // constant
230 int i = rng_->NextInt(static_cast<int>(values.size()));
231 return Type::Constant(values[i], region_);
232 }
233 case 3: { // range
234 int i = rng_->NextInt(static_cast<int>(integers.size()));
235 int j = rng_->NextInt(static_cast<int>(integers.size()));
236 i::Handle<i::Object> min = integers[i];
237 i::Handle<i::Object> max = integers[j];
238 if (min->Number() > max->Number()) std::swap(min, max);
239 return Type::Range(min, max, region_);
240 }
241 case 4: { // context
242 int depth = rng_->NextInt(3);
243 TypeHandle type = Type::Internal(region_);
244 for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
245 return type;
246 }
247 case 5: { // array
248 TypeHandle element = Fuzz(depth / 2);
249 return Type::Array(element, region_);
250 }
251 case 6:
252 case 7: { // function
253 TypeHandle result = Fuzz(depth / 2);
254 TypeHandle receiver = Fuzz(depth / 2);
255 int arity = rng_->NextInt(3);
256 TypeHandle type = Type::Function(result, receiver, arity, region_);
257 for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
258 TypeHandle parameter = Fuzz(depth / 2);
259 type->AsFunction()->InitParameter(i, parameter);
260 }
261 return type;
262 }
263 default: { // union
264 int n = rng_->NextInt(10);
265 TypeHandle type = None;
266 for (int i = 0; i < n; ++i) {
267 TypeHandle operand = Fuzz(depth - 1);
268 type = Type::Union(type, operand, region_);
269 }
270 return type;
271 }
272 }
273 UNREACHABLE();
274 }
275
276 Region* region() { return region_; }
277
278 private:
279 Region* region_;
280 v8::base::RandomNumberGenerator* rng_;
281 };
282
283
284 // TODO(titzer): generate a large set of deterministic inputs for these tests.
285 class TyperTest : public GraphTest {
286 public:
287 TyperTest()
288 : types_(zone(), isolate()),
289 typer_(graph(), MaybeHandle<Context>()),
290 javascript_(zone()) {
291 Node* s = graph()->NewNode(common()->Start(3));
292 graph()->SetStart(s);
293 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
294 rng_ = isolate()->random_number_generator();
295
296 integers.push_back(0);
297 integers.push_back(0);
298 integers.push_back(-1);
299 integers.push_back(+1);
300 integers.push_back(-V8_INFINITY);
301 integers.push_back(+V8_INFINITY);
302 for (int i = 0; i < 5; ++i) {
303 double x = rng_->NextInt();
304 integers.push_back(x);
305 x *= rng_->NextInt();
306 if (!IsMinusZero(x)) integers.push_back(x);
307 }
308
309 int32s.push_back(0);
310 int32s.push_back(0);
311 int32s.push_back(-1);
312 int32s.push_back(+1);
313 int32s.push_back(kMinInt);
314 int32s.push_back(kMaxInt);
315 for (int i = 0; i < 10; ++i) {
316 int32s.push_back(rng_->NextInt());
317 }
318 }
319
320 Types<Type, Type*, Zone> types_;
321 Typer typer_;
322 JSOperatorBuilder javascript_;
323 Node* context_node_;
324 v8::base::RandomNumberGenerator* rng_;
325 std::vector<double> integers;
326 std::vector<double> int32s;
327
328 Type* TypeBinaryOp(const Operator* op, Type* lhs, Type* rhs) {
329 Node* p0 = Parameter(0);
330 Node* p1 = Parameter(1);
331 NodeProperties::SetBounds(p0, Bounds(lhs));
332 NodeProperties::SetBounds(p1, Bounds(rhs));
333 Node* n = graph()->NewNode(op, p0, p1, context_node_, graph()->start(),
334 graph()->start());
335 return NodeProperties::GetBounds(n).upper;
336 }
337
338 Type* RandomRange(bool int32 = false) {
339 std::vector<double>& numbers = int32 ? int32s : integers;
340 double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
341 double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
342 return NewRange(i, j);
343 }
344
345 Type* NewRange(double i, double j) {
346 Factory* f = isolate()->factory();
347 i::Handle<i::Object> min = f->NewNumber(i);
348 i::Handle<i::Object> max = f->NewNumber(j);
349 if (min->Number() > max->Number()) std::swap(min, max);
350 return Type::Range(min, max, zone());
351 }
352
353 double RandomInt(double min, double max) {
354 switch (rng_->NextInt(4)) {
355 case 0:
356 return min;
357 case 1:
358 return max;
359 default:
360 break;
361 }
362 if (min == +V8_INFINITY) return +V8_INFINITY;
363 if (max == -V8_INFINITY) return -V8_INFINITY;
364 if (min == -V8_INFINITY && max == +V8_INFINITY) {
365 return rng_->NextInt() * static_cast<double>(rng_->NextInt());
366 }
367 double result = nearbyint(min + (max - min) * rng_->NextDouble());
368 if (IsMinusZero(result)) return 0;
369 if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
370 DCHECK(min <= result && result <= max);
371 return result;
372 }
373
374 double RandomInt(Type::RangeType* range) {
375 return RandomInt(range->Min()->Number(), range->Max()->Number());
376 }
377
378 // Careful, this function runs O(max_width^5) trials.
379 template <class BinaryFunction>
380 void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun,
381 int max_width) {
382 const int min_min = -2 - max_width / 2;
383 const int max_min = 2 + max_width / 2;
384 for (int width = 0; width < max_width; width++) {
385 for (int lmin = min_min; lmin <= max_min; lmin++) {
386 for (int rmin = min_min; rmin <= max_min; rmin++) {
387 Type* r1 = NewRange(lmin, lmin + width);
388 Type* r2 = NewRange(rmin, rmin + width);
389 Type* expected_type = TypeBinaryOp(op, r1, r2);
390
391 for (int x1 = lmin; x1 < lmin + width; x1++) {
392 for (int x2 = rmin; x2 < rmin + width; x2++) {
393 double result_value = opfun(x1, x2);
394 Type* result_type = Type::Constant(
395 isolate()->factory()->NewNumber(result_value), zone());
396 EXPECT_TRUE(result_type->Is(expected_type));
397 }
398 }
399 }
400 }
401 }
402 }
403
404 template <class BinaryFunction>
405 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
406 TestBinaryArithOpCloseToZero(op, opfun, 8);
407 for (int i = 0; i < 100; ++i) {
408 Type::RangeType* r1 = RandomRange()->AsRange();
409 Type::RangeType* r2 = RandomRange()->AsRange();
410 Type* expected_type = TypeBinaryOp(op, r1, r2);
411 for (int i = 0; i < 10; i++) {
412 double x1 = RandomInt(r1);
413 double x2 = RandomInt(r2);
414 double result_value = opfun(x1, x2);
415 Type* result_type = Type::Constant(
416 isolate()->factory()->NewNumber(result_value), zone());
417 EXPECT_TRUE(result_type->Is(expected_type));
418 }
419 }
420 }
421
422 template <class BinaryFunction>
423 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
424 for (int i = 0; i < 100; ++i) {
425 Type::RangeType* r1 = RandomRange()->AsRange();
426 Type::RangeType* r2 = RandomRange()->AsRange();
427 Type* expected_type = TypeBinaryOp(op, r1, r2);
428 for (int i = 0; i < 10; i++) {
429 double x1 = RandomInt(r1);
430 double x2 = RandomInt(r2);
431 bool result_value = opfun(x1, x2);
432 Type* result_type =
433 Type::Constant(result_value ? isolate()->factory()->true_value()
434 : isolate()->factory()->false_value(),
435 zone());
436 EXPECT_TRUE(result_type->Is(expected_type));
437 }
438 }
439 }
440
441 template <class BinaryFunction>
442 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
443 for (int i = 0; i < 100; ++i) {
444 Type::RangeType* r1 = RandomRange(true)->AsRange();
445 Type::RangeType* r2 = RandomRange(true)->AsRange();
446 Type* expected_type = TypeBinaryOp(op, r1, r2);
447 for (int i = 0; i < 10; i++) {
448 int32_t x1 = static_cast<int32_t>(RandomInt(r1));
449 int32_t x2 = static_cast<int32_t>(RandomInt(r2));
450 double result_value = opfun(x1, x2);
451 Type* result_type = Type::Constant(
452 isolate()->factory()->NewNumber(result_value), zone());
453 EXPECT_TRUE(result_type->Is(expected_type));
454 }
455 }
456 }
457
458 Type* RandomSubtype(Type* type) {
459 Type* subtype;
460 do {
461 subtype = types_.Fuzz();
462 } while (!subtype->Is(type));
463 return subtype;
464 }
465
466 void TestBinaryMonotonicity(const Operator* op) {
467 for (int i = 0; i < 50; ++i) {
468 Type* type1 = types_.Fuzz();
469 Type* type2 = types_.Fuzz();
470 Type* type = TypeBinaryOp(op, type1, type2);
471 Type* subtype1 = RandomSubtype(type1);
472 ;
473 Type* subtype2 = RandomSubtype(type2);
474 ;
475 Type* subtype = TypeBinaryOp(op, subtype1, subtype2);
476 EXPECT_TRUE(subtype->Is(type));
477 }
478 }
479 };
480
481
482 static int32_t shift_left(int32_t x, int32_t y) { return x << y; }
483 static int32_t shift_right(int32_t x, int32_t y) { return x >> y; }
484 static int32_t bit_or(int32_t x, int32_t y) { return x | y; }
485 static int32_t bit_and(int32_t x, int32_t y) { return x & y; }
486 static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
487 }
488
489
490 //------------------------------------------------------------------------------
491 // Soundness
492 // For simplicity, we currently only test soundness on expression operators
493 // that have a direct equivalent in C++. Also, testing is currently limited
494 // to ranges as input types.
495
496
497 TEST_F(TyperTest, TypeJSAdd2) {
498 TestBinaryArithOp(javascript_.Add(), std::plus<double>());
499 }
500
501
502 TEST_F(TyperTest, TypeJSSubtract) {
503 TestBinaryArithOp(javascript_.Subtract(), std::minus<double>());
504 }
505
506
507 TEST_F(TyperTest, TypeJSMultiply) {
508 TestBinaryArithOp(javascript_.Multiply(), std::multiplies<double>());
509 }
510
511
512 TEST_F(TyperTest, TypeJSDivide) {
513 TestBinaryArithOp(javascript_.Divide(), std::divides<double>());
514 }
515
516
517 TEST_F(TyperTest, TypeJSModulus) {
518 TestBinaryArithOp(javascript_.Modulus(), modulo);
519 }
520
521
522 TEST_F(TyperTest, TypeJSBitwiseOr) {
523 TestBinaryBitOp(javascript_.BitwiseOr(), bit_or);
524 }
525
526
527 TEST_F(TyperTest, TypeJSBitwiseAnd) {
528 TestBinaryBitOp(javascript_.BitwiseAnd(), bit_and);
529 }
530
531
532 TEST_F(TyperTest, TypeJSBitwiseXor) {
533 TestBinaryBitOp(javascript_.BitwiseXor(), bit_xor);
534 }
535
536
537 TEST_F(TyperTest, TypeJSShiftLeft) {
538 TestBinaryBitOp(javascript_.ShiftLeft(), shift_left);
539 }
540
541
542 TEST_F(TyperTest, TypeJSShiftRight) {
543 TestBinaryBitOp(javascript_.ShiftRight(), shift_right);
544 }
545
546
547 TEST_F(TyperTest, TypeJSLessThan) {
548 TestBinaryCompareOp(javascript_.LessThan(), std::less<double>());
549 }
550
551
552 TEST_F(TyperTest, TypeJSLessThanOrEqual) {
553 TestBinaryCompareOp(javascript_.LessThanOrEqual(), std::less_equal<double>());
554 }
555
556
557 TEST_F(TyperTest, TypeJSGreaterThan) {
558 TestBinaryCompareOp(javascript_.GreaterThan(), std::greater<double>());
559 }
560
561
562 TEST_F(TyperTest, TypeJSGreaterThanOrEqual) {
563 TestBinaryCompareOp(javascript_.GreaterThanOrEqual(),
564 std::greater_equal<double>());
565 }
566
567
568 TEST_F(TyperTest, TypeJSEqual) {
569 TestBinaryCompareOp(javascript_.Equal(), std::equal_to<double>());
570 }
571
572
573 TEST_F(TyperTest, TypeJSNotEqual) {
574 TestBinaryCompareOp(javascript_.NotEqual(), std::not_equal_to<double>());
575 }
576
577
578 // For numbers there's no difference between strict and non-strict equality.
579 TEST_F(TyperTest, TypeJSStrictEqual) {
580 TestBinaryCompareOp(javascript_.StrictEqual(), std::equal_to<double>());
581 }
582
583
584 TEST_F(TyperTest, TypeJSStrictNotEqual) {
585 TestBinaryCompareOp(javascript_.StrictNotEqual(),
586 std::not_equal_to<double>());
587 }
588
589
590 //------------------------------------------------------------------------------
591 // Monotonicity
592
593
594 // List should be in sync with JS_SIMPLE_BINOP_LIS
595 #define JSBINOP_LIST(V) \
596 V(Equal) \
597 V(NotEqual) \
598 V(StrictEqual) \
599 V(StrictNotEqual) \
600 V(LessThan) \
601 V(GreaterThan) \
602 V(LessThanOrEqual) \
603 V(GreaterThanOrEqual) \
604 V(BitwiseOr) \
605 V(BitwiseXor) \
606 V(BitwiseAnd) \
607 V(ShiftLeft) \
608 V(ShiftRight) \
609 V(ShiftRightLogical) \
610 V(Add) \
611 V(Subtract) \
612 V(Multiply) \
613 V(Divide) \
614 V(Modulus)
615
616
617 #define TEST_FUNC(name) \
618 TEST_F(TyperTest, Monotonicity_##name) { \
619 TestBinaryMonotonicity(javascript_.name()); \
620 }
621 JSBINOP_LIST(TEST_FUNC)
622 #undef TEST_FUNC
OLDNEW
« no previous file with comments | « test/cctest/types-fuzz.h ('k') | test/unittests/unittests.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698