Generate TypedArrayInitialize builtin in hydrogen.

R=danno@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18059 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
dslomov@chromium.org 2013-11-25 14:41:46 +00:00
parent 5e177bd658
commit c3a4d718ce
17 changed files with 338 additions and 47 deletions

View File

@ -1667,6 +1667,15 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
result = AssignEnvironment(result);
}
return result;
} else if (instr->representation().IsExternal()) {
ASSERT(instr->left()->representation().IsExternal());
ASSERT(instr->right()->representation().IsInteger32());
ASSERT(!instr->CheckFlag(HValue::kCanOverflow));
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
LAddI* add = new(zone()) LAddI(left, right);
LInstruction* result = DefineAsRegister(add);
return result;
} else if (instr->representation().IsDouble()) {
if (instr->left()->IsMul()) {
return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());

View File

@ -1262,6 +1262,26 @@ HValue* HBitwise::Canonicalize() {
}
Representation HAdd::RepresentationFromInputs() {
Representation left_rep = left()->representation();
if (left_rep.IsExternal()) {
return Representation::External();
}
return HArithmeticBinaryOperation::RepresentationFromInputs();
}
Representation HAdd::RequiredInputRepresentation(int index) {
if (index == 2) {
Representation left_rep = left()->representation();
if (left_rep.IsExternal()) {
return Representation::Integer32();
}
}
return HArithmeticBinaryOperation::RequiredInputRepresentation(index);
}
static bool IsIdentityOperation(HValue* arg1, HValue* arg2, int32_t identity) {
return arg1->representation().IsSpecialization() &&
arg2->EqualsInteger32Constant(identity);

View File

@ -4732,8 +4732,9 @@ class HAdd V8_FINAL : public HArithmeticBinaryOperation {
// Add is only commutative if two integer values are added and not if two
// tagged values are added (because it might be a String concatenation).
// We also do not commute (pointer + offset).
virtual bool IsCommutative() const V8_OVERRIDE {
return !representation().IsTagged();
return !representation().IsTagged() && !representation().IsExternal();
}
virtual HValue* EnsureAndPropagateNotMinusZero(
@ -4769,6 +4770,10 @@ class HAdd V8_FINAL : public HArithmeticBinaryOperation {
}
}
virtual Representation RepresentationFromInputs() V8_OVERRIDE;
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE;
DECLARE_CONCRETE_INSTRUCTION(Add)
protected:
@ -6062,6 +6067,43 @@ class HObjectAccess V8_FINAL {
// Create an access for the payload of a Cell or JSGlobalPropertyCell.
static HObjectAccess ForCellPayload(Isolate* isolate);
static HObjectAccess ForJSTypedArrayLength() {
return HObjectAccess::ForJSObjectOffset(JSTypedArray::kLengthOffset);
}
static HObjectAccess ForJSArrayBufferBackingStore() {
return HObjectAccess::ForJSObjectOffset(
JSArrayBuffer::kBackingStoreOffset, Representation::External());
}
static HObjectAccess ForExternalArrayExternalPointer() {
return HObjectAccess::ForJSObjectOffset(
ExternalArray::kExternalPointerOffset, Representation::External());
}
static HObjectAccess ForJSArrayBufferViewWeakNext() {
return HObjectAccess::ForJSObjectOffset(JSArrayBufferView::kWeakNextOffset);
}
static HObjectAccess ForJSArrayBufferWeakFirstView() {
return HObjectAccess::ForJSObjectOffset(
JSArrayBuffer::kWeakFirstViewOffset);
}
static HObjectAccess ForJSArrayBufferViewBuffer() {
return HObjectAccess::ForJSObjectOffset(JSArrayBufferView::kBufferOffset);
}
static HObjectAccess ForJSArrayBufferViewByteOffset() {
return HObjectAccess::ForJSObjectOffset(
JSArrayBufferView::kByteOffsetOffset);
}
static HObjectAccess ForJSArrayBufferViewByteLength() {
return HObjectAccess::ForJSObjectOffset(
JSArrayBufferView::kByteLengthOffset);
}
void PrintTo(StringStream* stream);
inline bool Equals(HObjectAccess that) const {
@ -6478,6 +6520,8 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
} else if (field_representation().IsDouble() ||
field_representation().IsSmi()) {
return field_representation();
} else if (field_representation().IsExternal()) {
return Representation::External();
}
}
return Representation::Tagged();

View File

@ -58,6 +58,7 @@
#include "hydrogen-uint32-analysis.h"
#include "lithium-allocator.h"
#include "parser.h"
#include "runtime.h"
#include "scopeinfo.h"
#include "scopes.h"
#include "stub-cache.h"
@ -8060,6 +8061,42 @@ const HOptimizedGraphBuilder::InlineFunctionGenerator
#undef INLINE_FUNCTION_GENERATOR_ADDRESS
template <class ViewClass>
void HGraphBuilder::BuildArrayBufferViewInitialization(
HValue* obj,
HValue* buffer,
HValue* byte_offset,
HValue* byte_length) {
for (int offset = ViewClass::kSize;
offset < ViewClass::kSizeWithInternalFields;
offset += kPointerSize) {
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSObjectOffset(offset),
Add<HConstant>(static_cast<int32_t>(0)));
}
Add<HStoreNamedField>(
obj,
HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
Add<HStoreNamedField>(
obj,
HObjectAccess::ForJSArrayBufferViewByteOffset(),
byte_offset);
Add<HStoreNamedField>(
obj,
HObjectAccess::ForJSArrayBufferViewByteLength(),
byte_length);
HObjectAccess weak_first_view_access =
HObjectAccess::ForJSArrayBufferWeakFirstView();
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSArrayBufferViewWeakNext(),
Add<HLoadNamedField>(buffer, weak_first_view_access));
Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
}
void HOptimizedGraphBuilder::VisitDataViewInitialize(
CallRuntime* expr) {
ZoneList<Expression*>* arguments = expr->arguments();
@ -8078,31 +8115,127 @@ void HOptimizedGraphBuilder::VisitDataViewInitialize(
CHECK_ALIVE(VisitForValue(arguments->at(3)));
HValue* byte_length = Pop();
for (int offset = JSDataView::kSize;
offset < JSDataView::kSizeWithInternalFields;
offset += kPointerSize) {
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSObjectOffset(offset),
Add<HConstant>(static_cast<int32_t>(0)));
BuildArrayBufferViewInitialization<JSDataView>(
obj, buffer, byte_offset, byte_length);
}
void HOptimizedGraphBuilder::VisitTypedArrayInitialize(
CallRuntime* expr) {
ZoneList<Expression*>* arguments = expr->arguments();
NoObservableSideEffectsScope scope(this);
static const int kObjectArg = 0;
static const int kArrayIdArg = 1;
static const int kBufferArg = 2;
static const int kByteOffsetArg = 3;
static const int kByteLengthArg = 4;
static const int kArgsLength = 5;
ASSERT(arguments->length() == kArgsLength);
CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg)));
HValue* obj = Pop();
ASSERT(arguments->at(kArrayIdArg)->node_type() == AstNode::kLiteral);
Handle<Object> value =
static_cast<Literal*>(arguments->at(kArrayIdArg))->value();
ASSERT(value->IsSmi());
int array_id = Smi::cast(*value)->value();
CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
HValue* buffer = Pop();
HValue* byte_offset;
bool is_zero_byte_offset;
if (arguments->at(kByteOffsetArg)->node_type() == AstNode::kLiteral
&& Smi::FromInt(0) ==
*static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) {
byte_offset = Add<HConstant>(static_cast<int32_t>(0));
is_zero_byte_offset = true;
} else {
CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
byte_offset = Pop();
is_zero_byte_offset = false;
}
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSObjectOffset(JSDataView::kBufferOffset), buffer);
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSObjectOffset(JSDataView::kByteOffsetOffset),
byte_offset);
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSObjectOffset(JSDataView::kByteLengthOffset),
byte_length);
CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
HValue* byte_length = Pop();
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSObjectOffset(JSDataView::kWeakNextOffset),
Add<HLoadNamedField>(buffer,
HObjectAccess::ForJSObjectOffset(
JSArrayBuffer::kWeakFirstViewOffset)));
Add<HStoreNamedField>(buffer,
HObjectAccess::ForJSObjectOffset(JSArrayBuffer::kWeakFirstViewOffset),
obj);
IfBuilder byte_offset_smi(this);
if (!is_zero_byte_offset) {
byte_offset_smi.If<HIsSmiAndBranch>(byte_offset);
byte_offset_smi.Then();
}
{ // byte_offset is Smi.
BuildArrayBufferViewInitialization<JSTypedArray>(
obj, buffer, byte_offset, byte_length);
ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
Runtime::ArrayIdToTypeAndSize(array_id, &array_type, &element_size);
HInstruction* length = AddUncasted<HDiv>(byte_length,
Add<HConstant>(static_cast<int32_t>(element_size)));
Add<HStoreNamedField>(obj,
HObjectAccess::ForJSTypedArrayLength(),
length);
HValue* elements =
Add<HAllocate>(
Add<HConstant>(ExternalArray::kAlignedSize),
HType::JSArray(),
NOT_TENURED,
static_cast<InstanceType>(FIRST_EXTERNAL_ARRAY_TYPE + array_type));
Handle<Map> external_array_map(
isolate()->heap()->MapForExternalArrayType(array_type));
Add<HStoreNamedField>(elements,
HObjectAccess::ForMap(),
Add<HConstant>(external_array_map));
HValue* backing_store = Add<HLoadNamedField>(
buffer, HObjectAccess::ForJSArrayBufferBackingStore());
HValue* typed_array_start;
if (is_zero_byte_offset) {
typed_array_start = backing_store;
} else {
HInstruction* external_pointer =
AddUncasted<HAdd>(backing_store, byte_offset);
// Arguments are checked prior to call to TypedArrayInitialize,
// including byte_offset.
external_pointer->ClearFlag(HValue::kCanOverflow);
typed_array_start = external_pointer;
}
Add<HStoreNamedField>(elements,
HObjectAccess::ForExternalArrayExternalPointer(),
typed_array_start);
Add<HStoreNamedField>(elements,
HObjectAccess::ForFixedArrayLength(),
length);
Add<HStoreNamedField>(
obj, HObjectAccess::ForElementsPointer(), elements);
}
if (!is_zero_byte_offset) {
byte_offset_smi.Else();
{ // byte_offset is not Smi.
Push(Add<HPushArgument>(obj));
VisitArgument(arguments->at(kArrayIdArg));
Push(Add<HPushArgument>(buffer));
Push(Add<HPushArgument>(byte_offset));
Push(Add<HPushArgument>(byte_length));
Add<HCallRuntime>(expr->name(), expr->function(), kArgsLength);
Drop(kArgsLength);
}
}
byte_offset_smi.End();
}
@ -8121,6 +8254,16 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
return VisitDataViewInitialize(expr);
}
if (function->function_id == Runtime::kTypedArrayInitialize) {
return VisitTypedArrayInitialize(expr);
}
if (function->function_id == Runtime::kMaxSmi) {
ASSERT(expr->arguments()->length() == 0);
HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
return ast_context()->ReturnInstruction(max_smi, expr->id());
}
if (function->intrinsic_type == Runtime::INLINE) {
ASSERT(expr->name()->length() > 0);
ASSERT(expr->name()->Get(0) == '_');

View File

@ -1736,6 +1736,12 @@ class HGraphBuilder {
position_ = position;
}
template <typename ViewClass>
void BuildArrayBufferViewInitialization(HValue* obj,
HValue* buffer,
HValue* byte_offset,
HValue* byte_length);
private:
HGraphBuilder();
@ -2195,6 +2201,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
SmallMapList* types,
Handle<String> name);
void VisitTypedArrayInitialize(CallRuntime* expr);
bool IsCallNewArrayInlineable(CallNew* expr);
void BuildInlinedCallNewArray(CallNew* expr);

