[maglev] Elide hasOwnProperty on fast for-in
WIP Bug: v8:7700 Change-Id: I48feba3e38967ba38873efdef6827d2218fbc426 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4184202 Commit-Queue: Victor Gomes <victorgomes@chromium.org> Auto-Submit: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Victor Gomes <victorgomes@chromium.org> Cr-Commit-Position: refs/heads/main@{#85683}
This commit is contained in:
parent
d12417f875
commit
58076e4263
@ -34,6 +34,19 @@ constexpr Condition ConditionFor(Operation operation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int ShiftFromScale(int n) {
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
return 0;
|
||||||
|
case 2:
|
||||||
|
return 1;
|
||||||
|
case 4:
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class MaglevAssembler::ScratchRegisterScope {
|
class MaglevAssembler::ScratchRegisterScope {
|
||||||
public:
|
public:
|
||||||
explicit ScratchRegisterScope(MaglevAssembler* masm) : wrapped_scope_(masm) {
|
explicit ScratchRegisterScope(MaglevAssembler* masm) : wrapped_scope_(masm) {
|
||||||
@ -352,6 +365,18 @@ inline void MaglevAssembler::BuildTypedArrayDataPointer(Register data_pointer,
|
|||||||
Add(data_pointer, data_pointer, base);
|
Add(data_pointer, data_pointer, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::LoadTaggedFieldByIndex(Register result,
|
||||||
|
Register object,
|
||||||
|
Register index, int scale,
|
||||||
|
int offset) {
|
||||||
|
if (scale == 1) {
|
||||||
|
Add(result, object, index);
|
||||||
|
} else {
|
||||||
|
Add(result, object, Operand(index, LSL, ShiftFromScale(scale / 2)));
|
||||||
|
}
|
||||||
|
MacroAssembler::LoadTaggedField(result, FieldMemOperand(result, offset));
|
||||||
|
}
|
||||||
|
|
||||||
inline void MaglevAssembler::LoadBoundedSizeFromObject(Register result,
|
inline void MaglevAssembler::LoadBoundedSizeFromObject(Register result,
|
||||||
Register object,
|
Register object,
|
||||||
int offset) {
|
int offset) {
|
||||||
@ -472,6 +497,9 @@ inline void MaglevAssembler::Move(Register dst, Handle<HeapObject> obj) {
|
|||||||
inline void MaglevAssembler::SignExtend32To64Bits(Register dst, Register src) {
|
inline void MaglevAssembler::SignExtend32To64Bits(Register dst, Register src) {
|
||||||
Mov(dst, Operand(src.W(), SXTW));
|
Mov(dst, Operand(src.W(), SXTW));
|
||||||
}
|
}
|
||||||
|
inline void MaglevAssembler::NegateInt32(Register val) {
|
||||||
|
Neg(val.W(), val.W());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename NodeT>
|
template <typename NodeT>
|
||||||
inline void MaglevAssembler::DeoptIfBufferDetached(Register array,
|
inline void MaglevAssembler::DeoptIfBufferDetached(Register array,
|
||||||
@ -585,6 +613,23 @@ inline void MaglevAssembler::CompareInt32AndJumpIf(Register r1, Register r2,
|
|||||||
CompareAndBranch(r1.W(), r2.W(), cond, target);
|
CompareAndBranch(r1.W(), r2.W(), cond, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::CompareInt32AndJumpIf(Register r1, int32_t value,
|
||||||
|
Condition cond,
|
||||||
|
Label* target,
|
||||||
|
Label::Distance distance) {
|
||||||
|
CompareAndBranch(r1.W(), Immediate(value), cond, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::TestInt32AndJumpIfAnySet(
|
||||||
|
Register r1, int32_t mask, Label* target, Label::Distance distance) {
|
||||||
|
TestAndBranchIfAnySet(r1.W(), mask, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::TestInt32AndJumpIfAllClear(
|
||||||
|
Register r1, int32_t mask, Label* target, Label::Distance distance) {
|
||||||
|
TestAndBranchIfAllClear(r1.W(), mask, target);
|
||||||
|
}
|
||||||
|
|
||||||
inline void MaglevAssembler::LoadHeapNumberValue(DoubleRegister result,
|
inline void MaglevAssembler::LoadHeapNumberValue(DoubleRegister result,
|
||||||
Register heap_number) {
|
Register heap_number) {
|
||||||
Ldr(result, FieldMemOperand(heap_number, HeapNumber::kValueOffset));
|
Ldr(result, FieldMemOperand(heap_number, HeapNumber::kValueOffset));
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "src/codegen/arm64/assembler-arm64-inl.h"
|
#include "src/codegen/arm64/assembler-arm64-inl.h"
|
||||||
#include "src/codegen/arm64/register-arm64.h"
|
#include "src/codegen/arm64/register-arm64.h"
|
||||||
#include "src/codegen/interface-descriptors-inl.h"
|
#include "src/codegen/interface-descriptors-inl.h"
|
||||||
|
#include "src/maglev/arm64/maglev-assembler-arm64-inl.h"
|
||||||
#include "src/maglev/maglev-assembler-inl.h"
|
#include "src/maglev/maglev-assembler-inl.h"
|
||||||
#include "src/maglev/maglev-graph-processor.h"
|
#include "src/maglev/maglev-graph-processor.h"
|
||||||
#include "src/maglev/maglev-graph.h"
|
#include "src/maglev/maglev-graph.h"
|
||||||
@ -1711,13 +1712,15 @@ void GenerateTypedArrayLoad(MaglevAssembler* masm, NodeT* node, Register object,
|
|||||||
if constexpr (std::is_same_v<ResultReg, Register>) {
|
if constexpr (std::is_same_v<ResultReg, Register>) {
|
||||||
if (IsSignedIntTypedArrayElementsKind(kind)) {
|
if (IsSignedIntTypedArrayElementsKind(kind)) {
|
||||||
int element_size = ElementsKindSize(kind);
|
int element_size = ElementsKindSize(kind);
|
||||||
__ Add(data_pointer, data_pointer, Operand(index, LSL, element_size / 2));
|
__ Add(data_pointer, data_pointer,
|
||||||
|
Operand(index, LSL, ShiftFromScale(element_size)));
|
||||||
__ LoadSignedField(result_reg.W(), MemOperand(data_pointer),
|
__ LoadSignedField(result_reg.W(), MemOperand(data_pointer),
|
||||||
element_size);
|
element_size);
|
||||||
} else {
|
} else {
|
||||||
DCHECK(IsUnsignedIntTypedArrayElementsKind(kind));
|
DCHECK(IsUnsignedIntTypedArrayElementsKind(kind));
|
||||||
int element_size = ElementsKindSize(kind);
|
int element_size = ElementsKindSize(kind);
|
||||||
__ Add(data_pointer, data_pointer, Operand(index, LSL, element_size / 2));
|
__ Add(data_pointer, data_pointer,
|
||||||
|
Operand(index, LSL, ShiftFromScale(element_size)));
|
||||||
__ LoadUnsignedField(result_reg.W(), MemOperand(data_pointer),
|
__ LoadUnsignedField(result_reg.W(), MemOperand(data_pointer),
|
||||||
element_size);
|
element_size);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#ifndef V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_
|
#ifndef V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_
|
||||||
#define V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_
|
#define V8_MAGLEV_MAGLEV_ASSEMBLER_INL_H_
|
||||||
|
|
||||||
|
#include "src/maglev/maglev-assembler.h"
|
||||||
|
|
||||||
#ifdef V8_TARGET_ARCH_ARM64
|
#ifdef V8_TARGET_ARCH_ARM64
|
||||||
#include "src/maglev/arm64/maglev-assembler-arm64-inl.h"
|
#include "src/maglev/arm64/maglev-assembler-arm64-inl.h"
|
||||||
#elif V8_TARGET_ARCH_X64
|
#elif V8_TARGET_ARCH_X64
|
||||||
@ -242,6 +244,27 @@ inline void MaglevAssembler::Branch(Condition condition, Label* if_true,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::LoadTaggedField(Register result,
|
||||||
|
MemOperand operand) {
|
||||||
|
MacroAssembler::LoadTaggedField(result, operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::LoadTaggedField(Register result, Register object,
|
||||||
|
int offset) {
|
||||||
|
MacroAssembler::LoadTaggedField(result, FieldMemOperand(object, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::LoadTaggedSignedField(Register result,
|
||||||
|
MemOperand operand) {
|
||||||
|
MacroAssembler::LoadTaggedField(result, operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::LoadTaggedSignedField(Register result,
|
||||||
|
Register object,
|
||||||
|
int offset) {
|
||||||
|
MacroAssembler::LoadTaggedField(result, FieldMemOperand(object, offset));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace maglev
|
} // namespace maglev
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -98,6 +98,13 @@ class MaglevAssembler : public MacroAssembler {
|
|||||||
|
|
||||||
Register FromAnyToRegister(const Input& input, Register scratch);
|
Register FromAnyToRegister(const Input& input, Register scratch);
|
||||||
|
|
||||||
|
inline void LoadTaggedField(Register result, MemOperand operand);
|
||||||
|
inline void LoadTaggedField(Register result, Register object, int offset);
|
||||||
|
inline void LoadTaggedSignedField(Register result, MemOperand operand);
|
||||||
|
inline void LoadTaggedSignedField(Register result, Register object,
|
||||||
|
int offset);
|
||||||
|
inline void LoadTaggedFieldByIndex(Register result, Register object,
|
||||||
|
Register index, int scale, int offset);
|
||||||
inline void LoadBoundedSizeFromObject(Register result, Register object,
|
inline void LoadBoundedSizeFromObject(Register result, Register object,
|
||||||
int offset);
|
int offset);
|
||||||
inline void LoadExternalPointerField(Register result, MemOperand operand);
|
inline void LoadExternalPointerField(Register result, MemOperand operand);
|
||||||
@ -187,6 +194,7 @@ class MaglevAssembler : public MacroAssembler {
|
|||||||
inline void LoadByte(Register dst, MemOperand src);
|
inline void LoadByte(Register dst, MemOperand src);
|
||||||
|
|
||||||
inline void SignExtend32To64Bits(Register dst, Register src);
|
inline void SignExtend32To64Bits(Register dst, Register src);
|
||||||
|
inline void NegateInt32(Register val);
|
||||||
|
|
||||||
template <typename NodeT>
|
template <typename NodeT>
|
||||||
inline void DeoptIfBufferDetached(Register array, Register scratch,
|
inline void DeoptIfBufferDetached(Register array, Register scratch,
|
||||||
@ -226,6 +234,14 @@ class MaglevAssembler : public MacroAssembler {
|
|||||||
inline void CompareInt32AndJumpIf(Register r1, Register r2, Condition cond,
|
inline void CompareInt32AndJumpIf(Register r1, Register r2, Condition cond,
|
||||||
Label* target,
|
Label* target,
|
||||||
Label::Distance distance = Label::kFar);
|
Label::Distance distance = Label::kFar);
|
||||||
|
inline void CompareInt32AndJumpIf(Register r1, int32_t value, Condition cond,
|
||||||
|
Label* target,
|
||||||
|
Label::Distance distance = Label::kFar);
|
||||||
|
inline void TestInt32AndJumpIfAnySet(Register r1, int32_t mask, Label* target,
|
||||||
|
Label::Distance distance = Label::kFar);
|
||||||
|
inline void TestInt32AndJumpIfAllClear(
|
||||||
|
Register r1, int32_t mask, Label* target,
|
||||||
|
Label::Distance distance = Label::kFar);
|
||||||
|
|
||||||
inline void Int32ToDouble(DoubleRegister result, Register n);
|
inline void Int32ToDouble(DoubleRegister result, Register n);
|
||||||
inline void SmiToDouble(DoubleRegister result, Register smi);
|
inline void SmiToDouble(DoubleRegister result, Register smi);
|
||||||
|
@ -1639,6 +1639,7 @@ void MaglevGraphBuilder::BuildCheckMaps(
|
|||||||
if (merger.emit_check_with_migration()) {
|
if (merger.emit_check_with_migration()) {
|
||||||
AddNewNode<CheckMapsWithMigration>({object}, merger.intersect_set(),
|
AddNewNode<CheckMapsWithMigration>({object}, merger.intersect_set(),
|
||||||
GetCheckType(known_info->type));
|
GetCheckType(known_info->type));
|
||||||
|
MarkPossibleMapMigration();
|
||||||
} else {
|
} else {
|
||||||
AddNewNode<CheckMaps>({object}, merger.intersect_set(),
|
AddNewNode<CheckMaps>({object}, merger.intersect_set(),
|
||||||
GetCheckType(known_info->type));
|
GetCheckType(known_info->type));
|
||||||
@ -2546,6 +2547,28 @@ void MaglevGraphBuilder::VisitGetKeyedProperty() {
|
|||||||
broker()->GetFeedbackForPropertyAccess(
|
broker()->GetFeedbackForPropertyAccess(
|
||||||
feedback_source, compiler::AccessMode::kLoad, base::nullopt);
|
feedback_source, compiler::AccessMode::kLoad, base::nullopt);
|
||||||
|
|
||||||
|
if (current_for_in_state.index != nullptr &&
|
||||||
|
current_for_in_state.receiver == object &&
|
||||||
|
current_for_in_state.key == current_interpreter_frame_.accumulator()) {
|
||||||
|
if (current_for_in_state.receiver_needs_map_check) {
|
||||||
|
auto* receiver_map =
|
||||||
|
AddNewNode<LoadTaggedField>({object}, HeapObject::kMapOffset);
|
||||||
|
AddNewNode<CheckDynamicValue>(
|
||||||
|
{receiver_map, current_for_in_state.cache_type});
|
||||||
|
current_for_in_state.receiver_needs_map_check = false;
|
||||||
|
}
|
||||||
|
// TODO(leszeks): Cache the indices across the loop.
|
||||||
|
auto* cache_array = AddNewNode<LoadTaggedField>(
|
||||||
|
{current_for_in_state.enum_cache}, EnumCache::kIndicesOffset);
|
||||||
|
// TODO(leszeks): Do we need to check that the indices aren't empty?
|
||||||
|
// TODO(leszeks): Cache the field index per iteration.
|
||||||
|
auto* field_index = AddNewNode<LoadFixedArrayElement>(
|
||||||
|
{cache_array, current_for_in_state.index});
|
||||||
|
SetAccumulator(
|
||||||
|
AddNewNode<LoadTaggedFieldByFieldIndex>({object, field_index}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (processed_feedback.kind()) {
|
switch (processed_feedback.kind()) {
|
||||||
case compiler::ProcessedFeedback::kInsufficient:
|
case compiler::ProcessedFeedback::kInsufficient:
|
||||||
EmitUnconditionalDeopt(
|
EmitUnconditionalDeopt(
|
||||||
@ -3255,6 +3278,21 @@ ReduceResult MaglevGraphBuilder::TryReduceFunctionPrototypeCall(
|
|||||||
return BuildGenericCall(receiver, context, Call::TargetType::kAny, args);
|
return BuildGenericCall(receiver, context, Call::TargetType::kAny, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReduceResult MaglevGraphBuilder::TryReduceObjectPrototypeHasOwnProperty(
|
||||||
|
compiler::JSFunctionRef target, CallArguments& args) {
|
||||||
|
// We can't reduce Function#call when there is no receiver function.
|
||||||
|
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
|
||||||
|
return ReduceResult::Fail();
|
||||||
|
}
|
||||||
|
if (args.receiver() != current_for_in_state.receiver) {
|
||||||
|
return ReduceResult::Fail();
|
||||||
|
}
|
||||||
|
if (args.count() != 1 || args[0] != current_for_in_state.key) {
|
||||||
|
return ReduceResult::Fail();
|
||||||
|
}
|
||||||
|
return GetRootConstant(RootIndex::kTrueValue);
|
||||||
|
}
|
||||||
|
|
||||||
ReduceResult MaglevGraphBuilder::TryReduceMathPow(
|
ReduceResult MaglevGraphBuilder::TryReduceMathPow(
|
||||||
compiler::JSFunctionRef target, CallArguments& args) {
|
compiler::JSFunctionRef target, CallArguments& args) {
|
||||||
if (args.count() < 2) {
|
if (args.count() < 2) {
|
||||||
@ -4663,12 +4701,27 @@ void MaglevGraphBuilder::BuildBranchIfToBooleanTrue(ValueNode* node,
|
|||||||
JumpType jump_type) {
|
JumpType jump_type) {
|
||||||
int fallthrough_offset = next_offset();
|
int fallthrough_offset = next_offset();
|
||||||
int jump_offset = iterator_.GetJumpTargetOffset();
|
int jump_offset = iterator_.GetJumpTargetOffset();
|
||||||
|
|
||||||
|
if (IsConstantNode(node->opcode())) {
|
||||||
|
bool constant_is_true = FromConstantToBool(local_isolate(), node);
|
||||||
|
bool is_jump_taken = constant_is_true == (jump_type == kJumpIfTrue);
|
||||||
|
if (is_jump_taken) {
|
||||||
|
BasicBlock* block = FinishBlock<Jump>({}, &jump_targets_[jump_offset]);
|
||||||
|
MergeDeadIntoFrameState(fallthrough_offset);
|
||||||
|
MergeIntoFrameState(block, jump_offset);
|
||||||
|
} else {
|
||||||
|
MergeDeadIntoFrameState(jump_offset);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BasicBlockRef* true_target = jump_type == kJumpIfTrue
|
BasicBlockRef* true_target = jump_type == kJumpIfTrue
|
||||||
? &jump_targets_[jump_offset]
|
? &jump_targets_[jump_offset]
|
||||||
: &jump_targets_[fallthrough_offset];
|
: &jump_targets_[fallthrough_offset];
|
||||||
BasicBlockRef* false_target = jump_type == kJumpIfFalse
|
BasicBlockRef* false_target = jump_type == kJumpIfFalse
|
||||||
? &jump_targets_[jump_offset]
|
? &jump_targets_[jump_offset]
|
||||||
: &jump_targets_[fallthrough_offset];
|
: &jump_targets_[fallthrough_offset];
|
||||||
|
|
||||||
BasicBlock* block =
|
BasicBlock* block =
|
||||||
FinishBlock<BranchIfToBooleanTrue>({node}, true_target, false_target);
|
FinishBlock<BranchIfToBooleanTrue>({node}, true_target, false_target);
|
||||||
if (jump_type == kJumpIfTrue) {
|
if (jump_type == kJumpIfTrue) {
|
||||||
@ -4767,6 +4820,7 @@ void MaglevGraphBuilder::VisitForInPrepare() {
|
|||||||
|
|
||||||
ForInHint hint = broker()->GetFeedbackForForIn(feedback_source);
|
ForInHint hint = broker()->GetFeedbackForForIn(feedback_source);
|
||||||
|
|
||||||
|
current_for_in_state = ForInState();
|
||||||
switch (hint) {
|
switch (hint) {
|
||||||
case ForInHint::kNone:
|
case ForInHint::kNone:
|
||||||
case ForInHint::kEnumCacheKeysAndIndices:
|
case ForInHint::kEnumCacheKeysAndIndices:
|
||||||
@ -4781,6 +4835,7 @@ void MaglevGraphBuilder::VisitForInPrepare() {
|
|||||||
{descriptor_array}, DescriptorArray::kEnumCacheOffset);
|
{descriptor_array}, DescriptorArray::kEnumCacheOffset);
|
||||||
auto* cache_array =
|
auto* cache_array =
|
||||||
AddNewNode<LoadTaggedField>({enum_cache}, EnumCache::kKeysOffset);
|
AddNewNode<LoadTaggedField>({enum_cache}, EnumCache::kKeysOffset);
|
||||||
|
current_for_in_state.enum_cache = enum_cache;
|
||||||
|
|
||||||
auto* cache_length = AddNewNode<LoadEnumCacheLength>({enumerator});
|
auto* cache_length = AddNewNode<LoadEnumCacheLength>({enumerator});
|
||||||
|
|
||||||
@ -4804,6 +4859,8 @@ void MaglevGraphBuilder::VisitForInPrepare() {
|
|||||||
// cache_array, and cache_length respectively. Cache type is already set
|
// cache_array, and cache_length respectively. Cache type is already set
|
||||||
// above, so store the remaining two now.
|
// above, so store the remaining two now.
|
||||||
StoreRegisterPair({cache_array_reg, cache_length_reg}, result);
|
StoreRegisterPair({cache_array_reg, cache_length_reg}, result);
|
||||||
|
// Force a conversion to Int32 for the cache length value.
|
||||||
|
GetInt32(cache_length_reg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4811,10 +4868,14 @@ void MaglevGraphBuilder::VisitForInPrepare() {
|
|||||||
|
|
||||||
void MaglevGraphBuilder::VisitForInContinue() {
|
void MaglevGraphBuilder::VisitForInContinue() {
|
||||||
// ForInContinue <index> <cache_length>
|
// ForInContinue <index> <cache_length>
|
||||||
ValueNode* index = LoadRegisterTagged(0);
|
ValueNode* index = LoadRegisterInt32(0);
|
||||||
ValueNode* cache_length = LoadRegisterTagged(1);
|
ValueNode* cache_length = LoadRegisterInt32(1);
|
||||||
// TODO(verwaest): Fold with the next instruction.
|
if (TryBuildBranchFor<BranchIfInt32Compare>({index, cache_length},
|
||||||
SetAccumulator(AddNewNode<TaggedNotEqual>({index, cache_length}));
|
Operation::kLessThan)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetAccumulator(
|
||||||
|
AddNewNode<Int32NodeFor<Operation::kLessThan>>({index, cache_length}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaglevGraphBuilder::VisitForInNext() {
|
void MaglevGraphBuilder::VisitForInNext() {
|
||||||
@ -4839,7 +4900,26 @@ void MaglevGraphBuilder::VisitForInNext() {
|
|||||||
auto* receiver_map =
|
auto* receiver_map =
|
||||||
AddNewNode<LoadTaggedField>({receiver}, HeapObject::kMapOffset);
|
AddNewNode<LoadTaggedField>({receiver}, HeapObject::kMapOffset);
|
||||||
AddNewNode<CheckDynamicValue>({receiver_map, cache_type});
|
AddNewNode<CheckDynamicValue>({receiver_map, cache_type});
|
||||||
SetAccumulator(AddNewNode<LoadFixedArrayElement>({cache_array, index}));
|
auto* key = AddNewNode<LoadFixedArrayElement>({cache_array, index});
|
||||||
|
SetAccumulator(key);
|
||||||
|
|
||||||
|
current_for_in_state.receiver = receiver;
|
||||||
|
if (ToObject* to_object =
|
||||||
|
current_for_in_state.receiver->TryCast<ToObject>()) {
|
||||||
|
current_for_in_state.receiver = to_object->value_input().node();
|
||||||
|
}
|
||||||
|
current_for_in_state.receiver_needs_map_check = false;
|
||||||
|
current_for_in_state.cache_type = cache_type;
|
||||||
|
current_for_in_state.key = key;
|
||||||
|
if (hint == ForInHint::kEnumCacheKeysAndIndices) {
|
||||||
|
current_for_in_state.index = index;
|
||||||
|
}
|
||||||
|
// We know that the enum cache entry is not undefined, so skip over the
|
||||||
|
// next JumpIfUndefined.
|
||||||
|
DCHECK_EQ(iterator_.next_bytecode(),
|
||||||
|
interpreter::Bytecode::kJumpIfUndefined);
|
||||||
|
iterator_.Advance();
|
||||||
|
MergeDeadIntoFrameState(iterator_.GetJumpTargetOffset());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ForInHint::kAny: {
|
case ForInHint::kAny: {
|
||||||
@ -4856,6 +4936,7 @@ void MaglevGraphBuilder::VisitForInNext() {
|
|||||||
void MaglevGraphBuilder::VisitForInStep() {
|
void MaglevGraphBuilder::VisitForInStep() {
|
||||||
ValueNode* index = LoadRegisterInt32(0);
|
ValueNode* index = LoadRegisterInt32(0);
|
||||||
SetAccumulator(AddNewNode<Int32NodeFor<Operation::kIncrement>>({index}));
|
SetAccumulator(AddNewNode<Int32NodeFor<Operation::kIncrement>>({index}));
|
||||||
|
current_for_in_state = ForInState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaglevGraphBuilder::VisitSetPendingMessage() {
|
void MaglevGraphBuilder::VisitSetPendingMessage() {
|
||||||
|
@ -1117,6 +1117,10 @@ class MaglevGraphBuilder {
|
|||||||
: nullptr);
|
: nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkPossibleMapMigration() {
|
||||||
|
current_for_in_state.receiver_needs_map_check = true;
|
||||||
|
}
|
||||||
|
|
||||||
void MarkPossibleSideEffect() {
|
void MarkPossibleSideEffect() {
|
||||||
// If there was a potential side effect, invalidate the previous checkpoint.
|
// If there was a potential side effect, invalidate the previous checkpoint.
|
||||||
latest_checkpointed_frame_.reset();
|
latest_checkpointed_frame_.reset();
|
||||||
@ -1142,6 +1146,9 @@ class MaglevGraphBuilder {
|
|||||||
// clear those.
|
// clear those.
|
||||||
known_node_aspects().loaded_properties.clear();
|
known_node_aspects().loaded_properties.clear();
|
||||||
known_node_aspects().loaded_context_slots.clear();
|
known_node_aspects().loaded_context_slots.clear();
|
||||||
|
|
||||||
|
// Any side effect could also be a map migration.
|
||||||
|
MarkPossibleMapMigration();
|
||||||
}
|
}
|
||||||
|
|
||||||
int next_offset() const {
|
int next_offset() const {
|
||||||
@ -1268,19 +1275,20 @@ class MaglevGraphBuilder {
|
|||||||
V(MathTan) \
|
V(MathTan) \
|
||||||
V(MathTanh)
|
V(MathTanh)
|
||||||
|
|
||||||
#define MAGLEV_REDUCED_BUILTIN(V) \
|
#define MAGLEV_REDUCED_BUILTIN(V) \
|
||||||
V(DataViewPrototypeGetInt8) \
|
V(DataViewPrototypeGetInt8) \
|
||||||
V(DataViewPrototypeSetInt8) \
|
V(DataViewPrototypeSetInt8) \
|
||||||
V(DataViewPrototypeGetInt16) \
|
V(DataViewPrototypeGetInt16) \
|
||||||
V(DataViewPrototypeSetInt16) \
|
V(DataViewPrototypeSetInt16) \
|
||||||
V(DataViewPrototypeGetInt32) \
|
V(DataViewPrototypeGetInt32) \
|
||||||
V(DataViewPrototypeSetInt32) \
|
V(DataViewPrototypeSetInt32) \
|
||||||
V(DataViewPrototypeGetFloat64) \
|
V(DataViewPrototypeGetFloat64) \
|
||||||
V(DataViewPrototypeSetFloat64) \
|
V(DataViewPrototypeSetFloat64) \
|
||||||
V(FunctionPrototypeCall) \
|
V(FunctionPrototypeCall) \
|
||||||
V(MathPow) \
|
V(ObjectPrototypeHasOwnProperty) \
|
||||||
V(StringFromCharCode) \
|
V(MathPow) \
|
||||||
V(StringPrototypeCharCodeAt) \
|
V(StringFromCharCode) \
|
||||||
|
V(StringPrototypeCharCodeAt) \
|
||||||
MATH_UNARY_IEEE_BUILTIN(V)
|
MATH_UNARY_IEEE_BUILTIN(V)
|
||||||
|
|
||||||
#define DEFINE_BUILTIN_REDUCER(Name) \
|
#define DEFINE_BUILTIN_REDUCER(Name) \
|
||||||
@ -1589,6 +1597,16 @@ class MaglevGraphBuilder {
|
|||||||
BasicBlock* current_block_ = nullptr;
|
BasicBlock* current_block_ = nullptr;
|
||||||
base::Optional<InterpretedDeoptFrame> latest_checkpointed_frame_;
|
base::Optional<InterpretedDeoptFrame> latest_checkpointed_frame_;
|
||||||
SourcePosition current_source_position_;
|
SourcePosition current_source_position_;
|
||||||
|
struct ForInState {
|
||||||
|
ValueNode* receiver = nullptr;
|
||||||
|
ValueNode* cache_type = nullptr;
|
||||||
|
ValueNode* enum_cache = nullptr;
|
||||||
|
ValueNode* key = nullptr;
|
||||||
|
ValueNode* index = nullptr;
|
||||||
|
bool receiver_needs_map_check = false;
|
||||||
|
};
|
||||||
|
// TODO(leszeks): Allow having a stack of these.
|
||||||
|
ForInState current_for_in_state = ForInState();
|
||||||
|
|
||||||
BasicBlockRef* jump_targets_;
|
BasicBlockRef* jump_targets_;
|
||||||
MergePointInterpreterFrameState** merge_states_;
|
MergePointInterpreterFrameState** merge_states_;
|
||||||
|
@ -182,9 +182,8 @@ bool RootConstant::ToBoolean(LocalIsolate* local_isolate) const {
|
|||||||
return RootToBoolean(index_);
|
return RootToBoolean(index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FromConstantToBool(MaglevAssembler* masm, ValueNode* node) {
|
bool FromConstantToBool(LocalIsolate* local_isolate, ValueNode* node) {
|
||||||
DCHECK(IsConstantNode(node->opcode()));
|
DCHECK(IsConstantNode(node->opcode()));
|
||||||
LocalIsolate* local_isolate = masm->isolate()->AsLocalIsolate();
|
|
||||||
switch (node->opcode()) {
|
switch (node->opcode()) {
|
||||||
#define CASE(Name) \
|
#define CASE(Name) \
|
||||||
case Opcode::k##Name: { \
|
case Opcode::k##Name: { \
|
||||||
@ -197,6 +196,14 @@ bool FromConstantToBool(MaglevAssembler* masm, ValueNode* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FromConstantToBool(MaglevAssembler* masm, ValueNode* node) {
|
||||||
|
// TODO(leszeks): Getting the main thread local isolate is not what we
|
||||||
|
// actually want here, but it's all we have, and it happens to work because
|
||||||
|
// really all we're using it for is ReadOnlyRoots. We should change ToBoolean
|
||||||
|
// to be able to pass ReadOnlyRoots in directly.
|
||||||
|
return FromConstantToBool(masm->isolate()->AsLocalIsolate(), node);
|
||||||
|
}
|
||||||
|
|
||||||
DeoptInfo::DeoptInfo(Zone* zone, DeoptFrame top_frame,
|
DeoptInfo::DeoptInfo(Zone* zone, DeoptFrame top_frame,
|
||||||
compiler::FeedbackSource feedback_to_update)
|
compiler::FeedbackSource feedback_to_update)
|
||||||
: top_frame_(top_frame),
|
: top_frame_(top_frame),
|
||||||
@ -969,6 +976,185 @@ void LoadTaggedField::GenerateCode(MaglevAssembler* masm,
|
|||||||
__ DecompressTagged(ToRegister(result()), FieldMemOperand(object, offset()));
|
__ DecompressTagged(ToRegister(result()), FieldMemOperand(object, offset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoadTaggedFieldByFieldIndex::SetValueLocationConstraints() {
|
||||||
|
UseRegister(object_input());
|
||||||
|
UseAndClobberRegister(index_input());
|
||||||
|
DefineAsRegister(this);
|
||||||
|
set_temporaries_needed(1);
|
||||||
|
set_double_temporaries_needed(1);
|
||||||
|
}
|
||||||
|
void LoadTaggedFieldByFieldIndex::GenerateCode(MaglevAssembler* masm,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
Register object = ToRegister(object_input());
|
||||||
|
Register index = ToRegister(index_input());
|
||||||
|
Register result_reg = ToRegister(result());
|
||||||
|
__ AssertNotSmi(object);
|
||||||
|
__ AssertSmi(index);
|
||||||
|
|
||||||
|
ZoneLabelRef done(masm);
|
||||||
|
|
||||||
|
// For in-object properties, the index is encoded as:
|
||||||
|
//
|
||||||
|
// index = actual_index | is_double_bit | smi_tag_bit
|
||||||
|
// = actual_index << 2 | is_double_bit << 1
|
||||||
|
//
|
||||||
|
// The value we want is at the field offset:
|
||||||
|
//
|
||||||
|
// (actual_index << kTaggedSizeLog2) + JSObject::kHeaderSize
|
||||||
|
//
|
||||||
|
// We could get index from actual_index by shifting away the double and smi
|
||||||
|
// bits. But, note that `kTaggedSizeLog2 == 2` and `index` encodes
|
||||||
|
// `actual_index` with a two bit shift. So, we can do some rearranging
|
||||||
|
// to get the offset without shifting:
|
||||||
|
//
|
||||||
|
// ((index >> 2) << kTaggedSizeLog2 + JSObject::kHeaderSize
|
||||||
|
//
|
||||||
|
// [Expand definitions of index and kTaggedSizeLog2]
|
||||||
|
// = (((actual_index << 2 | is_double_bit << 1) >> 2) << 2)
|
||||||
|
// + JSObject::kHeaderSize
|
||||||
|
//
|
||||||
|
// [Cancel out shift down and shift up, clear is_double bit by subtracting]
|
||||||
|
// = (actual_index << 2 | is_double_bit << 1) - (is_double_bit << 1)
|
||||||
|
// + JSObject::kHeaderSize
|
||||||
|
//
|
||||||
|
// [Fold together the constants, and collapse definition of index]
|
||||||
|
// = index + (JSObject::kHeaderSize - (is_double_bit << 1))
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// For out-of-object properties, the encoding is:
|
||||||
|
//
|
||||||
|
// index = (-1 - actual_index) | is_double_bit | smi_tag_bit
|
||||||
|
// = (-1 - actual_index) << 2 | is_double_bit << 1
|
||||||
|
// = (-1 - actual_index) * 4 + (is_double_bit ? 2 : 0)
|
||||||
|
// = -(actual_index * 4) + (is_double_bit ? 2 : 0) - 4
|
||||||
|
// = -(actual_index << 2) + (is_double_bit ? 2 : 0) - 4
|
||||||
|
//
|
||||||
|
// The value we want is in the property array at offset:
|
||||||
|
//
|
||||||
|
// (actual_index << kTaggedSizeLog2) + FixedArray::kHeaderSize
|
||||||
|
//
|
||||||
|
// [Expand definition of kTaggedSizeLog2]
|
||||||
|
// = (actual_index << 2) + FixedArray::kHeaderSize
|
||||||
|
//
|
||||||
|
// [Substitute in index]
|
||||||
|
// = (-index + (is_double_bit ? 2 : 0) - 4) + FixedArray::kHeaderSize
|
||||||
|
//
|
||||||
|
// [Fold together the constants]
|
||||||
|
// = -index + (FixedArray::kHeaderSize + (is_double_bit ? 2 : 0) - 4))
|
||||||
|
//
|
||||||
|
// This allows us to simply negate the index register and do a load with
|
||||||
|
// otherwise constant offset.
|
||||||
|
|
||||||
|
// Check if field is a mutable double field.
|
||||||
|
static constexpr int32_t kIsDoubleBitMask = 1 << kSmiTagSize;
|
||||||
|
__ TestInt32AndJumpIfAnySet(
|
||||||
|
index, kIsDoubleBitMask,
|
||||||
|
__ MakeDeferredCode(
|
||||||
|
[](MaglevAssembler* masm, Register object, Register index,
|
||||||
|
Register result_reg, RegisterSnapshot register_snapshot,
|
||||||
|
ZoneLabelRef done) {
|
||||||
|
// The field is a Double field, a.k.a. a mutable HeapNumber.
|
||||||
|
static const int kIsDoubleBit = 1;
|
||||||
|
|
||||||
|
// Check if field is in-object or out-of-object. The is_double bit
|
||||||
|
// value doesn't matter, since negative values will stay negative.
|
||||||
|
Label if_outofobject, loaded_field;
|
||||||
|
__ CompareInt32AndJumpIf(index, 0, kLessThan, &if_outofobject);
|
||||||
|
|
||||||
|
// The field is located in the {object} itself.
|
||||||
|
{
|
||||||
|
// See giant comment above.
|
||||||
|
static_assert(kTaggedSizeLog2 == 2);
|
||||||
|
static_assert(kSmiTagSize == 1);
|
||||||
|
// We haven't untagged, so we need to sign extend.
|
||||||
|
__ SignExtend32To64Bits(index, index);
|
||||||
|
__ LoadTaggedFieldByIndex(
|
||||||
|
result_reg, object, index, 1,
|
||||||
|
JSObject::kHeaderSize - (kIsDoubleBit << kSmiTagSize));
|
||||||
|
__ Jump(&loaded_field);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&if_outofobject);
|
||||||
|
{
|
||||||
|
MaglevAssembler::ScratchRegisterScope temps(masm);
|
||||||
|
Register property_array = temps.Acquire();
|
||||||
|
// Load the property array.
|
||||||
|
__ LoadTaggedField(
|
||||||
|
property_array,
|
||||||
|
FieldMemOperand(object, JSObject::kPropertiesOrHashOffset));
|
||||||
|
|
||||||
|
// See giant comment above.
|
||||||
|
static_assert(kSmiTagSize == 1);
|
||||||
|
__ NegateInt32(index);
|
||||||
|
__ LoadTaggedFieldByIndex(
|
||||||
|
result_reg, property_array, index, 1,
|
||||||
|
FixedArray::kHeaderSize + (kIsDoubleBit << kSmiTagSize) - 4);
|
||||||
|
__ Jump(&loaded_field);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&loaded_field);
|
||||||
|
// We may have transitioned in-place away from double, so check that
|
||||||
|
// this is a HeapNumber -- otherwise the load is fine and we don't
|
||||||
|
// need to copy anything anyway.
|
||||||
|
__ JumpIfSmi(result_reg, *done);
|
||||||
|
// index is no longer needed and is clobbered by this node, so
|
||||||
|
// reuse it as a scratch reg storing the map.
|
||||||
|
Register map = index;
|
||||||
|
__ LoadMap(map, result_reg);
|
||||||
|
__ JumpIfNotRoot(map, RootIndex::kHeapNumberMap, *done);
|
||||||
|
MaglevAssembler::ScratchRegisterScope temps(masm);
|
||||||
|
DoubleRegister double_value = temps.AcquireDouble();
|
||||||
|
__ LoadHeapNumberValue(double_value, result_reg);
|
||||||
|
__ AllocateHeapNumber(register_snapshot, result_reg, double_value);
|
||||||
|
__ Jump(*done);
|
||||||
|
},
|
||||||
|
object, index, result_reg, register_snapshot(), done));
|
||||||
|
|
||||||
|
// The field is a proper Tagged field on {object}. The {index} is shifted
|
||||||
|
// to the left by one in the code below.
|
||||||
|
{
|
||||||
|
static const int kIsDoubleBit = 0;
|
||||||
|
|
||||||
|
// Check if field is in-object or out-of-object. The is_double bit value
|
||||||
|
// doesn't matter, since negative values will stay negative.
|
||||||
|
Label if_outofobject;
|
||||||
|
__ CompareInt32AndJumpIf(index, 0, kLessThan, &if_outofobject);
|
||||||
|
|
||||||
|
// The field is located in the {object} itself.
|
||||||
|
{
|
||||||
|
// See giant comment above.
|
||||||
|
static_assert(kTaggedSizeLog2 == 2);
|
||||||
|
static_assert(kSmiTagSize == 1);
|
||||||
|
// We haven't untagged, so we need to sign extend.
|
||||||
|
__ SignExtend32To64Bits(index, index);
|
||||||
|
__ LoadTaggedFieldByIndex(
|
||||||
|
result_reg, object, index, 1,
|
||||||
|
JSObject::kHeaderSize - (kIsDoubleBit << kSmiTagSize));
|
||||||
|
__ Jump(*done);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&if_outofobject);
|
||||||
|
{
|
||||||
|
MaglevAssembler::ScratchRegisterScope temps(masm);
|
||||||
|
Register property_array = temps.Acquire();
|
||||||
|
// Load the property array.
|
||||||
|
__ LoadTaggedField(
|
||||||
|
property_array,
|
||||||
|
FieldMemOperand(object, JSObject::kPropertiesOrHashOffset));
|
||||||
|
|
||||||
|
// See giant comment above.
|
||||||
|
static_assert(kSmiTagSize == 1);
|
||||||
|
__ NegateInt32(index);
|
||||||
|
__ LoadTaggedFieldByIndex(
|
||||||
|
result_reg, property_array, index, 1,
|
||||||
|
FixedArray::kHeaderSize + (kIsDoubleBit << kSmiTagSize) - 4);
|
||||||
|
// Fallthrough to `done`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(*done);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <typename NodeT, typename Function, typename... Args>
|
template <typename NodeT, typename Function, typename... Args>
|
||||||
|
@ -165,6 +165,7 @@ class CompactInterpreterFrameState;
|
|||||||
V(LoadPolymorphicTaggedField) \
|
V(LoadPolymorphicTaggedField) \
|
||||||
V(LoadTaggedField) \
|
V(LoadTaggedField) \
|
||||||
V(LoadDoubleField) \
|
V(LoadDoubleField) \
|
||||||
|
V(LoadTaggedFieldByFieldIndex) \
|
||||||
V(LoadFixedArrayElement) \
|
V(LoadFixedArrayElement) \
|
||||||
V(LoadFixedDoubleArrayElement) \
|
V(LoadFixedDoubleArrayElement) \
|
||||||
V(LoadSignedIntDataViewElement) \
|
V(LoadSignedIntDataViewElement) \
|
||||||
@ -414,6 +415,7 @@ enum class ValueRepresentation : uint8_t {
|
|||||||
|
|
||||||
constexpr Condition ConditionFor(Operation cond);
|
constexpr Condition ConditionFor(Operation cond);
|
||||||
|
|
||||||
|
bool FromConstantToBool(LocalIsolate* local_isolate, ValueNode* node);
|
||||||
bool FromConstantToBool(MaglevAssembler* masm, ValueNode* node);
|
bool FromConstantToBool(MaglevAssembler* masm, ValueNode* node);
|
||||||
|
|
||||||
inline int ExternalArrayElementSize(const ExternalArrayType element_type) {
|
inline int ExternalArrayElementSize(const ExternalArrayType element_type) {
|
||||||
@ -4298,6 +4300,29 @@ class LoadDoubleField : public FixedInputValueNodeT<1, LoadDoubleField> {
|
|||||||
const int offset_;
|
const int offset_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LoadTaggedFieldByFieldIndex
|
||||||
|
: public FixedInputValueNodeT<2, LoadTaggedFieldByFieldIndex> {
|
||||||
|
using Base = FixedInputValueNodeT<2, LoadTaggedFieldByFieldIndex>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LoadTaggedFieldByFieldIndex(uint64_t bitfield) : Base(bitfield) {}
|
||||||
|
|
||||||
|
static constexpr OpProperties kProperties =
|
||||||
|
OpProperties::Reading() | OpProperties::DeferredCall();
|
||||||
|
static constexpr typename Base::InputTypes kInputTypes{
|
||||||
|
ValueRepresentation::kTagged, ValueRepresentation::kTagged};
|
||||||
|
|
||||||
|
static constexpr int kObjectIndex = 0;
|
||||||
|
static constexpr int kIndexIndex = 1;
|
||||||
|
Input& object_input() { return input(kObjectIndex); }
|
||||||
|
Input& index_input() { return input(kIndexIndex); }
|
||||||
|
|
||||||
|
int MaxCallStackArgs() const { return 0; }
|
||||||
|
void SetValueLocationConstraints();
|
||||||
|
void GenerateCode(MaglevAssembler*, const ProcessingState&);
|
||||||
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
|
||||||
|
};
|
||||||
|
|
||||||
class LoadFixedArrayElement
|
class LoadFixedArrayElement
|
||||||
: public FixedInputValueNodeT<2, LoadFixedArrayElement> {
|
: public FixedInputValueNodeT<2, LoadFixedArrayElement> {
|
||||||
using Base = FixedInputValueNodeT<2, LoadFixedArrayElement>;
|
using Base = FixedInputValueNodeT<2, LoadFixedArrayElement>;
|
||||||
|
@ -38,6 +38,19 @@ constexpr Condition ConditionFor(Operation operation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ScaleFactor ScaleFactorFromInt(int n) {
|
||||||
|
switch (n) {
|
||||||
|
case 1:
|
||||||
|
return times_1;
|
||||||
|
case 2:
|
||||||
|
return times_2;
|
||||||
|
case 4:
|
||||||
|
return times_4;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class MaglevAssembler::ScratchRegisterScope {
|
class MaglevAssembler::ScratchRegisterScope {
|
||||||
public:
|
public:
|
||||||
explicit ScratchRegisterScope(MaglevAssembler* masm)
|
explicit ScratchRegisterScope(MaglevAssembler* masm)
|
||||||
@ -223,6 +236,14 @@ inline void MaglevAssembler::BuildTypedArrayDataPointer(Register data_pointer,
|
|||||||
addq(data_pointer, base);
|
addq(data_pointer, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::LoadTaggedFieldByIndex(Register result,
|
||||||
|
Register object,
|
||||||
|
Register index, int scale,
|
||||||
|
int offset) {
|
||||||
|
LoadTaggedField(
|
||||||
|
result, FieldOperand(object, index, ScaleFactorFromInt(scale), offset));
|
||||||
|
}
|
||||||
|
|
||||||
inline void MaglevAssembler::LoadBoundedSizeFromObject(Register result,
|
inline void MaglevAssembler::LoadBoundedSizeFromObject(Register result,
|
||||||
Register object,
|
Register object,
|
||||||
int offset) {
|
int offset) {
|
||||||
@ -361,6 +382,7 @@ inline void MaglevAssembler::Move(Register dst, Handle<HeapObject> obj) {
|
|||||||
inline void MaglevAssembler::SignExtend32To64Bits(Register dst, Register src) {
|
inline void MaglevAssembler::SignExtend32To64Bits(Register dst, Register src) {
|
||||||
movsxlq(dst, src);
|
movsxlq(dst, src);
|
||||||
}
|
}
|
||||||
|
inline void MaglevAssembler::NegateInt32(Register val) { negl(val); }
|
||||||
|
|
||||||
template <typename NodeT>
|
template <typename NodeT>
|
||||||
inline void MaglevAssembler::DeoptIfBufferDetached(Register array,
|
inline void MaglevAssembler::DeoptIfBufferDetached(Register array,
|
||||||
@ -468,6 +490,26 @@ void MaglevAssembler::CompareInt32AndJumpIf(Register r1, Register r2,
|
|||||||
JumpIf(cond, target, distance);
|
JumpIf(cond, target, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::CompareInt32AndJumpIf(Register r1, int32_t value,
|
||||||
|
Condition cond,
|
||||||
|
Label* target,
|
||||||
|
Label::Distance distance) {
|
||||||
|
CompareInt32(r1, value);
|
||||||
|
JumpIf(cond, target, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::TestInt32AndJumpIfAnySet(
|
||||||
|
Register r1, int32_t mask, Label* target, Label::Distance distance) {
|
||||||
|
testl(r1, Immediate(mask));
|
||||||
|
JumpIf(kNotZero, target, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MaglevAssembler::TestInt32AndJumpIfAllClear(
|
||||||
|
Register r1, int32_t mask, Label* target, Label::Distance distance) {
|
||||||
|
testl(r1, Immediate(mask));
|
||||||
|
JumpIf(kZero, target, distance);
|
||||||
|
}
|
||||||
|
|
||||||
inline void MaglevAssembler::LoadHeapNumberValue(DoubleRegister result,
|
inline void MaglevAssembler::LoadHeapNumberValue(DoubleRegister result,
|
||||||
Register heap_number) {
|
Register heap_number) {
|
||||||
Movsd(result, FieldOperand(heap_number, HeapNumber::kValueOffset));
|
Movsd(result, FieldOperand(heap_number, HeapNumber::kValueOffset));
|
||||||
|
@ -977,19 +977,6 @@ void StoreDoubleDataViewElement::GenerateCode(MaglevAssembler* masm,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
ScaleFactor ScaleFactorFromInt(int n) {
|
|
||||||
switch (n) {
|
|
||||||
case 1:
|
|
||||||
return times_1;
|
|
||||||
case 2:
|
|
||||||
return times_2;
|
|
||||||
case 4:
|
|
||||||
return times_4;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool check_detached, typename ResultReg, typename NodeT>
|
template <bool check_detached, typename ResultReg, typename NodeT>
|
||||||
void GenerateTypedArrayLoad(MaglevAssembler* masm, NodeT* node, Register object,
|
void GenerateTypedArrayLoad(MaglevAssembler* masm, NodeT* node, Register object,
|
||||||
Register index, ResultReg result_reg,
|
Register index, ResultReg result_reg,
|
||||||
|
Loading…
Reference in New Issue
Block a user