Path: blob/master/src/hotspot/share/asm/assembler.hpp
40951 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_ASM_ASSEMBLER_HPP25#define SHARE_ASM_ASSEMBLER_HPP2627#include "asm/codeBuffer.hpp"28#include "asm/register.hpp"29#include "code/oopRecorder.hpp"30#include "code/relocInfo.hpp"31#include "memory/allocation.hpp"32#include "utilities/debug.hpp"33#include "utilities/growableArray.hpp"34#include "utilities/macros.hpp"3536// This file contains platform-independent assembler declarations.3738class MacroAssembler;39class AbstractAssembler;40class Label;4142/**43* Labels represent destinations for control transfer instructions. Such44* instructions can accept a Label as their target argument. A Label is45* bound to the current location in the code stream by calling the46* MacroAssembler's 'bind' method, which in turn calls the Label's 'bind'47* method. A Label may be referenced by an instruction before it's bound48* (i.e., 'forward referenced'). 'bind' stores the current code offset49* in the Label object.50*51* If an instruction references a bound Label, the offset field(s) within52* the instruction are immediately filled in based on the Label's code53* offset. If an instruction references an unbound label, that54* instruction is put on a list of instructions that must be patched55* (i.e., 'resolved') when the Label is bound.56*57* 'bind' will call the platform-specific 'patch_instruction' method to58* fill in the offset field(s) for each unresolved instruction (if there59* are any). 'patch_instruction' lives in one of the60* cpu/<arch>/vm/assembler_<arch>* files.61*62* Instead of using a linked list of unresolved instructions, a Label has63* an array of unresolved instruction code offsets. _patch_index64* contains the total number of forward references. If the Label's array65* overflows (i.e., _patch_index grows larger than the array size), a66* GrowableArray is allocated to hold the remaining offsets. (The cache67* size is 4 for now, which handles over 99.5% of the cases)68*69* Labels may only be used within a single CodeSection. If you need70* to create references between code sections, use explicit relocations.71*/72class Label {73private:74enum { PatchCacheSize = 4 debug_only( +4 ) };7576// _loc encodes both the binding state (via its sign)77// and the binding locator (via its value) of a label.78//79// _loc >= 0 bound label, loc() encodes the target (jump) position80// _loc == -1 unbound label81int _loc;8283// References to instructions that jump to this unresolved label.84// These instructions need to be patched when the label is bound85// using the platform-specific patchInstruction() method.86//87// To avoid having to allocate from the C-heap each time, we provide88// a local cache and use the overflow only if we exceed the local cache89int _patches[PatchCacheSize];90int _patch_index;91GrowableArray<int>* _patch_overflow;9293Label(const Label&) { ShouldNotReachHere(); }94protected:9596// The label will be bound to a location near its users.97bool _is_near;9899#ifdef ASSERT100// Sourcre file and line location of jump instruction101int _lines[PatchCacheSize];102const char* _files[PatchCacheSize];103#endif104public:105106/**107* After binding, be sure 'patch_instructions' is called later to link108*/109void bind_loc(int loc) {110assert(loc >= 0, "illegal locator");111assert(_loc == -1, "already bound");112_loc = loc;113}114void bind_loc(int pos, int sect) { bind_loc(CodeBuffer::locator(pos, sect)); }115116#ifndef PRODUCT117// Iterates over all unresolved instructions for printing118void print_instructions(MacroAssembler* masm) const;119#endif // PRODUCT120121/**122* Returns the position of the the Label in the code buffer123* The position is a 'locator', which encodes both offset and section.124*/125int loc() const {126assert(_loc >= 0, "unbound label");127return _loc;128}129int loc_pos() const { return CodeBuffer::locator_pos(loc()); }130int loc_sect() const { return CodeBuffer::locator_sect(loc()); }131132bool is_bound() const { return _loc >= 0; }133bool is_unbound() const { return _loc == -1 && _patch_index > 0; }134bool is_unused() const { return _loc == -1 && _patch_index == 0; }135136// The label will be bound to a location near its users. Users can137// optimize on this information, e.g. generate short branches.138bool is_near() { return _is_near; }139140/**141* Adds a reference to an unresolved displacement instruction to142* this unbound label143*144* @param cb the code buffer being patched145* @param branch_loc the locator of the branch instruction in the code buffer146*/147void add_patch_at(CodeBuffer* cb, int branch_loc, const char* file = NULL, int line = 0);148149/**150* Iterate over the list of patches, resolving the instructions151* Call patch_instruction on each 'branch_loc' value152*/153void patch_instructions(MacroAssembler* masm);154155void init() {156_loc = -1;157_patch_index = 0;158_patch_overflow = NULL;159_is_near = false;160}161162Label() {163init();164}165166~Label() {167assert(is_bound() || is_unused(), "Label was never bound to a location, but it was used as a jmp target");168}169170void reset() {171init(); //leave _patch_overflow because it points to CodeBuffer.172}173};174175// A NearLabel must be bound to a location near its users. Users can176// optimize on this information, e.g. generate short branches.177class NearLabel : public Label {178public:179NearLabel() : Label() { _is_near = true; }180};181182// A union type for code which has to assemble both constant and183// non-constant operands, when the distinction cannot be made184// statically.185class RegisterOrConstant {186private:187Register _r;188intptr_t _c;189190public:191RegisterOrConstant(): _r(noreg), _c(0) {}192RegisterOrConstant(Register r): _r(r), _c(0) {}193RegisterOrConstant(intptr_t c): _r(noreg), _c(c) {}194195Register as_register() const { assert(is_register(),""); return _r; }196intptr_t as_constant() const { assert(is_constant(),""); return _c; }197198Register register_or_noreg() const { return _r; }199intptr_t constant_or_zero() const { return _c; }200201bool is_register() const { return _r != noreg; }202bool is_constant() const { return _r == noreg; }203};204205// The Abstract Assembler: Pure assembler doing NO optimizations on the206// instruction level; i.e., what you write is what you get.207// The Assembler is generating code into a CodeBuffer.208class AbstractAssembler : public ResourceObj {209friend class Label;210211protected:212CodeSection* _code_section; // section within the code buffer213OopRecorder* _oop_recorder; // support for relocInfo::oop_type214215public:216// Code emission & accessing217address addr_at(int pos) const { return code_section()->start() + pos; }218219protected:220// This routine is called with a label is used for an address.221// Labels and displacements truck in offsets, but target must return a PC.222address target(Label& L) { return code_section()->target(L, pc()); }223224bool is8bit(int x) const { return -0x80 <= x && x < 0x80; }225bool isByte(int x) const { return 0 <= x && x < 0x100; }226bool isShiftCount(int x) const { return 0 <= x && x < 32; }227228// Instruction boundaries (required when emitting relocatable values).229class InstructionMark: public StackObj {230private:231AbstractAssembler* _assm;232233public:234InstructionMark(AbstractAssembler* assm) : _assm(assm) {235assert(assm->inst_mark() == NULL, "overlapping instructions");236_assm->set_inst_mark();237}238~InstructionMark() {239_assm->clear_inst_mark();240}241};242friend class InstructionMark;243#ifdef ASSERT244// Make it return true on platforms which need to verify245// instruction boundaries for some operations.246static bool pd_check_instruction_mark();247248// Add delta to short branch distance to verify that it still fit into imm8.249int _short_branch_delta;250251int short_branch_delta() const { return _short_branch_delta; }252void set_short_branch_delta() { _short_branch_delta = 32; }253void clear_short_branch_delta() { _short_branch_delta = 0; }254255class ShortBranchVerifier: public StackObj {256private:257AbstractAssembler* _assm;258259public:260ShortBranchVerifier(AbstractAssembler* assm) : _assm(assm) {261assert(assm->short_branch_delta() == 0, "overlapping instructions");262_assm->set_short_branch_delta();263}264~ShortBranchVerifier() {265_assm->clear_short_branch_delta();266}267};268#else269// Dummy in product.270class ShortBranchVerifier: public StackObj {271public:272ShortBranchVerifier(AbstractAssembler* assm) {}273};274#endif275276public:277278// Creation279AbstractAssembler(CodeBuffer* code);280281// ensure buf contains all code (call this before using/copying the code)282void flush();283284void emit_int8( int8_t x1) { code_section()->emit_int8(x1); }285286void emit_int16( int16_t x) { code_section()->emit_int16(x); }287void emit_int16( int8_t x1, int8_t x2) { code_section()->emit_int16(x1, x2); }288289void emit_int24( int8_t x1, int8_t x2, int8_t x3) { code_section()->emit_int24(x1, x2, x3); }290291void emit_int32( int32_t x) { code_section()->emit_int32(x); }292void emit_int32( int8_t x1, int8_t x2, int8_t x3, int8_t x4) { code_section()->emit_int32(x1, x2, x3, x4); }293294void emit_int64( int64_t x) { code_section()->emit_int64(x); }295296void emit_float( jfloat x) { code_section()->emit_float(x); }297void emit_double( jdouble x) { code_section()->emit_double(x); }298void emit_address(address x) { code_section()->emit_address(x); }299300enum { min_simm10 = -512 };301302// Test if x is within signed immediate range for width.303static bool is_simm(int64_t x, uint w) {304precond(1 < w && w < 64);305int64_t limes = INT64_C(1) << (w - 1);306return -limes <= x && x < limes;307}308309static bool is_simm8(int64_t x) { return is_simm(x, 8); }310static bool is_simm9(int64_t x) { return is_simm(x, 9); }311static bool is_simm10(int64_t x) { return is_simm(x, 10); }312static bool is_simm16(int64_t x) { return is_simm(x, 16); }313static bool is_simm32(int64_t x) { return is_simm(x, 32); }314315// Test if x is within unsigned immediate range for width.316static bool is_uimm(uint64_t x, uint w) {317precond(0 < w && w < 64);318uint64_t limes = UINT64_C(1) << w;319return x < limes;320}321322static bool is_uimm12(uint64_t x) { return is_uimm(x, 12); }323324// Accessors325CodeSection* code_section() const { return _code_section; }326CodeBuffer* code() const { return code_section()->outer(); }327int sect() const { return code_section()->index(); }328address pc() const { return code_section()->end(); }329int offset() const { return code_section()->size(); }330int locator() const { return CodeBuffer::locator(offset(), sect()); }331332OopRecorder* oop_recorder() const { return _oop_recorder; }333void set_oop_recorder(OopRecorder* r) { _oop_recorder = r; }334335address inst_mark() const { return code_section()->mark(); }336void set_inst_mark() { code_section()->set_mark(); }337void clear_inst_mark() { code_section()->clear_mark(); }338339// Constants in code340void relocate(RelocationHolder const& rspec, int format = 0) {341assert(!pd_check_instruction_mark()342|| inst_mark() == NULL || inst_mark() == code_section()->end(),343"call relocate() between instructions");344code_section()->relocate(code_section()->end(), rspec, format);345}346void relocate( relocInfo::relocType rtype, int format = 0) {347code_section()->relocate(code_section()->end(), rtype, format);348}349350static int code_fill_byte(); // used to pad out odd-sized code buffers351352// Associate a comment with the current offset. It will be printed353// along with the disassembly when printing nmethods. Currently354// only supported in the instruction section of the code buffer.355void block_comment(const char* comment);356// Copy str to a buffer that has the same lifetime as the CodeBuffer357const char* code_string(const char* str);358359// Label functions360void bind(Label& L); // binds an unbound label L to the current code position361362// Move to a different section in the same code buffer.363void set_code_section(CodeSection* cs);364365// Inform assembler when generating stub code and relocation info366address start_a_stub(int required_space);367void end_a_stub();368// Ditto for constants.369address start_a_const(int required_space, int required_align = sizeof(double));370void end_a_const(CodeSection* cs); // Pass the codesection to continue in (insts or stubs?).371372// constants support373//374// We must remember the code section (insts or stubs) in c1375// so we can reset to the proper section in end_a_const().376address int_constant(jint c) {377CodeSection* c1 = _code_section;378address ptr = start_a_const(sizeof(c), sizeof(c));379if (ptr != NULL) {380emit_int32(c);381end_a_const(c1);382}383return ptr;384}385address long_constant(jlong c) {386CodeSection* c1 = _code_section;387address ptr = start_a_const(sizeof(c), sizeof(c));388if (ptr != NULL) {389emit_int64(c);390end_a_const(c1);391}392return ptr;393}394address double_constant(jdouble c) {395CodeSection* c1 = _code_section;396address ptr = start_a_const(sizeof(c), sizeof(c));397if (ptr != NULL) {398emit_double(c);399end_a_const(c1);400}401return ptr;402}403address float_constant(jfloat c) {404CodeSection* c1 = _code_section;405address ptr = start_a_const(sizeof(c), sizeof(c));406if (ptr != NULL) {407emit_float(c);408end_a_const(c1);409}410return ptr;411}412address address_constant(address c) {413CodeSection* c1 = _code_section;414address ptr = start_a_const(sizeof(c), sizeof(c));415if (ptr != NULL) {416emit_address(c);417end_a_const(c1);418}419return ptr;420}421address address_constant(address c, RelocationHolder const& rspec) {422CodeSection* c1 = _code_section;423address ptr = start_a_const(sizeof(c), sizeof(c));424if (ptr != NULL) {425relocate(rspec);426emit_address(c);427end_a_const(c1);428}429return ptr;430}431432// Bang stack to trigger StackOverflowError at a safe location433// implementation delegates to machine-specific bang_stack_with_offset434void generate_stack_overflow_check( int frame_size_in_bytes );435virtual void bang_stack_with_offset(int offset) = 0;436437438/**439* A platform-dependent method to patch a jump instruction that refers440* to this label.441*442* @param branch the location of the instruction to patch443* @param masm the assembler which generated the branch444*/445void pd_patch_instruction(address branch, address target, const char* file, int line);446447};448449#include CPU_HEADER(assembler)450451#endif // SHARE_ASM_ASSEMBLER_HPP452453454