View File

@ -1653,6 +1653,21 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
return result;
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::ADD, instr);
} else if (instr->representation().IsExternal()) {
ASSERT(instr->left()->representation().IsExternal());
ASSERT(instr->right()->representation().IsInteger32());
ASSERT(!instr->CheckFlag(HValue::kCanOverflow));
bool use_lea = LAddI::UseLea(instr);
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_candidate = instr->right();
LOperand* right = use_lea
? UseRegisterOrConstantAtStart(right_candidate)
: UseOrConstantAtStart(right_candidate);
LAddI* add = new(zone()) LAddI(left, right);
LInstruction* result = use_lea
? DefineAsRegister(add)
: DefineSameAsFirst(add);
return result;
} else {
return DoArithmeticT(Token::ADD, instr);
}

View File

@ -131,6 +131,10 @@ class Representation {
}
bool is_more_general_than(const Representation& other) const {
if (kind_ == kExternal && other.kind_ == kNone) return true;
if (kind_ == kExternal && other.kind_ == kExternal) return false;
if (kind_ == kNone && other.kind_ == kExternal) return false;
ASSERT(kind_ != kExternal);
ASSERT(other.kind_ != kExternal);
if (IsHeapObject()) return other.IsDouble() || other.IsNone();

View File

@ -863,20 +863,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) {
}
enum TypedArrayId {
// arrayIds below should be synchromized with typedarray.js natives.
ARRAY_ID_UINT8 = 1,
ARRAY_ID_INT8 = 2,
ARRAY_ID_UINT16 = 3,
ARRAY_ID_INT16 = 4,
ARRAY_ID_UINT32 = 5,
ARRAY_ID_INT32 = 6,
ARRAY_ID_FLOAT32 = 7,
ARRAY_ID_FLOAT64 = 8,
ARRAY_ID_UINT8C = 9
};
static void ArrayIdToTypeAndSize(
void Runtime::ArrayIdToTypeAndSize(
int arrayId, ExternalArrayType* array_type, size_t* element_size) {
switch (arrayId) {
case ARRAY_ID_UINT8:
@ -938,7 +925,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
holder->set_buffer(*buffer);
holder->set_byte_offset(*byte_offset_object);
@ -990,7 +977,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
size_t element_size = 1; // Bogus initialization.
ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
size_t length = NumberToSize(isolate, *length_obj);

View File

@ -830,6 +830,22 @@ class Runtime : public AllStatic {
Isolate* isolate,
JSArrayBuffer* phantom_array_buffer);
enum TypedArrayId {
// arrayIds below should be synchromized with typedarray.js natives.
ARRAY_ID_UINT8 = 1,
ARRAY_ID_INT8 = 2,
ARRAY_ID_UINT16 = 3,
ARRAY_ID_INT16 = 4,
ARRAY_ID_UINT32 = 5,
ARRAY_ID_INT32 = 6,
ARRAY_ID_FLOAT32 = 7,
ARRAY_ID_FLOAT64 = 8,
ARRAY_ID_UINT8C = 9
};
static void ArrayIdToTypeAndSize(int array_id,
ExternalArrayType *type, size_t *element_size);
// Helper functions used stubs.
static void PerformGC(Object* result, Isolate* isolate);

View File

@ -78,7 +78,8 @@ macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
newByteLength = newLength * ELEMENT_SIZE;
}
if (offset + newByteLength > bufferByteLength) {
if ((offset + newByteLength > bufferByteLength)
|| (newLength > %MaxSmi())) {
throw MakeRangeError("invalid_typed_array_length");
}
%TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength);

View File

@ -1781,14 +1781,22 @@ void LCodeGen::DoAddI(LAddI* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
Representation target_rep = instr->hydrogen()->representation();
bool is_q = target_rep.IsSmi() || target_rep.IsExternal();
if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
if (right->IsConstantOperand()) {
int32_t offset = ToInteger32(LConstantOperand::cast(right));
__ leal(ToRegister(instr->result()),
MemOperand(ToRegister(left), offset));
if (is_q) {
__ lea(ToRegister(instr->result()),
MemOperand(ToRegister(left), offset));
} else {
__ leal(ToRegister(instr->result()),
MemOperand(ToRegister(left), offset));
}
} else {
Operand address(ToRegister(left), ToRegister(right), times_1, 0);
if (instr->hydrogen()->representation().IsSmi()) {
if (is_q) {
__ lea(ToRegister(instr->result()), address);
} else {
__ leal(ToRegister(instr->result()), address);
@ -1796,16 +1804,21 @@ void LCodeGen::DoAddI(LAddI* instr) {
}
} else {
if (right->IsConstantOperand()) {
__ addl(ToRegister(left),
Immediate(ToInteger32(LConstantOperand::cast(right))));
if (is_q) {
__ addq(ToRegister(left),
Immediate(ToInteger32(LConstantOperand::cast(right))));
} else {
__ addl(ToRegister(left),
Immediate(ToInteger32(LConstantOperand::cast(right))));
}
} else if (right->IsRegister()) {
if (instr->hydrogen_value()->representation().IsSmi()) {
if (is_q) {
__ addq(ToRegister(left), ToRegister(right));
} else {
__ addl(ToRegister(left), ToRegister(right));
}
} else {
if (instr->hydrogen_value()->representation().IsSmi()) {
if (is_q) {
__ addq(ToRegister(left), ToOperand(right));
} else {
__ addl(ToRegister(left), ToOperand(right));

View File

@ -1557,6 +1557,21 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
result = AssignEnvironment(result);
}
return result;
} else if (instr->representation().IsExternal()) {
ASSERT(instr->left()->representation().IsExternal());
ASSERT(instr->right()->representation().IsInteger32());
ASSERT(!instr->CheckFlag(HValue::kCanOverflow));
bool use_lea = LAddI::UseLea(instr);
LOperand* left = UseRegisterAtStart(instr->left());
HValue* right_candidate = instr->right();
LOperand* right = use_lea
? UseRegisterOrConstantAtStart(right_candidate)
: UseOrConstantAtStart(right_candidate);
LAddI* add = new(zone()) LAddI(left, right);
LInstruction* result = use_lea
? DefineAsRegister(add)
: DefineSameAsFirst(add);
return result;
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::ADD, instr);
} else {

View File

@ -121,4 +121,8 @@ TEST(RepresentationMoreGeneralThan) {
TestPairNegative(Representation::HeapObject(), Representation::Integer32());
TestPairPositive(Representation::Double(), Representation::Integer32());
TestPairPositive(Representation::Tagged(), Representation::Integer32());
TestPairNegative(Representation::None(), Representation::External());
TestPairNegative(Representation::External(), Representation::External());
TestPairPositive(Representation::External(), Representation::None());
}

View File

@ -204,6 +204,9 @@ var knownProblems = {
"_OneByteSeqStringSetChar": true,
"_TwoByteSeqStringSetChar": true,
// Only applicable to TypedArrays.
"TypedArrayInitialize": true,
// Only applicable to generators.
"_GeneratorNext": true,
"_GeneratorThrow": true,

View File

@ -205,6 +205,9 @@ var knownProblems = {
"_OneByteSeqStringSetChar": true,
"_TwoByteSeqStringSetChar": true,
// Only applicable to TypedArrays.
"TypedArrayInitialize": true,
// Only applicable to generators.
"_GeneratorNext": true,
"_GeneratorThrow": true,

View File

@ -204,6 +204,9 @@ var knownProblems = {
"_OneByteSeqStringSetChar": true,
"_TwoByteSeqStringSetChar": true,
// Only applicable to TypedArrays.
"TypedArrayInitialize": true,
// Only applicable to generators.
"_GeneratorNext": true,
"_GeneratorThrow": true,

View File

@ -204,6 +204,9 @@ var knownProblems = {
"_OneByteSeqStringSetChar": true,
"_TwoByteSeqStringSetChar": true,
// Only applicable to TypedArrays.
"TypedArrayInitialize": true,
// Only applicable to generators.
"_GeneratorNext": true,
"_GeneratorThrow": true,