[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:
parent
40dd065823
commit
71ea148ec3
2
BUILD.gn
2
BUILD.gn
@ -1078,6 +1078,8 @@ v8_source_set("v8_initializers") {
|
|||||||
"src/builtins/builtins-typedarray-gen.cc",
|
"src/builtins/builtins-typedarray-gen.cc",
|
||||||
"src/builtins/builtins-utils-gen.h",
|
"src/builtins/builtins-utils-gen.h",
|
||||||
"src/builtins/builtins-wasm-gen.cc",
|
"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/builtins/setup-builtins-internal.cc",
|
||||||
"src/heap/setup-heap-internal.cc",
|
"src/heap/setup-heap-internal.cc",
|
||||||
"src/ic/accessor-assembler.cc",
|
"src/ic/accessor-assembler.cc",
|
||||||
|
@ -195,6 +195,8 @@
|
|||||||
'../src/builtins/builtins-typedarray-gen.cc',
|
'../src/builtins/builtins-typedarray-gen.cc',
|
||||||
'../src/builtins/builtins-utils-gen.h',
|
'../src/builtins/builtins-utils-gen.h',
|
||||||
'../src/builtins/builtins-wasm-gen.cc',
|
'../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/builtins/setup-builtins-internal.cc',
|
||||||
'../src/heap/setup-heap-internal.cc',
|
'../src/heap/setup-heap-internal.cc',
|
||||||
'../src/ic/accessor-assembler.cc',
|
'../src/ic/accessor-assembler.cc',
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "src/builtins/builtins-constructor-gen.h"
|
#include "src/builtins/builtins-constructor-gen.h"
|
||||||
#include "src/builtins/builtins-utils-gen.h"
|
#include "src/builtins/builtins-utils-gen.h"
|
||||||
#include "src/builtins/builtins.h"
|
#include "src/builtins/builtins.h"
|
||||||
|
#include "src/builtins/growable-fixed-array-gen.h"
|
||||||
#include "src/code-factory.h"
|
#include "src/code-factory.h"
|
||||||
#include "src/code-stub-assembler.h"
|
#include "src/code-stub-assembler.h"
|
||||||
#include "src/counters.h"
|
#include "src/counters.h"
|
||||||
@ -1795,153 +1796,6 @@ Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string,
|
|||||||
return var_result.value();
|
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,
|
void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
|
||||||
Node* const regexp,
|
Node* const regexp,
|
||||||
Node* const string,
|
Node* const string,
|
||||||
@ -1975,7 +1829,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
|
|||||||
|
|
||||||
// Allocate an array to store the resulting match strings.
|
// Allocate an array to store the resulting match strings.
|
||||||
|
|
||||||
GrowableFixedArray array(this);
|
GrowableFixedArray array(state());
|
||||||
|
|
||||||
// Loop preparations. Within the loop, collect results from RegExpExec
|
// Loop preparations. Within the loop, collect results from RegExpExec
|
||||||
// and store match strings in the array.
|
// 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.
|
// 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.
|
// 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.
|
// Wrap the match in a JSArray.
|
||||||
|
|
||||||
Node* const result = array.ToJSArray(context);
|
Node* const result = array.ToJSArray(CAST(context));
|
||||||
Return(result);
|
Return(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2343,7 +2197,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
|
|||||||
|
|
||||||
// Loop preparations.
|
// Loop preparations.
|
||||||
|
|
||||||
GrowableFixedArray array(this);
|
GrowableFixedArray array(state());
|
||||||
|
|
||||||
VARIABLE(var_last_matched_until, MachineRepresentation::kTagged);
|
VARIABLE(var_last_matched_until, MachineRepresentation::kTagged);
|
||||||
VARIABLE(var_next_search_from, 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 from = last_matched_until;
|
||||||
Node* const to = match_from;
|
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);
|
array.Push(substr);
|
||||||
|
|
||||||
GotoIf(WordEqual(array.length(), int_limit), &out);
|
GotoIf(WordEqual(array.length(), int_limit), &out);
|
||||||
@ -2476,7 +2330,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
|
|||||||
|
|
||||||
BIND(&store_value);
|
BIND(&store_value);
|
||||||
{
|
{
|
||||||
array.Push(var_value.value());
|
array.Push(CAST(var_value.value()));
|
||||||
GotoIf(WordEqual(array.length(), int_limit), &out);
|
GotoIf(WordEqual(array.length(), int_limit), &out);
|
||||||
|
|
||||||
Node* const new_reg = IntPtrAdd(reg, IntPtrConstant(2));
|
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 from = var_last_matched_until.value();
|
||||||
Node* const to = string_length;
|
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);
|
array.Push(substr);
|
||||||
|
|
||||||
Goto(&out);
|
Goto(&out);
|
||||||
@ -2508,7 +2362,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
|
|||||||
|
|
||||||
BIND(&out);
|
BIND(&out);
|
||||||
{
|
{
|
||||||
Node* const result = array.ToJSArray(context);
|
Node* const result = array.ToJSArray(CAST(context));
|
||||||
Return(result);
|
Return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
100
src/builtins/growable-fixed-array-gen.cc
Normal file
100
src/builtins/growable-fixed-array-gen.cc
Normal 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
|
56
src/builtins/growable-fixed-array-gen.h
Normal file
56
src/builtins/growable-fixed-array-gen.h
Normal 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_
|
Loading…
Reference in New Issue
Block a user