From 7f7354f3fdd2ddbec0e48c9dbc157ca4d728cef1 Mon Sep 17 00:00:00 2001 From: "neis@chromium.org" Date: Fri, 17 Oct 2014 11:46:06 +0000 Subject: [PATCH] Test monotonicity of expression typings. R=rossberg@chromium.org BUG= Review URL: https://codereview.chromium.org/653093002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24693 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- test/cctest/compiler/test-typer.cc | 74 ++++++++- test/cctest/test-types.cc | 279 +------------------------------- test/cctest/types-fuzz.h | 317 +++++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+), 286 deletions(-) create mode 100644 test/cctest/types-fuzz.h diff --git a/test/cctest/compiler/test-typer.cc b/test/cctest/compiler/test-typer.cc index f8aefad..eb5b987 100644 --- a/test/cctest/compiler/test-typer.cc +++ b/test/cctest/compiler/test-typer.cc @@ -2,20 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - -// This tests the correctness of the typer. -// -// For simplicity, it currently only tests it on expression operators that have -// a direct equivalent in C++. Also, testing is currently limited to ranges as -// input types. - - #include #include "src/compiler/node-properties-inl.h" #include "src/compiler/typer.h" #include "test/cctest/cctest.h" #include "test/cctest/compiler/graph-builder-tester.h" +#include "test/cctest/types-fuzz.h" using namespace v8::internal; using namespace v8::internal::compiler; @@ -26,6 +19,7 @@ class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { public: TyperTester() : GraphAndBuilders(main_zone()), + types_(main_zone(), isolate()), typer_(graph(), MaybeHandle()), javascript_(main_zone()) { Node* s = graph()->NewNode(common()->Start(3)); @@ -57,6 +51,7 @@ class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { } } + Types types_; Typer typer_; JSOperatorBuilder javascript_; Node* context_node_; @@ -160,6 +155,26 @@ class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { CHECK(result_type->Is(expected_type)); } } + + Type* RandomSubtype(Type* type) { + Type* subtype; + do { + subtype = types_.Fuzz(); + } while (!subtype->Is(type)); + return subtype; + } + + void TestBinaryMonotonicity(const Operator* op) { + for (int i = 0; i < 50; ++i) { + Type* type1 = types_.Fuzz(); + Type* type2 = types_.Fuzz(); + Type* type = TypeBinaryOp(op, type1, type2); + Type* subtype1 = RandomSubtype(type1);; + Type* subtype2 = RandomSubtype(type2);; + Type* subtype = TypeBinaryOp(op, subtype1, subtype2); + CHECK(subtype->Is(type)); + } + } }; @@ -170,6 +185,13 @@ static int32_t bit_and(int32_t x, int32_t y) { return x & y; } static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; } +//------------------------------------------------------------------------------ +// Soundness +// For simplicity, we currently only test soundness on expression operators +// that have a direct equivalent in C++. Also, testing is currently limited +// to ranges as input types. + + TEST(TypeJSAdd) { TyperTester t; t.TestBinaryArithOp(t.javascript_.Subtract(), std::plus()); @@ -274,3 +296,39 @@ TEST(TypeJSStrictNotEqual) { t.TestBinaryCompareOp( t.javascript_.StrictNotEqual(), std::not_equal_to()); } + + +//------------------------------------------------------------------------------ +// Monotonicity + + +// List should be in sync with JS_SIMPLE_BINOP_LIST. +#define JSBINOP_LIST(V) \ + V(Equal) \ + V(NotEqual) \ + V(StrictEqual) \ + V(StrictNotEqual) \ + V(LessThan) \ + V(GreaterThan) \ + V(LessThanOrEqual) \ + V(GreaterThanOrEqual) \ + V(BitwiseOr) \ + V(BitwiseXor) \ + V(BitwiseAnd) \ + V(ShiftLeft) \ + V(ShiftRight) \ + V(ShiftRightLogical) \ + V(Add) \ + V(Subtract) \ + V(Multiply) \ + V(Divide) \ + V(Modulus) + + +TEST(Monotonicity) { + TyperTester t; + #define TEST_OP(name) \ + t.TestBinaryMonotonicity(t.javascript_.name()); + JSBINOP_LIST(TEST_OP) + #undef TEST_OP +} diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index 86a8d4e..c30be77 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -8,6 +8,7 @@ #include "src/isolate-inl.h" #include "src/types.h" #include "test/cctest/cctest.h" +#include "test/cctest/types-fuzz.h" using namespace v8::internal; @@ -90,284 +91,6 @@ struct HeapRep { }; -template -class Types { - public: - Types(Region* region, Isolate* isolate) - : region_(region), rng_(isolate->random_number_generator()) { - #define DECLARE_TYPE(name, value) \ - name = Type::name(region); \ - if (SmiValuesAre31Bits() || \ - (!Type::name(region)->Equals(Type::OtherSigned32()) && \ - !Type::name(region)->Equals(Type::OtherUnsigned31()))) { \ - /* Hack: Avoid generating those empty bitset types. */ \ - types.push_back(name); \ - } - PROPER_BITSET_TYPE_LIST(DECLARE_TYPE) - #undef DECLARE_TYPE - - object_map = isolate->factory()->NewMap( - JS_OBJECT_TYPE, JSObject::kHeaderSize); - array_map = isolate->factory()->NewMap( - JS_ARRAY_TYPE, JSArray::kSize); - number_map = isolate->factory()->NewMap( - HEAP_NUMBER_TYPE, HeapNumber::kSize); - uninitialized_map = isolate->factory()->uninitialized_map(); - ObjectClass = Type::Class(object_map, region); - ArrayClass = Type::Class(array_map, region); - NumberClass = Type::Class(number_map, region); - UninitializedClass = Type::Class(uninitialized_map, region); - - maps.push_back(object_map); - maps.push_back(array_map); - maps.push_back(uninitialized_map); - for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) { - types.push_back(Type::Class(*it, region)); - } - - smi = handle(Smi::FromInt(666), isolate); - signed32 = isolate->factory()->NewHeapNumber(0x40000000); - object1 = isolate->factory()->NewJSObjectFromMap(object_map); - object2 = isolate->factory()->NewJSObjectFromMap(object_map); - array = isolate->factory()->NewJSArray(20); - uninitialized = isolate->factory()->uninitialized_value(); - SmiConstant = Type::Constant(smi, region); - Signed32Constant = Type::Constant(signed32, region); - ObjectConstant1 = Type::Constant(object1, region); - ObjectConstant2 = Type::Constant(object2, region); - ArrayConstant = Type::Constant(array, region); - UninitializedConstant = Type::Constant(uninitialized, region); - - values.push_back(smi); - values.push_back(signed32); - values.push_back(object1); - values.push_back(object2); - values.push_back(array); - values.push_back(uninitialized); - for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { - types.push_back(Type::Constant(*it, region)); - } - - integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY)); - integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY)); - integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10))); - integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10))); - for (int i = 0; i < 10; ++i) { - double x = rng_->NextInt(); - integers.push_back(isolate->factory()->NewNumber(x)); - x *= rng_->NextInt(); - if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x)); - } - - NumberArray = Type::Array(Number, region); - StringArray = Type::Array(String, region); - AnyArray = Type::Array(Any, region); - - SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region); - NumberFunction1 = Type::Function(Number, Number, region); - NumberFunction2 = Type::Function(Number, Number, Number, region); - MethodFunction = Type::Function(String, Object, 0, region); - - for (int i = 0; i < 30; ++i) { - types.push_back(Fuzz()); - } - } - - Handle object_map; - Handle array_map; - Handle number_map; - Handle uninitialized_map; - - Handle smi; - Handle signed32; - Handle object1; - Handle object2; - Handle array; - Handle uninitialized; - - #define DECLARE_TYPE(name, value) TypeHandle name; - BITSET_TYPE_LIST(DECLARE_TYPE) - #undef DECLARE_TYPE - - TypeHandle ObjectClass; - TypeHandle ArrayClass; - TypeHandle NumberClass; - TypeHandle UninitializedClass; - - TypeHandle SmiConstant; - TypeHandle Signed32Constant; - TypeHandle ObjectConstant1; - TypeHandle ObjectConstant2; - TypeHandle ArrayConstant; - TypeHandle UninitializedConstant; - - TypeHandle NumberArray; - TypeHandle StringArray; - TypeHandle AnyArray; - - TypeHandle SignedFunction1; - TypeHandle NumberFunction1; - TypeHandle NumberFunction2; - TypeHandle MethodFunction; - - typedef std::vector TypeVector; - typedef std::vector > MapVector; - typedef std::vector > ValueVector; - - TypeVector types; - MapVector maps; - ValueVector values; - ValueVector integers; // "Integer" values used for range limits. - - TypeHandle Of(Handle value) { - return Type::Of(value, region_); - } - - TypeHandle NowOf(Handle value) { - return Type::NowOf(value, region_); - } - - TypeHandle Class(Handle map) { - return Type::Class(map, region_); - } - - TypeHandle Constant(Handle value) { - return Type::Constant(value, region_); - } - - TypeHandle Range(Handle min, Handle max) { - return Type::Range(min, max, region_); - } - - TypeHandle Context(TypeHandle outer) { - return Type::Context(outer, region_); - } - - TypeHandle Array1(TypeHandle element) { - return Type::Array(element, region_); - } - - TypeHandle Function0(TypeHandle result, TypeHandle receiver) { - return Type::Function(result, receiver, 0, region_); - } - - TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) { - TypeHandle type = Type::Function(result, receiver, 1, region_); - type->AsFunction()->InitParameter(0, arg); - return type; - } - - TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) { - return Type::Function(result, arg1, arg2, region_); - } - - TypeHandle Union(TypeHandle t1, TypeHandle t2) { - return Type::Union(t1, t2, region_); - } - TypeHandle Intersect(TypeHandle t1, TypeHandle t2) { - return Type::Intersect(t1, t2, region_); - } - - template - TypeHandle Convert(TypeHandle2 t) { - return Type::template Convert(t, region_); - } - - TypeHandle Random() { - return types[rng_->NextInt(static_cast(types.size()))]; - } - - TypeHandle Fuzz(int depth = 4) { - switch (rng_->NextInt(depth == 0 ? 3 : 20)) { - case 0: { // bitset - #define COUNT_BITSET_TYPES(type, value) + 1 - int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES); - #undef COUNT_BITSET_TYPES - // Pick a bunch of named bitsets and return their intersection. - TypeHandle result = Type::Any(region_); - for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) { - int j = rng_->NextInt(n); - #define PICK_BITSET_TYPE(type, value) \ - if (j-- == 0) { \ - if (!SmiValuesAre31Bits() && \ - (Type::type(region_)->Equals(Type::OtherSigned32()) || \ - Type::type(region_)->Equals(Type::OtherUnsigned31()))) { \ - /* Hack: Avoid generating those empty bitset types. */ \ - continue; \ - } \ - TypeHandle tmp = Type::Intersect( \ - result, Type::type(region_), region_); \ - if (tmp->Is(Type::None()) && i != 0) { \ - break; \ - } else { \ - result = tmp; \ - continue; \ - } \ - } - PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE) - #undef PICK_BITSET_TYPE - } - return result; - } - case 1: { // class - int i = rng_->NextInt(static_cast(maps.size())); - return Type::Class(maps[i], region_); - } - case 2: { // constant - int i = rng_->NextInt(static_cast(values.size())); - return Type::Constant(values[i], region_); - } - case 3: { // range - int i = rng_->NextInt(static_cast(integers.size())); - int j = rng_->NextInt(static_cast(integers.size())); - i::Handle min = integers[i]; - i::Handle max = integers[j]; - if (min->Number() > max->Number()) std::swap(min, max); - return Type::Range(min, max, region_); - } - case 4: { // context - int depth = rng_->NextInt(3); - TypeHandle type = Type::Internal(region_); - for (int i = 0; i < depth; ++i) type = Type::Context(type, region_); - return type; - } - case 5: { // array - TypeHandle element = Fuzz(depth / 2); - return Type::Array(element, region_); - } - case 6: - case 7: { // function - TypeHandle result = Fuzz(depth / 2); - TypeHandle receiver = Fuzz(depth / 2); - int arity = rng_->NextInt(3); - TypeHandle type = Type::Function(result, receiver, arity, region_); - for (int i = 0; i < type->AsFunction()->Arity(); ++i) { - TypeHandle parameter = Fuzz(depth / 2); - type->AsFunction()->InitParameter(i, parameter); - } - return type; - } - default: { // union - int n = rng_->NextInt(10); - TypeHandle type = None; - for (int i = 0; i < n; ++i) { - TypeHandle operand = Fuzz(depth - 1); - type = Type::Union(type, operand, region_); - } - return type; - } - } - UNREACHABLE(); - } - - Region* region() { return region_; } - - private: - Region* region_; - v8::base::RandomNumberGenerator* rng_; -}; - - template struct Tests : Rep { typedef Types TypesInstance; diff --git a/test/cctest/types-fuzz.h b/test/cctest/types-fuzz.h new file mode 100644 index 0000000..23e33ad --- /dev/null +++ b/test/cctest/types-fuzz.h @@ -0,0 +1,317 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_TEST_CCTEST_TYPES_H_ +#define V8_TEST_CCTEST_TYPES_H_ + +#include "src/v8.h" + +namespace v8 { +namespace internal { + + +template +class Types { + public: + Types(Region* region, Isolate* isolate) + : region_(region), rng_(isolate->random_number_generator()) { + #define DECLARE_TYPE(name, value) \ + name = Type::name(region); \ + if (SmiValuesAre31Bits() || \ + (!Type::name(region)->Equals(Type::OtherSigned32()) && \ + !Type::name(region)->Equals(Type::OtherUnsigned31()))) { \ + /* Hack: Avoid generating those empty bitset types. */ \ + types.push_back(name); \ + } + PROPER_BITSET_TYPE_LIST(DECLARE_TYPE) + #undef DECLARE_TYPE + + object_map = isolate->factory()->NewMap( + JS_OBJECT_TYPE, JSObject::kHeaderSize); + array_map = isolate->factory()->NewMap( + JS_ARRAY_TYPE, JSArray::kSize); + number_map = isolate->factory()->NewMap( + HEAP_NUMBER_TYPE, HeapNumber::kSize); + uninitialized_map = isolate->factory()->uninitialized_map(); + ObjectClass = Type::Class(object_map, region); + ArrayClass = Type::Class(array_map, region); + NumberClass = Type::Class(number_map, region); + UninitializedClass = Type::Class(uninitialized_map, region); + + maps.push_back(object_map); + maps.push_back(array_map); + maps.push_back(uninitialized_map); + for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) { + types.push_back(Type::Class(*it, region)); + } + + smi = handle(Smi::FromInt(666), isolate); + signed32 = isolate->factory()->NewHeapNumber(0x40000000); + object1 = isolate->factory()->NewJSObjectFromMap(object_map); + object2 = isolate->factory()->NewJSObjectFromMap(object_map); + array = isolate->factory()->NewJSArray(20); + uninitialized = isolate->factory()->uninitialized_value(); + SmiConstant = Type::Constant(smi, region); + Signed32Constant = Type::Constant(signed32, region); + ObjectConstant1 = Type::Constant(object1, region); + ObjectConstant2 = Type::Constant(object2, region); + ArrayConstant = Type::Constant(array, region); + UninitializedConstant = Type::Constant(uninitialized, region); + + values.push_back(smi); + values.push_back(signed32); + values.push_back(object1); + values.push_back(object2); + values.push_back(array); + values.push_back(uninitialized); + for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { + types.push_back(Type::Constant(*it, region)); + } + + integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY)); + integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY)); + integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10))); + integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10))); + for (int i = 0; i < 10; ++i) { + double x = rng_->NextInt(); + integers.push_back(isolate->factory()->NewNumber(x)); + x *= rng_->NextInt(); + if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x)); + } + + NumberArray = Type::Array(Number, region); + StringArray = Type::Array(String, region); + AnyArray = Type::Array(Any, region); + + SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region); + NumberFunction1 = Type::Function(Number, Number, region); + NumberFunction2 = Type::Function(Number, Number, Number, region); + MethodFunction = Type::Function(String, Object, 0, region); + + for (int i = 0; i < 30; ++i) { + types.push_back(Fuzz()); + } + } + + Handle object_map; + Handle array_map; + Handle number_map; + Handle uninitialized_map; + + Handle smi; + Handle signed32; + Handle object1; + Handle object2; + Handle array; + Handle uninitialized; + + #define DECLARE_TYPE(name, value) TypeHandle name; + BITSET_TYPE_LIST(DECLARE_TYPE) + #undef DECLARE_TYPE + + TypeHandle ObjectClass; + TypeHandle ArrayClass; + TypeHandle NumberClass; + TypeHandle UninitializedClass; + + TypeHandle SmiConstant; + TypeHandle Signed32Constant; + TypeHandle ObjectConstant1; + TypeHandle ObjectConstant2; + TypeHandle ArrayConstant; + TypeHandle UninitializedConstant; + + TypeHandle NumberArray; + TypeHandle StringArray; + TypeHandle AnyArray; + + TypeHandle SignedFunction1; + TypeHandle NumberFunction1; + TypeHandle NumberFunction2; + TypeHandle MethodFunction; + + typedef std::vector TypeVector; + typedef std::vector > MapVector; + typedef std::vector > ValueVector; + + TypeVector types; + MapVector maps; + ValueVector values; + ValueVector integers; // "Integer" values used for range limits. + + TypeHandle Of(Handle value) { + return Type::Of(value, region_); + } + + TypeHandle NowOf(Handle value) { + return Type::NowOf(value, region_); + } + + TypeHandle Class(Handle map) { + return Type::Class(map, region_); + } + + TypeHandle Constant(Handle value) { + return Type::Constant(value, region_); + } + + TypeHandle Range(Handle min, Handle max) { + return Type::Range(min, max, region_); + } + + TypeHandle Context(TypeHandle outer) { + return Type::Context(outer, region_); + } + + TypeHandle Array1(TypeHandle element) { + return Type::Array(element, region_); + } + + TypeHandle Function0(TypeHandle result, TypeHandle receiver) { + return Type::Function(result, receiver, 0, region_); + } + + TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) { + TypeHandle type = Type::Function(result, receiver, 1, region_); + type->AsFunction()->InitParameter(0, arg); + return type; + } + + TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) { + return Type::Function(result, arg1, arg2, region_); + } + + TypeHandle Union(TypeHandle t1, TypeHandle t2) { + return Type::Union(t1, t2, region_); + } + TypeHandle Intersect(TypeHandle t1, TypeHandle t2) { + return Type::Intersect(t1, t2, region_); + } + + template + TypeHandle Convert(TypeHandle2 t) { + return Type::template Convert(t, region_); + } + + TypeHandle Random() { + return types[rng_->NextInt(static_cast(types.size()))]; + } + + TypeHandle Fuzz(int depth = 4) { + switch (rng_->NextInt(depth == 0 ? 3 : 20)) { + case 0: { // bitset + #define COUNT_BITSET_TYPES(type, value) + 1 + int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES); + #undef COUNT_BITSET_TYPES + // Pick a bunch of named bitsets and return their intersection. + TypeHandle result = Type::Any(region_); + for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) { + int j = rng_->NextInt(n); + #define PICK_BITSET_TYPE(type, value) \ + if (j-- == 0) { \ + if (!SmiValuesAre31Bits() && \ + (Type::type(region_)->Equals(Type::OtherSigned32()) || \ + Type::type(region_)->Equals(Type::OtherUnsigned31()))) { \ + /* Hack: Avoid generating those empty bitset types. */ \ + continue; \ + } \ + TypeHandle tmp = Type::Intersect( \ + result, Type::type(region_), region_); \ + if (tmp->Is(Type::None()) && i != 0) { \ + break; \ + } else { \ + result = tmp; \ + continue; \ + } \ + } + PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE) + #undef PICK_BITSET_TYPE + } + return result; + } + case 1: { // class + int i = rng_->NextInt(static_cast(maps.size())); + return Type::Class(maps[i], region_); + } + case 2: { // constant + int i = rng_->NextInt(static_cast(values.size())); + return Type::Constant(values[i], region_); + } + case 3: { // range + int i = rng_->NextInt(static_cast(integers.size())); + int j = rng_->NextInt(static_cast(integers.size())); + i::Handle min = integers[i]; + i::Handle max = integers[j]; + if (min->Number() > max->Number()) std::swap(min, max); + return Type::Range(min, max, region_); + } + case 4: { // context + int depth = rng_->NextInt(3); + TypeHandle type = Type::Internal(region_); + for (int i = 0; i < depth; ++i) type = Type::Context(type, region_); + return type; + } + case 5: { // array + TypeHandle element = Fuzz(depth / 2); + return Type::Array(element, region_); + } + case 6: + case 7: { // function + TypeHandle result = Fuzz(depth / 2); + TypeHandle receiver = Fuzz(depth / 2); + int arity = rng_->NextInt(3); + TypeHandle type = Type::Function(result, receiver, arity, region_); + for (int i = 0; i < type->AsFunction()->Arity(); ++i) { + TypeHandle parameter = Fuzz(depth / 2); + type->AsFunction()->InitParameter(i, parameter); + } + return type; + } + default: { // union + int n = rng_->NextInt(10); + TypeHandle type = None; + for (int i = 0; i < n; ++i) { + TypeHandle operand = Fuzz(depth - 1); + type = Type::Union(type, operand, region_); + } + return type; + } + } + UNREACHABLE(); + } + + Region* region() { return region_; } + + private: + Region* region_; + v8::base::RandomNumberGenerator* rng_; +}; + + +} } // namespace v8::internal + +#endif -- 2.7.4