Commit f9dd3446 authored by bbudge's avatar bbudge Committed by Commit bot

Add new Float32x4 type for SIMD.js.

LOG=N
BUG=v8:4124

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

Cr-Commit-Position: refs/heads/master@{#28797}
parent e59e40a3
......@@ -275,7 +275,8 @@ class V8_EXPORT HeapGraphNode {
// snapshot items together.
kConsString = 10, // Concatenated string. A pair of pointers to strings.
kSlicedString = 11, // Sliced string. A fragment of another string.
kSymbol = 12 // A Symbol (ES6).
kSymbol = 12, // A Symbol (ES6).
kSimdValue = 13 // A SIMD value stored in the heap (Proposed ES7).
};
/** Returns node type (see HeapGraphNode::Type). */
......
......@@ -1923,6 +1923,12 @@ class V8_EXPORT Value : public Data {
*/
bool IsFloat64Array() const;
/**
* Returns true if this value is a SIMD Float32x4.
* This is an experimental feature.
*/
bool IsFloat32x4() const;
/**
* Returns true if this value is a DataView.
* This is an experimental feature.
......@@ -6949,10 +6955,10 @@ class Internals {
static const int kNodeIsIndependentShift = 3;
static const int kNodeIsPartiallyDependentShift = 4;
static const int kJSObjectType = 0xbe;
static const int kJSObjectType = 0xbf;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x86;
static const int kForeignType = 0x87;
static const int kUndefinedOddballKind = 5;
static const int kNullOddballKind = 3;
......
......@@ -1077,6 +1077,14 @@ Handle<HeapNumber> Factory::NewHeapNumber(double value,
}
Handle<Float32x4> Factory::NewFloat32x4(float w, float x, float y, float z,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(), isolate()->heap()->AllocateFloat32x4(w, x, y, z, pretenure),
Float32x4);
}
Handle<Object> Factory::NewError(const char* maker,
MessageTemplate::Template template_index,
Handle<Object> arg0, Handle<Object> arg1,
......
......@@ -361,6 +361,8 @@ class Factory final {
Handle<HeapNumber> NewHeapNumber(double value,
MutableMode mode = IMMUTABLE,
PretenureFlag pretenure = NOT_TENURED);
Handle<Float32x4> NewFloat32x4(float w, float x, float y, float z,
PretenureFlag pretenure = NOT_TENURED);
// These objects are used by the api to create env-independent data
// structures in the heap.
......
......@@ -124,6 +124,7 @@ const int kShortSize = sizeof(short); // NOLINT
const int kIntSize = sizeof(int); // NOLINT
const int kInt32Size = sizeof(int32_t); // NOLINT
const int kInt64Size = sizeof(int64_t); // NOLINT
const int kFloatSize = sizeof(float); // NOLINT
const int kDoubleSize = sizeof(double); // NOLINT
const int kIntptrSize = sizeof(intptr_t); // NOLINT
const int kPointerSize = sizeof(void*); // NOLINT
......
......@@ -154,6 +154,7 @@ const char* HeapEntry::TypeAsString() {
case kConsString: return "/concatenated string/";
case kSlicedString: return "/sliced string/";
case kSymbol: return "/symbol/";
case kSimdValue: return "/simd/";
default: return "???";
}
}
......@@ -861,6 +862,8 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
return AddEntry(object, HeapEntry::kArray, "");
} else if (object->IsHeapNumber()) {
return AddEntry(object, HeapEntry::kHeapNumber, "number");
} else if (object->IsFloat32x4()) {
return AddEntry(object, HeapEntry::kSimdValue, "simd");
}
return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object));
}
......
......@@ -82,7 +82,8 @@ class HeapEntry BASE_EMBEDDED {
kSynthetic = v8::HeapGraphNode::kSynthetic,
kConsString = v8::HeapGraphNode::kConsString,
kSlicedString = v8::HeapGraphNode::kSlicedString,
kSymbol = v8::HeapGraphNode::kSymbol
kSymbol = v8::HeapGraphNode::kSymbol,
kSimdValue = v8::HeapGraphNode::kSimdValue
};
static const int kNoEntry;
......
......@@ -2742,6 +2742,7 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number)
ALLOCATE_MAP(MUTABLE_HEAP_NUMBER_TYPE, HeapNumber::kSize,
mutable_heap_number)
ALLOCATE_MAP(FLOAT32X4_TYPE, Float32x4::kSize, float32x4)
ALLOCATE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol)
ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign)
......@@ -2891,6 +2892,32 @@ AllocationResult Heap::AllocateHeapNumber(double value, MutableMode mode,
}
AllocationResult Heap::AllocateFloat32x4(float w, float x, float y, float z,
PretenureFlag pretenure) {
// Statically ensure that it is safe to allocate SIMD values in paged
// spaces.
int size = Float32x4::kSize;
STATIC_ASSERT(Float32x4::kSize <= Page::kMaxRegularHeapObjectSize);
AllocationSpace space = SelectSpace(size, pretenure);
HeapObject* result;
{
AllocationResult allocation =
AllocateRaw(size, space, OLD_SPACE, kSimd128Unaligned);
if (!allocation.To(&result)) return allocation;
}
result->set_map_no_write_barrier(float32x4_map());
Float32x4* float32x4 = Float32x4::cast(result);
float32x4->set_lane(0, w);
float32x4->set_lane(1, x);
float32x4->set_lane(2, y);
float32x4->set_lane(3, z);
return result;
}
AllocationResult Heap::AllocateCell(Object* value) {
int size = Cell::kSize;
STATIC_ASSERT(Cell::kSize <= Page::kMaxRegularHeapObjectSize);
......
......@@ -46,6 +46,7 @@ namespace internal {
V(Map, meta_map, MetaMap) \
V(Map, heap_number_map, HeapNumberMap) \
V(Map, mutable_heap_number_map, MutableHeapNumberMap) \
V(Map, float32x4_map, Float32x4Map) \
V(Map, native_context_map, NativeContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \
V(Map, code_map, CodeMap) \
......@@ -344,6 +345,7 @@ namespace internal {
V(MetaMap) \
V(HeapNumberMap) \
V(MutableHeapNumberMap) \
V(Float32x4Map) \
V(NativeContextMap) \
V(FixedArrayMap) \
V(CodeMap) \
......@@ -1602,12 +1604,17 @@ class Heap {
bool alloc_props = true,
AllocationSite* allocation_site = NULL);
// Allocated a HeapNumber from value.
// Allocates a HeapNumber from value.
MUST_USE_RESULT AllocationResult
AllocateHeapNumber(double value, MutableMode mode = IMMUTABLE,
PretenureFlag pretenure = NOT_TENURED);
// Allocate a byte array of the specified length
// Allocates a Float32x4 from the given lane values.
MUST_USE_RESULT AllocationResult
AllocateFloat32x4(float w, float x, float y, float z,
PretenureFlag pretenure = NOT_TENURED);
// Allocates a byte array of the specified length
MUST_USE_RESULT AllocationResult
AllocateByteArray(int length, PretenureFlag pretenure = NOT_TENURED);
......
......@@ -138,6 +138,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case HEAP_NUMBER_TYPE:
case MUTABLE_HEAP_NUMBER_TYPE:
case FLOAT32X4_TYPE:
#define EXTERNAL_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case EXTERNAL_##TYPE##_ARRAY_TYPE:
......
......@@ -58,6 +58,9 @@ void HeapObject::HeapObjectVerify() {
case MUTABLE_HEAP_NUMBER_TYPE:
HeapNumber::cast(this)->HeapNumberVerify();
break;
case FLOAT32X4_TYPE:
Float32x4::cast(this)->Float32x4Verify();
break;
case FIXED_ARRAY_TYPE:
FixedArray::cast(this)->FixedArrayVerify();
break;
......@@ -214,6 +217,9 @@ void HeapNumber::HeapNumberVerify() {
}
void Float32x4::Float32x4Verify() { CHECK(IsFloat32x4()); }
void ByteArray::ByteArrayVerify() {
CHECK(IsByteArray());
}
......
......@@ -170,6 +170,7 @@ bool Object::IsHeapObject() const {
TYPE_CHECKER(HeapNumber, HEAP_NUMBER_TYPE)
TYPE_CHECKER(MutableHeapNumber, MUTABLE_HEAP_NUMBER_TYPE)
TYPE_CHECKER(Float32x4, FLOAT32X4_TYPE)
TYPE_CHECKER(Symbol, SYMBOL_TYPE)
......@@ -1321,6 +1322,12 @@ MaybeHandle<Object> JSProxy::SetElementWithHandler(Handle<JSProxy> proxy,
#define WRITE_INT32_FIELD(p, offset, value) \
(*reinterpret_cast<int32_t*>(FIELD_ADDR(p, offset)) = value)
#define READ_FLOAT_FIELD(p, offset) \
(*reinterpret_cast<const float*>(FIELD_ADDR_CONST(p, offset)))
#define WRITE_FLOAT_FIELD(p, offset, value) \
(*reinterpret_cast<float*>(FIELD_ADDR(p, offset)) = value)
#define READ_UINT64_FIELD(p, offset) \
(*reinterpret_cast<const uint64_t*>(FIELD_ADDR_CONST(p, offset)))
......@@ -1579,6 +1586,30 @@ int HeapNumber::get_sign() {
}
float Float32x4::get_lane(int lane) const {
DCHECK(lane < 4 && lane >= 0);
#if defined(V8_TARGET_LITTLE_ENDIAN)
return READ_FLOAT_FIELD(this, kValueOffset + lane * kFloatSize);
#elif defined(V8_TARGET_BIG_ENDIAN)
return READ_FLOAT_FIELD(this, kValueOffset + (3 - lane) * kFloatSize);
#else
#error Unknown byte ordering
#endif
}
void Float32x4::set_lane(int lane, float value) {
DCHECK(lane < 4 && lane >= 0);
#if defined(V8_TARGET_LITTLE_ENDIAN)
WRITE_FLOAT_FIELD(this, kValueOffset + lane * kFloatSize, value);
#elif defined(V8_TARGET_BIG_ENDIAN)
WRITE_FLOAT_FIELD(this, kValueOffset + (3 - lane) * kFloatSize, value);
#else
#error Unknown byte ordering
#endif
}
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
......@@ -2818,6 +2849,7 @@ AllocationAlignment HeapObject::RequiredAlignment() {
return kDoubleAligned;
}
if (IsHeapNumber()) return kDoubleUnaligned;
if (IsFloat32x4()) return kSimd128Unaligned;
#endif // V8_HOST_ARCH_32_BIT
return kWordAligned;
}
......@@ -3359,6 +3391,7 @@ CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(FixedArrayBase)
CAST_ACCESSOR(FixedDoubleArray)
CAST_ACCESSOR(FixedTypedArrayBase)
CAST_ACCESSOR(Float32x4)
CAST_ACCESSOR(Foreign)
CAST_ACCESSOR(GlobalDictionary)
CAST_ACCESSOR(GlobalObject)
......
......@@ -60,6 +60,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
HeapNumber::cast(this)->HeapNumberPrint(os);
os << ">";
break;
case FLOAT32X4_TYPE:
Float32x4::cast(this)->Float32x4Print(os);
break;
case FIXED_DOUBLE_ARRAY_TYPE:
FixedDoubleArray::cast(this)->FixedDoubleArrayPrint(os);
break;
......
......@@ -97,6 +97,7 @@ bool Object::BooleanValue() {
if (IsUndetectableObject()) return false; // Undetectable object is false.
if (IsString()) return String::cast(this)->length() != 0;
if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
if (IsFloat32x4()) return true; // Simd value types always evaluate to true.
return true;
}
......@@ -1400,6 +1401,12 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
os << '>';
break;
}
case FLOAT32X4_TYPE: {
os << "<Float32x4: ";
Float32x4::cast(this)->Float32x4Print(os);
os << ">";
break;
}
case JS_PROXY_TYPE:
os << "<JSProxy>";
break;
......@@ -1546,6 +1553,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case HEAP_NUMBER_TYPE:
case MUTABLE_HEAP_NUMBER_TYPE:
case FLOAT32X4_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
case FREE_SPACE_TYPE:
......@@ -1591,6 +1599,12 @@ void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
}
void Float32x4::Float32x4Print(std::ostream& os) { // NOLINT
os << get_lane(0) << ", " << get_lane(1) << ", " << get_lane(2) << ", "
<< get_lane(3);
}
String* JSReceiver::class_name() {
if (IsJSFunction() || IsJSFunctionProxy()) {
return GetHeap()->Function_string();
......
......@@ -121,6 +121,7 @@
// - ExternalTwoByteInternalizedString
// - Symbol
// - HeapNumber
// - Float32x4
// - Cell
// - PropertyCell
// - Code
......@@ -394,6 +395,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
\
V(HEAP_NUMBER_TYPE) \
V(MUTABLE_HEAP_NUMBER_TYPE) \
V(FLOAT32X4_TYPE) \
V(FOREIGN_TYPE) \
V(BYTE_ARRAY_TYPE) \
V(FREE_SPACE_TYPE) \
......@@ -690,6 +692,7 @@ enum InstanceType {
// objects.
HEAP_NUMBER_TYPE,
MUTABLE_HEAP_NUMBER_TYPE,
FLOAT32X4_TYPE, // FIRST_SIMD_TYPE, LAST_SIMD_TYPE
FOREIGN_TYPE,
BYTE_ARRAY_TYPE,
FREE_SPACE_TYPE,
......@@ -782,6 +785,9 @@ enum InstanceType {
FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE,
LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE,
FIRST_NONSTRING_TYPE = SYMBOL_TYPE,
// Boundaries for testing for a SIMD type.
FIRST_SIMD_TYPE = FLOAT32X4_TYPE,
LAST_SIMD_TYPE = FLOAT32X4_TYPE,
// Boundaries for testing for an external array.
FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_INT8_ARRAY_TYPE,
LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE,
......@@ -948,6 +954,7 @@ template <class C> inline bool Is(Object* obj);
V(FixedFloat32Array) \
V(FixedFloat64Array) \
V(FixedUint8ClampedArray) \
V(Float32x4) \
V(ByteArray) \
V(FreeSpace) \
V(JSReceiver) \
......@@ -1610,6 +1617,28 @@ class HeapNumber: public HeapObject {
};
// The Float32x4 class describes heap allocated SIMD values holding 4 32-bit
// IEEE floats.
class Float32x4 : public HeapObject {
public:
inline float get_lane(int lane) const;
inline void set_lane(int lane, float value);
DECLARE_CAST(Float32x4)
// Dispatched behavior.
void Float32x4Print(std::ostream& os); // NOLINT
DECLARE_VERIFIER(Float32x4)
// Layout description.
static const int kValueOffset = HeapObject::kHeaderSize;
static const int kSize = kValueOffset + kSimd128Size;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Float32x4);
};
enum EnsureElementsMode {
DONT_ALLOW_DOUBLE_ELEMENTS,
ALLOW_COPIED_DOUBLE_ELEMENTS,
......
......@@ -93,6 +93,7 @@ class TestHeap : public i::Heap {
using i::Heap::AllocateByteArray;
using i::Heap::AllocateFixedArray;
using i::Heap::AllocateHeapNumber;
using i::Heap::AllocateFloat32x4;
using i::Heap::AllocateJSObject;
using i::Heap::AllocateJSObjectFromMap;
using i::Heap::AllocateMap;
......
......@@ -59,6 +59,7 @@ TEST(HeapMaps) {
Heap* heap = CcTest::heap();
CheckMap(heap->meta_map(), MAP_TYPE, Map::kSize);
CheckMap(heap->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
CheckMap(heap->float32x4_map(), FLOAT32X4_TYPE, Float32x4::kSize);
CheckMap(heap->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
CheckMap(heap->string_map(), STRING_TYPE, kVariableSizeSentinel);
}
......@@ -213,6 +214,60 @@ TEST(HeapObjects) {
}
template <typename T, typename LANE_TYPE, int LANES>
static void CheckSimdLanes(T* value) {
// Get the original values, and check that all lanes can be set to new values
// without disturbing the other lanes.
LANE_TYPE lane_values[LANES];
for (int i = 0; i < LANES; i++) {
lane_values[i] = value->get_lane(i);
}
for (int i = 0; i < LANES; i++) {
lane_values[i] += 1;
value->set_lane(i, lane_values[i]);
for (int j = 0; j < LANES; j++) {
CHECK_EQ(lane_values[j], value->get_lane(j));
}
}
}
TEST(SimdObjects) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
HandleScope sc(isolate);
Handle<Object> value = factory->NewFloat32x4(1, 2, 3, 4);
CHECK(value->IsFloat32x4());
CHECK(value->BooleanValue()); // SIMD values map to true.
Float32x4* float32x4 = *Handle<Float32x4>::cast(value);
CheckSimdLanes<Float32x4, float, 4>(float32x4);
// Check ToString for SIMD values.
// TODO(bbudge): Switch to Check* style function to test ToString().
value = factory->NewFloat32x4(1, 2, 3, 4);
float32x4 = *Handle<Float32x4>::cast(value);
std::ostringstream os;
float32x4->Float32x4Print(os);
CHECK_EQ("1, 2, 3, 4", os.str());
// Check unusual lane values.
float32x4->set_lane(0, 0);
CHECK_EQ(0, float32x4->get_lane(0));
float32x4->set_lane(1, -0.0);
CHECK_EQ(-0.0, float32x4->get_lane(1));
float quiet_NaN = std::numeric_limits<float>::quiet_NaN();
float signaling_NaN = std::numeric_limits<float>::signaling_NaN();
float32x4->set_lane(2, quiet_NaN);
CHECK(std::isnan(float32x4->get_lane(2)));
float32x4->set_lane(3, signaling_NaN);
CHECK(std::isnan(float32x4->get_lane(3)));
}
TEST(Tagging) {
CcTest::InitializeVM();
int request = 24;
......
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