GenerateCode(CodeAssemblerState* state, const AssemblerOptions& options); bool Is64() const; bool IsFloat64RoundUpSupported() const; bool IsFloat64RoundDownSupported() const; bool IsFloat64RoundTiesEvenSupported() const; bool IsFloat64RoundTruncateSupported() const; bool IsInt32AbsWithOverflowSupported() const; bool IsInt64AbsWithOverflowSupported() const; bool IsIntPtrAbsWithOverflowSupported() const; // Shortened aliases for use in CodeAssembler subclasses. using Label = CodeAssemblerLabel; using Variable = CodeAssemblerVariable; template using TVariable = TypedCodeAssemblerVariable; using VariableList = CodeAssemblerVariableList; // =========================================================================== // Base Assembler // =========================================================================== template class CheckedNode { public: #ifdef DEBUG CheckedNode(Node* node, CodeAssembler* code_assembler, const char* location) : node_(node), code_assembler_(code_assembler), location_(location) {} #else CheckedNode(compiler::Node* node, CodeAssembler*, const char*) : node_(node) {} #endif template operator TNode() { static_assert( !std::is_same::value, "Can't cast to MaybeObject, use explicit conversion functions. "); static_assert(types_have_common_values::value, "Incompatible types: this cast can never succeed."); static_assert(std::is_convertible, TNode>::value, "Coercion to untagged values cannot be " "checked."); static_assert( !FromTyped || !std::is_convertible, TNode>::value, "Unnecessary CAST: types are convertible."); #ifdef DEBUG if (FLAG_debug_code) { if (std::is_same::value) { code_assembler_->GenerateCheckMaybeObjectIsObject(node_, location_); } Node* function = code_assembler_->ExternalConstant( ExternalReference::check_object_type()); code_assembler_->CallCFunction3( MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::AnyTagged(), function, node_, code_assembler_->SmiConstant( static_cast(ObjectTypeOf::value)), code_assembler_->StringConstant(location_)); } #endif return TNode::UncheckedCast(node_); } template operator SloppyTNode() { return implicit_cast>(*this); } Node* node() const { return node_; } private: Node* node_; #ifdef DEBUG CodeAssembler* code_assembler_; const char* location_; #endif }; template TNode UncheckedCast(Node* value) { return TNode::UncheckedCast(value); } template TNode UncheckedCast(TNode value) { static_assert(types_have_common_values::value, "Incompatible types: this cast can never succeed."); return TNode::UncheckedCast(value); } // ReinterpretCast(v) has the power to cast even when the type of v is // unrelated to T. Use with care. template TNode ReinterpretCast(Node* value) { return TNode::UncheckedCast(value); } CheckedNode Cast(Node* value, const char* location = "") { return {value, this, location}; } template CheckedNode Cast(TNode value, const char* location = "") { return {value, this, location}; } #ifdef DEBUG #define STRINGIFY(x) #x #define TO_STRING_LITERAL(x) STRINGIFY(x) #define CAST(x) \ Cast(x, "CAST(" #x ") at " __FILE__ ":" TO_STRING_LITERAL(__LINE__)) #else #define CAST(x) Cast(x) #endif #ifdef DEBUG void GenerateCheckMaybeObjectIsObject(Node* node, const char* location); #endif // Constants. TNode Int32Constant(int32_t value); TNode Int64Constant(int64_t value); TNode IntPtrConstant(intptr_t value); TNode NumberConstant(double value); TNode SmiConstant(Smi* value); TNode SmiConstant(int value); template ::value>::type> TNode SmiConstant(E value) { STATIC_ASSERT(sizeof(E) <= sizeof(int)); return SmiConstant(static_cast(value)); } TNode UntypedHeapConstant(Handle object); template TNode HeapConstant(Handle object) { return UncheckedCast(UntypedHeapConstant(object)); } TNode StringConstant(const char* str); TNode BooleanConstant(bool value); TNode ExternalConstant(ExternalReference address); TNode Float64Constant(double value); TNode NaNConstant(); TNode Int32TrueConstant() { return ReinterpretCast(Int32Constant(1)); } TNode Int32FalseConstant() { return ReinterpretCast(Int32Constant(0)); } TNode BoolConstant(bool value) { return value ? Int32TrueConstant() : Int32FalseConstant(); } bool ToInt32Constant(Node* node, int32_t& out_value); bool ToInt64Constant(Node* node, int64_t& out_value); bool ToSmiConstant(Node* node, Smi*& out_value); bool ToIntPtrConstant(Node* node, intptr_t& out_value); bool IsUndefinedConstant(TNode node); bool IsNullConstant(TNode node); TNode Signed(TNode x) { return UncheckedCast(x); } TNode Signed(TNode x) { return UncheckedCast(x); } TNode Unsigned(TNode x) { return UncheckedCast(x); } TNode Unsigned(TNode x) { return UncheckedCast(x); } static constexpr int kTargetParameterIndex = -1; Node* Parameter(int value); TNode GetJSContextParameter(); void Return(SloppyTNode value); void Return(SloppyTNode value1, SloppyTNode value2); void Return(SloppyTNode value1, SloppyTNode value2, SloppyTNode value3); void PopAndReturn(Node* pop, Node* value); void ReturnIf(Node* condition, Node* value); void ReturnRaw(Node* value); void DebugAbort(Node* message); void DebugBreak(); void Unreachable(); void Comment(const char* format, ...); void Bind(Label* label); #if DEBUG void Bind(Label* label, AssemblerDebugInfo debug_info); #endif // DEBUG void Goto(Label* label); void GotoIf(SloppyTNode condition, Label* true_label); void GotoIfNot(SloppyTNode condition, Label* false_label); void Branch(SloppyTNode condition, Label* true_label, Label* false_label); void Branch(TNode condition, std::function true_body, std::function false_body); void Branch(TNode condition, Label* true_label, std::function false_body); void Branch(TNode condition, std::function true_body, Label* false_label); void Switch(Node* index, Label* default_label, const int32_t* case_values, Label** case_labels, size_t case_count); // Access to the frame pointer Node* LoadFramePointer(); Node* LoadParentFramePointer(); // Access to the stack pointer Node* LoadStackPointer(); // Poison |value| on speculative paths. TNode TaggedPoisonOnSpeculation(SloppyTNode value); TNode WordPoisonOnSpeculation(SloppyTNode value); // Load raw memory location. Node* Load(MachineType rep, Node* base, LoadSensitivity needs_poisoning = LoadSensitivity::kSafe); template TNode Load(MachineType rep, TNode> base) { DCHECK( IsSubtype(rep.representation(), MachineRepresentationOf::value)); return UncheckedCast(Load(rep, static_cast(base))); } Node* Load(MachineType rep, Node* base, Node* offset, LoadSensitivity needs_poisoning = LoadSensitivity::kSafe); Node* AtomicLoad(MachineType rep, Node* base, Node* offset); // Load a value from the root array. TNode LoadRoot(Heap::RootListIndex root_index); // Store value to raw memory location. Node* Store(Node* base, Node* value); Node* Store(Node* base, Node* offset, Node* value); Node* StoreWithMapWriteBarrier(Node* base, Node* offset, Node* value); Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* value); Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* offset, Node* value); Node* AtomicStore(MachineRepresentation rep, Node* base, Node* offset, Node* value); // Exchange value at raw memory location Node* AtomicExchange(MachineType type, Node* base, Node* offset, Node* value); // Compare and Exchange value at raw memory location Node* AtomicCompareExchange(MachineType type, Node* base, Node* offset, Node* old_value, Node* new_value); Node* AtomicAdd(MachineType type, Node* base, Node* offset, Node* value); Node* AtomicSub(MachineType type, Node* base, Node* offset, Node* value); Node* AtomicAnd(MachineType type, Node* base, Node* offset, Node* value); Node* AtomicOr(MachineType type, Node* base, Node* offset, Node* value); Node* AtomicXor(MachineType type, Node* base, Node* offset, Node* value); // Store a value to the root array. Node* StoreRoot(Heap::RootListIndex root_index, Node* value); // Basic arithmetic operations. #define DECLARE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type) \ TNode name(SloppyTNode a, SloppyTNode b); CODE_ASSEMBLER_BINARY_OP_LIST(DECLARE_CODE_ASSEMBLER_BINARY_OP) #undef DECLARE_CODE_ASSEMBLER_BINARY_OP TNode WordShr(TNode left, TNode right) { return UncheckedCast( WordShr(static_cast(left), static_cast(right))); } TNode WordAnd(TNode left, TNode right) { return UncheckedCast( WordAnd(static_cast(left), static_cast(right))); } template ::value && std::is_base_of::value>::type> TNode WordEqual(TNode left, TNode right) { return WordEqual(ReinterpretCast(left), ReinterpretCast(right)); } TNode