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

[maglev] Add CreateObjectLiteral nodes

Bug: v8:7700
Change-Id: Ia76a091e013aa7649da132c113fcefef06534f3b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3616511
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80278}
parent 2c508701
......@@ -11,10 +11,12 @@
#include "src/compiler/processed-feedback.h"
#include "src/handles/maybe-handles-inl.h"
#include "src/ic/handler-configuration-inl.h"
#include "src/interpreter/bytecode-flags.h"
#include "src/maglev/maglev-compilation-unit.h"
#include "src/maglev/maglev-interpreter-frame-state.h"
#include "src/maglev/maglev-ir.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/name-inl.h"
#include "src/objects/property-cell.h"
#include "src/objects/slots-inl.h"
......@@ -1006,7 +1008,30 @@ void MaglevGraphBuilder::VisitCreateEmptyArrayLiteral() {
{}, compiler::FeedbackSource{feedback(), slot_index}));
}
MAGLEV_UNIMPLEMENTED_BYTECODE(CreateObjectLiteral)
void MaglevGraphBuilder::VisitCreateObjectLiteral() {
ValueNode* boilerplate_desc =
GetConstant(GetRefOperand<ObjectBoilerplateDescription>(0));
FeedbackSlot slot_index = GetSlotOperand(1);
int bytecode_flags = GetFlagOperand(2);
int literal_flags =
interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags);
ValueNode* result;
if (interpreter::CreateObjectLiteralFlags::FastCloneSupportedBit::decode(
bytecode_flags)) {
// TODO(victorgomes): CreateShallowObjectLiteral should not need the
// boilerplate descriptor. However the current builtin checks that the
// feedback exists and fallsback to CreateObjectLiteral if it doesn't.
result = AddNewNode<CreateShallowObjectLiteral>(
{boilerplate_desc}, literal_flags,
compiler::FeedbackSource{feedback(), slot_index});
} else {
result = AddNewNode<CreateObjectLiteral>(
{boilerplate_desc}, literal_flags,
compiler::FeedbackSource{feedback(), slot_index});
}
SetAccumulator(result);
}
MAGLEV_UNIMPLEMENTED_BYTECODE(CreateEmptyObjectLiteral)
MAGLEV_UNIMPLEMENTED_BYTECODE(CloneObject)
MAGLEV_UNIMPLEMENTED_BYTECODE(GetTemplateObject)
......
......@@ -269,6 +269,10 @@ class MaglevGraphBuilder {
return iterator_.GetSlotOperand(operand_index);
}
uint32_t GetFlagOperand(int operand_index) const {
return iterator_.GetFlagOperand(operand_index);
}
template <class T, typename = std::enable_if_t<
std::is_convertible<T*, Object*>::value>>
typename compiler::ref_traits<T>::ref_type GetRefOperand(int operand_index) {
......
......@@ -92,6 +92,8 @@ class MaglevGraphVerifier {
case Opcode::kBranchIfToBooleanTrue:
case Opcode::kReturn:
case Opcode::kCheckedFloat64Unbox:
case Opcode::kCreateObjectLiteral:
case Opcode::kCreateShallowObjectLiteral:
DCHECK_EQ(node->input_count(), 1);
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
break;
......
......@@ -505,6 +505,39 @@ void CreateEmptyArrayLiteral::GenerateCode(MaglevCodeGenState* code_gen_state,
__ CallBuiltin(Builtin::kCreateEmptyArrayLiteral);
}
void CreateObjectLiteral::AllocateVreg(MaglevVregAllocationState* vreg_state,
const ProcessingState& state) {
UseRegister(boilerplate_descriptor());
DefineAsFixed(vreg_state, this, kReturnRegister0);
}
void CreateObjectLiteral::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
__ Move(kContextRegister, code_gen_state->native_context().object());
__ Push(feedback().vector);
__ Push(Smi::FromInt(feedback().index()));
__ Push(ToRegister(boilerplate_descriptor()));
__ Push(Smi::FromInt(flags()));
__ CallRuntime(Runtime::kCreateObjectLiteral);
}
void CreateShallowObjectLiteral::AllocateVreg(
MaglevVregAllocationState* vreg_state, const ProcessingState& state) {
using D = CreateShallowObjectLiteralDescriptor;
UseFixed(boilerplate_descriptor(), D::GetRegisterParameter(D::kDesc));
DefineAsFixed(vreg_state, this, kReturnRegister0);
}
void CreateShallowObjectLiteral::GenerateCode(
MaglevCodeGenState* code_gen_state, const ProcessingState& state) {
using D = CreateShallowObjectLiteralDescriptor;
DCHECK_EQ(ToRegister(boilerplate_descriptor()),
D::GetRegisterParameter(D::kDesc));
__ Move(kContextRegister, code_gen_state->native_context().object());
__ Move(D::GetRegisterParameter(D::kFlags), Smi::FromInt(flags()));
__ Move(D::GetRegisterParameter(D::kSlot), Smi::FromInt(feedback().index()));
__ Move(D::GetRegisterParameter(D::kMaybeFeedbackVector), feedback().vector);
__ CallBuiltin(Builtin::kCreateShallowObjectLiteral);
}
void CheckMaps::AllocateVreg(MaglevVregAllocationState* vreg_state,
const ProcessingState& state) {
UseRegister(actual_map_input());
......
......@@ -65,30 +65,32 @@ class CompactInterpreterFrameState;
V(GenericGreaterThan) \
V(GenericGreaterThanOrEqual)
#define VALUE_NODE_LIST(V) \
V(Call) \
V(Constant) \
V(Construct) \
V(CreateEmptyArrayLiteral) \
V(InitialValue) \
V(LoadTaggedField) \
V(LoadDoubleField) \
V(LoadGlobal) \
V(LoadNamedGeneric) \
V(SetNamedGeneric) \
V(Phi) \
V(RegisterInput) \
V(RootConstant) \
V(SmiConstant) \
V(CheckedSmiTag) \
V(CheckedSmiUntag) \
V(Int32AddWithOverflow) \
V(Int32Constant) \
V(Float64Constant) \
V(ChangeInt32ToFloat64) \
V(Float64Box) \
V(CheckedFloat64Unbox) \
V(Float64Add) \
#define VALUE_NODE_LIST(V) \
V(Call) \
V(Constant) \
V(Construct) \
V(CreateEmptyArrayLiteral) \
V(CreateObjectLiteral) \
V(CreateShallowObjectLiteral) \
V(InitialValue) \
V(LoadTaggedField) \
V(LoadDoubleField) \
V(LoadGlobal) \
V(LoadNamedGeneric) \
V(SetNamedGeneric) \
V(Phi) \
V(RegisterInput) \
V(RootConstant) \
V(SmiConstant) \
V(CheckedSmiTag) \
V(CheckedSmiUntag) \
V(Int32AddWithOverflow) \
V(Int32Constant) \
V(Float64Constant) \
V(ChangeInt32ToFloat64) \
V(Float64Box) \
V(CheckedFloat64Unbox) \
V(Float64Add) \
GENERIC_OPERATIONS_NODE_LIST(V)
#define NODE_LIST(V) \
......@@ -1279,6 +1281,66 @@ class CreateEmptyArrayLiteral
const compiler::FeedbackSource feedback_;
};
class CreateObjectLiteral
: public FixedInputValueNodeT<1, CreateObjectLiteral> {
using Base = FixedInputValueNodeT<1, CreateObjectLiteral>;
public:
explicit CreateObjectLiteral(uint32_t bitfield, int flags,
const compiler::FeedbackSource& feedback)
: Base(bitfield), flags_(flags), feedback_(feedback) {}
static constexpr int kObjectBoilerplateDescription = 0;
Input& boilerplate_descriptor() {
return input(kObjectBoilerplateDescription);
}
int flags() const { return flags_; }
compiler::FeedbackSource feedback() const { return feedback_; }
// The implementation currently calls runtime.
static constexpr OpProperties kProperties = OpProperties::Call();
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
const int flags_;
const compiler::FeedbackSource feedback_;
};
class CreateShallowObjectLiteral
: public FixedInputValueNodeT<1, CreateShallowObjectLiteral> {
using Base = FixedInputValueNodeT<1, CreateShallowObjectLiteral>;
public:
explicit CreateShallowObjectLiteral(uint32_t bitfield, int flags,
const compiler::FeedbackSource& feedback)
: Base(bitfield), flags_(flags), feedback_(feedback) {}
// TODO(victorgomes): We should not need a boilerplate descriptor in
// CreateShallowObjectLiteral.
static constexpr int kObjectBoilerplateDescription = 0;
Input& boilerplate_descriptor() {
return input(kObjectBoilerplateDescription);
}
int flags() const { return flags_; }
compiler::FeedbackSource feedback() const { return feedback_; }
// The implementation currently calls runtime.
static constexpr OpProperties kProperties = OpProperties::Call();
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
const int flags_;
const compiler::FeedbackSource feedback_;
};
class CheckMaps : public FixedInputNodeT<1, CheckMaps> {
using Base = FixedInputNodeT<1, CheckMaps>;
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --maglev --no-stress-opt
// Empty array.
(function() {
function f() {
return [];
}
%PrepareFunctionForOptimization(f);
f();
%OptimizeMaglevOnNextCall(f);
assertEquals(0, f().length);
assertTrue(isMaglevved(f));
})();
// TODO(victorgomes): Array literal.
// TODO(victorgomes): Empty object.
// Calls builtin create shallow object.
(function() {
function f() {
return {a: 42, b: 24};
}
%PrepareFunctionForOptimization(f);
f();
%OptimizeMaglevOnNextCall(f);
assertEquals(42, f().a);
assertTrue(isMaglevved(f));
})();
// Calls runtime create literal object.
(function() {
function f() {
return { out: { in: 42 } }
}
%PrepareFunctionForOptimization(f);
f();
%OptimizeMaglevOnNextCall(f);
assertEquals(42, f().out.in);
assertTrue(isMaglevved(f));
})();
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