Commit 2bfe09a6 authored by Benedikt Meurer's avatar Benedikt Meurer

[turbofan] Fix typing of typed array loads/stores.

R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/794113002

Cr-Commit-Position: refs/heads/master@{#25765}
parent f196a953
......@@ -731,13 +731,12 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
Node* key = NodeProperties::GetValueInput(node, 1);
Node* base = NodeProperties::GetValueInput(node, 0);
Type* key_type = NodeProperties::GetBounds(key).upper;
Type* base_type = NodeProperties::GetBounds(base).upper;
// TODO(mstarzinger): This lowering is not correct if:
// a) The typed array or it's buffer is neutered.
if (base_type->IsConstant() &&
base_type->AsConstant()->Value()->IsJSTypedArray()) {
HeapObjectMatcher<Object> mbase(base);
if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
Handle<JSTypedArray> const array =
Handle<JSTypedArray>::cast(base_type->AsConstant()->Value());
Handle<JSTypedArray>::cast(mbase.Value().handle());
array->GetBuffer()->set_is_neuterable(false);
BufferAccess const access(array->type());
size_t const k = ElementSizeLog2Of(access.machine_type());
......@@ -777,14 +776,13 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
Node* base = NodeProperties::GetValueInput(node, 0);
Node* value = NodeProperties::GetValueInput(node, 2);
Type* key_type = NodeProperties::GetBounds(key).upper;
Type* base_type = NodeProperties::GetBounds(base).upper;
Type* value_type = NodeProperties::GetBounds(value).upper;
// TODO(mstarzinger): This lowering is not correct if:
// a) The typed array or its buffer is neutered.
if (base_type->IsConstant() &&
base_type->AsConstant()->Value()->IsJSTypedArray()) {
HeapObjectMatcher<Object> mbase(base);
if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
Handle<JSTypedArray> const array =
Handle<JSTypedArray>::cast(base_type->AsConstant()->Value());
Handle<JSTypedArray>::cast(mbase.Value().handle());
array->GetBuffer()->set_is_neuterable(false);
BufferAccess const access(array->type());
size_t const k = ElementSizeLog2Of(access.machine_type());
......
......@@ -16,6 +16,16 @@ namespace v8 {
namespace internal {
namespace compiler {
#define NATIVE_TYPES(V) \
V(Int8) \
V(Uint8) \
V(Int16) \
V(Uint16) \
V(Int32) \
V(Uint32) \
V(Float32) \
V(Float64)
enum LazyCachedType {
kNumberFunc0,
kNumberFunc1,
......@@ -23,25 +33,18 @@ enum LazyCachedType {
kImulFunc,
kClz32Func,
kArrayBufferFunc,
kInt8ArrayFunc,
kInt16ArrayFunc,
kInt32ArrayFunc,
kUint8ArrayFunc,
kUint16ArrayFunc,
kUint32ArrayFunc,
kFloat32ArrayFunc,
kFloat64ArrayFunc,
#define NATIVE_TYPE_CASE(Type) k##Type, k##Type##Array, k##Type##ArrayFunc,
NATIVE_TYPES(NATIVE_TYPE_CASE)
#undef NATIVE_TYPE_CASE
kNumLazyCachedTypes
};
// Constructs and caches types lazily.
// TODO(turbofan): these types could be globally cached or cached per isolate.
struct LazyTypeCache : public ZoneObject {
Zone* zone;
Type* cache_[kNumLazyCachedTypes];
explicit LazyTypeCache(Zone* z) : zone(z) {
class LazyTypeCache FINAL : public ZoneObject {
public:
explicit LazyTypeCache(Zone* zone) : zone_(zone) {
memset(cache_, 0, sizeof(cache_));
}
......@@ -52,82 +55,88 @@ struct LazyTypeCache : public ZoneObject {
return cache_[index];
}
private:
Type* Create(LazyCachedType type) {
Factory* f = zone->isolate()->factory();
Handle<Smi> zero(Smi::FromInt(0), zone->isolate());
#define NATIVE_TYPE(sem, rep) Type::Intersect(Type::sem(), Type::rep(), zone)
switch (type) {
case kNumberFunc0: {
return Type::Function(Type::Number(), zone);
}
case kNumberFunc1: {
return Type::Function(Type::Number(), Type::Number(), zone);
}
case kNumberFunc2: {
case kInt8:
return CreateNative(CreateRange<int8_t>(), Type::UntaggedInt8());
case kUint8:
return CreateNative(CreateRange<uint8_t>(), Type::UntaggedInt8());
case kInt16:
return CreateNative(CreateRange<int16_t>(), Type::UntaggedInt16());
case kUint16:
return CreateNative(CreateRange<uint16_t>(), Type::UntaggedInt16());
case kInt32:
return CreateNative(Type::Signed32(), Type::UntaggedInt32());
case kUint32:
return CreateNative(Type::Unsigned32(), Type::UntaggedInt32());
case kFloat32:
return CreateNative(Type::Number(), Type::UntaggedFloat32());
case kFloat64:
return CreateNative(Type::Number(), Type::UntaggedFloat64());
case kNumberFunc0:
return Type::Function(Type::Number(), zone());
case kNumberFunc1:
return Type::Function(Type::Number(), Type::Number(), zone());
case kNumberFunc2:
return Type::Function(Type::Number(), Type::Number(), Type::Number(),
zone);
}
case kImulFunc: {
zone());
case kImulFunc:
return Type::Function(Type::Signed32(), Type::Integral32(),
Type::Integral32(), zone);
}
case kClz32Func: {
return Type::Function(Type::Range(zero, f->NewNumber(32), zone),
Type::Number(), zone);
}
case kArrayBufferFunc: {
return Type::Function(Type::Buffer(zone), Type::Unsigned32(), zone);
}
case kInt8ArrayFunc: {
return GetArrayFunc(Type::Intersect(
Type::Range(f->NewNumber(kMinInt8), f->NewNumber(kMaxInt8), zone),
Type::UntaggedInt8(), zone));
}
case kInt16ArrayFunc: {
return GetArrayFunc(Type::Intersect(
Type::Range(f->NewNumber(kMinInt16), f->NewNumber(kMaxInt16), zone),
Type::UntaggedInt16(), zone));
}
case kInt32ArrayFunc: {
return GetArrayFunc(NATIVE_TYPE(Signed32, UntaggedInt32));
}
case kUint8ArrayFunc: {
return GetArrayFunc(
Type::Intersect(Type::Range(zero, f->NewNumber(kMaxUInt8), zone),
Type::UntaggedInt8(), zone));
}
case kUint16ArrayFunc: {
return GetArrayFunc(
Type::Intersect(Type::Range(zero, f->NewNumber(kMaxUInt16), zone),
Type::UntaggedInt16(), zone));
}
case kUint32ArrayFunc: {
return GetArrayFunc(NATIVE_TYPE(Unsigned32, UntaggedInt32));
}
case kFloat32ArrayFunc: {
return GetArrayFunc(NATIVE_TYPE(Number, UntaggedFloat32));
}
case kFloat64ArrayFunc: {
return GetArrayFunc(NATIVE_TYPE(Number, UntaggedFloat64));
}
default:
Type::Integral32(), zone());
case kClz32Func:
return Type::Function(CreateRange(0, 32), Type::Number(), zone());
case kArrayBufferFunc:
return Type::Function(Type::Buffer(zone()), Type::Unsigned32(), zone());
#define NATIVE_TYPE_CASE(Type) \
case k##Type##Array: \
return CreateArray(Get(k##Type)); \
case k##Type##ArrayFunc: \
return CreateArrayFunction(Get(k##Type##Array));
NATIVE_TYPES(NATIVE_TYPE_CASE)
#undef NATIVE_TYPE_CASE
case kNumLazyCachedTypes:
break;
}
#undef NATIVE_TYPE
UNREACHABLE();
return NULL;
}
Type* GetArrayFunc(Type* element) {
Type* arg1 = Type::Union(Type::Unsigned32(), Type::Object(), zone);
Type* arg2 = Type::Union(Type::Unsigned32(), Type::Undefined(), zone);
Type* CreateArray(Type* element) const {
return Type::Array(element, zone());
}
Type* CreateArrayFunction(Type* array) const {
Type* arg1 = Type::Union(Type::Unsigned32(), Type::Object(), zone());
Type* arg2 = Type::Union(Type::Unsigned32(), Type::Undefined(), zone());
Type* arg3 = arg2;
return Type::Function(Type::Array(element, zone), arg1, arg2, arg3, zone);
return Type::Function(array, arg1, arg2, arg3, zone());
}
Type* CreateNative(Type* semantic, Type* representation) const {
return Type::Intersect(semantic, representation, zone());
}
template <typename T>
Type* CreateRange() const {
return CreateRange(std::numeric_limits<T>::min(),
std::numeric_limits<T>::max());
}
Type* CreateRange(double min, double max) const {
return Type::Range(factory()->NewNumber(min), factory()->NewNumber(max),
zone());
}
Factory* factory() const { return isolate()->factory(); }
Isolate* isolate() const { return zone()->isolate(); }
Zone* zone() const { return zone_; }
Type* cache_[kNumLazyCachedTypes];
Zone* zone_;
};
class Typer::Decorator : public GraphDecorator {
public:
explicit Decorator(Typer* typer) : typer_(typer) {}
......@@ -182,12 +191,6 @@ Typer::Typer(Graph* graph, MaybeHandle<Context> context)
integer = Type::Range(minusinfinity, infinity, zone);
weakint = Type::Union(integer, nan_or_minuszero, zone);
signed8_ = Type::Range(f->NewNumber(kMinInt8), f->NewNumber(kMaxInt8), zone);
unsigned8_ = Type::Range(zero, f->NewNumber(kMaxUInt8), zone);
signed16_ =
Type::Range(f->NewNumber(kMinInt16), f->NewNumber(kMaxInt16), zone);
unsigned16_ = Type::Range(zero, f->NewNumber(kMaxUInt16), zone);
number_fun0_ = Type::Function(number, zone);
number_fun1_ = Type::Function(number, number, zone);
number_fun2_ = Type::Function(number, number, number, zone);
......@@ -1606,22 +1609,14 @@ Bounds Typer::Visitor::TypeLoadField(Node* node) {
Bounds Typer::Visitor::TypeLoadBuffer(Node* node) {
// TODO(bmeurer): This typing is not yet correct. Since we can still access
// out of bounds, the type in the general case has to include Undefined.
switch (BufferAccessOf(node->op()).external_array_type()) {
case kExternalInt8Array:
return Bounds(typer_->signed8_);
case kExternalUint8Array:
return Bounds(typer_->unsigned8_);
case kExternalInt16Array:
return Bounds(typer_->signed16_);
case kExternalUint16Array:
return Bounds(typer_->unsigned16_);
case kExternalInt32Array:
return Bounds(Type::Signed32());
case kExternalUint32Array:
return Bounds(Type::Unsigned32());
case kExternalFloat32Array:
case kExternalFloat64Array:
return Bounds(Type::Number());
#define NATIVE_TYPE_CASE(Type) \
case kExternal##Type##Array: \
return Bounds(typer_->cache_->Get(k##Type));
NATIVE_TYPES(NATIVE_TYPE_CASE)
#undef NATIVE_TYPE_CASE
case kExternalUint8ClampedArray:
break;
}
......@@ -2088,6 +2083,17 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
return typer_->cache_->Get(kFloat64ArrayFunc);
}
}
} else if (value->IsJSTypedArray()) {
switch (JSTypedArray::cast(*value)->type()) {
#define NATIVE_TYPE_CASE(Type) \
case kExternal##Type##Array: \
return typer_->cache_->Get(k##Type##Array);
NATIVE_TYPES(NATIVE_TYPE_CASE)
#undef NATIVE_TYPE_CASE
case kExternalUint8ClampedArray:
// TODO(rossberg): Do we want some ClampedArray type to express this?
break;
}
}
return Type::Constant(value, zone());
}
......
......@@ -15,7 +15,9 @@ namespace v8 {
namespace internal {
namespace compiler {
struct LazyTypeCache;
// Forward declarations.
class LazyTypeCache;
class Typer {
public:
......@@ -54,10 +56,6 @@ class Typer {
Type* falsish;
Type* integer;
Type* weakint;
Type* signed8_;
Type* unsigned8_;
Type* signed16_;
Type* unsigned16_;
Type* number_fun0_;
Type* number_fun1_;
Type* number_fun2_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment