[csa] Move the GrowableFixedArray into its own file.

We want to be able to use this from other builtins as well, so move it
to somewhere common.

Also adds typing and cleans up the coding style to match newer CSA code
a bit more. GrowableFixedArray is now a subclass of CodeStubAssembler
to make things easier and cleaner. The growing strategy has also been
slightly changed so that empty arrays can be produced.

Change-Id: I20cbd1069d489a6875804736d3e5abab80d0f777
Reviewed-on: https://chromium-review.googlesource.com/901324
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51107}
This commit is contained in:
Peter Marshall 2018-02-05 17:10:42 +01:00 committed by Commit Bot
parent 40dd065823
commit 71ea148ec3
5 changed files with 169 additions and 155 deletions

View File

@ -1078,6 +1078,8 @@ v8_source_set("v8_initializers") {
"src/builtins/builtins-typedarray-gen.cc",
"src/builtins/builtins-utils-gen.h",
"src/builtins/builtins-wasm-gen.cc",
"src/builtins/growable-fixed-array-gen.cc",
"src/builtins/growable-fixed-array-gen.h",
"src/builtins/setup-builtins-internal.cc",
"src/heap/setup-heap-internal.cc",
"src/ic/accessor-assembler.cc",

View File

@ -195,6 +195,8 @@
'../src/builtins/builtins-typedarray-gen.cc',
'../src/builtins/builtins-utils-gen.h',
'../src/builtins/builtins-wasm-gen.cc',
'../src/builtins/growable-fixed-array-gen.cc',
'../src/builtins/growable-fixed-array-gen.h',
'../src/builtins/setup-builtins-internal.cc',
'../src/heap/setup-heap-internal.cc',
'../src/ic/accessor-assembler.cc',

View File

@ -7,6 +7,7 @@
#include "src/builtins/builtins-constructor-gen.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/builtins/growable-fixed-array-gen.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/counters.h"
@ -1795,153 +1796,6 @@ Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string,
return var_result.value();
}
namespace {
// Utility class implementing a growable fixed array through CSA.
class GrowableFixedArray {
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
public:
explicit GrowableFixedArray(CodeStubAssembler* a)
: assembler_(a),
var_array_(a, MachineRepresentation::kTagged),
var_length_(a, MachineType::PointerRepresentation()),
var_capacity_(a, MachineType::PointerRepresentation()) {
Initialize();
}
Node* length() const { return var_length_.value(); }
Variable* var_array() { return &var_array_; }
Variable* var_length() { return &var_length_; }
Variable* var_capacity() { return &var_capacity_; }
void Push(Node* const value) {
CodeStubAssembler* a = assembler_;
Node* const length = var_length_.value();
Node* const capacity = var_capacity_.value();
Label grow(a), store(a);
a->Branch(a->IntPtrEqual(capacity, length), &grow, &store);
a->BIND(&grow);
{
Node* const new_capacity = NewCapacity(a, capacity);
Node* const new_array = ResizeFixedArray(length, new_capacity);
var_capacity_.Bind(new_capacity);
var_array_.Bind(new_array);
a->Goto(&store);
}
a->BIND(&store);
{
Node* const array = var_array_.value();
a->StoreFixedArrayElement(array, length, value);
Node* const new_length = a->IntPtrAdd(length, a->IntPtrConstant(1));
var_length_.Bind(new_length);
}
}
Node* ToJSArray(Node* const context) {
CodeStubAssembler* a = assembler_;
const ElementsKind kind = PACKED_ELEMENTS;
Node* const native_context = a->LoadNativeContext(context);
Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context);
// Shrink to fit if necessary.
{
Label next(a);
Node* const length = var_length_.value();
Node* const capacity = var_capacity_.value();
a->GotoIf(a->WordEqual(length, capacity), &next);
Node* const array = ResizeFixedArray(length, length);
var_array_.Bind(array);
var_capacity_.Bind(length);
a->Goto(&next);
a->BIND(&next);
}
Node* const result_length = a->SmiTag(length());
Node* const result = a->AllocateUninitializedJSArrayWithoutElements(
array_map, result_length, nullptr);
// Note: We do not currently shrink the fixed array.
a->StoreObjectField(result, JSObject::kElementsOffset, var_array_.value());
return result;
}
private:
void Initialize() {
CodeStubAssembler* a = assembler_;
const ElementsKind kind = PACKED_ELEMENTS;
static const int kInitialArraySize = 8;
Node* const capacity = a->IntPtrConstant(kInitialArraySize);
Node* const array = a->AllocateFixedArray(kind, capacity);
a->FillFixedArrayWithValue(kind, array, a->IntPtrConstant(0), capacity,
Heap::kTheHoleValueRootIndex);
var_array_.Bind(array);
var_capacity_.Bind(capacity);
var_length_.Bind(a->IntPtrConstant(0));
}
Node* NewCapacity(CodeStubAssembler* a,
compiler::SloppyTNode<IntPtrT> current_capacity) {
CSA_ASSERT(a, a->IntPtrGreaterThan(current_capacity, a->IntPtrConstant(0)));
// Growth rate is analog to JSObject::NewElementsCapacity:
// new_capacity = (current_capacity + (current_capacity >> 1)) + 16.
Node* const new_capacity = a->IntPtrAdd(
a->IntPtrAdd(current_capacity, a->WordShr(current_capacity, 1)),
a->IntPtrConstant(16));
return new_capacity;
}
// Creates a new array with {new_capacity} and copies the first
// {element_count} elements from the current array.
Node* ResizeFixedArray(Node* const element_count, Node* const new_capacity) {
CodeStubAssembler* a = assembler_;
CSA_ASSERT(a, a->IntPtrGreaterThan(element_count, a->IntPtrConstant(0)));
CSA_ASSERT(a, a->IntPtrGreaterThan(new_capacity, a->IntPtrConstant(0)));
CSA_ASSERT(a, a->IntPtrGreaterThanOrEqual(new_capacity, element_count));
Node* const from_array = var_array_.value();
CodeStubAssembler::ExtractFixedArrayFlags flags;
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays;
Node* to_array = a->ExtractFixedArray(from_array, nullptr, element_count,
new_capacity, flags);
return to_array;
}
private:
CodeStubAssembler* const assembler_;
Variable var_array_;
Variable var_length_;
Variable var_capacity_;
};
} // namespace
void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
Node* const regexp,
Node* const string,
@ -1975,7 +1829,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
// Allocate an array to store the resulting match strings.
GrowableFixedArray array(this);
GrowableFixedArray array(state());
// Loop preparations. Within the loop, collect results from RegExpExec
// and store match strings in the array.
@ -2052,7 +1906,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
// Store the match, growing the fixed array if needed.
array.Push(match);
array.Push(CAST(match));
// Advance last index if the match is the empty string.
@ -2087,7 +1941,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
{
// Wrap the match in a JSArray.
Node* const result = array.ToJSArray(context);
Node* const result = array.ToJSArray(CAST(context));
Return(result);
}
}
@ -2343,7 +2197,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
// Loop preparations.
GrowableFixedArray array(this);
GrowableFixedArray array(state());
VARIABLE(var_last_matched_until, MachineRepresentation::kTagged);
VARIABLE(var_next_search_from, MachineRepresentation::kTagged);
@ -2423,7 +2277,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
Node* const from = last_matched_until;
Node* const to = match_from;
Node* const substr = SubString(context, string, from, to);
TNode<String> const substr = CAST(SubString(context, string, from, to));
array.Push(substr);
GotoIf(WordEqual(array.length(), int_limit), &out);
@ -2476,7 +2330,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&store_value);
{
array.Push(var_value.value());
array.Push(CAST(var_value.value()));
GotoIf(WordEqual(array.length(), int_limit), &out);
Node* const new_reg = IntPtrAdd(reg, IntPtrConstant(2));
@ -2500,7 +2354,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
Node* const from = var_last_matched_until.value();
Node* const to = string_length;
Node* const substr = SubString(context, string, from, to);
TNode<String> const substr = CAST(SubString(context, string, from, to));
array.Push(substr);
Goto(&out);
@ -2508,7 +2362,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&out);
{
Node* const result = array.ToJSArray(context);
Node* const result = array.ToJSArray(CAST(context));
Return(result);
}

View File

@ -0,0 +1,100 @@
// Copyright 2018 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/builtins/growable-fixed-array-gen.h"
#include "src/compiler/code-assembler.h"
namespace v8 {
namespace internal {
void GrowableFixedArray::Push(TNode<Object> const value) {
TNode<IntPtrT> const length = var_length_;
TNode<IntPtrT> const capacity = var_capacity_;
Label grow(this), store(this);
Branch(IntPtrEqual(capacity, length), &grow, &store);
BIND(&grow);
{
var_capacity_ = NewCapacity(capacity);
var_array_ = ResizeFixedArray(length, var_capacity_);
Goto(&store);
}
BIND(&store);
{
TNode<FixedArray> const array = var_array_;
StoreFixedArrayElement(array, length, value);
var_length_ = IntPtrAdd(length, IntPtrConstant(1));
}
}
TNode<JSArray> GrowableFixedArray::ToJSArray(TNode<Context> const context) {
const ElementsKind kind = PACKED_ELEMENTS;
TNode<Context> const native_context = LoadNativeContext(context);
TNode<Map> const array_map = LoadJSArrayElementsMap(kind, native_context);
// Shrink to fit if necessary.
{
Label next(this);
TNode<IntPtrT> const length = var_length_;
TNode<IntPtrT> const capacity = var_capacity_;
GotoIf(WordEqual(length, capacity), &next);
var_array_ = ResizeFixedArray(length, length);
var_capacity_ = length;
Goto(&next);
BIND(&next);
}
TNode<Smi> const result_length = SmiTag(length());
TNode<JSArray> const result =
CAST(AllocateUninitializedJSArrayWithoutElements(array_map, result_length,
nullptr));
StoreObjectField(result, JSObject::kElementsOffset, var_array_);
return result;
}
TNode<IntPtrT> GrowableFixedArray::NewCapacity(
TNode<IntPtrT> current_capacity) {
CSA_ASSERT(this,
IntPtrGreaterThanOrEqual(current_capacity, IntPtrConstant(0)));
// Growth rate is analog to JSObject::NewElementsCapacity:
// new_capacity = (current_capacity + (current_capacity >> 1)) + 16.
TNode<IntPtrT> const new_capacity =
IntPtrAdd(IntPtrAdd(current_capacity, WordShr(current_capacity, 1)),
IntPtrConstant(16));
return new_capacity;
}
TNode<FixedArray> GrowableFixedArray::ResizeFixedArray(
TNode<IntPtrT> const element_count, TNode<IntPtrT> const new_capacity) {
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(element_count, IntPtrConstant(0)));
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(new_capacity, IntPtrConstant(0)));
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(new_capacity, element_count));
TNode<FixedArray> const from_array = var_array_;
CodeStubAssembler::ExtractFixedArrayFlags flags;
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays;
TNode<FixedArray> to_array = CAST(ExtractFixedArray(
from_array, nullptr, element_count, new_capacity, flags));
return to_array;
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,56 @@
// Copyright 2018 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.
#ifndef V8_BUILTINS_GROWABLE_FIXED_ARRAY_GEN_H_
#define V8_BUILTINS_GROWABLE_FIXED_ARRAY_GEN_H_
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
template <class T>
using TNode = compiler::TNode<T>;
// Utility class implementing a growable fixed array through CSA.
class GrowableFixedArray : public CodeStubAssembler {
public:
explicit GrowableFixedArray(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state),
var_array_(this),
var_length_(this),
var_capacity_(this) {
var_array_ = EmptyFixedArrayConstant();
var_capacity_ = IntPtrConstant(0);
var_length_ = IntPtrConstant(0);
}
TNode<IntPtrT> length() const { return var_length_; }
TVariable<FixedArray>* var_array() { return &var_array_; }
TVariable<IntPtrT>* var_length() { return &var_length_; }
TVariable<IntPtrT>* var_capacity() { return &var_capacity_; }
void Push(TNode<Object> const value);
TNode<JSArray> ToJSArray(TNode<Context> const context);
private:
TNode<IntPtrT> NewCapacity(TNode<IntPtrT> current_capacity);
// Creates a new array with {new_capacity} and copies the first
// {element_count} elements from the current array.
TNode<FixedArray> ResizeFixedArray(TNode<IntPtrT> const element_count,
TNode<IntPtrT> const new_capacity);
private:
TVariable<FixedArray> var_array_;
TVariable<IntPtrT> var_length_;
TVariable<IntPtrT> var_capacity_;
};
} // namespace internal
} // namespace v8
#endif // V8_BUILTINS_GROWABLE_FIXED_ARRAY_GEN_H_