Revision: 24386
Author:   [email protected]
Date:     Thu Oct  2 08:38:37 2014 UTC
Log:      [turbofan] Fix lowering of typed loads/stores.

We can only access to external typed arrays; lowering of internal
typed arrays would require a map check plus eager deoptimization.
Also embed the array buffer reference directly instead of embedding
the typed array.

TEST=cctest,mjsunit,unittests
[email protected]

Review URL: https://codereview.chromium.org/621863002
https://code.google.com/p/v8/source/detail?r=24386

Added:
/branches/bleeding_edge/test/unittests/compiler/js-typed-lowering-unittest.cc
Modified:
 /branches/bleeding_edge/src/compiler/access-builder.cc
 /branches/bleeding_edge/src/compiler/js-typed-lowering.cc
 /branches/bleeding_edge/src/compiler/simplified-operator.cc
 /branches/bleeding_edge/src/compiler/simplified-operator.h
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/factory.h
 /branches/bleeding_edge/src/handles.h
 /branches/bleeding_edge/test/unittests/compiler/graph-unittest.cc
 /branches/bleeding_edge/test/unittests/compiler/graph-unittest.h
/branches/bleeding_edge/test/unittests/compiler/js-builtin-reducer-unittest.cc
 /branches/bleeding_edge/test/unittests/test-utils.cc
 /branches/bleeding_edge/test/unittests/test-utils.h
 /branches/bleeding_edge/test/unittests/unittests.gyp

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/unittests/compiler/js-typed-lowering-unittest.cc Thu Oct 2 08:38:37 2014 UTC
@@ -0,0 +1,151 @@
+// 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
=======================================
--- /branches/bleeding_edge/src/compiler/access-builder.cc Wed Oct 1 07:42:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/access-builder.cc Thu Oct 2 08:38:37 2014 UTC
@@ -11,43 +11,43 @@

 // 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};
 }


=======================================
--- /branches/bleeding_edge/src/compiler/js-typed-lowering.cc Wed Oct 1 11:08:37 2014 UTC +++ /branches/bleeding_edge/src/compiler/js-typed-lowering.cc Thu Oct 2 08:38:37 2014 UTC
@@ -533,35 +533,34 @@
   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();
 }
@@ -574,35 +573,34 @@
   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();
 }
=======================================
--- /branches/bleeding_edge/src/compiler/simplified-operator.cc Wed Oct 1 07:42:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/simplified-operator.cc Thu Oct 2 08:38:37 2014 UTC
@@ -25,6 +25,32 @@
   UNREACHABLE();
   return os;
 }
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/compiler/simplified-operator.h Wed Oct 1 07:42:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/simplified-operator.h Thu Oct 2 08:38:37 2014 UTC
@@ -38,13 +38,18 @@
 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 };

=======================================
--- /branches/bleeding_edge/src/factory.cc      Thu Sep 25 08:25:25 2014 UTC
+++ /branches/bleeding_edge/src/factory.cc      Thu Oct  2 08:38:37 2014 UTC
@@ -1716,8 +1716,22 @@
 }


-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) \
@@ -1733,6 +1747,8 @@
   }
 }

+}  // namespace
+

 Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
Handle<JSFunction> typed_array_fun_handle(GetTypedArrayFun(type, isolate()));
@@ -1742,6 +1758,28 @@
       isolate()->heap()->AllocateJSObject(*typed_array_fun_handle),
       JSTypedArray);
 }
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/factory.h       Wed Oct  1 11:53:29 2014 UTC
+++ /branches/bleeding_edge/src/factory.h       Thu Oct  2 08:38:37 2014 UTC
@@ -434,6 +434,11 @@

   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.
=======================================
--- /branches/bleeding_edge/src/handles.h       Mon Aug  4 11:34:54 2014 UTC
+++ /branches/bleeding_edge/src/handles.h       Thu Oct  2 08:38:37 2014 UTC
@@ -53,7 +53,8 @@
   }

   // 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;
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/graph-unittest.cc Wed Oct 1 11:08:37 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/graph-unittest.cc Thu Oct 2 08:38:37 2014 UTC
@@ -7,6 +7,7 @@
 #include <ostream>  // NOLINT(readability/streams)

 #include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"

 using testing::_;
 using testing::MakeMatcher;
@@ -66,10 +67,18 @@
 Node* GraphTest::NumberConstant(volatile double value) {
   return graph()->NewNode(common()->NumberConstant(value));
 }
+
+
+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;
 }


@@ -83,6 +92,12 @@
   return HeapConstant(
       Unique<HeapObject>::CreateImmovable(factory()->true_value()));
 }
+
+
+Node* GraphTest::UndefinedConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
+}


 Matcher<Node*> GraphTest::IsFalseConstant() {
@@ -430,6 +445,172 @@
 };


+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,
@@ -713,6 +894,39 @@
       descriptor_matcher, value0_matcher, value1_matcher, value2_matcher,
       value3_matcher, effect_matcher, control_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,
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/graph-unittest.h Wed Oct 1 11:08:37 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/graph-unittest.h Thu Oct 2 08:38:37 2014 UTC
@@ -15,12 +15,19 @@
 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;


@@ -36,9 +43,11 @@
   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();
@@ -88,6 +97,22 @@
                                 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,
=======================================
--- /branches/bleeding_edge/test/unittests/compiler/js-builtin-reducer-unittest.cc Wed Oct 1 08:34:25 2014 UTC +++ /branches/bleeding_edge/test/unittests/compiler/js-builtin-reducer-unittest.cc Thu Oct 2 08:38:37 2014 UTC
@@ -34,11 +34,6 @@
     NodeProperties::SetBounds(n, Bounds(Type::None(), t));
     return n;
   }
-
-  Node* UndefinedConstant() {
-    return HeapConstant(
-        Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
-  }

   JSOperatorBuilder* javascript() { return &javascript_; }

=======================================
--- /branches/bleeding_edge/test/unittests/test-utils.cc Wed Oct 1 08:34:25 2014 UTC +++ /branches/bleeding_edge/test/unittests/test-utils.cc Thu Oct 2 08:38:37 2014 UTC
@@ -8,6 +8,32 @@

 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;

=======================================
--- /branches/bleeding_edge/test/unittests/test-utils.h Wed Oct 1 08:34:25 2014 UTC +++ /branches/bleeding_edge/test/unittests/test-utils.h Thu Oct 2 08:38:37 2014 UTC
@@ -12,6 +12,9 @@

 namespace v8 {

+std::ostream& operator<<(std::ostream&, ExternalArrayType);
+
+
 class TestWithIsolate : public ::testing::Test {
  public:
   TestWithIsolate();
=======================================
--- /branches/bleeding_edge/test/unittests/unittests.gyp Wed Oct 1 08:54:21 2014 UTC +++ /branches/bleeding_edge/test/unittests/unittests.gyp Thu Oct 2 08:38:37 2014 UTC
@@ -44,6 +44,7 @@
         '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',

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to