// static
FieldAccess AccessBuilder::ForMap() {
- return {kTaggedBase, HeapObject::kMapOffset, Handle<Name>(), Type::Any(),
+ return {kTaggedBase, HeapObject::kMapOffset, MaybeHandle<Name>(), Type::Any(),
kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForJSObjectProperties() {
- return {kTaggedBase, JSObject::kPropertiesOffset, Handle<Name>(), Type::Any(),
- kMachAnyTagged};
+ return {kTaggedBase, JSObject::kPropertiesOffset, MaybeHandle<Name>(),
+ Type::Any(), kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForJSObjectElements() {
- return {kTaggedBase, JSObject::kElementsOffset, Handle<Name>(),
+ return {kTaggedBase, JSObject::kElementsOffset, MaybeHandle<Name>(),
Type::Internal(), kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForJSFunctionContext() {
- return {kTaggedBase, JSFunction::kContextOffset, Handle<Name>(),
+ return {kTaggedBase, JSFunction::kContextOffset, MaybeHandle<Name>(),
Type::Internal(), kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForJSArrayBufferBackingStore() {
- return {kTaggedBase, JSArrayBuffer::kBackingStoreOffset, Handle<Name>(),
+ return {kTaggedBase, JSArrayBuffer::kBackingStoreOffset, MaybeHandle<Name>(),
Type::UntaggedPtr(), kMachPtr};
}
// static
FieldAccess AccessBuilder::ForExternalArrayPointer() {
- return {kTaggedBase, ExternalArray::kExternalPointerOffset, Handle<Name>(),
- Type::UntaggedPtr(), kMachPtr};
+ return {kTaggedBase, ExternalArray::kExternalPointerOffset,
+ MaybeHandle<Name>(), Type::UntaggedPtr(), kMachPtr};
}
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 turns external (i.e. MaterializeArrayBuffer)
- // b) The typed array or it's buffer is neutered.
- // c) The index is out of bounds.
+ // a) The typed array or it's buffer is neutered.
+ // b) The index is out of bounds.
if (base_type->IsConstant() && key_type->Is(Type::Integral32()) &&
base_type->AsConstant()->Value()->IsJSTypedArray()) {
// JSLoadProperty(typed-array, int32)
- JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
- ElementsKind elements_kind = array->map()->elements_kind();
- ExternalArrayType type = array->type();
- uint32_t length;
- CHECK(array->length()->ToUint32(&length));
- ElementAccess element_access;
- Node* elements = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
- NodeProperties::GetEffectInput(node));
- if (IsExternalArrayElementsKind(elements_kind)) {
- elements = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()),
- elements, NodeProperties::GetEffectInput(node));
- element_access = AccessBuilder::ForTypedArrayElement(type, true);
- } else {
- DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
- element_access = AccessBuilder::ForTypedArrayElement(type, false);
+ Handle<JSTypedArray> array =
+ Handle<JSTypedArray>::cast(base_type->AsConstant()->Value());
+ if (IsExternalArrayElementsKind(array->map()->elements_kind())) {
+ Handle<JSArrayBuffer> buffer =
+ handle(JSArrayBuffer::cast(array->buffer()));
+ ExternalArrayType type = array->type();
+ uint32_t length;
+ CHECK(array->length()->ToUint32(&length));
+ Node* elements =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferBackingStore()),
+ jsgraph()->HeapConstant(buffer), graph()->start());
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ node->set_op(simplified()->LoadElement(
+ AccessBuilder::ForTypedArrayElement(type, true)));
+ node->ReplaceInput(0, elements);
+ node->ReplaceInput(2, jsgraph()->Uint32Constant(length));
+ node->ReplaceInput(3, effect);
+ node->ReplaceInput(4, control);
+ node->TrimInputCount(5);
+ return Changed(node);
}
- Node* value = graph()->NewNode(
- simplified()->LoadElement(element_access), elements, key,
- jsgraph()->Uint32Constant(length), NodeProperties::GetEffectInput(node),
- NodeProperties::GetControlInput(node));
- return ReplaceEagerly(node, value);
}
return NoChange();
}
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 turns external (i.e. MaterializeArrayBuffer)
- // b) The typed array or its buffer is neutered.
+ // a) The typed array or its buffer is neutered.
if (key_type->Is(Type::Integral32()) && base_type->IsConstant() &&
base_type->AsConstant()->Value()->IsJSTypedArray()) {
// JSStoreProperty(typed-array, int32, value)
- JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
- ElementsKind elements_kind = array->map()->elements_kind();
- ExternalArrayType type = array->type();
- uint32_t length;
- CHECK(array->length()->ToUint32(&length));
- ElementAccess element_access;
- Node* elements = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
- NodeProperties::GetEffectInput(node));
- if (IsExternalArrayElementsKind(elements_kind)) {
- elements = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()),
- elements, NodeProperties::GetEffectInput(node));
- element_access = AccessBuilder::ForTypedArrayElement(type, true);
- } else {
- DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
- element_access = AccessBuilder::ForTypedArrayElement(type, false);
+ Handle<JSTypedArray> array =
+ Handle<JSTypedArray>::cast(base_type->AsConstant()->Value());
+ if (IsExternalArrayElementsKind(array->map()->elements_kind())) {
+ Handle<JSArrayBuffer> buffer =
+ handle(JSArrayBuffer::cast(array->buffer()));
+ ExternalArrayType type = array->type();
+ uint32_t length;
+ CHECK(array->length()->ToUint32(&length));
+ Node* elements =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferBackingStore()),
+ jsgraph()->HeapConstant(buffer), graph()->start());
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ node->set_op(simplified()->StoreElement(
+ AccessBuilder::ForTypedArrayElement(type, true)));
+ node->ReplaceInput(0, elements);
+ node->ReplaceInput(2, jsgraph()->Uint32Constant(length));
+ node->ReplaceInput(3, value);
+ node->ReplaceInput(4, effect);
+ node->ReplaceInput(5, control);
+ node->TrimInputCount(6);
+ return Changed(node);
}
- Node* store =
- graph()->NewNode(simplified()->StoreElement(element_access), elements,
- key, jsgraph()->Uint32Constant(length), value,
- NodeProperties::GetEffectInput(node),
- NodeProperties::GetControlInput(node));
- return ReplaceEagerly(node, store);
}
return NoChange();
}
}
+bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
+ return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
+ lhs.type == rhs.type && lhs.machine_type == rhs.machine_type;
+}
+
+
+bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
+ return !(lhs == rhs);
+}
+
+
+std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
+ os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
+#ifdef OBJECT_PRINT
+ Handle<Name> name;
+ if (access.name.ToHandle(&name)) {
+ name->Print(os);
+ os << ", ";
+ }
+#endif
+ access.type->PrintTo(os);
+ os << ", " << access.machine_type << "]";
+ return os;
+}
+
+
std::ostream& operator<<(std::ostream& os, BoundsCheckMode bounds_check_mode) {
switch (bounds_check_mode) {
case kNoBoundsCheck:
struct FieldAccess {
BaseTaggedness base_is_tagged; // specifies if the base pointer is tagged.
int offset; // offset of the field, without tag.
- Handle<Name> name; // debugging only.
+ MaybeHandle<Name> name; // debugging only.
Type* type; // type of the field.
MachineType machine_type; // machine type of the field.
int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
};
+bool operator==(FieldAccess const& lhs, FieldAccess const& rhs);
+bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs);
+
+std::ostream& operator<<(std::ostream&, FieldAccess const&);
+
enum BoundsCheckMode { kNoBoundsCheck, kTypedArrayBoundsCheck };
}
-static JSFunction* GetTypedArrayFun(ExternalArrayType type,
- Isolate* isolate) {
+namespace {
+
+ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) {
+ switch (type) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return EXTERNAL_##TYPE##_ELEMENTS;
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+ }
+ UNREACHABLE();
+ return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
+#undef TYPED_ARRAY_CASE
+}
+
+
+JSFunction* GetTypedArrayFun(ExternalArrayType type, Isolate* isolate) {
Context* native_context = isolate->context()->native_context();
switch (type) {
#define TYPED_ARRAY_FUN(Type, type, TYPE, ctype, size) \
}
}
+} // namespace
+
Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
Handle<JSFunction> typed_array_fun_handle(GetTypedArrayFun(type, isolate()));
}
+Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type,
+ Handle<JSArrayBuffer> buffer,
+ size_t length) {
+ DCHECK(length <= static_cast<size_t>(kMaxInt));
+ Handle<JSTypedArray> array = NewJSTypedArray(type);
+ array->set_buffer(*buffer);
+ array->set_weak_next(buffer->weak_first_view());
+ buffer->set_weak_first_view(*array);
+ array->set_byte_offset(Smi::FromInt(0));
+ array->set_byte_length(buffer->byte_length());
+ Handle<Object> length_handle = NewNumberFromSize(length);
+ array->set_length(*length_handle);
+ Handle<ExternalArray> elements =
+ NewExternalArray(static_cast<int>(length), type, buffer->backing_store());
+ JSObject::SetMapAndElements(array,
+ JSObject::GetElementsTransitionMap(
+ array, GetExternalArrayElementsKind(type)),
+ elements);
+ return array;
+}
+
+
Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
Handle<Object> prototype) {
// Allocate map.
Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type);
+ // Creates a new JSTypedArray with the specified buffer.
+ Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type,
+ Handle<JSArrayBuffer> buffer,
+ size_t length);
+
Handle<JSDataView> NewJSDataView();
// Allocates a Harmony proxy.
}
// Convert to a Handle with a type that can be upcasted to.
- template <class S> INLINE(bool ToHandle(Handle<S>* out)) {
+ template <class S>
+ V8_INLINE bool ToHandle(Handle<S>* out) const {
if (location_ == NULL) {
*out = Handle<T>::null();
return false;
#include <ostream> // NOLINT(readability/streams)
#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
using testing::_;
using testing::MakeMatcher;
}
+Node* GraphTest::HeapConstant(const Handle<HeapObject>& value) {
+ return HeapConstant(Unique<HeapObject>::CreateUninitialized(value));
+}
+
+
Node* GraphTest::HeapConstant(const Unique<HeapObject>& value) {
- return graph()->NewNode(common()->HeapConstant(value));
+ Node* node = graph()->NewNode(common()->HeapConstant(value));
+ Type* type = Type::Constant(value.handle(), zone());
+ NodeProperties::SetBounds(node, Bounds(type));
+ return node;
}
}
+Node* GraphTest::UndefinedConstant() {
+ return HeapConstant(
+ Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
+}
+
+
Matcher<Node*> GraphTest::IsFalseConstant() {
return IsHeapConstant(
Unique<HeapObject>::CreateImmovable(factory()->false_value()));
};
+class IsLoadFieldMatcher FINAL : public NodeMatcher {
+ public:
+ IsLoadFieldMatcher(const Matcher<FieldAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& effect_matcher)
+ : NodeMatcher(IrOpcode::kLoadField),
+ access_matcher_(access_matcher),
+ base_matcher_(base_matcher),
+ effect_matcher_(effect_matcher) {}
+
+ virtual void DescribeTo(std::ostream* os) const OVERRIDE {
+ NodeMatcher::DescribeTo(os);
+ *os << " whose access (";
+ access_matcher_.DescribeTo(os);
+ *os << "), base (";
+ base_matcher_.DescribeTo(os);
+ *os << ") and effect (";
+ effect_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(Node* node,
+ MatchResultListener* listener) const OVERRIDE {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(OpParameter<FieldAccess>(node), "access",
+ access_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+ base_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+ effect_matcher_, listener));
+ }
+
+ private:
+ const Matcher<FieldAccess> access_matcher_;
+ const Matcher<Node*> base_matcher_;
+ const Matcher<Node*> effect_matcher_;
+};
+
+
+class IsLoadElementMatcher FINAL : public NodeMatcher {
+ public:
+ IsLoadElementMatcher(const Matcher<ElementAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& length_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher)
+ : NodeMatcher(IrOpcode::kLoadElement),
+ access_matcher_(access_matcher),
+ base_matcher_(base_matcher),
+ index_matcher_(index_matcher),
+ length_matcher_(length_matcher),
+ effect_matcher_(effect_matcher),
+ control_matcher_(control_matcher) {}
+
+ virtual void DescribeTo(std::ostream* os) const OVERRIDE {
+ NodeMatcher::DescribeTo(os);
+ *os << " whose access (";
+ access_matcher_.DescribeTo(os);
+ *os << "), base (";
+ base_matcher_.DescribeTo(os);
+ *os << "), index (";
+ index_matcher_.DescribeTo(os);
+ *os << "), length (";
+ length_matcher_.DescribeTo(os);
+ *os << "), effect (";
+ effect_matcher_.DescribeTo(os);
+ *os << ") and control (";
+ control_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(Node* node,
+ MatchResultListener* listener) const OVERRIDE {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(OpParameter<ElementAccess>(node), "access",
+ access_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+ base_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+ "index", index_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+ "length", length_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+ effect_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+ "control", control_matcher_, listener));
+ }
+
+ private:
+ const Matcher<ElementAccess> access_matcher_;
+ const Matcher<Node*> base_matcher_;
+ const Matcher<Node*> index_matcher_;
+ const Matcher<Node*> length_matcher_;
+ const Matcher<Node*> effect_matcher_;
+ const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreElementMatcher FINAL : public NodeMatcher {
+ public:
+ IsStoreElementMatcher(const Matcher<ElementAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& length_matcher,
+ const Matcher<Node*>& value_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher)
+ : NodeMatcher(IrOpcode::kStoreElement),
+ access_matcher_(access_matcher),
+ base_matcher_(base_matcher),
+ index_matcher_(index_matcher),
+ length_matcher_(length_matcher),
+ value_matcher_(value_matcher),
+ effect_matcher_(effect_matcher),
+ control_matcher_(control_matcher) {}
+
+ virtual void DescribeTo(std::ostream* os) const OVERRIDE {
+ NodeMatcher::DescribeTo(os);
+ *os << " whose access (";
+ access_matcher_.DescribeTo(os);
+ *os << "), base (";
+ base_matcher_.DescribeTo(os);
+ *os << "), index (";
+ index_matcher_.DescribeTo(os);
+ *os << "), length (";
+ length_matcher_.DescribeTo(os);
+ *os << "), value (";
+ value_matcher_.DescribeTo(os);
+ *os << "), effect (";
+ effect_matcher_.DescribeTo(os);
+ *os << ") and control (";
+ control_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(Node* node,
+ MatchResultListener* listener) const OVERRIDE {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(OpParameter<ElementAccess>(node), "access",
+ access_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+ base_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+ "index", index_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+ "length", length_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
+ "value", value_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+ effect_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+ "control", control_matcher_, listener));
+ }
+
+ private:
+ const Matcher<ElementAccess> access_matcher_;
+ const Matcher<Node*> base_matcher_;
+ const Matcher<Node*> index_matcher_;
+ const Matcher<Node*> length_matcher_;
+ const Matcher<Node*> value_matcher_;
+ const Matcher<Node*> effect_matcher_;
+ const Matcher<Node*> control_matcher_;
+};
+
+
class IsLoadMatcher FINAL : public NodeMatcher {
public:
IsLoadMatcher(const Matcher<LoadRepresentation>& rep_matcher,
}
+Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& effect_matcher) {
+ return MakeMatcher(
+ new IsLoadFieldMatcher(access_matcher, base_matcher, effect_matcher));
+}
+
+
+Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& length_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ return MakeMatcher(new IsLoadElementMatcher(access_matcher, base_matcher,
+ index_matcher, length_matcher,
+ effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& length_matcher,
+ const Matcher<Node*>& value_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ return MakeMatcher(new IsStoreElementMatcher(
+ access_matcher, base_matcher, index_matcher, length_matcher,
+ value_matcher, effect_matcher, control_matcher));
+}
+
+
Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& index_matcher,
namespace internal {
// Forward declarations.
+template <class T>
+class Handle;
class HeapObject;
template <class T>
class Unique;
namespace compiler {
+// Forward declarations.
+struct ElementAccess;
+struct FieldAccess;
+
+
using ::testing::Matcher;
Node* Int32Constant(int32_t value);
Node* Int64Constant(int64_t value);
Node* NumberConstant(volatile double value);
+ Node* HeapConstant(const Handle<HeapObject>& value);
Node* HeapConstant(const Unique<HeapObject>& value);
Node* FalseConstant();
Node* TrueConstant();
+ Node* UndefinedConstant();
Matcher<Node*> IsFalseConstant();
Matcher<Node*> IsTrueConstant();
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& effect_matcher);
+Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& length_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& length_matcher,
+ const Matcher<Node*>& value_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
const Matcher<Node*>& base_matcher,
return n;
}
- Node* UndefinedConstant() {
- return HeapConstant(
- Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
- }
-
JSOperatorBuilder* javascript() { return &javascript_; }
private:
--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+const ExternalArrayType kExternalArrayTypes[] = {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) kExternal##Type##Array,
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+};
+
+
+const StrictMode kStrictModes[] = {SLOPPY, STRICT};
+
+} // namespace
+
+
+class JSTypedLoweringTest : public GraphTest {
+ public:
+ JSTypedLoweringTest() : GraphTest(3), javascript_(zone()) {}
+ virtual ~JSTypedLoweringTest() {}
+
+ protected:
+ Reduction Reduce(Node* node) {
+ Typer typer(zone());
+ MachineOperatorBuilder machine;
+ JSGraph jsgraph(graph(), common(), javascript(), &typer, &machine);
+ JSTypedLowering reducer(&jsgraph);
+ return reducer.Reduce(node);
+ }
+
+ Node* Parameter(Type* type, int index = 0) {
+ Node* node = graph()->NewNode(common()->Parameter(index), graph()->start());
+ NodeProperties::SetBounds(node, Bounds(Type::None(), type));
+ return node;
+ }
+
+ Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
+ Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
+ Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length);
+ return buffer;
+ }
+
+ JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+ JSOperatorBuilder javascript_;
+};
+
+
+// -----------------------------------------------------------------------------
+// JSLoadProperty
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
+ const size_t kLength = 17;
+ uint8_t backing_store[kLength * 8];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, arraysize(backing_store));
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, kLength);
+
+ Node* key = Parameter(Type::Integral32());
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->LoadProperty(),
+ HeapConstant(array), key, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsLoadElement(
+ AccessBuilder::ForTypedArrayElement(type, true),
+ IsLoadField(
+ AccessBuilder::ForJSArrayBufferBackingStore(),
+ IsHeapConstant(Unique<HeapObject>::CreateImmovable(buffer)),
+ effect),
+ key, IsInt32Constant(static_cast<int>(kLength)), effect, control));
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreProperty
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
+ const size_t kLength = 17;
+ uint8_t backing_store[kLength * 8];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, arraysize(backing_store));
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, kLength);
+
+ Node* key = Parameter(Type::Integral32());
+ Node* value = Parameter(Type::Any());
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+ HeapConstant(array), key, value, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsStoreElement(
+ AccessBuilder::ForTypedArrayElement(type, true),
+ IsLoadField(
+ AccessBuilder::ForJSArrayBufferBackingStore(),
+ IsHeapConstant(Unique<HeapObject>::CreateImmovable(buffer)),
+ effect),
+ key, IsInt32Constant(static_cast<int>(kLength)), value, effect,
+ control));
+ }
+ }
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
namespace v8 {
+std::ostream& operator<<(std::ostream& os, ExternalArrayType type) {
+ switch (type) {
+ case kExternalInt8Array:
+ return os << "ExternalInt8Array";
+ case kExternalUint8Array:
+ return os << "ExternalUint8Array";
+ case kExternalInt16Array:
+ return os << "ExternalInt16Array";
+ case kExternalUint16Array:
+ return os << "ExternalUint16Array";
+ case kExternalInt32Array:
+ return os << "ExternalInt32Array";
+ case kExternalUint32Array:
+ return os << "ExternalUint32Array";
+ case kExternalFloat32Array:
+ return os << "ExternalFloat32Array";
+ case kExternalFloat64Array:
+ return os << "ExternalFloat64Array";
+ case kExternalUint8ClampedArray:
+ return os << "ExternalUint8ClampedArray";
+ }
+ UNREACHABLE();
+ return os;
+}
+
+
// static
Isolate* TestWithIsolate::isolate_ = NULL;
namespace v8 {
+std::ostream& operator<<(std::ostream&, ExternalArrayType);
+
+
class TestWithIsolate : public ::testing::Test {
public:
TestWithIsolate();
'compiler/instruction-selector-unittest.h',
'compiler/js-builtin-reducer-unittest.cc',
'compiler/js-operator-unittest.cc',
+ 'compiler/js-typed-lowering-unittest.cc',
'compiler/machine-operator-reducer-unittest.cc',
'compiler/machine-operator-unittest.cc',
'compiler/simplified-operator-reducer-unittest.cc',