mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:27:39 +00:00
[vm/compiler] Various cleanups involving CreateArrayInstr.
* Rename values and methods like kElementTypePos or element_type() to corresponding names like kTypeArgumentsPos or type_arguments() (since the input to CreateArrayInstr is the type arguments vector for the array, not just the type of the element.) * Create a AllocateArrayABI struct for the input and output registers of the AllocateArray stub and use those where applicable. * Explicitly list what registers are clobbered in the AllocateArray stubs in their documentation comment. * Avoid clobbering the type arguments input register in the arm64 version of AllocateArrayInstr, so all input registers are preserved across all architectures. TEST=Refactoring, so existing tests. Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-linux-debug-x64c-try,vm-kernel-linux-debug-simarm64c-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm64c-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-precomp-nnbd-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-nnbd-linux-release-simarm-try,vm-kernel-nnbd-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-nnbd-linux-release-simarm64-try Change-Id: I3a7c2b6afdd307c26f8d4f97a4c8bd7684e7b242 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/201183 Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Clement Skau <cskau@google.com>
This commit is contained in:
parent
10cabb4d08
commit
619f46cd19
|
@ -2961,7 +2961,7 @@ Definition* LoadFieldInstr::Canonicalize(FlowGraph* flow_graph) {
|
|||
break;
|
||||
}
|
||||
} else if (CreateArrayInstr* create_array = array->AsCreateArray()) {
|
||||
return create_array->element_type()->definition();
|
||||
return create_array->type_arguments()->definition();
|
||||
} else if (LoadFieldInstr* load_array = array->AsLoadField()) {
|
||||
const Slot& slot = load_array->slot();
|
||||
switch (slot.kind()) {
|
||||
|
|
|
@ -6405,20 +6405,20 @@ class TemplateArrayAllocation : public ArrayAllocationInstr {
|
|||
class CreateArrayInstr : public TemplateArrayAllocation<2> {
|
||||
public:
|
||||
CreateArrayInstr(const InstructionSource& source,
|
||||
Value* element_type,
|
||||
Value* type_arguments,
|
||||
Value* num_elements,
|
||||
intptr_t deopt_id)
|
||||
: TemplateArrayAllocation(source, deopt_id) {
|
||||
SetInputAt(kElementTypePos, element_type);
|
||||
SetInputAt(kTypeArgumentsPos, type_arguments);
|
||||
SetInputAt(kLengthPos, num_elements);
|
||||
}
|
||||
|
||||
enum { kElementTypePos = 0, kLengthPos = 1 };
|
||||
enum { kTypeArgumentsPos = 0, kLengthPos = 1 };
|
||||
|
||||
DECLARE_INSTRUCTION(CreateArray)
|
||||
virtual CompileType ComputeType() const;
|
||||
|
||||
Value* element_type() const { return inputs_[kElementTypePos]; }
|
||||
Value* type_arguments() const { return inputs_[kTypeArgumentsPos]; }
|
||||
virtual Value* num_elements() const { return inputs_[kLengthPos]; }
|
||||
|
||||
virtual bool HasUnknownSideEffects() const { return false; }
|
||||
|
|
|
@ -3114,9 +3114,11 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(Zone* zone,
|
|||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
|
||||
locs->set_in(kLengthPos, Location::RegisterLocation(R2));
|
||||
locs->set_out(0, Location::RegisterLocation(R0));
|
||||
locs->set_in(kTypeArgumentsPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kTypeArgumentsReg));
|
||||
locs->set_in(kLengthPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kLengthReg));
|
||||
locs->set_out(0, Location::RegisterLocation(AllocateArrayABI::kResultReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
|
@ -3126,31 +3128,31 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
compiler::Label* slow_path,
|
||||
compiler::Label* done) {
|
||||
const int kInlineArraySize = 12; // Same as kInlineInstanceSize.
|
||||
const Register kLengthReg = R2;
|
||||
const Register kElemTypeReg = R1;
|
||||
const intptr_t instance_size = Array::InstanceSize(num_elements);
|
||||
|
||||
__ TryAllocateArray(kArrayCid, instance_size, slow_path,
|
||||
R0, // instance
|
||||
R3, // end address
|
||||
AllocateArrayABI::kResultReg, // instance
|
||||
R3, // end address
|
||||
R8, R6);
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R3: new object end address.
|
||||
|
||||
// Store the type argument field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
R0,
|
||||
compiler::FieldAddress(R0,
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
compiler::target::Array::type_arguments_offset()),
|
||||
kElemTypeReg);
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
R0, compiler::FieldAddress(R0, compiler::target::Array::length_offset()),
|
||||
kLengthReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
compiler::target::Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R3: new object end address.
|
||||
// R6: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
|
@ -3166,12 +3168,15 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
__ LoadImmediate(R9, 0x1);
|
||||
#endif // DEBUG
|
||||
}
|
||||
__ AddImmediate(R6, R0, sizeof(UntaggedArray) - kHeapObjectTag);
|
||||
__ AddImmediate(R6, AllocateArrayABI::kResultReg,
|
||||
sizeof(UntaggedArray) - kHeapObjectTag);
|
||||
if (array_size < (kInlineArraySize * compiler::target::kWordSize)) {
|
||||
__ InitializeFieldsNoBarrierUnrolled(
|
||||
R0, R6, 0, num_elements * compiler::target::kWordSize, R8, R9);
|
||||
AllocateArrayABI::kResultReg, R6, 0,
|
||||
num_elements * compiler::target::kWordSize, R8, R9);
|
||||
} else {
|
||||
__ InitializeFieldsNoBarrier(R0, R6, R3, R8, R9);
|
||||
__ InitializeFieldsNoBarrier(AllocateArrayABI::kResultReg, R6, R3, R8,
|
||||
R9);
|
||||
}
|
||||
}
|
||||
__ b(done);
|
||||
|
@ -3183,16 +3188,9 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
const Class& list_class =
|
||||
Class::Handle(compiler->isolate_group()->class_table()->At(kArrayCid));
|
||||
RegisterTypeArgumentsUse(compiler->function(), type_usage_info, list_class,
|
||||
element_type()->definition());
|
||||
type_arguments()->definition());
|
||||
}
|
||||
|
||||
const Register kLengthReg = R2;
|
||||
const Register kElemTypeReg = R1;
|
||||
const Register kResultReg = R0;
|
||||
|
||||
ASSERT(locs()->in(kElementTypePos).reg() == kElemTypeReg);
|
||||
ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
|
||||
|
||||
compiler::Label slow_path, done;
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
if (compiler->is_optimizing() && !FLAG_precompiled_mode &&
|
||||
|
@ -3214,7 +3212,6 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
UntaggedPcDescriptors::kOther, locs(), deopt_id(),
|
||||
env());
|
||||
__ Bind(&done);
|
||||
ASSERT(locs()->out(0).reg() == kResultReg);
|
||||
}
|
||||
|
||||
LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
|
|
|
@ -2674,9 +2674,11 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(Zone* zone,
|
|||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
|
||||
locs->set_in(kLengthPos, Location::RegisterLocation(R2));
|
||||
locs->set_out(0, Location::RegisterLocation(R0));
|
||||
locs->set_in(kTypeArgumentsPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kTypeArgumentsReg));
|
||||
locs->set_in(kLengthPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kLengthReg));
|
||||
locs->set_out(0, Location::RegisterLocation(AllocateArrayABI::kResultReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
|
@ -2686,29 +2688,32 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
compiler::Label* slow_path,
|
||||
compiler::Label* done) {
|
||||
const int kInlineArraySize = 12; // Same as kInlineInstanceSize.
|
||||
const Register kLengthReg = R2;
|
||||
const Register kElemTypeReg = R1;
|
||||
const intptr_t instance_size = Array::InstanceSize(num_elements);
|
||||
|
||||
__ TryAllocateArray(kArrayCid, instance_size, slow_path,
|
||||
R0, // instance
|
||||
R3, // end address
|
||||
AllocateArrayABI::kResultReg, // instance
|
||||
R3, // end address
|
||||
R6, R8);
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R3: new object end address.
|
||||
|
||||
// Store the type argument field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
R0, compiler::FieldAddress(R0, Array::type_arguments_offset()),
|
||||
kElemTypeReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
Array::type_arguments_offset()),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
R0, compiler::FieldAddress(R0, Array::length_offset()), kLengthReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// TODO(zra): Use stp once added.
|
||||
// Initialize all array elements to raw_null.
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R3: new object end address.
|
||||
// R8: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
|
@ -2716,7 +2721,8 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
if (num_elements > 0) {
|
||||
const intptr_t array_size = instance_size - sizeof(UntaggedArray);
|
||||
__ LoadObject(R6, Object::null_object());
|
||||
__ AddImmediate(R8, R0, sizeof(UntaggedArray) - kHeapObjectTag);
|
||||
__ AddImmediate(R8, AllocateArrayABI::kResultReg,
|
||||
sizeof(UntaggedArray) - kHeapObjectTag);
|
||||
if (array_size < (kInlineArraySize * kWordSize)) {
|
||||
intptr_t current_offset = 0;
|
||||
while (current_offset < array_size) {
|
||||
|
@ -2743,16 +2749,9 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
const Class& list_class =
|
||||
Class::Handle(compiler->isolate_group()->class_table()->At(kArrayCid));
|
||||
RegisterTypeArgumentsUse(compiler->function(), type_usage_info, list_class,
|
||||
element_type()->definition());
|
||||
type_arguments()->definition());
|
||||
}
|
||||
|
||||
const Register kLengthReg = R2;
|
||||
const Register kElemTypeReg = R1;
|
||||
const Register kResultReg = R0;
|
||||
|
||||
ASSERT(locs()->in(kElementTypePos).reg() == kElemTypeReg);
|
||||
ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
|
||||
|
||||
compiler::Label slow_path, done;
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
if (compiler->is_optimizing() && !FLAG_precompiled_mode &&
|
||||
|
@ -2773,7 +2772,6 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
compiler->GenerateStubCall(source(), allocate_array_stub,
|
||||
UntaggedPcDescriptors::kOther, locs(), deopt_id(),
|
||||
env());
|
||||
ASSERT(locs()->out(0).reg() == kResultReg);
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
|
|
|
@ -2393,9 +2393,11 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(Zone* zone,
|
|||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(ECX));
|
||||
locs->set_in(1, Location::RegisterLocation(EDX));
|
||||
locs->set_out(0, Location::RegisterLocation(EAX));
|
||||
locs->set_in(kTypeArgumentsPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kTypeArgumentsReg));
|
||||
locs->set_in(kLengthPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kLengthReg));
|
||||
locs->set_out(0, Location::RegisterLocation(AllocateArrayABI::kResultReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
|
@ -2405,29 +2407,32 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
compiler::Label* slow_path,
|
||||
compiler::Label* done) {
|
||||
const int kInlineArraySize = 12; // Same as kInlineInstanceSize.
|
||||
const Register kLengthReg = EDX;
|
||||
const Register kElemTypeReg = ECX;
|
||||
const intptr_t instance_size = Array::InstanceSize(num_elements);
|
||||
|
||||
// Instance in EAX.
|
||||
// Instance in AllocateArrayABI::kResultReg.
|
||||
// Object end address in EBX.
|
||||
__ TryAllocateArray(kArrayCid, instance_size, slow_path,
|
||||
compiler::Assembler::kFarJump,
|
||||
EAX, // instance
|
||||
EBX, // end address
|
||||
EDI); // temp
|
||||
AllocateArrayABI::kResultReg, // instance
|
||||
EBX, // end address
|
||||
EDI); // temp
|
||||
|
||||
// Store the type argument field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
EAX, compiler::FieldAddress(EAX, Array::type_arguments_offset()),
|
||||
kElemTypeReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
Array::type_arguments_offset()),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
EAX, compiler::FieldAddress(EAX, Array::length_offset()), kLengthReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// EAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// EBX: new object end address.
|
||||
// EDI: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
|
@ -2435,19 +2440,22 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
const intptr_t array_size = instance_size - sizeof(UntaggedArray);
|
||||
const compiler::Immediate& raw_null =
|
||||
compiler::Immediate(static_cast<intptr_t>(Object::null()));
|
||||
__ leal(EDI, compiler::FieldAddress(EAX, sizeof(UntaggedArray)));
|
||||
__ leal(EDI, compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
sizeof(UntaggedArray)));
|
||||
if (array_size < (kInlineArraySize * kWordSize)) {
|
||||
intptr_t current_offset = 0;
|
||||
__ movl(EBX, raw_null);
|
||||
while (current_offset < array_size) {
|
||||
__ StoreIntoObjectNoBarrier(EAX, compiler::Address(EDI, current_offset),
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
compiler::Address(EDI, current_offset),
|
||||
EBX);
|
||||
current_offset += kWordSize;
|
||||
}
|
||||
} else {
|
||||
compiler::Label init_loop;
|
||||
__ Bind(&init_loop);
|
||||
__ StoreIntoObjectNoBarrier(EAX, compiler::Address(EDI, 0),
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
compiler::Address(EDI, 0),
|
||||
Object::null_object());
|
||||
__ addl(EDI, compiler::Immediate(kWordSize));
|
||||
__ cmpl(EDI, EBX);
|
||||
|
@ -2458,13 +2466,6 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
}
|
||||
|
||||
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// Allocate the array. EDX = length, ECX = element type.
|
||||
const Register kLengthReg = EDX;
|
||||
const Register kElemTypeReg = ECX;
|
||||
const Register kResultReg = EAX;
|
||||
ASSERT(locs()->in(0).reg() == kElemTypeReg);
|
||||
ASSERT(locs()->in(1).reg() == kLengthReg);
|
||||
|
||||
compiler::Label slow_path, done;
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
if (compiler->is_optimizing() && num_elements()->BindsToConstant() &&
|
||||
|
@ -2485,7 +2486,6 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
UntaggedPcDescriptors::kOther, locs(), deopt_id(),
|
||||
env());
|
||||
__ Bind(&done);
|
||||
ASSERT(locs()->out(0).reg() == kResultReg);
|
||||
}
|
||||
|
||||
LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
|
|
|
@ -2769,9 +2769,11 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(Zone* zone,
|
|||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(RBX));
|
||||
locs->set_in(1, Location::RegisterLocation(R10));
|
||||
locs->set_out(0, Location::RegisterLocation(RAX));
|
||||
locs->set_in(kTypeArgumentsPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kTypeArgumentsReg));
|
||||
locs->set_in(kLengthPos,
|
||||
Location::RegisterLocation(AllocateArrayABI::kLengthReg));
|
||||
locs->set_out(0, Location::RegisterLocation(AllocateArrayABI::kResultReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
|
@ -2781,46 +2783,52 @@ static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|||
compiler::Label* slow_path,
|
||||
compiler::Label* done) {
|
||||
const int kInlineArraySize = 12; // Same as kInlineInstanceSize.
|
||||
const Register kLengthReg = R10;
|
||||
const Register kElemTypeReg = RBX;
|
||||
const intptr_t instance_size = Array::InstanceSize(num_elements);
|
||||
|
||||
__ TryAllocateArray(kArrayCid, instance_size, slow_path,
|
||||
compiler::Assembler::kFarJump,
|
||||
RAX, // instance
|
||||
RCX, // end address
|
||||
R13); // temp
|
||||
AllocateArrayABI::kResultReg, // instance
|
||||
RCX, // end address
|
||||
R13); // temp
|
||||
|
||||
// RAX: new object start as a tagged pointer.
|
||||
// Store the type argument field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
RAX, compiler::FieldAddress(RAX, Array::type_arguments_offset()),
|
||||
kElemTypeReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
Array::type_arguments_offset()),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
RAX, compiler::FieldAddress(RAX, Array::length_offset()), kLengthReg);
|
||||
AllocateArrayABI::kResultReg,
|
||||
compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// RAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// RCX: new object end address.
|
||||
// RDI: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
if (num_elements > 0) {
|
||||
const intptr_t array_size = instance_size - sizeof(UntaggedArray);
|
||||
__ LoadObject(R12, Object::null_object());
|
||||
__ leaq(RDI, compiler::FieldAddress(RAX, sizeof(UntaggedArray)));
|
||||
__ leaq(RDI, compiler::FieldAddress(AllocateArrayABI::kResultReg,
|
||||
sizeof(UntaggedArray)));
|
||||
if (array_size < (kInlineArraySize * kWordSize)) {
|
||||
intptr_t current_offset = 0;
|
||||
while (current_offset < array_size) {
|
||||
__ StoreIntoObjectNoBarrier(RAX, compiler::Address(RDI, current_offset),
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
compiler::Address(RDI, current_offset),
|
||||
R12);
|
||||
current_offset += kWordSize;
|
||||
}
|
||||
} else {
|
||||
compiler::Label init_loop;
|
||||
__ Bind(&init_loop);
|
||||
__ StoreIntoObjectNoBarrier(RAX, compiler::Address(RDI, 0), R12);
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
compiler::Address(RDI, 0), R12);
|
||||
__ addq(RDI, compiler::Immediate(kWordSize));
|
||||
__ cmpq(RDI, RCX);
|
||||
__ j(BELOW, &init_loop, compiler::Assembler::kNearJump);
|
||||
|
@ -2835,16 +2843,9 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
const Class& list_class =
|
||||
Class::Handle(compiler->isolate_group()->class_table()->At(kArrayCid));
|
||||
RegisterTypeArgumentsUse(compiler->function(), type_usage_info, list_class,
|
||||
element_type()->definition());
|
||||
type_arguments()->definition());
|
||||
}
|
||||
|
||||
// Allocate the array. R10 = length, RBX = element type.
|
||||
const Register kLengthReg = R10;
|
||||
const Register kElemTypeReg = RBX;
|
||||
const Register kResultReg = RAX;
|
||||
ASSERT(locs()->in(0).reg() == kElemTypeReg);
|
||||
ASSERT(locs()->in(1).reg() == kLengthReg);
|
||||
|
||||
compiler::Label slow_path, done;
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
if (compiler->is_optimizing() && !FLAG_precompiled_mode &&
|
||||
|
@ -2866,7 +2867,6 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
UntaggedPcDescriptors::kOther, locs(), deopt_id(),
|
||||
env());
|
||||
__ Bind(&done);
|
||||
ASSERT(locs()->out(0).reg() == kResultReg);
|
||||
}
|
||||
|
||||
LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
|
||||
|
|
|
@ -2111,7 +2111,7 @@ class LoadOptimizer : public ValueObject {
|
|||
if (auto load = use->instruction()->AsLoadField()) {
|
||||
if (load->slot().IsTypeArguments()) {
|
||||
place_id = GetPlaceId(load);
|
||||
forward_def = alloc->element_type()->definition();
|
||||
forward_def = alloc->type_arguments()->definition();
|
||||
}
|
||||
} else if (use->instruction()->IsLoadIndexed() ||
|
||||
use->instruction()->IsStoreIndexed()) {
|
||||
|
|
|
@ -1000,11 +1000,14 @@ void StubCodeCompiler::GenerateNoSuchMethodDispatcherStub(
|
|||
}
|
||||
|
||||
// Called for inline allocation of arrays.
|
||||
// Input parameters:
|
||||
// Input registers (preserved):
|
||||
// LR: return address.
|
||||
// R1: array element type (either NULL or an instantiated type).
|
||||
// R2: array length as Smi (must be preserved).
|
||||
// The newly allocated object is returned in R0.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// Output registers:
|
||||
// AllocateArrayABI::kResultReg: newly allocated array.
|
||||
// Clobbered:
|
||||
// R3, R4, R8, R9
|
||||
void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
Label slow_case;
|
||||
|
@ -1012,7 +1015,7 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// and is computed as:
|
||||
// RoundedAllocationSize(
|
||||
// (array_length * kwordSize) + target::Array::header_size()).
|
||||
__ mov(R3, Operand(R2)); // Array length.
|
||||
__ mov(R3, Operand(AllocateArrayABI::kLengthReg)); // Array length.
|
||||
// Check that length is a Smi.
|
||||
__ tst(R3, Operand(kSmiTagMask));
|
||||
__ b(&slow_case, NE);
|
||||
|
@ -1037,12 +1040,14 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
|
||||
// R9: Allocation size.
|
||||
// Potential new object start.
|
||||
__ ldr(R0, Address(THR, target::Thread::top_offset()));
|
||||
__ adds(R3, R0, Operand(R9)); // Potential next object start.
|
||||
__ ldr(AllocateArrayABI::kResultReg,
|
||||
Address(THR, target::Thread::top_offset()));
|
||||
__ adds(R3, AllocateArrayABI::kResultReg,
|
||||
Operand(R9)); // Potential next object start.
|
||||
__ b(&slow_case, CS); // Branch if unsigned overflow.
|
||||
|
||||
// Check if the allocation fits into the remaining space.
|
||||
// R0: potential new object start.
|
||||
// AllocateArrayABI::kResultReg: potential new object start.
|
||||
// R3: potential next object start.
|
||||
// R9: allocation size.
|
||||
__ ldr(TMP, Address(THR, target::Thread::end_offset()));
|
||||
|
@ -1052,10 +1057,11 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// Successfully allocated the object(s), now update top to point to
|
||||
// next object start and initialize the object.
|
||||
__ str(R3, Address(THR, target::Thread::top_offset()));
|
||||
__ add(R0, R0, Operand(kHeapObjectTag));
|
||||
__ add(AllocateArrayABI::kResultReg, AllocateArrayABI::kResultReg,
|
||||
Operand(kHeapObjectTag));
|
||||
|
||||
// Initialize the tags.
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R3: new object end address.
|
||||
// R9: allocation size.
|
||||
{
|
||||
|
@ -1072,22 +1078,27 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
|
||||
__ LoadImmediate(TMP, tags);
|
||||
__ orr(R8, R8, Operand(TMP));
|
||||
__ str(R8,
|
||||
FieldAddress(R0, target::Array::tags_offset())); // Store tags.
|
||||
__ str(R8, FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::tags_offset())); // Store tags.
|
||||
}
|
||||
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R3: new object end address.
|
||||
// Store the type argument field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
R0, FieldAddress(R0, target::Array::type_arguments_offset()), R1);
|
||||
AllocateArrayABI::kResultReg,
|
||||
FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::type_arguments_offset()),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
R0, FieldAddress(R0, target::Array::length_offset()), R2);
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R8, R9: null
|
||||
// R4: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
|
@ -1096,9 +1107,10 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
|
||||
__ LoadObject(R8, NullObject());
|
||||
__ mov(R9, Operand(R8));
|
||||
__ AddImmediate(R4, R0, target::Array::header_size() - kHeapObjectTag);
|
||||
__ InitializeFieldsNoBarrier(R0, R4, R3, R8, R9);
|
||||
__ Ret(); // Returns the newly allocated object in R0.
|
||||
__ AddImmediate(R4, AllocateArrayABI::kResultReg,
|
||||
target::Array::header_size() - kHeapObjectTag);
|
||||
__ InitializeFieldsNoBarrier(AllocateArrayABI::kResultReg, R4, R3, R8, R9);
|
||||
__ Ret();
|
||||
// Unable to allocate the array using the fast inline code, just call
|
||||
// into the runtime.
|
||||
__ Bind(&slow_case);
|
||||
|
@ -1110,11 +1122,13 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
__ LoadImmediate(TMP, 0);
|
||||
// Setup space on stack for return value.
|
||||
// Push array length as Smi and element type.
|
||||
__ PushList((1 << R1) | (1 << R2) | (1 << IP));
|
||||
__ PushList((1 << AllocateArrayABI::kTypeArgumentsReg) |
|
||||
(1 << AllocateArrayABI::kLengthReg) | (1 << IP));
|
||||
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
|
||||
// Pop arguments; result is popped in IP.
|
||||
__ PopList((1 << R1) | (1 << R2) | (1 << IP)); // R2 is restored.
|
||||
__ mov(R0, Operand(IP));
|
||||
__ PopList((1 << AllocateArrayABI::kTypeArgumentsReg) |
|
||||
(1 << AllocateArrayABI::kLengthReg) | (1 << IP));
|
||||
__ mov(AllocateArrayABI::kResultReg, Operand(IP));
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// Write-barrier elimination might be enabled for this array (depending on the
|
||||
|
|
|
@ -1118,12 +1118,14 @@ void StubCodeCompiler::GenerateNoSuchMethodDispatcherStub(
|
|||
}
|
||||
|
||||
// Called for inline allocation of arrays.
|
||||
// Input parameters:
|
||||
// Input registers (preserved):
|
||||
// LR: return address.
|
||||
// R2: array length as Smi.
|
||||
// R1: array element type (either NULL or an instantiated type).
|
||||
// NOTE: R2 cannot be clobbered here as the caller relies on it being saved.
|
||||
// The newly allocated object is returned in R0.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// Output registers:
|
||||
// AllocateArrayABI::kResultReg: newly allocated array.
|
||||
// Clobbered:
|
||||
// R3, R7
|
||||
void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
Label slow_case;
|
||||
|
@ -1132,12 +1134,12 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// RoundedAllocationSize(
|
||||
// (array_length * kwordSize) + target::Array::header_size()).
|
||||
// Check that length is a Smi.
|
||||
__ BranchIfNotSmi(R2, &slow_case);
|
||||
__ BranchIfNotSmi(AllocateArrayABI::kLengthReg, &slow_case);
|
||||
|
||||
// Check length >= 0 && length <= kMaxNewSpaceElements
|
||||
const intptr_t max_len =
|
||||
target::ToRawSmi(target::Array::kMaxNewSpaceElements);
|
||||
__ CompareImmediate(R2, max_len, kObjectBytes);
|
||||
__ CompareImmediate(AllocateArrayABI::kLengthReg, max_len, kObjectBytes);
|
||||
__ b(&slow_case, HI);
|
||||
|
||||
const intptr_t cid = kArrayCid;
|
||||
|
@ -1145,26 +1147,28 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
|
||||
// Calculate and align allocation size.
|
||||
// Load new object start and calculate next object start.
|
||||
// R1: array element type.
|
||||
// R2: array length as Smi.
|
||||
__ ldr(R0, Address(THR, target::Thread::top_offset()));
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
__ ldr(AllocateArrayABI::kResultReg,
|
||||
Address(THR, target::Thread::top_offset()));
|
||||
intptr_t fixed_size_plus_alignment_padding =
|
||||
target::Array::header_size() +
|
||||
target::ObjectAlignment::kObjectAlignment - 1;
|
||||
__ LoadImmediate(R3, fixed_size_plus_alignment_padding);
|
||||
__ add(R3, R3, Operand(R2, LSL, 2), kObjectBytes); // R2 is Smi.
|
||||
__ add(R3, R3, Operand(AllocateArrayABI::kLengthReg, LSL, 2),
|
||||
kObjectBytes); // R2 is Smi.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ andi(R3, R3,
|
||||
Immediate(~(target::ObjectAlignment::kObjectAlignment - 1)));
|
||||
// R0: potential new object start.
|
||||
// AllocateArrayABI::kResultReg: potential new object start.
|
||||
// R3: object size in bytes.
|
||||
__ adds(R7, R3, Operand(R0));
|
||||
__ adds(R7, R3, Operand(AllocateArrayABI::kResultReg));
|
||||
__ b(&slow_case, CS); // Branch if unsigned overflow.
|
||||
|
||||
// Check if the allocation fits into the remaining space.
|
||||
// R0: potential new object start.
|
||||
// R1: array element type.
|
||||
// R2: array length as Smi.
|
||||
// AllocateArrayABI::kResultReg: potential new object start.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// R3: array size.
|
||||
// R7: potential next object start.
|
||||
__ LoadFromOffset(TMP, THR, target::Thread::end_offset());
|
||||
|
@ -1173,66 +1177,72 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
|
||||
// Successfully allocated the object(s), now update top to point to
|
||||
// next object start and initialize the object.
|
||||
// R0: potential new object start.
|
||||
// AllocateArrayABI::kResultReg: potential new object start.
|
||||
// R3: array size.
|
||||
// R7: potential next object start.
|
||||
__ str(R7, Address(THR, target::Thread::top_offset()));
|
||||
__ add(R0, R0, Operand(kHeapObjectTag));
|
||||
__ add(AllocateArrayABI::kResultReg, AllocateArrayABI::kResultReg,
|
||||
Operand(kHeapObjectTag));
|
||||
|
||||
// R0: new object start as a tagged pointer.
|
||||
// R1: array element type.
|
||||
// R2: array length as Smi.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// R3: array size.
|
||||
// R7: new object end address.
|
||||
|
||||
// Store the type argument field.
|
||||
__ StoreIntoObjectOffsetNoBarrier(
|
||||
R0, target::Array::type_arguments_offset(), R1);
|
||||
__ StoreIntoObjectOffsetNoBarrier(AllocateArrayABI::kResultReg,
|
||||
target::Array::type_arguments_offset(),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectOffsetNoBarrier(R0, target::Array::length_offset(), R2);
|
||||
__ StoreIntoObjectOffsetNoBarrier(AllocateArrayABI::kResultReg,
|
||||
target::Array::length_offset(),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Calculate the size tag.
|
||||
// R0: new object start as a tagged pointer.
|
||||
// R2: array length as Smi.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// R3: array size.
|
||||
// R7: new object end address.
|
||||
const intptr_t shift = target::UntaggedObject::kTagBitsSizeTagPos -
|
||||
target::ObjectAlignment::kObjectAlignmentLog2;
|
||||
__ CompareImmediate(R3, target::UntaggedObject::kSizeTagMaxSizeTag);
|
||||
// If no size tag overflow, shift R1 left, else set R1 to zero.
|
||||
// If no size tag overflow, shift R3 left, else set R3 to zero.
|
||||
__ LslImmediate(TMP, R3, shift);
|
||||
__ csel(R1, TMP, R1, LS);
|
||||
__ csel(R1, ZR, R1, HI);
|
||||
__ csel(R3, TMP, R3, LS);
|
||||
__ csel(R3, ZR, R3, HI);
|
||||
|
||||
// Get the class index and insert it into the tags.
|
||||
const uword tags =
|
||||
target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
|
||||
|
||||
__ LoadImmediate(TMP, tags);
|
||||
__ orr(R1, R1, Operand(TMP));
|
||||
__ StoreFieldToOffset(R1, R0, target::Array::tags_offset());
|
||||
__ orr(R3, R3, Operand(TMP));
|
||||
__ StoreFieldToOffset(R3, AllocateArrayABI::kResultReg,
|
||||
target::Array::tags_offset());
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// R0: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// R7: new object end address.
|
||||
// R2: array length as Smi.
|
||||
__ AddImmediate(R1, R0, target::Array::data_offset() - kHeapObjectTag);
|
||||
// R1: iterator which initially points to the start of the variable
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
__ AddImmediate(R3, AllocateArrayABI::kResultReg,
|
||||
target::Array::data_offset() - kHeapObjectTag);
|
||||
// R3: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
Label loop, done;
|
||||
__ Bind(&loop);
|
||||
// TODO(cshapiro): StoreIntoObjectNoBarrier
|
||||
__ CompareRegisters(R1, R7);
|
||||
__ CompareRegisters(R3, R7);
|
||||
__ b(&done, CS);
|
||||
__ str(NULL_REG, Address(R1)); // Store if unsigned lower.
|
||||
__ AddImmediate(R1, target::kWordSize);
|
||||
__ b(&loop); // Loop until R1 == R7.
|
||||
__ str(NULL_REG, Address(R3)); // Store if unsigned lower.
|
||||
__ AddImmediate(R3, target::kWordSize);
|
||||
__ b(&loop); // Loop until R3 == R7.
|
||||
__ Bind(&done);
|
||||
|
||||
// Done allocating and initializing the array.
|
||||
// R0: new object.
|
||||
// R2: array length as Smi (preserved for the caller.)
|
||||
// AllocateArrayABI::kResultReg: new object.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi (preserved).
|
||||
__ ret();
|
||||
|
||||
// Unable to allocate the array using the fast inline code, just call
|
||||
|
@ -1245,13 +1255,13 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// Setup space on stack for return value.
|
||||
// Push array length as Smi and element type.
|
||||
__ Push(ZR);
|
||||
__ Push(R2);
|
||||
__ Push(R1);
|
||||
__ Push(AllocateArrayABI::kLengthReg);
|
||||
__ Push(AllocateArrayABI::kTypeArgumentsReg);
|
||||
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
|
||||
// Pop arguments; result is popped in IP.
|
||||
__ Pop(R1);
|
||||
__ Pop(R2);
|
||||
__ Pop(R0);
|
||||
__ Pop(AllocateArrayABI::kTypeArgumentsReg);
|
||||
__ Pop(AllocateArrayABI::kLengthReg);
|
||||
__ Pop(AllocateArrayABI::kResultReg);
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// Write-barrier elimination might be enabled for this array (depending on the
|
||||
|
|
|
@ -791,11 +791,13 @@ void StubCodeCompiler::GenerateNoSuchMethodDispatcherStub(
|
|||
}
|
||||
|
||||
// Called for inline allocation of arrays.
|
||||
// Input parameters:
|
||||
// EDX : Array length as Smi (must be preserved).
|
||||
// ECX : array element type (either NULL or an instantiated type).
|
||||
// Uses EAX, EBX, ECX, EDI as temporary registers.
|
||||
// The newly allocated object is returned in EAX.
|
||||
// Input registers (preserved):
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// Output registers:
|
||||
// AllocateArrayABI::kResultReg: newly allocated array.
|
||||
// Clobbered:
|
||||
// EBX, EDI
|
||||
void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
Label slow_case;
|
||||
|
@ -804,54 +806,57 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// RoundedAllocationSize(
|
||||
// (array_length * kwordSize) + target::Array::header_size()).
|
||||
// Assert that length is a Smi.
|
||||
__ testl(EDX, Immediate(kSmiTagMask));
|
||||
__ testl(AllocateArrayABI::kLengthReg, Immediate(kSmiTagMask));
|
||||
__ j(NOT_ZERO, &slow_case);
|
||||
|
||||
// Check for maximum allowed length.
|
||||
const Immediate& max_len =
|
||||
Immediate(target::ToRawSmi(target::Array::kMaxNewSpaceElements));
|
||||
__ cmpl(EDX, max_len);
|
||||
__ cmpl(AllocateArrayABI::kLengthReg, max_len);
|
||||
__ j(ABOVE, &slow_case);
|
||||
|
||||
NOT_IN_PRODUCT(__ MaybeTraceAllocation(kArrayCid, EAX, &slow_case,
|
||||
Assembler::kFarJump));
|
||||
NOT_IN_PRODUCT(__ MaybeTraceAllocation(kArrayCid,
|
||||
AllocateArrayABI::kResultReg,
|
||||
&slow_case, Assembler::kFarJump));
|
||||
|
||||
const intptr_t fixed_size_plus_alignment_padding =
|
||||
target::Array::header_size() +
|
||||
target::ObjectAlignment::kObjectAlignment - 1;
|
||||
// EDX is Smi.
|
||||
__ leal(EBX, Address(EDX, TIMES_2, fixed_size_plus_alignment_padding));
|
||||
// AllocateArrayABI::kLengthReg is Smi.
|
||||
__ leal(EBX, Address(AllocateArrayABI::kLengthReg, TIMES_2,
|
||||
fixed_size_plus_alignment_padding));
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ andl(EBX, Immediate(-target::ObjectAlignment::kObjectAlignment));
|
||||
|
||||
// ECX: array element type.
|
||||
// EDX: array length as Smi.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: array type arguments.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// EBX: allocation size.
|
||||
|
||||
const intptr_t cid = kArrayCid;
|
||||
__ movl(EAX, Address(THR, target::Thread::top_offset()));
|
||||
__ addl(EBX, EAX);
|
||||
__ movl(AllocateArrayABI::kResultReg,
|
||||
Address(THR, target::Thread::top_offset()));
|
||||
__ addl(EBX, AllocateArrayABI::kResultReg);
|
||||
__ j(CARRY, &slow_case);
|
||||
|
||||
// Check if the allocation fits into the remaining space.
|
||||
// EAX: potential new object start.
|
||||
// AllocateArrayABI::kResultReg: potential new object start.
|
||||
// EBX: potential next object start.
|
||||
// ECX: array element type.
|
||||
// EDX: array length as Smi).
|
||||
// AllocateArrayABI::kTypeArgumentsReg: array type arguments.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi).
|
||||
__ cmpl(EBX, Address(THR, target::Thread::end_offset()));
|
||||
__ j(ABOVE_EQUAL, &slow_case);
|
||||
|
||||
// Successfully allocated the object(s), now update top to point to
|
||||
// next object start and initialize the object.
|
||||
__ movl(Address(THR, target::Thread::top_offset()), EBX);
|
||||
__ subl(EBX, EAX);
|
||||
__ addl(EAX, Immediate(kHeapObjectTag));
|
||||
__ subl(EBX, AllocateArrayABI::kResultReg);
|
||||
__ addl(AllocateArrayABI::kResultReg, Immediate(kHeapObjectTag));
|
||||
|
||||
// Initialize the tags.
|
||||
// EAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// EBX: allocation size.
|
||||
// ECX: array element type.
|
||||
// EDX: array length as Smi.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: array type arguments.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
{
|
||||
Label size_tag_overflow, done;
|
||||
__ movl(EDI, EBX);
|
||||
|
@ -868,41 +873,50 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// Get the class index and insert it into the tags.
|
||||
uword tags = target::MakeTagWordForNewSpaceObject(cid, 0);
|
||||
__ orl(EDI, Immediate(tags));
|
||||
__ movl(FieldAddress(EAX, target::Object::tags_offset()), EDI); // Tags.
|
||||
__ movl(FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Object::tags_offset()),
|
||||
EDI); // Tags.
|
||||
}
|
||||
// EAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// EBX: allocation size.
|
||||
// ECX: array element type.
|
||||
// EDX: Array length as Smi (preserved).
|
||||
// AllocateArrayABI::kTypeArgumentsReg: array type arguments.
|
||||
// AllocateArrayABI::kLengthReg: Array length as Smi (preserved).
|
||||
// Store the type argument field.
|
||||
// No generational barrier needed, since we store into a new object.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
EAX, FieldAddress(EAX, target::Array::type_arguments_offset()), ECX);
|
||||
AllocateArrayABI::kResultReg,
|
||||
FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::type_arguments_offset()),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
EAX, FieldAddress(EAX, target::Array::length_offset()), EDX);
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// EAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// EBX: allocation size.
|
||||
// EDI: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
// ECX: array element type.
|
||||
// EDX: array length as Smi.
|
||||
__ leal(EBX, FieldAddress(EAX, EBX, TIMES_1, 0));
|
||||
__ leal(EDI, FieldAddress(EAX, target::Array::header_size()));
|
||||
// AllocateArrayABI::kTypeArgumentsReg: array type arguments.
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
__ leal(EBX, FieldAddress(AllocateArrayABI::kResultReg, EBX, TIMES_1, 0));
|
||||
__ leal(EDI, FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::header_size()));
|
||||
Label done;
|
||||
Label init_loop;
|
||||
__ Bind(&init_loop);
|
||||
__ cmpl(EDI, EBX);
|
||||
__ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
|
||||
// No generational barrier needed, since we are storing null.
|
||||
__ StoreIntoObjectNoBarrier(EAX, Address(EDI, 0), NullObject());
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg, Address(EDI, 0),
|
||||
NullObject());
|
||||
__ addl(EDI, Immediate(target::kWordSize));
|
||||
__ jmp(&init_loop, Assembler::kNearJump);
|
||||
__ Bind(&done);
|
||||
__ ret(); // returns the newly allocated object in EAX.
|
||||
__ ret();
|
||||
|
||||
// Unable to allocate the array using the fast inline code, just call
|
||||
// into the runtime.
|
||||
|
@ -912,12 +926,12 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// calling into the runtime.
|
||||
__ EnterStubFrame();
|
||||
__ pushl(Immediate(0)); // Setup space on stack for return value.
|
||||
__ pushl(EDX); // Array length as Smi.
|
||||
__ pushl(ECX); // Element type.
|
||||
__ pushl(AllocateArrayABI::kLengthReg); // Array length as Smi.
|
||||
__ pushl(AllocateArrayABI::kTypeArgumentsReg); // Type arguments.
|
||||
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
|
||||
__ popl(EAX); // Pop element type argument.
|
||||
__ popl(EDX); // Pop array length argument (preserved).
|
||||
__ popl(EAX); // Pop return value from return slot.
|
||||
__ popl(AllocateArrayABI::kTypeArgumentsReg); // Pop type arguments.
|
||||
__ popl(AllocateArrayABI::kLengthReg); // Pop array length argument.
|
||||
__ popl(AllocateArrayABI::kResultReg); // Pop return value from return slot.
|
||||
|
||||
// Write-barrier elimination might be enabled for this array (depending on the
|
||||
// array length). To be sure we will check if the allocated object is in old
|
||||
|
|
|
@ -1048,11 +1048,13 @@ void StubCodeCompiler::GenerateNoSuchMethodDispatcherStub(
|
|||
}
|
||||
|
||||
// Called for inline allocation of arrays.
|
||||
// Input parameters:
|
||||
// R10 : Array length as Smi.
|
||||
// RBX : array element type (either NULL or an instantiated type).
|
||||
// NOTE: R10 cannot be clobbered here as the caller relies on it being saved.
|
||||
// The newly allocated object is returned in RAX.
|
||||
// Input registers (preserved):
|
||||
// AllocateArrayABI::kLengthReg: array length as Smi.
|
||||
// AllocateArrayABI::kTypeArgumentsReg: type arguments of array.
|
||||
// Output registers:
|
||||
// AllocateArrayABI::kResultReg: newly allocated array.
|
||||
// Clobbered:
|
||||
// RCX, RDI, R12
|
||||
void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
if (!FLAG_use_slow_path && FLAG_inline_alloc) {
|
||||
Label slow_case;
|
||||
|
@ -1060,7 +1062,7 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// and is computed as:
|
||||
// RoundedAllocationSize(
|
||||
// (array_length * target::kwordSize) + target::Array::header_size()).
|
||||
__ movq(RDI, R10); // Array Length.
|
||||
__ movq(RDI, AllocateArrayABI::kLengthReg); // Array Length.
|
||||
// Check that length is Smi.
|
||||
__ testq(RDI, Immediate(kSmiTagMask));
|
||||
__ j(NOT_ZERO, &slow_case);
|
||||
|
@ -1084,15 +1086,16 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
__ andq(RDI, Immediate(-target::ObjectAlignment::kObjectAlignment));
|
||||
|
||||
const intptr_t cid = kArrayCid;
|
||||
__ movq(RAX, Address(THR, target::Thread::top_offset()));
|
||||
__ movq(AllocateArrayABI::kResultReg,
|
||||
Address(THR, target::Thread::top_offset()));
|
||||
|
||||
// RDI: allocation size.
|
||||
__ movq(RCX, RAX);
|
||||
__ movq(RCX, AllocateArrayABI::kResultReg);
|
||||
__ addq(RCX, RDI);
|
||||
__ j(CARRY, &slow_case);
|
||||
|
||||
// Check if the allocation fits into the remaining space.
|
||||
// RAX: potential new object start.
|
||||
// AllocateArrayABI::kResultReg: potential new object start.
|
||||
// RCX: potential next object start.
|
||||
// RDI: allocation size.
|
||||
__ cmpq(RCX, Address(THR, target::Thread::end_offset()));
|
||||
|
@ -1101,10 +1104,10 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// Successfully allocated the object(s), now update top to point to
|
||||
// next object start and initialize the object.
|
||||
__ movq(Address(THR, target::Thread::top_offset()), RCX);
|
||||
__ addq(RAX, Immediate(kHeapObjectTag));
|
||||
__ addq(AllocateArrayABI::kResultReg, Immediate(kHeapObjectTag));
|
||||
|
||||
// Initialize the tags.
|
||||
// RAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// RDI: allocation size.
|
||||
{
|
||||
Label size_tag_overflow, done;
|
||||
|
@ -1124,23 +1127,29 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
__ movq(FieldAddress(RAX, target::Array::tags_offset()), RDI); // Tags.
|
||||
}
|
||||
|
||||
// RAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// Store the type argument field.
|
||||
// No generational barrier needed, since we store into a new object.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
RAX, FieldAddress(RAX, target::Array::type_arguments_offset()), RBX);
|
||||
AllocateArrayABI::kResultReg,
|
||||
FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::type_arguments_offset()),
|
||||
AllocateArrayABI::kTypeArgumentsReg);
|
||||
|
||||
// Set the length field.
|
||||
__ StoreIntoObjectNoBarrier(
|
||||
RAX, FieldAddress(RAX, target::Array::length_offset()), R10);
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg,
|
||||
FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::length_offset()),
|
||||
AllocateArrayABI::kLengthReg);
|
||||
|
||||
// Initialize all array elements to raw_null.
|
||||
// RAX: new object start as a tagged pointer.
|
||||
// AllocateArrayABI::kResultReg: new object start as a tagged pointer.
|
||||
// RCX: new object end address.
|
||||
// RDI: iterator which initially points to the start of the variable
|
||||
// data area to be initialized.
|
||||
__ LoadObject(R12, NullObject());
|
||||
__ leaq(RDI, FieldAddress(RAX, target::Array::header_size()));
|
||||
__ leaq(RDI, FieldAddress(AllocateArrayABI::kResultReg,
|
||||
target::Array::header_size()));
|
||||
Label done;
|
||||
Label init_loop;
|
||||
__ Bind(&init_loop);
|
||||
|
@ -1152,11 +1161,12 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
#endif // DEBUG
|
||||
__ j(ABOVE_EQUAL, &done, kJumpLength);
|
||||
// No generational barrier needed, since we are storing null.
|
||||
__ StoreIntoObjectNoBarrier(RAX, Address(RDI, 0), R12);
|
||||
__ StoreIntoObjectNoBarrier(AllocateArrayABI::kResultReg, Address(RDI, 0),
|
||||
R12);
|
||||
__ addq(RDI, Immediate(target::kWordSize));
|
||||
__ jmp(&init_loop, kJumpLength);
|
||||
__ Bind(&done);
|
||||
__ ret(); // returns the newly allocated object in RAX.
|
||||
__ ret();
|
||||
|
||||
// Unable to allocate the array using the fast inline code, just call
|
||||
// into the runtime.
|
||||
|
@ -1165,14 +1175,13 @@ void StubCodeCompiler::GenerateAllocateArrayStub(Assembler* assembler) {
|
|||
// Create a stub frame as we are pushing some objects on the stack before
|
||||
// calling into the runtime.
|
||||
__ EnterStubFrame();
|
||||
// Setup space on stack for return value.
|
||||
__ pushq(Immediate(0));
|
||||
__ pushq(R10); // Array length as Smi.
|
||||
__ pushq(RBX); // Element type.
|
||||
__ pushq(Immediate(0)); // Space for return value.
|
||||
__ pushq(AllocateArrayABI::kLengthReg); // Array length as Smi.
|
||||
__ pushq(AllocateArrayABI::kTypeArgumentsReg); // Element type.
|
||||
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
|
||||
__ popq(RAX); // Pop element type argument.
|
||||
__ popq(R10); // Pop array length argument.
|
||||
__ popq(RAX); // Pop return value from return slot.
|
||||
__ popq(AllocateArrayABI::kTypeArgumentsReg); // Pop element type argument.
|
||||
__ popq(AllocateArrayABI::kLengthReg); // Pop array length argument.
|
||||
__ popq(AllocateArrayABI::kResultReg); // Pop allocated object.
|
||||
|
||||
// Write-barrier elimination might be enabled for this array (depending on the
|
||||
// array length). To be sure we will check if the allocated object is in old
|
||||
|
|
|
@ -470,7 +470,14 @@ struct AllocateBoxABI {
|
|||
static const Register kTempReg = R1;
|
||||
};
|
||||
|
||||
// ABI for Allocate<TypedData>ArrayStub.
|
||||
// ABI for AllocateArrayStub.
|
||||
struct AllocateArrayABI {
|
||||
static const Register kResultReg = R0;
|
||||
static const Register kLengthReg = R2;
|
||||
static const Register kTypeArgumentsReg = R1;
|
||||
};
|
||||
|
||||
// ABI for AllocateTypedDataArrayStub.
|
||||
struct AllocateTypedDataArrayABI {
|
||||
static const Register kLengthReg = R4;
|
||||
static const Register kResultReg = R0;
|
||||
|
|
|
@ -310,7 +310,14 @@ struct AllocateBoxABI {
|
|||
static const Register kTempReg = R1;
|
||||
};
|
||||
|
||||
// ABI for Allocate<TypedData>ArrayStub.
|
||||
// ABI for AllocateArrayStub.
|
||||
struct AllocateArrayABI {
|
||||
static const Register kResultReg = R0;
|
||||
static const Register kLengthReg = R2;
|
||||
static const Register kTypeArgumentsReg = R1;
|
||||
};
|
||||
|
||||
// ABI for AllocateTypedDataArrayStub.
|
||||
struct AllocateTypedDataArrayABI {
|
||||
static const Register kLengthReg = R4;
|
||||
static const Register kResultReg = R0;
|
||||
|
|
|
@ -209,7 +209,14 @@ struct AllocateClosureABI {
|
|||
static const Register kScratchReg = EDX;
|
||||
};
|
||||
|
||||
// ABI for Allocate<TypedData>ArrayStub.
|
||||
// ABI for AllocateArrayStub.
|
||||
struct AllocateArrayABI {
|
||||
static const Register kResultReg = EAX;
|
||||
static const Register kLengthReg = EDX;
|
||||
static const Register kTypeArgumentsReg = ECX;
|
||||
};
|
||||
|
||||
// ABI for AllocateTypedDataArrayStub.
|
||||
struct AllocateTypedDataArrayABI {
|
||||
static const Register kLengthReg = EAX;
|
||||
static const Register kResultReg = EAX;
|
||||
|
|
|
@ -282,7 +282,14 @@ struct AllocateBoxABI {
|
|||
static const Register kTempReg = RBX;
|
||||
};
|
||||
|
||||
// ABI for Allocate<TypedData>ArrayStub.
|
||||
// ABI for AllocateArrayStub.
|
||||
struct AllocateArrayABI {
|
||||
static const Register kResultReg = RAX;
|
||||
static const Register kLengthReg = R10;
|
||||
static const Register kTypeArgumentsReg = RBX;
|
||||
};
|
||||
|
||||
// ABI for AllocateTypedDataArrayStub.
|
||||
struct AllocateTypedDataArrayABI {
|
||||
static const Register kLengthReg = RAX;
|
||||
static const Register kResultReg = RAX;
|
||||
|
|
Loading…
Reference in a new issue