Commit 91e918c1 authored by Victor Gomes's avatar Victor Gomes Committed by V8 LUCI CQ

[maglev] Support TestTypeOf

Bug: v8:7700
Change-Id: I1cba243972ac9a22ef4a5873d6d6d1e55b99cb55
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3779678
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81865}
parent d188467b
......@@ -688,7 +688,19 @@ void MaglevGraphBuilder::VisitTestUndefined() {
SetAccumulator(AddNewNode<TaggedEqual>({value, undefined_constant}));
}
MAGLEV_UNIMPLEMENTED_BYTECODE(TestTypeOf)
void MaglevGraphBuilder::VisitTestTypeOf() {
using LiteralFlag = interpreter::TestTypeOfFlags::LiteralFlag;
// TODO(v8:7700): Add a branch version of TestTypeOf that does not need to
// materialise the boolean value.
LiteralFlag literal = interpreter::TestTypeOfFlags::Decode(GetFlagOperand(0));
if (literal == LiteralFlag::kOther) {
SetAccumulator(GetRootConstant(RootIndex::kFalseValue));
return;
}
ValueNode* value = GetAccumulatorTagged();
// TODO(victorgomes): Add fast path for constants.
SetAccumulator(AddNewNode<TestTypeOf>({value}, literal));
}
bool MaglevGraphBuilder::TryBuildPropertyCellAccess(
const compiler::GlobalAccessFeedback& global_access_feedback) {
......
......@@ -108,6 +108,7 @@ class MaglevGraphVerifier {
case Opcode::kFastCreateClosure:
case Opcode::kLogicalNot:
case Opcode::kTestUndetectable:
case Opcode::kTestTypeOf:
case Opcode::kReturn:
DCHECK_EQ(node->input_count(), 1);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
......
......@@ -1948,6 +1948,98 @@ void TestUndetectable::GenerateCode(MaglevCodeGenState* code_gen_state,
__ bind(&done);
}
void TestTypeOf::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(value());
DefineAsRegister(vreg_state, this);
}
void TestTypeOf::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
using LiteralFlag = interpreter::TestTypeOfFlags::LiteralFlag;
Register object = ToRegister(value());
// Use return register as temporary if needed.
Register tmp = ToRegister(result());
Label is_true, is_false, done;
switch (literal_) {
case LiteralFlag::kNumber:
__ JumpIfSmi(object, &is_true);
__ CompareRoot(FieldOperand(object, HeapObject::kMapOffset),
RootIndex::kHeapNumberMap);
__ j(not_equal, &is_false);
break;
case LiteralFlag::kString:
__ JumpIfSmi(object, &is_false);
__ LoadMap(tmp, object);
__ cmpw(FieldOperand(tmp, Map::kInstanceTypeOffset),
Immediate(FIRST_NONSTRING_TYPE));
__ j(greater_equal, &is_false);
break;
case LiteralFlag::kSymbol:
__ JumpIfSmi(object, &is_false);
__ LoadMap(tmp, object);
__ cmpw(FieldOperand(tmp, Map::kInstanceTypeOffset),
Immediate(SYMBOL_TYPE));
__ j(not_equal, &is_false);
break;
case LiteralFlag::kBoolean:
__ CompareRoot(object, RootIndex::kTrueValue);
__ j(equal, &is_true);
__ CompareRoot(object, RootIndex::kFalseValue);
__ j(not_equal, &is_false);
break;
case LiteralFlag::kBigInt:
__ JumpIfSmi(object, &is_false);
__ LoadMap(tmp, object);
__ cmpw(FieldOperand(tmp, Map::kInstanceTypeOffset),
Immediate(BIGINT_TYPE));
__ j(not_equal, &is_false);
break;
case LiteralFlag::kUndefined:
__ JumpIfSmi(object, &is_false);
// Check it has the undetectable bit set and it is not null.
__ LoadMap(tmp, object);
__ testl(FieldOperand(tmp, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsUndetectableBit::kMask));
__ j(zero, &is_false);
__ CompareRoot(object, RootIndex::kNullValue);
__ j(equal, &is_false);
break;
case LiteralFlag::kFunction:
__ JumpIfSmi(object, &is_false);
// Check if callable bit is set and not undetectable.
__ LoadMap(tmp, object);
__ movl(tmp, FieldOperand(tmp, Map::kBitFieldOffset));
__ andl(tmp, Immediate(Map::Bits1::IsUndetectableBit::kMask |
Map::Bits1::IsCallableBit::kMask));
__ cmpl(tmp, Immediate(Map::Bits1::IsCallableBit::kMask));
__ j(not_equal, &is_false);
break;
case LiteralFlag::kObject:
__ JumpIfSmi(object, &is_false);
// If the object is null then return true.
__ CompareRoot(object, RootIndex::kNullValue);
__ j(equal, &is_true);
// Check if the object is a receiver type,
__ LoadMap(tmp, object);
__ cmpw(FieldOperand(tmp, Map::kInstanceTypeOffset),
Immediate(FIRST_JS_RECEIVER_TYPE));
__ j(less, &is_false);
// ... and is not undefined (undetectable) nor callable.
__ testl(FieldOperand(tmp, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsUndetectableBit::kMask |
Map::Bits1::IsCallableBit::kMask));
__ j(not_zero, &is_false);
break;
case LiteralFlag::kOther:
UNREACHABLE();
}
__ bind(&is_true);
__ LoadRoot(ToRegister(result()), RootIndex::kTrueValue);
__ jmp(&done);
__ bind(&is_false);
__ LoadRoot(ToRegister(result()), RootIndex::kFalseValue);
__ bind(&done);
}
void ChangeInt32ToFloat64::AllocateVreg(MaglevVregAllocationState* vreg_state) {
UseRegister(input());
DefineAsRegister(vreg_state, this);
......
......@@ -17,6 +17,7 @@
#include "src/compiler/backend/instruction.h"
#include "src/compiler/heap-refs.h"
#include "src/deoptimizer/deoptimize-reason.h"
#include "src/interpreter/bytecode-flags.h"
#include "src/interpreter/bytecode-register.h"
#include "src/maglev/maglev-compilation-unit.h"
#include "src/objects/smi.h"
......@@ -149,6 +150,7 @@ class CompactInterpreterFrameState;
V(TaggedEqual) \
V(TestInstanceOf) \
V(TestUndetectable) \
V(TestTypeOf) \
CONSTANT_VALUE_NODE_LIST(V) \
INT32_OPERATIONS_NODE_LIST(V) \
FLOAT64_OPERATIONS_NODE_LIST(V) \
......@@ -1604,6 +1606,24 @@ class TestUndetectable : public FixedInputValueNodeT<1, TestUndetectable> {
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class TestTypeOf : public FixedInputValueNodeT<1, TestTypeOf> {
using Base = FixedInputValueNodeT<1, TestTypeOf>;
public:
explicit TestTypeOf(uint64_t bitfield,
interpreter::TestTypeOfFlags::LiteralFlag literal)
: Base(bitfield), literal_(literal) {}
Input& value() { return Node::input(0); }
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
interpreter::TestTypeOfFlags::LiteralFlag literal_;
};
class InitialValue : public FixedInputValueNodeT<0, InitialValue> {
using Base = FixedInputValueNodeT<0, InitialValue>;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment