void ArchDesc::build_map(OutputMap &map) {
FILE *fp_hpp = map.decl_file();
FILE *fp_cpp = map.def_file();
int idx = 0;
OperandForm *op;
OpClassForm *opc;
InstructForm *inst;
map.declaration();
fprintf(fp_cpp,"\n");
map.definition();
map.record_position(OutputMap::BEGIN_OPERANDS, idx );
_operands.reset();
for(; (op = (OperandForm*)_operands.iter()) != NULL; ) {
if ( op->ideal_only() ) continue;
fprintf(fp_cpp, " /* %4d */", idx); map.map(*op); fprintf(fp_cpp, ",\n");
++idx;
};
fprintf(fp_cpp, " // last operand\n");
map.record_position(OutputMap::BEGIN_OPCLASSES, idx );
_opclass.reset();
for(; (opc = (OpClassForm*)_opclass.iter()) != NULL; ) {
fprintf(fp_cpp, " /* %4d */", idx); map.map(*opc); fprintf(fp_cpp, ",\n");
++idx;
};
fprintf(fp_cpp, " // last operand class\n");
map.record_position(OutputMap::BEGIN_INTERNALS, idx );
_internalOpNames.reset();
char *name = NULL;
for(; (name = (char *)_internalOpNames.iter()) != NULL; ) {
fprintf(fp_cpp, " /* %4d */", idx); map.map(name); fprintf(fp_cpp, ",\n");
++idx;
};
fprintf(fp_cpp, " // last internally defined operand\n");
if( map.do_instructions() ) {
map.record_position(OutputMap::BEGIN_INSTRUCTIONS, idx );
map.record_position(OutputMap::BEGIN_INST_CHAIN_RULES, idx );
{
_instructions.reset();
for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( inst->ideal_only() ) continue;
if ( ! inst->is_simple_chain_rule(_globalNames) ) continue;
if ( inst->rematerialize(_globalNames, get_registers()) ) continue;
fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");
++idx;
};
map.record_position(OutputMap::BEGIN_REMATERIALIZE, idx );
_instructions.reset();
for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( inst->ideal_only() ) continue;
if ( ! inst->is_simple_chain_rule(_globalNames) ) continue;
if ( ! inst->rematerialize(_globalNames, get_registers()) ) continue;
fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");
++idx;
};
map.record_position(OutputMap::END_INST_CHAIN_RULES, idx );
}
{
_instructions.reset();
for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( inst->ideal_only() ) continue;
if ( inst->is_simple_chain_rule(_globalNames) ) continue;
if ( ! inst->rematerialize(_globalNames, get_registers()) ) continue;
fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");
++idx;
};
map.record_position(OutputMap::END_REMATERIALIZE, idx );
_instructions.reset();
for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( inst->ideal_only() ) continue;
if ( inst->is_simple_chain_rule(_globalNames) ) continue;
if ( inst->rematerialize(_globalNames, get_registers()) ) continue;
fprintf(fp_cpp, " /* %4d */", idx); map.map(*inst); fprintf(fp_cpp, ",\n");
++idx;
};
}
fprintf(fp_cpp, " // last instruction\n");
map.record_position(OutputMap::END_INSTRUCTIONS, idx );
}
map.closing();
};
char reg_save_policy(const char *calling_convention) {
char callconv;
if (!strcmp(calling_convention, "NS")) callconv = 'N';
else if (!strcmp(calling_convention, "SOE")) callconv = 'E';
else if (!strcmp(calling_convention, "SOC")) callconv = 'C';
else if (!strcmp(calling_convention, "AS")) callconv = 'A';
else callconv = 'Z';
return callconv;
}
void ArchDesc::generate_needs_clone_jvms(FILE *fp_cpp) {
fprintf(fp_cpp, "bool Compile::needs_clone_jvms() { return %s; }\n\n",
_needs_clone_jvms ? "true" : "false");
}
void ArchDesc::generate_adlc_verification(FILE *fp_cpp) {
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "#ifndef PRODUCT\n");
fprintf(fp_cpp, "void Compile::adlc_verification() {\n");
globalDefs().print_asserts(fp_cpp);
fprintf(fp_cpp, "}\n");
fprintf(fp_cpp, "#endif\n");
fprintf(fp_cpp, "\n");
}
void ArchDesc::addSourceBlocks(FILE *fp_cpp) {
if (_source.count() > 0)
_source.output(fp_cpp);
generate_adlc_verification(fp_cpp);
}
void ArchDesc::addHeaderBlocks(FILE *fp_hpp) {
if (_header.count() > 0)
_header.output(fp_hpp);
}
void ArchDesc::addPreHeaderBlocks(FILE *fp_hpp) {
globalDefs().print_defines(fp_hpp);
if (_pre_header.count() > 0)
_pre_header.output(fp_hpp);
}
void ArchDesc::buildReduceMaps(FILE *fp_hpp, FILE *fp_cpp) {
RegDef *rdef;
RegDef *next;
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "extern const char register_save_policy[];\n");
fprintf(fp_hpp, "extern const char c_reg_save_policy[];\n");
fprintf(fp_hpp, "extern const int register_save_type[];\n");
fprintf(fp_hpp, "\n");
fprintf(fp_cpp, "// Map from machine-independent register number to register_save_policy\n");
fprintf(fp_cpp, "const char register_save_policy[] = {\n");
_register->reset_RegDefs();
for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {
next = _register->iter_RegDefs();
char policy = reg_save_policy(rdef->_callconv);
const char *comma = (next != NULL) ? "," : " // no trailing comma";
fprintf(fp_cpp, " '%c'%s // %s\n", policy, comma, rdef->_regname);
}
fprintf(fp_cpp, "};\n\n");
fprintf(fp_cpp, "// Map from machine-independent register number to c_reg_save_policy\n");
fprintf(fp_cpp, "const char c_reg_save_policy[] = {\n");
_register->reset_RegDefs();
for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {
next = _register->iter_RegDefs();
char policy = reg_save_policy(rdef->_c_conv);
const char *comma = (next != NULL) ? "," : " // no trailing comma";
fprintf(fp_cpp, " '%c'%s // %s\n", policy, comma, rdef->_regname);
}
fprintf(fp_cpp, "};\n\n");
fprintf(fp_cpp, "// Map from machine-independent register number to register_save_type\n");
fprintf(fp_cpp, "const int register_save_type[] = {\n");
_register->reset_RegDefs();
for( rdef = _register->iter_RegDefs(); rdef != NULL; rdef = next ) {
next = _register->iter_RegDefs();
const char *comma = (next != NULL) ? "," : " // no trailing comma";
fprintf(fp_cpp, " %s%s\n", rdef->_idealtype, comma);
}
fprintf(fp_cpp, "};\n\n");
OutputReduceOp output_reduce_op(fp_hpp, fp_cpp, _globalNames, *this);
build_map(output_reduce_op);
OutputLeftOp output_left_op(fp_hpp, fp_cpp, _globalNames, *this);
build_map(output_left_op);
OutputRightOp output_right_op(fp_hpp, fp_cpp, _globalNames, *this);
build_map(output_right_op);
OutputRuleName output_rule_name(fp_hpp, fp_cpp, _globalNames, *this);
build_map(output_rule_name);
OutputSwallowed output_swallowed(fp_hpp, fp_cpp, _globalNames, *this);
build_map(output_swallowed);
}
static void path_to_constant(FILE *fp, FormDict &globals,
MatchNode *mnode, uint idx) {
if ( ! mnode) return;
unsigned position = 0;
const char *result = NULL;
const char *name = NULL;
const char *optype = NULL;
if ( (mnode->_lChild == NULL) && (mnode->_rChild == NULL)
&& mnode->base_operand(position, globals, result, name, optype) ) {
if ( strcmp(optype,"ConI") == 0 ) {
fprintf(fp, "_leaf->get_int()");
} else if ( (strcmp(optype,"ConP") == 0) ) {
fprintf(fp, "_leaf->bottom_type()->is_ptr()");
} else if ( (strcmp(optype,"ConN") == 0) ) {
fprintf(fp, "_leaf->bottom_type()->is_narrowoop()");
} else if ( (strcmp(optype,"ConNKlass") == 0) ) {
fprintf(fp, "_leaf->bottom_type()->is_narrowklass()");
} else if ( (strcmp(optype,"ConF") == 0) ) {
fprintf(fp, "_leaf->getf()");
} else if ( (strcmp(optype,"ConD") == 0) ) {
fprintf(fp, "_leaf->getd()");
} else if ( (strcmp(optype,"ConL") == 0) ) {
fprintf(fp, "_leaf->get_long()");
} else if ( (strcmp(optype,"Con")==0) ) {
fprintf(fp, "_leaf->get_int()");
assert( false, "Unsupported constant type, pointer or indefinite");
} else if ( (strcmp(optype,"Bool") == 0) ) {
fprintf(fp, "_leaf->as_Bool()->_test._test");
} else {
assert( false, "Unsupported constant type");
}
return;
}
uint lConsts = (mnode->_lChild) ? (mnode->_lChild->num_consts(globals) ) : 0;
uint rConsts = (mnode->_rChild) ? (mnode->_rChild->num_consts(globals) ) : 0;
if ( (mnode->_lChild) && (lConsts > idx) ) {
fprintf(fp, "_kids[0]->");
path_to_constant(fp, globals, mnode->_lChild, idx);
return;
}
if ( (mnode->_rChild) && (rConsts > (idx - lConsts) ) ) {
idx = idx - lConsts;
fprintf(fp, "_kids[1]->");
path_to_constant(fp, globals, mnode->_rChild, idx);
return;
}
assert( false, "ShouldNotReachHere()");
}
static void genMachOperCase(FILE *fp, FormDict &globalNames, ArchDesc &AD,
OperandForm &op) {
const char *opName = op._ident;
const char *opEnumName = AD.machOperEnum(opName);
uint num_consts = op.num_consts(globalNames);
fprintf(fp, " case %s:", opEnumName);
fprintf(fp, "\n return new (C) %sOper(", opName);
if ( (num_consts > 0) ) {
uint i = 0;
path_to_constant(fp, globalNames, op._matrule, i);
for ( i = 1; i < num_consts; ++i ) {
fprintf(fp, ", ");
path_to_constant(fp, globalNames, op._matrule, i);
}
}
fprintf(fp, " );\n");
}
void ArchDesc::buildMachOperGenerator(FILE *fp_cpp) {
int idx = 0;
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp,
"//------------------------- MachOper Generator ---------------\n");
fprintf(fp_cpp,
"// A switch statement on the dense-packed user-defined type system\n"
"// that invokes 'new' on the corresponding class constructor.\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "MachOper *State::MachOperGenerator");
fprintf(fp_cpp, "(int opcode, Compile* C)");
fprintf(fp_cpp, "{\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, " switch(opcode) {\n");
_operands.reset();
int opIndex = 0;
OperandForm *op;
for( ; (op = (OperandForm*)_operands.iter()) != NULL; ) {
if ( op->ideal_only() ) continue;
genMachOperCase(fp_cpp, _globalNames, *this, *op);
};
_internalOpNames.reset();
const char *iopn;
for( ; (iopn = _internalOpNames.iter()) != NULL; ) {
const char *opEnumName = machOperEnum(iopn);
fprintf(fp_cpp, " case %s:", opEnumName);
fprintf(fp_cpp, " return NULL;\n");
};
fprintf(fp_cpp, " \n");
fprintf(fp_cpp, " default:\n");
fprintf(fp_cpp, " fprintf(stderr, \"Default MachOper Generator invoked for: \\n\");\n");
fprintf(fp_cpp, " fprintf(stderr, \" opcode = %cd\\n\", opcode);\n", '%');
fprintf(fp_cpp, " break;\n");
fprintf(fp_cpp, " }\n");
fprintf(fp_cpp, " return NULL;\n");
fprintf(fp_cpp, "};\n");
}
void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *indent) {
const char *opType = NULL;
const char *opClass = inst->_ident;
fprintf(fp_cpp, "%s %sNode *node = new (C) %sNode();\n",indent, opClass,opClass);
if ( (inst->num_post_match_opnds() != 0) ) {
bool dont_care = false;
ComponentList &comp_list = inst->_components;
Component *comp = NULL;
comp_list.reset();
if ( comp_list.match_iter() != NULL ) dont_care = true;
comp_list.reset();
while ( comp = comp_list.post_match_iter() ) {
if ( dont_care && (! comp->isa(Component::USE)) ) {
continue;
}
dont_care = true;
ComponentList clist = inst->_components;
int index = clist.operand_position(comp->_name, comp->_usedef, inst);
const char *opcode = machOperEnum(comp->_type);
fprintf(fp_cpp, "%s node->set_opnd_array(%d, ", indent, index);
fprintf(fp_cpp, "MachOperGenerator(%s, C));\n", opcode);
}
}
else if ( inst->is_chain_of_constant(_globalNames, opType) ) {
fprintf(fp_cpp, "%s node->_opnd_array[%d] = ", indent,
inst->oper_input_base(_globalNames));
const char *opName = inst->_matrule->_rChild->_opType;
fprintf(fp_cpp, "new (C) %sOper(", opName);
OperandForm *op = (_globalNames[opName])->is_operand();
uint num_consts = op->num_consts(_globalNames);
if ( (num_consts > 0) ) {
uint i = 0;
path_to_constant(fp_cpp, _globalNames, op->_matrule, i);
for ( i = 1; i < num_consts; ++i ) {
fprintf(fp_cpp, ", ");
path_to_constant(fp_cpp, _globalNames, op->_matrule, i);
}
}
fprintf(fp_cpp, " );\n");
}
if (inst->captures_bottom_type(_globalNames)) {
if (strncmp("MachCall", inst->mach_base_class(_globalNames), strlen("MachCall"))) {
fprintf(fp_cpp, "%s node->_bottom_type = _leaf->bottom_type();\n", indent);
}
}
if( inst->is_ideal_if() ) {
fprintf(fp_cpp, "%s node->_prob = _leaf->as_If()->_prob;\n", indent);
fprintf(fp_cpp, "%s node->_fcnt = _leaf->as_If()->_fcnt;\n", indent);
}
if( inst->is_ideal_fastlock() ) {
fprintf(fp_cpp, "%s node->_counters = _leaf->as_FastLock()->counters();\n", indent);
fprintf(fp_cpp, "%s node->_rtm_counters = _leaf->as_FastLock()->rtm_counters();\n", indent);
fprintf(fp_cpp, "%s node->_stack_rtm_counters = _leaf->as_FastLock()->stack_rtm_counters();\n", indent);
}
}
void InstructForm::declare_cisc_version(ArchDesc &AD, FILE *fp_hpp) {
if( AD.can_cisc_spill() ) {
InstructForm *inst_cisc = cisc_spill_alternate();
if (inst_cisc != NULL) {
fprintf(fp_hpp, " virtual int cisc_operand() const { return %d; }\n", cisc_spill_operand());
fprintf(fp_hpp, " virtual MachNode *cisc_version(int offset, Compile* C);\n");
fprintf(fp_hpp, " virtual void use_cisc_RegMask();\n");
fprintf(fp_hpp, " virtual const RegMask *cisc_RegMask() const { return _cisc_RegMask; }\n");
}
}
}
bool InstructForm::define_cisc_version(ArchDesc &AD, FILE *fp_cpp) {
InstructForm *inst_cisc = this->cisc_spill_alternate();
if( AD.can_cisc_spill() && (inst_cisc != NULL) ) {
const char *name = inst_cisc->_ident;
assert( inst_cisc->num_opnds() == this->num_opnds(), "Must have same number of operands");
OperandForm *cisc_oper = AD.cisc_spill_operand();
assert( cisc_oper != NULL, "insanity check");
const char *cisc_oper_name = cisc_oper->_ident;
assert( cisc_oper_name != NULL, "insanity check");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "void %sNode::use_cisc_RegMask() {\n", this->_ident);
const char *reg_mask_name = cisc_reg_mask_name();
fprintf(fp_cpp, " _cisc_RegMask = &STACK_OR_%s;\n", reg_mask_name);
fprintf(fp_cpp, "}\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "// Build CISC version of this instruction\n");
fprintf(fp_cpp, "MachNode *%sNode::cisc_version( int offset, Compile* C ) {\n", this->_ident);
fprintf(fp_cpp, " %sNode *node = new (C) %sNode();\n", name, name);
if ( this->captures_bottom_type(AD.globalNames()) ) {
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
}
uint cur_num_opnds = num_opnds();
if (cur_num_opnds > 1 && cur_num_opnds != num_unique_opnds()) {
fprintf(fp_cpp," node->_num_opnds = %d;\n", num_unique_opnds());
}
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n");
fprintf(fp_cpp, " fill_new_machnode(node, C);\n");
fprintf(fp_cpp, " // Construct operand to access [stack_pointer + offset]\n");
fprintf(fp_cpp, " node->set_opnd_array(cisc_operand(), new (C) %sOper(offset));\n", cisc_oper_name);
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, " return node;\n");
fprintf(fp_cpp, "}\n");
fprintf(fp_cpp, "\n");
return true;
}
return false;
}
void InstructForm::declare_short_branch_methods(FILE *fp_hpp) {
if (has_short_branch_form()) {
fprintf(fp_hpp, " virtual MachNode *short_branch_version(Compile* C);\n");
}
}
bool InstructForm::define_short_branch_methods(ArchDesc &AD, FILE *fp_cpp) {
if (has_short_branch_form()) {
InstructForm *short_branch = short_branch_form();
const char *name = short_branch->_ident;
fprintf(fp_cpp, "// Build short branch version of this instruction\n");
fprintf(fp_cpp, "MachNode *%sNode::short_branch_version(Compile* C) {\n", this->_ident);
fprintf(fp_cpp, " %sNode *node = new (C) %sNode();\n", name, name);
if( is_ideal_if() ) {
fprintf(fp_cpp, " node->_prob = _prob;\n");
fprintf(fp_cpp, " node->_fcnt = _fcnt;\n");
}
if ( this->captures_bottom_type(AD.globalNames()) ) {
fprintf(fp_cpp, " node->_bottom_type = bottom_type();\n");
}
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, " // Copy _idx, inputs and operands to new node\n");
fprintf(fp_cpp, " fill_new_machnode(node, C);\n");
fprintf(fp_cpp, " return node;\n");
fprintf(fp_cpp, "}\n");
fprintf(fp_cpp,"\n");
return true;
}
return false;
}
void ArchDesc::buildMachNodeGenerator(FILE *fp_cpp) {
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp,
"//------------------------- MachNode Generator ---------------\n");
fprintf(fp_cpp,
"// A switch statement on the dense-packed user-defined type system\n"
"// that invokes 'new' on the corresponding class constructor.\n");
fprintf(fp_cpp, "\n");
fprintf(fp_cpp, "MachNode *State::MachNodeGenerator");
fprintf(fp_cpp, "(int opcode, Compile* C)");
fprintf(fp_cpp, "{\n");
fprintf(fp_cpp, " switch(opcode) {\n");
_instructions.reset();
int opIndex = operandFormCount();
InstructForm *inst;
for( ; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( inst->_matrule == NULL ) continue;
int opcode = opIndex++;
const char *opClass = inst->_ident;
char *opType = NULL;
fprintf(fp_cpp, " case %s_rule:", opClass);
fprintf(fp_cpp, " {\n");
buildMachNode(fp_cpp, inst, " ");
fprintf(fp_cpp, " return node;\n");
fprintf(fp_cpp, " }\n");
}
fprintf(fp_cpp, " \n");
fprintf(fp_cpp, " default:\n");
fprintf(fp_cpp, " fprintf(stderr, \"Default MachNode Generator invoked for: \\n\");\n");
fprintf(fp_cpp, " fprintf(stderr, \" opcode = %cd\\n\", opcode);\n", '%');
fprintf(fp_cpp, " break;\n");
fprintf(fp_cpp, " };\n");
fprintf(fp_cpp, " return NULL;\n");
fprintf(fp_cpp, "}\n");
}
void ArchDesc::buildInstructMatchCheck(FILE *fp_cpp) const {
fprintf(fp_cpp, "\n\n");
fprintf(fp_cpp, "const bool Matcher::has_match_rule(int opcode) {\n");
fprintf(fp_cpp, " assert(_last_machine_leaf < opcode && opcode < _last_opcode, \"opcode in range\");\n");
fprintf(fp_cpp, " return _hasMatchRule[opcode];\n");
fprintf(fp_cpp, "}\n\n");
fprintf(fp_cpp, "const bool Matcher::_hasMatchRule[_last_opcode] = {\n");
int i;
for (i = 0; i < _last_opcode - 1; i++) {
fprintf(fp_cpp, " %-5s, // %s\n",
_has_match_rule[i] ? "true" : "false",
NodeClassNames[i]);
}
fprintf(fp_cpp, " %-5s // %s\n",
_has_match_rule[i] ? "true" : "false",
NodeClassNames[i]);
fprintf(fp_cpp, "};\n");
}
void ArchDesc::buildFrameMethods(FILE *fp_cpp) {
fprintf(fp_cpp,"\n\n");
fprintf(fp_cpp,"bool Matcher::stack_direction() const { return %s; }\n\n",
_frame->_direction ? "true" : "false");
fprintf(fp_cpp,"int Compile::sync_stack_slots() const { return %s; }\n\n",
_frame->_sync_stack_slots);
fprintf(fp_cpp,"uint Matcher::stack_alignment_in_bytes() { return %s; }\n\n",
_frame->_alignment);
fprintf(fp_cpp,"OptoReg::Name Matcher::return_addr() const {");
if (_frame->_return_addr_loc) {
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_return_addr);
}
else {
fprintf(fp_cpp," return OptoReg::stack2reg(%s); }\n\n",
_frame->_return_addr);
}
fprintf(fp_cpp,"uint Compile::in_preserve_stack_slots() ");
fprintf(fp_cpp,"{ return %s; }\n\n", _frame->_in_preserve_slots);
fprintf(fp_cpp,"uint Compile::out_preserve_stack_slots() ");
fprintf(fp_cpp,"{ return SharedRuntime::out_preserve_stack_slots(); }\n\n");
fprintf(fp_cpp,"uint Compile::varargs_C_out_slots_killed() const ");
fprintf(fp_cpp,"{ return %s; }\n\n", _frame->_varargs_C_out_slots_killed);
fprintf(fp_cpp,"void Matcher::calling_convention(BasicType *sig_bt, VMRegPair *regs, uint length, bool is_outgoing) {\n");
fprintf(fp_cpp,"%s\n", _frame->_calling_convention);
fprintf(fp_cpp,"}\n\n");
fprintf(fp_cpp,"void Matcher::c_calling_convention(BasicType *sig_bt, VMRegPair *regs, uint length) {\n");
fprintf(fp_cpp,"%s\n", _frame->_c_calling_convention);
fprintf(fp_cpp,"}\n\n");
fprintf(fp_cpp,"OptoRegPair Matcher::return_value(uint ideal_reg, bool is_outgoing) {\n");
fprintf(fp_cpp,"%s\n", _frame->_return_value);
fprintf(fp_cpp,"}\n\n");
fprintf(fp_cpp,"OptoRegPair Matcher::c_return_value(uint ideal_reg, bool is_outgoing) {\n");
fprintf(fp_cpp,"%s\n", _frame->_c_return_value);
fprintf(fp_cpp,"}\n\n");
fprintf(fp_cpp,"OptoReg::Name Matcher::inline_cache_reg() {");
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_inline_cache_reg);
fprintf(fp_cpp,"int Matcher::inline_cache_reg_encode() {");
fprintf(fp_cpp," return _regEncode[inline_cache_reg()]; }\n\n");
fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_method_oop_reg() {");
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_interpreter_method_oop_reg);
fprintf(fp_cpp,"int Matcher::interpreter_method_oop_reg_encode() {");
fprintf(fp_cpp," return _regEncode[interpreter_method_oop_reg()]; }\n\n");
fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_frame_pointer_reg() {");
if (_frame->_interpreter_frame_pointer_reg == NULL)
fprintf(fp_cpp," return OptoReg::Bad; }\n\n");
else
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_interpreter_frame_pointer_reg);
Java and native code; makes my head hurt to think about it.
fprintf(fp_cpp,"OptoReg::Name Matcher::frame_pointer() const {");
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_frame_pointer);
fprintf(fp_cpp,"OptoReg::Name Matcher::c_frame_pointer() const {");
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_frame_pointer);
fprintf(fp_cpp, "// Number of callee-save + always-save registers\n");
fprintf(fp_cpp, "int Matcher::number_of_saved_registers() {\n");
RegDef *rdef;
int nof_saved_registers = 0;
_register->reset_RegDefs();
while( (rdef = _register->iter_RegDefs()) != NULL ) {
if( !strcmp(rdef->_callconv, "SOE") || !strcmp(rdef->_callconv, "AS") )
++nof_saved_registers;
}
fprintf(fp_cpp, " return %d;\n", nof_saved_registers);
fprintf(fp_cpp, "};\n\n");
}
static int PrintAdlcCisc = 0;
void ArchDesc::identify_cisc_spill_instructions() {
if (_frame == NULL)
return;
if( _frame->_cisc_spilling_operand_name != NULL ) {
const Form *form = _globalNames[_frame->_cisc_spilling_operand_name];
OperandForm *oper = form ? form->is_operand() : NULL;
if( oper != NULL ) {
if ( oper->_matrule != NULL ) {
MatchRule &mrule = *oper->_matrule;
if( strcmp(mrule._opType,"AddP") == 0 ) {
MatchNode *left = mrule._lChild;
MatchNode *right= mrule._rChild;
if( left != NULL && right != NULL ) {
const Form *left_op = _globalNames[left->_opType]->is_operand();
const Form *right_op = _globalNames[right->_opType]->is_operand();
if( (left_op != NULL && right_op != NULL)
&& (left_op->interface_type(_globalNames) == Form::register_interface)
&& (right_op->interface_type(_globalNames) == Form::constant_interface) ) {
set_cisc_spill_operand( oper );
if( _cisc_spill_debug ) {
fprintf(stderr, "\n\nVerified CISC-spill operand %s\n\n", oper->_ident);
}
}
}
}
}
}
}
if( cisc_spill_operand() != NULL ) {
_instructions.reset();
InstructForm *instr;
for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( instr->_matrule == NULL ) continue;
MatchRule &mrule = *instr->_matrule;
Predicate *pred = instr->build_predicate();
const char *rootOp = instr->_ident;
mrule._machType = rootOp;
const char *result = instr->reduce_result();
if( PrintAdlcCisc ) fprintf(stderr, " new instruction %s \n", instr->_ident ? instr->_ident : " ");
bool found_cisc_alternate = false;
_instructions.reset2();
InstructForm *instr2;
for( ; !found_cisc_alternate && (instr2 = (InstructForm*)_instructions.iter2()) != NULL; ) {
if( PrintAdlcCisc ) fprintf(stderr, " instr2 == %s \n", instr2->_ident ? instr2->_ident : " ");
if ( instr2->_matrule != NULL
&& (instr != instr2 ) // Skip self
&& (instr2->reduce_result() != NULL) // want same result
&& (strcmp(result, instr2->reduce_result()) == 0)) {
MatchRule &mrule2 = *instr2->_matrule;
Predicate *pred2 = instr2->build_predicate();
found_cisc_alternate = instr->cisc_spills_to(*this, instr2);
}
}
}
}
}
void ArchDesc::build_cisc_spill_instructions(FILE *fp_hpp, FILE *fp_cpp) {
fprintf(fp_cpp, "// The following instructions can cisc-spill\n");
_instructions.reset();
InstructForm *inst = NULL;
for(; (inst = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( inst->ideal_only() ) continue;
const char *inst_name = inst->_ident;
int operand = inst->cisc_spill_operand();
if( operand != AdlcVMDeps::Not_cisc_spillable ) {
InstructForm *inst2 = inst->cisc_spill_alternate();
fprintf(fp_cpp, "// %s can cisc-spill operand %d to %s\n", inst->_ident, operand, inst2->_ident);
}
}
fprintf(fp_cpp, "\n\n");
}
void ArchDesc::identify_short_branches() {
_instructions.reset();
InstructForm *instr;
while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {
if (instr->_matrule != NULL &&
instr->is_short_branch()) {
_instructions.reset2();
InstructForm *instr2;
while( (instr2 = (InstructForm*)_instructions.iter2()) != NULL ) {
instr2->check_branch_variant(*this, instr);
}
}
}
}
void ArchDesc::identify_unique_operands() {
_instructions.reset();
InstructForm *instr;
while( (instr = (InstructForm*)_instructions.iter()) != NULL ) {
if (!instr->ideal_only()) {
instr->set_unique_opnds();
}
}
}
C:\hotspot-69087d08d473\src\share\vm/adlc/output_h.cpp
#include "adlc.hpp"
#if defined(PPC64)
#define commentSeperator "\t//"
#else
#define commentSeperator "!"
#endif
static void defineRegCount(FILE *fp, RegisterForm *registers) {
if (registers) {
int regCount = AdlcVMDeps::Physical + registers->_rdefs.count();
fprintf(fp,"\n");
fprintf(fp,"// the number of reserved registers + machine registers.\n");
fprintf(fp,"#define REG_COUNT %d\n", regCount);
}
}
void ArchDesc::buildMachRegisterNumbers(FILE *fp_hpp) {
if (_register) {
RegDef *reg_def = NULL;
defineRegCount(fp_hpp, _register);
int saved_on_entry = 0;
int c_saved_on_entry = 0;
_register->reset_RegDefs();
while( (reg_def = _register->iter_RegDefs()) != NULL ) {
if( strcmp(reg_def->_callconv,"SOE") == 0 ||
strcmp(reg_def->_callconv,"AS") == 0 ) ++saved_on_entry;
if( strcmp(reg_def->_c_conv,"SOE") == 0 ||
strcmp(reg_def->_c_conv,"AS") == 0 ) ++c_saved_on_entry;
}
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "// the number of save_on_entry + always_saved registers.\n");
fprintf(fp_hpp, "#define MAX_SAVED_ON_ENTRY_REG_COUNT %d\n", max(saved_on_entry,c_saved_on_entry));
fprintf(fp_hpp, "#define SAVED_ON_ENTRY_REG_COUNT %d\n", saved_on_entry);
fprintf(fp_hpp, "#define C_SAVED_ON_ENTRY_REG_COUNT %d\n", c_saved_on_entry);
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "// Enumerate machine register numbers starting after reserved regs.\n");
fprintf(fp_hpp, "// in the order of occurrence in the register block.\n");
fprintf(fp_hpp, "enum MachRegisterNumbers {\n");
_register->reset_RegDefs();
int i = 0;
while( (reg_def = _register->iter_RegDefs()) != NULL ) {
fprintf(fp_hpp," %s_num,", reg_def->_regname);
for (int j = 0; j < 20-(int)strlen(reg_def->_regname); j++) fprintf(fp_hpp, " ");
fprintf(fp_hpp," // enum %3d, regnum %3d, reg encode %3s\n",
i++,
reg_def->register_num(),
reg_def->register_encode());
}
fprintf(fp_hpp, " _last_Mach_Reg // %d\n", i);
fprintf(fp_hpp, "};\n");
}
fprintf(fp_hpp, "\n// Size of register-mask in ints\n");
fprintf(fp_hpp, "#define RM_SIZE %d\n",RegisterForm::RegMask_Size());
fprintf(fp_hpp, "// Unroll factor for loops over the data in a RegMask\n");
fprintf(fp_hpp, "#define FORALL_BODY ");
int len = RegisterForm::RegMask_Size();
for( int i = 0; i < len; i++ )
fprintf(fp_hpp, "BODY(%d) ",i);
fprintf(fp_hpp, "\n\n");
fprintf(fp_hpp,"class RegMask;\n");
}
void ArchDesc::buildMachRegisterEncodes(FILE *fp_hpp) {
if (_register) {
RegDef *reg_def = NULL;
RegDef *reg_def_next = NULL;
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "// Enumerate machine registers starting after reserved regs.\n");
fprintf(fp_hpp, "// in the order of occurrence in the alloc_class(es).\n");
fprintf(fp_hpp, "enum MachRegisterEncodes {\n");
size_t maxlen = 0;
_register->reset_RegDefs();
reg_def = _register->iter_RegDefs();
while (reg_def != NULL) {
size_t len = strlen(reg_def->_regname);
if (len > maxlen) maxlen = len;
reg_def = _register->iter_RegDefs();
}
_register->reset_RegDefs();
reg_def_next = _register->iter_RegDefs();
while( (reg_def = reg_def_next) != NULL ) {
reg_def_next = _register->iter_RegDefs();
fprintf(fp_hpp," %s_enc", reg_def->_regname);
for (size_t i = strlen(reg_def->_regname); i < maxlen; i++) fprintf(fp_hpp, " ");
fprintf(fp_hpp," = %3s%s\n", reg_def->register_encode(), reg_def_next == NULL? "" : "," );
}
fprintf(fp_hpp, "};\n");
} // Done with register form
}
static void declareRegNames(FILE *fp, RegisterForm *registers) {
if (registers) {
}
}
void ArchDesc::declareRegSizes(FILE *fp) {
}
static void declareRegEncodes(FILE *fp, RegisterForm *registers) {
if (registers) {
}
}
static void out_RegMask(FILE *fp) {
fprintf(fp," virtual const RegMask &out_RegMask() const;\n");
}
static void in_RegMask(FILE *fp) {
fprintf(fp," virtual const RegMask *in_RegMask(int index) const;\n");
}
static void declareConstStorage(FILE *fp, FormDict &globals, OperandForm *oper) {
int i = 0;
Component *comp;
if (oper->num_consts(globals) == 0) return;
oper->_components.reset();
if ((comp = oper->_components.iter()) == NULL) {
assert(oper->num_consts(globals) == 1, "Bad component list detected.\n");
const char *type = oper->ideal_type(globals);
if (!strcmp(type, "ConI")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," int32 _c%d;\n", i);
}
else if (!strcmp(type, "ConP")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," const TypePtr *_c%d;\n", i);
}
else if (!strcmp(type, "ConN")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," const TypeNarrowOop *_c%d;\n", i);
}
else if (!strcmp(type, "ConNKlass")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," const TypeNarrowKlass *_c%d;\n", i);
}
else if (!strcmp(type, "ConL")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," jlong _c%d;\n", i);
}
else if (!strcmp(type, "ConF")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," jfloat _c%d;\n", i);
}
else if (!strcmp(type, "ConD")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp," jdouble _c%d;\n", i);
}
else if (!strcmp(type, "Bool")) {
fprintf(fp,"private:\n");
fprintf(fp," BoolTest::mask _c%d;\n", i);
fprintf(fp,"public:\n");
}
else {
assert(0, "Non-constant operand lacks component list.");
}
} // end if NULL
else {
oper->_components.reset();
while ((comp = oper->_components.iter()) != NULL) {
if (!strcmp(comp->base_type(globals), "ConI")) {
fprintf(fp," jint _c%d;\n", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConP")) {
fprintf(fp," const TypePtr *_c%d;\n", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConN")) {
fprintf(fp," const TypePtr *_c%d;\n", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConNKlass")) {
fprintf(fp," const TypePtr *_c%d;\n", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConL")) {
fprintf(fp," jlong _c%d;\n", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConF")) {
fprintf(fp," jfloat _c%d;\n", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConD")) {
fprintf(fp," jdouble _c%d;\n", i);
i++;
}
}
}
}
static void defineConstructor(FILE *fp, const char *name, uint num_consts,
ComponentList &lst, bool is_ideal_bool,
Form::DataType constant_type, FormDict &globals) {
fprintf(fp,"public:\n");
fprintf(fp," %sOper(", name);
if( num_consts == 0 ) {
fprintf(fp,") {}\n");
return;
}
uint i = 0;
Component *comp;
lst.reset();
if ((comp = lst.iter()) == NULL) {
assert(num_consts == 1, "Bad component list detected.\n");
switch( constant_type ) {
case Form::idealI : {
fprintf(fp,is_ideal_bool ? "BoolTest::mask c%d" : "int32 c%d", i);
break;
}
case Form::idealN : { fprintf(fp,"const TypeNarrowOop *c%d", i); break; }
case Form::idealNKlass : { fprintf(fp,"const TypeNarrowKlass *c%d", i); break; }
case Form::idealP : { fprintf(fp,"const TypePtr *c%d", i); break; }
case Form::idealL : { fprintf(fp,"jlong c%d", i); break; }
case Form::idealF : { fprintf(fp,"jfloat c%d", i); break; }
case Form::idealD : { fprintf(fp,"jdouble c%d", i); break; }
default:
assert(!is_ideal_bool, "Non-constant operand lacks component list.");
break;
}
} // end if NULL
else {
lst.reset();
while((comp = lst.iter()) != NULL) {
if (!strcmp(comp->base_type(globals), "ConI")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"int32 c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConP")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"const TypePtr *c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConN")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"const TypePtr *c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConNKlass")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"const TypePtr *c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConL")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"jlong c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConF")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"jfloat c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "ConD")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"jdouble c%d", i);
i++;
}
else if (!strcmp(comp->base_type(globals), "Bool")) {
if (i > 0) fprintf(fp,", ");
fprintf(fp,"BoolTest::mask c%d", i);
i++;
}
}
}
fprintf(fp,") : ");
i = 0;
fprintf(fp,"_c%d(c%d)", i, i);
for( i = 1; i < num_consts; ++i) {
fprintf(fp,", _c%d(c%d)", i, i);
}
fprintf(fp," {}\n");
}
static void defineCCodeDump(OperandForm* oper, FILE *fp, int i) {
assert(oper != NULL, "what");
CondInterface* cond = oper->_interface->is_CondInterface();
fprintf(fp, " if( _c%d == BoolTest::eq ) st->print_raw(\"%s\");\n",i,cond->_equal_format);
fprintf(fp, " else if( _c%d == BoolTest::ne ) st->print_raw(\"%s\");\n",i,cond->_not_equal_format);
fprintf(fp, " else if( _c%d == BoolTest::le ) st->print_raw(\"%s\");\n",i,cond->_less_equal_format);
fprintf(fp, " else if( _c%d == BoolTest::ge ) st->print_raw(\"%s\");\n",i,cond->_greater_equal_format);
fprintf(fp, " else if( _c%d == BoolTest::lt ) st->print_raw(\"%s\");\n",i,cond->_less_format);
fprintf(fp, " else if( _c%d == BoolTest::gt ) st->print_raw(\"%s\");\n",i,cond->_greater_format);
fprintf(fp, " else if( _c%d == BoolTest::overflow ) st->print_raw(\"%s\");\n",i,cond->_overflow_format);
fprintf(fp, " else if( _c%d == BoolTest::no_overflow ) st->print_raw(\"%s\");\n",i,cond->_no_overflow_format);
}
static uint dump_spec_constant(FILE *fp, const char *ideal_type, uint i, OperandForm* oper) {
if (!strcmp(ideal_type, "ConI")) {
fprintf(fp," st->print(\"#%%d\", _c%d);\n", i);
fprintf(fp," st->print(\"/0x%%08x\", _c%d);\n", i);
++i;
}
else if (!strcmp(ideal_type, "ConP")) {
fprintf(fp," _c%d->dump_on(st);\n", i);
++i;
}
else if (!strcmp(ideal_type, "ConN")) {
fprintf(fp," _c%d->dump_on(st);\n", i);
++i;
}
else if (!strcmp(ideal_type, "ConNKlass")) {
fprintf(fp," _c%d->dump_on(st);\n", i);
++i;
}
else if (!strcmp(ideal_type, "ConL")) {
fprintf(fp," st->print(\"#\" INT64_FORMAT, (int64_t)_c%d);\n", i);
fprintf(fp," st->print(\"/\" PTR64_FORMAT, (uint64_t)_c%d);\n", i);
++i;
}
else if (!strcmp(ideal_type, "ConF")) {
fprintf(fp," st->print(\"#%%f\", _c%d);\n", i);
fprintf(fp," jint _c%di = JavaValue(_c%d).get_jint();\n", i, i);
fprintf(fp," st->print(\"/0x%%x/\", _c%di);\n", i);
++i;
}
else if (!strcmp(ideal_type, "ConD")) {
fprintf(fp," st->print(\"#%%f\", _c%d);\n", i);
fprintf(fp," jlong _c%dl = JavaValue(_c%d).get_jlong();\n", i, i);
fprintf(fp," st->print(\"/\" PTR64_FORMAT, (uint64_t)_c%dl);\n", i);
++i;
}
else if (!strcmp(ideal_type, "Bool")) {
defineCCodeDump(oper, fp,i);
++i;
}
return i;
}
void gen_oper_format(FILE *fp, FormDict &globals, OperandForm &oper, bool for_c_file = false) {
if (!for_c_file) {
fprintf(fp," virtual void int_format(PhaseRegAlloc *ra, const MachNode *node, outputStream *st) const;\n");
fprintf(fp," virtual void ext_format(PhaseRegAlloc *ra, const MachNode *node, int idx, outputStream *st) const;\n");
return;
}
int idx = 0; // position of operand in match rule
fprintf(fp, "\n#ifndef PRODUCT\n");
fprintf(fp,"void %sOper::int_format(PhaseRegAlloc *ra, const MachNode *node, outputStream *st) const {\n", oper._ident);
if (oper._format) {
if ( oper._format->_strings.count() != 0 ) {
const char *string = NULL;
oper._format->_rep_vars.reset();
oper._format->_strings.reset();
while ( (string = oper._format->_strings.iter()) != NULL ) {
if ( string != NameList::_signal ) {
fprintf(fp," st->print_raw(\"%s\");\n", string);
} else {
const char *rep_var = oper._format->_rep_vars.iter();
const Form* form = oper._localNames[rep_var];
if (form == NULL) {
globalAD->syntax_err(oper._linenum,
"\'%s\' not found in format for %s\n", rep_var, oper._ident);
assert(form, "replacement variable was not found in local names");
}
OperandForm *op = form->is_operand();
if ( op->_matrule && op->_matrule->is_base_register(globals) ) {
idx = oper.register_position( globals, rep_var);
}
else if (op->_matrule && op->_matrule->is_base_constant(globals)) {
idx = oper.constant_position( globals, rep_var);
} else {
idx = 0;
}
if ( op != NULL ) op->int_format(fp, globals, idx);
if ( idx == -1 ) {
fprintf(stderr,
"Using a name, %s, that isn't in match rule\n", rep_var);
assert( strcmp(op->_ident,"label")==0, "Unimplemented");
}
} // Done with a replacement variable
} // Done with all format strings
} else {
oper.int_format(fp, globals, 0);
}
} else { // oper._format == NULL
if ( strcmp(oper._ident,"Universe")==0 ) {
fprintf(fp, " st->print(\"$$univ\");\n");
}
}
if( oper.is_ideal_bool() ) {
defineCCodeDump(&oper, fp,0);
}
fprintf(fp,"}\n");
fprintf(fp,"void %sOper::ext_format(PhaseRegAlloc *ra, const MachNode *node, int idx, outputStream *st) const {\n", oper._ident);
if (oper._format) {
if ( oper._format->_strings.count() != 0 ) {
if ( oper._format->_rep_vars.count() != 0 ) {
}
const char *string = NULL;
oper._format->_rep_vars.reset();
oper._format->_strings.reset();
while ( (string = oper._format->_strings.iter()) != NULL ) {
if ( string != NameList::_signal ) {
fprintf(fp," st->print_raw(\"%s\");\n", string);
} else {
const char *rep_var = oper._format->_rep_vars.iter();
const Form* form = oper._localNames[rep_var];
if (form == NULL) {
globalAD->syntax_err(oper._linenum,
"\'%s\' not found in format for %s\n", rep_var, oper._ident);
assert(form, "replacement variable was not found in local names");
}
OperandForm *op = form->is_operand();
if ( op->_matrule && op->_matrule->is_base_register(globals) ) {
idx = oper.register_position( globals, rep_var);
}
else if (op->_matrule && op->_matrule->is_base_constant(globals)) {
idx = oper.constant_position( globals, rep_var);
} else {
idx = 0;
}
if ( op != NULL ) op->ext_format(fp, globals, idx);
idx = oper._components.operand_position_format(rep_var, &oper);
if ( idx == -1 ) {
fprintf(stderr,
"Using a name, %s, that isn't in match rule\n", rep_var);
assert( strcmp(op->_ident,"label")==0, "Unimplemented");
}
} // Done with a replacement variable
} // Done with all format strings
} else {
oper.ext_format(fp, globals, 0);
}
} else { // oper._format == NULL
if ( strcmp(oper._ident,"Universe")==0 ) {
fprintf(fp, " st->print(\"$$univ\");\n");
}
}
if( oper.is_ideal_bool() ) {
defineCCodeDump(&oper, fp,0);
}
fprintf(fp, "}\n");
fprintf(fp, "#endif\n");
}
void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &inst, bool for_c_file = false) {
if (!for_c_file) {
fprintf(fp," virtual void format(PhaseRegAlloc *ra, outputStream *st) const;\n");
return;
}
fprintf(fp, "#ifndef PRODUCT\n");
fprintf(fp, "void %sNode::format(PhaseRegAlloc *ra, outputStream *st) const {\n", inst._ident);
if( inst._format ) {
if( inst._format->_rep_vars.count() )
inst.index_temps(fp, globals);
const char *string = NULL;
inst._format->_rep_vars.reset();
inst._format->_strings.reset();
while( (string = inst._format->_strings.iter()) != NULL ) {
fprintf(fp," ");
if( string == NameList::_signal ) { // Replacement variable
const char* rep_var = inst._format->_rep_vars.iter();
inst.rep_var_format( fp, rep_var);
} else if( string == NameList::_signal3 ) { // Replacement variable in raw text
const char* rep_var = inst._format->_rep_vars.iter();
const Form *form = inst._localNames[rep_var];
if (form == NULL) {
fprintf(stderr, "unknown replacement variable in format statement: '%s'\n", rep_var);
assert(false, "ShouldNotReachHere()");
}
OpClassForm *opc = form->is_opclass();
assert( opc, "replacement variable was not found in local names");
int idx = inst.operand_position_format(rep_var);
if ( idx == -1 ) {
assert( strcmp(opc->_ident,"label")==0, "Unimplemented");
assert( false, "ShouldNotReachHere()");
}
if (inst.is_noninput_operand(idx)) {
assert( false, "ShouldNotReachHere()");
} else {
fprintf(fp,"opnd_array(%d)",idx);
}
rep_var = inst._format->_rep_vars.iter();
inst._format->_strings.iter();
if ( strcmp(rep_var,"$constant") == 0 && opc->is_operand()) {
Form::DataType constant_type = form->is_operand()->is_base_constant(globals);
if ( constant_type == Form::idealD ) {
fprintf(fp,"->constantD()");
} else if ( constant_type == Form::idealF ) {
fprintf(fp,"->constantF()");
} else if ( constant_type == Form::idealL ) {
fprintf(fp,"->constantL()");
} else {
fprintf(fp,"->constant()");
}
} else if ( strcmp(rep_var,"$cmpcode") == 0) {
fprintf(fp,"->ccode()");
} else {
assert( false, "ShouldNotReachHere()");
}
} else if( string == NameList::_signal2 ) // Raw program text
fputs(inst._format->_strings.iter(), fp);
else
fprintf(fp,"st->print_raw(\"%s\");\n", string);
} // Done with all format strings
} // Done generating the user-defined portion of the format
Form::CallType call_type = inst.is_ideal_call();
if( call_type != Form::invalid_type ) {
switch( call_type ) {
case Form::JAVA_DYNAMIC:
fprintf(fp," _method->print_short_name(st);\n");
break;
case Form::JAVA_STATIC:
fprintf(fp," if( _method ) _method->print_short_name(st);\n");
fprintf(fp," else st->print(\" wrapper for: %%s\", _name);\n");
fprintf(fp," if( !_method ) dump_trap_args(st);\n");
break;
case Form::JAVA_COMPILED:
case Form::JAVA_INTERP:
break;
case Form::JAVA_RUNTIME:
case Form::JAVA_LEAF:
case Form::JAVA_NATIVE:
fprintf(fp," st->print(\" %%s\", _name);");
break;
default:
assert(0,"ShouldNotReachHere");
}
fprintf(fp, " st->cr();\n" );
fprintf(fp, " if (_jvms) _jvms->format(ra, this, st); else st->print_cr(\" No JVM State Info\");\n" );
fprintf(fp, " st->print(\" # \");\n" );
fprintf(fp, " if( _jvms && _oop_map ) _oop_map->print_on(st);\n");
}
else if(inst.is_ideal_safepoint()) {
fprintf(fp, " st->print_raw(\"\");\n" );
fprintf(fp, " if (_jvms) _jvms->format(ra, this, st); else st->print_cr(\" No JVM State Info\");\n" );
fprintf(fp, " st->print(\" # \");\n" );
fprintf(fp, " if( _jvms && _oop_map ) _oop_map->print_on(st);\n");
}
else if( inst.is_ideal_if() ) {
fprintf(fp, " st->print(\" P=%%f C=%%f\",_prob,_fcnt);\n" );
}
else if( inst.is_ideal_mem() ) {
fprintf(fp, " if (ra->C->alias_type(adr_type())->field() != NULL) {\n");
fprintf(fp, " ciField* f = ra->C->alias_type(adr_type())->field();\n");
fprintf(fp, " st->print(\" %s Field: \");\n", commentSeperator);
fprintf(fp, " if (f->is_volatile())\n");
fprintf(fp, " st->print(\"volatile \");\n");
fprintf(fp, " f->holder()->name()->print_symbol_on(st);\n");
fprintf(fp, " st->print(\".\");\n");
fprintf(fp, " f->name()->print_symbol_on(st);\n");
fprintf(fp, " if (f->is_constant())\n");
fprintf(fp, " st->print(\" (constant)\");\n");
fprintf(fp, " } else {\n");
fprintf(fp, " if (ra->C->alias_type(adr_type())->is_volatile())\n");
fprintf(fp, " st->print(\" volatile!\");\n");
fprintf(fp, " }\n");
}
fprintf(fp, "}\n#endif\n");
}
void ArchDesc::declare_pipe_classes(FILE *fp_hpp) {
if (!_pipeline)
return;
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "// Pipeline_Use_Cycle_Mask Class\n");
fprintf(fp_hpp, "class Pipeline_Use_Cycle_Mask {\n");
if (_pipeline->_maxcycleused <=
#ifdef SPARC
64
#else
32
#endif
) {
fprintf(fp_hpp, "protected:\n");
fprintf(fp_hpp, " %s _mask;\n\n", _pipeline->_maxcycleused <= 32 ? "uint" : "uint64_t" );
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask() : _mask(0) {}\n\n");
if (_pipeline->_maxcycleused <= 32)
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask) : _mask(mask) {}\n\n");
else {
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask1, uint mask2) : _mask((((uint64_t)mask1) << 32) | mask2) {}\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint64_t mask) : _mask(mask) {}\n\n");
}
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator=(const Pipeline_Use_Cycle_Mask &in) {\n");
fprintf(fp_hpp, " _mask = in._mask;\n");
fprintf(fp_hpp, " return *this;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n");
fprintf(fp_hpp, " return ((_mask & in2._mask) != 0);\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n");
fprintf(fp_hpp, " _mask <<= n;\n");
fprintf(fp_hpp, " return *this;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " void Or(const Pipeline_Use_Cycle_Mask &in2) {\n");
fprintf(fp_hpp, " _mask |= in2._mask;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " friend Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &, const Pipeline_Use_Cycle_Mask &);\n");
fprintf(fp_hpp, " friend Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &, const Pipeline_Use_Cycle_Mask &);\n\n");
}
else {
fprintf(fp_hpp, "protected:\n");
uint masklen = (_pipeline->_maxcycleused + 31) >> 5;
uint l;
fprintf(fp_hpp, " uint ");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "_mask%d%s", l, l < masklen ? ", " : ";\n\n");
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask() : ");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "_mask%d(0)%s", l, l < masklen ? ", " : " {}\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "uint mask%d%s", l, l < masklen ? ", " : ") : ");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "_mask%d(mask%d)%s", l, l, l < masklen ? ", " : " {}\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator=(const Pipeline_Use_Cycle_Mask &in) {\n");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, " _mask%d = in._mask%d;\n", l, l);
fprintf(fp_hpp, " return *this;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask intersect(const Pipeline_Use_Cycle_Mask &in2) {\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask out;\n");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, " out._mask%d = _mask%d & in2._mask%d;\n", l, l, l);
fprintf(fp_hpp, " return out;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n");
fprintf(fp_hpp, " return (");
for (l = 1; l <= masklen; l++)
fprintf(fp_hpp, "((_mask%d & in2._mask%d) != 0)%s", l, l, l < masklen ? " || " : "");
fprintf(fp_hpp, ") ? true : false;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n");
fprintf(fp_hpp, " if (n >= 32)\n");
fprintf(fp_hpp, " do {\n ");
for (l = masklen; l > 1; l--)
fprintf(fp_hpp, " _mask%d = _mask%d;", l, l-1);
fprintf(fp_hpp, " _mask%d = 0;\n", 1);
fprintf(fp_hpp, " } while ((n -= 32) >= 32);\n\n");
fprintf(fp_hpp, " if (n > 0) {\n");
fprintf(fp_hpp, " uint m = 32 - n;\n");
fprintf(fp_hpp, " uint mask = (1 << n) - 1;\n");
fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1);
for (l = 2; l < masklen; l++) {
fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l);
}
fprintf(fp_hpp, " _mask%d <<= n; _mask%d |= temp%d;\n", masklen, masklen, masklen);
fprintf(fp_hpp, " }\n");
fprintf(fp_hpp, " return *this;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " void Or(const Pipeline_Use_Cycle_Mask &);\n\n");
fprintf(fp_hpp, " friend Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &, const Pipeline_Use_Cycle_Mask &);\n");
fprintf(fp_hpp, " friend Pipeline_Use_Cycle_Mask operator|(const Pipeline_Use_Cycle_Mask &, const Pipeline_Use_Cycle_Mask &);\n\n");
}
fprintf(fp_hpp, " friend class Pipeline_Use;\n\n");
fprintf(fp_hpp, " friend class Pipeline_Use_Element;\n\n");
fprintf(fp_hpp, "};\n\n");
uint rescount = 0;
const char *resource;
for ( _pipeline->_reslist.reset(); (resource = _pipeline->_reslist.iter()) != NULL; ) {
int mask = _pipeline->_resdict[resource]->is_resource()->mask();
if ((mask & (mask-1)) == 0)
rescount++;
}
fprintf(fp_hpp, "// Pipeline_Use_Element Class\n");
fprintf(fp_hpp, "class Pipeline_Use_Element {\n");
fprintf(fp_hpp, "protected:\n");
fprintf(fp_hpp, " // Mask of used functional units\n");
fprintf(fp_hpp, " uint _used;\n\n");
fprintf(fp_hpp, " // Lower and upper bound of functional unit number range\n");
fprintf(fp_hpp, " uint _lb, _ub;\n\n");
fprintf(fp_hpp, " // Indicates multiple functionals units available\n");
fprintf(fp_hpp, " bool _multiple;\n\n");
fprintf(fp_hpp, " // Mask of specific used cycles\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask _mask;\n\n");
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Pipeline_Use_Element() {}\n\n");
fprintf(fp_hpp, " Pipeline_Use_Element(uint used, uint lb, uint ub, bool multiple, Pipeline_Use_Cycle_Mask mask)\n");
fprintf(fp_hpp, " : _used(used), _lb(lb), _ub(ub), _multiple(multiple), _mask(mask) {}\n\n");
fprintf(fp_hpp, " uint used() const { return _used; }\n\n");
fprintf(fp_hpp, " uint lowerBound() const { return _lb; }\n\n");
fprintf(fp_hpp, " uint upperBound() const { return _ub; }\n\n");
fprintf(fp_hpp, " bool multiple() const { return _multiple; }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask mask() const { return _mask; }\n\n");
fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Element &in2) const {\n");
fprintf(fp_hpp, " return ((_used & in2._used) != 0 && _mask.overlaps(in2._mask));\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " void step(uint cycles) {\n");
fprintf(fp_hpp, " _used = 0;\n");
fprintf(fp_hpp, " _mask <<= cycles;\n");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " friend class Pipeline_Use;\n");
fprintf(fp_hpp, "};\n\n");
fprintf(fp_hpp, "// Pipeline_Use Class\n");
fprintf(fp_hpp, "class Pipeline_Use {\n");
fprintf(fp_hpp, "protected:\n");
fprintf(fp_hpp, " // These resources can be used\n");
fprintf(fp_hpp, " uint _resources_used;\n\n");
fprintf(fp_hpp, " // These resources are used; excludes multiple choice functional units\n");
fprintf(fp_hpp, " uint _resources_used_exclusively;\n\n");
fprintf(fp_hpp, " // Number of elements\n");
fprintf(fp_hpp, " uint _count;\n\n");
fprintf(fp_hpp, " // This is the array of Pipeline_Use_Elements\n");
fprintf(fp_hpp, " Pipeline_Use_Element * _elements;\n\n");
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Pipeline_Use(uint resources_used, uint resources_used_exclusively, uint count, Pipeline_Use_Element *elements)\n");
fprintf(fp_hpp, " : _resources_used(resources_used)\n");
fprintf(fp_hpp, " , _resources_used_exclusively(resources_used_exclusively)\n");
fprintf(fp_hpp, " , _count(count)\n");
fprintf(fp_hpp, " , _elements(elements)\n");
fprintf(fp_hpp, " {}\n\n");
fprintf(fp_hpp, " uint resourcesUsed() const { return _resources_used; }\n\n");
fprintf(fp_hpp, " uint resourcesUsedExclusively() const { return _resources_used_exclusively; }\n\n");
fprintf(fp_hpp, " uint count() const { return _count; }\n\n");
fprintf(fp_hpp, " Pipeline_Use_Element * element(uint i) const { return &_elements[i]; }\n\n");
fprintf(fp_hpp, " uint full_latency(uint delay, const Pipeline_Use &pred) const;\n\n");
fprintf(fp_hpp, " void add_usage(const Pipeline_Use &pred);\n\n");
fprintf(fp_hpp, " void reset() {\n");
fprintf(fp_hpp, " _resources_used = _resources_used_exclusively = 0;\n");
fprintf(fp_hpp, " };\n\n");
fprintf(fp_hpp, " void step(uint cycles) {\n");
fprintf(fp_hpp, " reset();\n");
fprintf(fp_hpp, " for (uint i = 0; i < %d; i++)\n",
rescount);
fprintf(fp_hpp, " (&_elements[i])->step(cycles);\n");
fprintf(fp_hpp, " };\n\n");
fprintf(fp_hpp, " static const Pipeline_Use elaborated_use;\n");
fprintf(fp_hpp, " static const Pipeline_Use_Element elaborated_elements[%d];\n\n",
rescount);
fprintf(fp_hpp, " friend class Pipeline;\n");
fprintf(fp_hpp, "};\n\n");
fprintf(fp_hpp, "// Pipeline Class\n");
fprintf(fp_hpp, "class Pipeline {\n");
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " static bool enabled() { return %s; }\n\n",
_pipeline ? "true" : "false" );
assert( _pipeline->_maxInstrsPerBundle &&
( _pipeline->_instrUnitSize || _pipeline->_bundleUnitSize) &&
_pipeline->_instrFetchUnitSize &&
_pipeline->_instrFetchUnits,
"unspecified pipeline architecture units");
uint unitSize = _pipeline->_instrUnitSize ? _pipeline->_instrUnitSize : _pipeline->_bundleUnitSize;
fprintf(fp_hpp, " enum {\n");
fprintf(fp_hpp, " _variable_size_instructions = %d,\n",
_pipeline->_variableSizeInstrs ? 1 : 0);
fprintf(fp_hpp, " _fixed_size_instructions = %d,\n",
_pipeline->_variableSizeInstrs ? 0 : 1);
fprintf(fp_hpp, " _branch_has_delay_slot = %d,\n",
_pipeline->_branchHasDelaySlot ? 1 : 0);
fprintf(fp_hpp, " _max_instrs_per_bundle = %d,\n",
_pipeline->_maxInstrsPerBundle);
fprintf(fp_hpp, " _max_bundles_per_cycle = %d,\n",
_pipeline->_maxBundlesPerCycle);
fprintf(fp_hpp, " _max_instrs_per_cycle = %d\n",
_pipeline->_maxBundlesPerCycle * _pipeline->_maxInstrsPerBundle);
fprintf(fp_hpp, " };\n\n");
fprintf(fp_hpp, " static bool instr_has_unit_size() { return %s; }\n\n",
_pipeline->_instrUnitSize != 0 ? "true" : "false" );
if( _pipeline->_bundleUnitSize != 0 )
if( _pipeline->_instrUnitSize != 0 )
fprintf(fp_hpp, "// Individual Instructions may be bundled together by the hardware\n\n");
else
fprintf(fp_hpp, "// Instructions exist only in bundles\n\n");
else
fprintf(fp_hpp, "// Bundling is not supported\n\n");
if( _pipeline->_instrUnitSize != 0 )
fprintf(fp_hpp, " // Size of an instruction\n");
else
fprintf(fp_hpp, " // Size of an individual instruction does not exist - unsupported\n");
fprintf(fp_hpp, " static uint instr_unit_size() {");
if( _pipeline->_instrUnitSize == 0 )
fprintf(fp_hpp, " assert( false, \"Instructions are only in bundles\" );");
fprintf(fp_hpp, " return %d; };\n\n", _pipeline->_instrUnitSize);
if( _pipeline->_bundleUnitSize != 0 )
fprintf(fp_hpp, " // Size of a bundle\n");
else
fprintf(fp_hpp, " // Bundles do not exist - unsupported\n");
fprintf(fp_hpp, " static uint bundle_unit_size() {");
if( _pipeline->_bundleUnitSize == 0 )
fprintf(fp_hpp, " assert( false, \"Bundles are not supported\" );");
fprintf(fp_hpp, " return %d; };\n\n", _pipeline->_bundleUnitSize);
fprintf(fp_hpp, " static bool requires_bundling() { return %s; }\n\n",
_pipeline->_bundleUnitSize != 0 && _pipeline->_instrUnitSize == 0 ? "true" : "false" );
fprintf(fp_hpp, "private:\n");
fprintf(fp_hpp, " Pipeline(); // Not a legal constructor\n");
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, " const unsigned char _read_stage_count;\n");
fprintf(fp_hpp, " const unsigned char _write_stage;\n");
fprintf(fp_hpp, " const unsigned char _fixed_latency;\n");
fprintf(fp_hpp, " const unsigned char _instruction_count;\n");
fprintf(fp_hpp, " const bool _has_fixed_latency;\n");
fprintf(fp_hpp, " const bool _has_branch_delay;\n");
fprintf(fp_hpp, " const bool _has_multiple_bundles;\n");
fprintf(fp_hpp, " const bool _force_serialization;\n");
fprintf(fp_hpp, " const bool _may_have_no_code;\n");
fprintf(fp_hpp, " const enum machPipelineStages * const _read_stages;\n");
fprintf(fp_hpp, " const enum machPipelineStages * const _resource_stage;\n");
fprintf(fp_hpp, " const uint * const _resource_cycles;\n");
fprintf(fp_hpp, " const Pipeline_Use _resource_use;\n");
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Pipeline(uint write_stage,\n");
fprintf(fp_hpp, " uint count,\n");
fprintf(fp_hpp, " bool has_fixed_latency,\n");
fprintf(fp_hpp, " uint fixed_latency,\n");
fprintf(fp_hpp, " uint instruction_count,\n");
fprintf(fp_hpp, " bool has_branch_delay,\n");
fprintf(fp_hpp, " bool has_multiple_bundles,\n");
fprintf(fp_hpp, " bool force_serialization,\n");
fprintf(fp_hpp, " bool may_have_no_code,\n");
fprintf(fp_hpp, " enum machPipelineStages * const dst,\n");
fprintf(fp_hpp, " enum machPipelineStages * const stage,\n");
fprintf(fp_hpp, " uint * const cycles,\n");
fprintf(fp_hpp, " Pipeline_Use resource_use)\n");
fprintf(fp_hpp, " : _write_stage(write_stage)\n");
fprintf(fp_hpp, " , _read_stage_count(count)\n");
fprintf(fp_hpp, " , _has_fixed_latency(has_fixed_latency)\n");
fprintf(fp_hpp, " , _fixed_latency(fixed_latency)\n");
fprintf(fp_hpp, " , _read_stages(dst)\n");
fprintf(fp_hpp, " , _resource_stage(stage)\n");
fprintf(fp_hpp, " , _resource_cycles(cycles)\n");
fprintf(fp_hpp, " , _resource_use(resource_use)\n");
fprintf(fp_hpp, " , _instruction_count(instruction_count)\n");
fprintf(fp_hpp, " , _has_branch_delay(has_branch_delay)\n");
fprintf(fp_hpp, " , _has_multiple_bundles(has_multiple_bundles)\n");
fprintf(fp_hpp, " , _force_serialization(force_serialization)\n");
fprintf(fp_hpp, " , _may_have_no_code(may_have_no_code)\n");
fprintf(fp_hpp, " {};\n");
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, " uint writeStage() const {\n");
fprintf(fp_hpp, " return (_write_stage);\n");
fprintf(fp_hpp, " }\n");
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, " enum machPipelineStages readStage(int ndx) const {\n");
fprintf(fp_hpp, " return (ndx < _read_stage_count ? _read_stages[ndx] : stage_undefined);");
fprintf(fp_hpp, " }\n\n");
fprintf(fp_hpp, " uint resourcesUsed() const {\n");
fprintf(fp_hpp, " return _resource_use.resourcesUsed();\n }\n\n");
fprintf(fp_hpp, " uint resourcesUsedExclusively() const {\n");
fprintf(fp_hpp, " return _resource_use.resourcesUsedExclusively();\n }\n\n");
fprintf(fp_hpp, " bool hasFixedLatency() const {\n");
fprintf(fp_hpp, " return (_has_fixed_latency);\n }\n\n");
fprintf(fp_hpp, " uint fixedLatency() const {\n");
fprintf(fp_hpp, " return (_fixed_latency);\n }\n\n");
fprintf(fp_hpp, " uint functional_unit_latency(uint start, const Pipeline *pred) const;\n\n");
fprintf(fp_hpp, " uint operand_latency(uint opnd, const Pipeline *pred) const;\n\n");
fprintf(fp_hpp, " const Pipeline_Use& resourceUse() const {\n");
fprintf(fp_hpp, " return (_resource_use); }\n\n");
fprintf(fp_hpp, " const Pipeline_Use_Element * resourceUseElement(uint i) const {\n");
fprintf(fp_hpp, " return (&_resource_use._elements[i]); }\n\n");
fprintf(fp_hpp, " uint resourceUseCount() const {\n");
fprintf(fp_hpp, " return (_resource_use._count); }\n\n");
fprintf(fp_hpp, " uint instructionCount() const {\n");
fprintf(fp_hpp, " return (_instruction_count); }\n\n");
fprintf(fp_hpp, " bool hasBranchDelay() const {\n");
fprintf(fp_hpp, " return (_has_branch_delay); }\n\n");
fprintf(fp_hpp, " bool hasMultipleBundles() const {\n");
fprintf(fp_hpp, " return (_has_multiple_bundles); }\n\n");
fprintf(fp_hpp, " bool forceSerialization() const {\n");
fprintf(fp_hpp, " return (_force_serialization); }\n\n");
fprintf(fp_hpp, " bool mayHaveNoCode() const {\n");
fprintf(fp_hpp, " return (_may_have_no_code); }\n\n");
fprintf(fp_hpp, "//const Pipeline_Use_Cycle_Mask& resourceUseMask(int resource) const {\n");
fprintf(fp_hpp, "// return (_resource_use_masks[resource]); }\n\n");
fprintf(fp_hpp, "\n#ifndef PRODUCT\n");
fprintf(fp_hpp, " static const char * stageName(uint i);\n");
fprintf(fp_hpp, "#endif\n");
fprintf(fp_hpp, "};\n\n");
fprintf(fp_hpp, "// Bundle class\n");
fprintf(fp_hpp, "class Bundle {\n");
uint mshift = 0;
for (uint msize = _pipeline->_maxInstrsPerBundle * _pipeline->_maxBundlesPerCycle; msize != 0; msize >>= 1)
mshift++;
uint rshift = rescount;
fprintf(fp_hpp, "protected:\n");
fprintf(fp_hpp, " enum {\n");
fprintf(fp_hpp, " _unused_delay = 0x%x,\n", 0);
fprintf(fp_hpp, " _use_nop_delay = 0x%x,\n", 1);
fprintf(fp_hpp, " _use_unconditional_delay = 0x%x,\n", 2);
fprintf(fp_hpp, " _use_conditional_delay = 0x%x,\n", 3);
fprintf(fp_hpp, " _used_in_conditional_delay = 0x%x,\n", 4);
fprintf(fp_hpp, " _used_in_unconditional_delay = 0x%x,\n", 5);
fprintf(fp_hpp, " _used_in_all_conditional_delays = 0x%x,\n", 6);
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, " _use_delay = 0x%x,\n", 3);
fprintf(fp_hpp, " _used_in_delay = 0x%x\n", 4);
fprintf(fp_hpp, " };\n\n");
fprintf(fp_hpp, " uint _flags : 3,\n");
fprintf(fp_hpp, " _starts_bundle : 1,\n");
fprintf(fp_hpp, " _instr_count : %d,\n", mshift);
fprintf(fp_hpp, " _resources_used : %d;\n", rshift);
fprintf(fp_hpp, "public:\n");
fprintf(fp_hpp, " Bundle() : _flags(_unused_delay), _starts_bundle(0), _instr_count(0), _resources_used(0) {}\n\n");
fprintf(fp_hpp, " void set_instr_count(uint i) { _instr_count = i; }\n");
fprintf(fp_hpp, " void set_resources_used(uint i) { _resources_used = i; }\n");
fprintf(fp_hpp, " void clear_usage() { _flags = _unused_delay; }\n");
fprintf(fp_hpp, " void set_starts_bundle() { _starts_bundle = true; }\n");
fprintf(fp_hpp, " uint flags() const { return (_flags); }\n");
fprintf(fp_hpp, " uint instr_count() const { return (_instr_count); }\n");
fprintf(fp_hpp, " uint resources_used() const { return (_resources_used); }\n");
fprintf(fp_hpp, " bool starts_bundle() const { return (_starts_bundle != 0); }\n");
fprintf(fp_hpp, " void set_use_nop_delay() { _flags = _use_nop_delay; }\n");
fprintf(fp_hpp, " void set_use_unconditional_delay() { _flags = _use_unconditional_delay; }\n");
fprintf(fp_hpp, " void set_use_conditional_delay() { _flags = _use_conditional_delay; }\n");
fprintf(fp_hpp, " void set_used_in_unconditional_delay() { _flags = _used_in_unconditional_delay; }\n");
fprintf(fp_hpp, " void set_used_in_conditional_delay() { _flags = _used_in_conditional_delay; }\n");
fprintf(fp_hpp, " void set_used_in_all_conditional_delays() { _flags = _used_in_all_conditional_delays; }\n");
fprintf(fp_hpp, " bool use_nop_delay() { return (_flags == _use_nop_delay); }\n");
fprintf(fp_hpp, " bool use_unconditional_delay() { return (_flags == _use_unconditional_delay); }\n");
fprintf(fp_hpp, " bool use_conditional_delay() { return (_flags == _use_conditional_delay); }\n");
fprintf(fp_hpp, " bool used_in_unconditional_delay() { return (_flags == _used_in_unconditional_delay); }\n");
fprintf(fp_hpp, " bool used_in_conditional_delay() { return (_flags == _used_in_conditional_delay); }\n");
fprintf(fp_hpp, " bool used_in_all_conditional_delays() { return (_flags == _used_in_all_conditional_delays); }\n");
fprintf(fp_hpp, " bool use_delay() { return ((_flags & _use_delay) != 0); }\n");
fprintf(fp_hpp, " bool used_in_delay() { return ((_flags & _used_in_delay) != 0); }\n\n");
fprintf(fp_hpp, " enum {\n");
fprintf(fp_hpp, " _nop_count = %d\n",
_pipeline->_nopcnt);
fprintf(fp_hpp, " };\n\n");
fprintf(fp_hpp, " static void initialize_nops(MachNode *nop_list[%d], Compile* C);\n\n",
_pipeline->_nopcnt);
fprintf(fp_hpp, "#ifndef PRODUCT\n");
fprintf(fp_hpp, " void dump(outputStream *st = tty) const;\n");
fprintf(fp_hpp, "#endif\n");
fprintf(fp_hpp, "};\n\n");
}
void ArchDesc::declareClasses(FILE *fp) {
declareRegNames(fp, _register);
declareRegEncodes(fp, _register);
fprintf(fp,"\n");
fprintf(fp,"// Total number of operands defined in architecture definition\n");
int num_operands = 0;
OperandForm *op;
for (_operands.reset(); (op = (OperandForm*)_operands.iter()) != NULL; ) {
if (op->ideal_only()) continue;
++num_operands;
}
int first_operand_class = num_operands;
OpClassForm *opc;
for (_opclass.reset(); (opc = (OpClassForm*)_opclass.iter()) != NULL; ) {
if (opc->ideal_only()) continue;
++num_operands;
}
fprintf(fp,"#define FIRST_OPERAND_CLASS %d\n", first_operand_class);
fprintf(fp,"#define NUM_OPERANDS %d\n", num_operands);
fprintf(fp,"\n");
fprintf(fp,"// Total number of instructions defined in architecture definition\n");
fprintf(fp,"#define NUM_INSTRUCTIONS %d\n",instructFormCount());
fprintf(fp,"\n");
fprintf(fp,"//----------------------------Declare classes derived from MachOper----------\n");
_operands.reset();
OperandForm *oper;
for( ; (oper = (OperandForm*)_operands.iter()) != NULL;) {
if (oper->ideal_only() ) continue;
if ( strcmp(oper->_ident,"label") == 0 ) continue;
if ( strcmp(oper->_ident,"method") == 0 ) continue;
fprintf(fp,"\n");
fprintf(fp,"class %sOper : public MachOper { \n",oper->_ident);
fprintf(fp,"private:\n");
{
uint num_edges = oper->num_edges(_globalNames);
if( num_edges != 1 ) { // Use MachOper::num_edges() {return 1;}
fprintf(fp," virtual uint num_edges() const { return %d; }\n",
num_edges );
}
if( num_edges > 0 ) {
in_RegMask(fp);
}
}
declareConstStorage(fp,_globalNames,oper);
if( oper->is_ideal_bool() ) {
fprintf(fp," virtual int ccode() const { \n");
fprintf(fp," switch (_c0) {\n");
fprintf(fp," case BoolTest::eq : return equal();\n");
fprintf(fp," case BoolTest::gt : return greater();\n");
fprintf(fp," case BoolTest::lt : return less();\n");
fprintf(fp," case BoolTest::ne : return not_equal();\n");
fprintf(fp," case BoolTest::le : return less_equal();\n");
fprintf(fp," case BoolTest::ge : return greater_equal();\n");
fprintf(fp," case BoolTest::overflow : return overflow();\n");
fprintf(fp," case BoolTest::no_overflow: return no_overflow();\n");
fprintf(fp," default : ShouldNotReachHere(); return 0;\n");
fprintf(fp," }\n");
fprintf(fp," };\n");
}
if( oper->is_ideal_bool() ) {
fprintf(fp," virtual void negate() { \n");
fprintf(fp," _c0 = (BoolTest::mask)((int)_c0^0x4); \n");
fprintf(fp," };\n");
}
Form::DataType constant_type = oper->simple_type(_globalNames);
defineConstructor(fp, oper->_ident, oper->num_consts(_globalNames),
oper->_components, oper->is_ideal_bool(),
constant_type, _globalNames);
fprintf(fp," virtual MachOper *clone(Compile* C) const;\n");
if( oper->has_conI(_globalNames) ||
oper->has_conL(_globalNames) )
fprintf(fp, " virtual void set_con( jint c0 ) { _c0 = c0; }\n");
fprintf(fp," virtual uint opcode() const { return %s; }\n",
machOperEnum(oper->_ident));
if ((oper->_matrule) && (oper->_matrule->_lChild == NULL) &&
(oper->_matrule->_rChild == NULL)) {
unsigned int position = 0;
const char *opret, *opname, *optype;
oper->_matrule->base_operand(position,_globalNames,opret,opname,optype);
fprintf(fp," virtual const Type *type() const {");
const char *type = getIdealType(optype);
if( type != NULL ) {
Form::DataType data_type = oper->is_base_constant(_globalNames);
if( data_type == Form::idealP || data_type == Form::idealN || data_type == Form::idealNKlass ) {
fprintf(fp," return _c0;");
} else {
fprintf(fp," return %s;", getIdealType(optype));
}
} else {
fprintf(fp," ShouldNotCallThis(); return Type::BOTTOM;");
}
fprintf(fp," }\n");
} else {
Form::DataType data_type = oper->is_user_name_for_sReg();
if( data_type != Form::none ){
const char *type = NULL;
switch( data_type ) {
case Form::idealI: type = "TypeInt::INT"; break;
case Form::idealP: type = "TypePtr::BOTTOM";break;
case Form::idealF: type = "Type::FLOAT"; break;
case Form::idealD: type = "Type::DOUBLE"; break;
case Form::idealL: type = "TypeLong::LONG"; break;
case Form::none: // fall through
default:
assert( false, "No support for this type of stackSlot");
}
fprintf(fp," virtual const Type *type() const { return %s; } // stackSlotX\n", type);
}
}
if ( oper->_matrule && oper->_matrule->is_base_register(_globalNames) ) {
} else if ( oper->ideal_to_sReg_type(oper->_ident) != Form::none ) {
fprintf(fp," virtual int reg(PhaseRegAlloc *ra_, const Node *node) const {\n");
fprintf(fp," return (int)OptoReg::reg2stack(ra_->get_reg_first(node));/* sReg */\n");
fprintf(fp," }\n");
fprintf(fp," virtual int reg(PhaseRegAlloc *ra_, const Node *node, int idx) const {\n");
fprintf(fp," return (int)OptoReg::reg2stack(ra_->get_reg_first(node->in(idx)));/* sReg */\n");
fprintf(fp," }\n");
}
if (oper->_interface != NULL) {
fprintf(fp,"\n");
if ( oper->_interface->is_MemInterface() != NULL ) {
MemInterface *mem_interface = oper->_interface->is_MemInterface();
const char *base = mem_interface->_base;
if( base != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "base", base);
}
char *index = mem_interface->_index;
if( index != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "index", index);
}
const char *scale = mem_interface->_scale;
if( scale != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "scale", scale);
}
const char *disp = mem_interface->_disp;
if( disp != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "disp", disp);
oper->disp_is_oop(fp, _globalNames);
}
if( oper->stack_slots_only(_globalNames) ) {
fprintf(fp," virtual int constant_disp() const { return Type::OffsetBot; }");
} else if ( disp != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "constant_disp", disp);
}
} // end Memory Interface
else if (oper->_interface->is_CondInterface() != NULL) {
CondInterface *cInterface = oper->_interface->is_CondInterface();
const char *equal = cInterface->_equal;
if( equal != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "equal", equal);
}
const char *not_equal = cInterface->_not_equal;
if( not_equal != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "not_equal", not_equal);
}
const char *less = cInterface->_less;
if( less != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "less", less);
}
const char *greater_equal = cInterface->_greater_equal;
if( greater_equal != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "greater_equal", greater_equal);
}
const char *less_equal = cInterface->_less_equal;
if( less_equal != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "less_equal", less_equal);
}
const char *greater = cInterface->_greater;
if( greater != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "greater", greater);
}
const char *overflow = cInterface->_overflow;
if( overflow != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "overflow", overflow);
}
const char *no_overflow = cInterface->_no_overflow;
if( no_overflow != NULL ) {
define_oper_interface(fp, *oper, _globalNames, "no_overflow", no_overflow);
}
} // end Conditional Interface
else if (oper->_interface->is_ConstInterface() != NULL ) {
assert( oper->num_consts(_globalNames) == 1,
"Must have one constant when using CONST_INTER encoding");
if (!strcmp(oper->ideal_type(_globalNames), "ConI")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " return (intptr_t)_c0;");
fprintf(fp," }\n");
}
else if (!strcmp(oper->ideal_type(_globalNames), "ConP")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " return _c0->get_con();");
fprintf(fp, " }\n");
fprintf(fp," virtual relocInfo::relocType constant_reloc() const {");
fprintf(fp, " return _c0->reloc();");
fprintf(fp, " }\n");
}
else if (!strcmp(oper->ideal_type(_globalNames), "ConN")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " return _c0->get_ptrtype()->get_con();");
fprintf(fp, " }\n");
fprintf(fp," virtual relocInfo::relocType constant_reloc() const {");
fprintf(fp, " return _c0->get_ptrtype()->reloc();");
fprintf(fp, " }\n");
}
else if (!strcmp(oper->ideal_type(_globalNames), "ConNKlass")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " return _c0->get_ptrtype()->get_con();");
fprintf(fp, " }\n");
fprintf(fp," virtual relocInfo::relocType constant_reloc() const {");
fprintf(fp, " return _c0->get_ptrtype()->reloc();");
fprintf(fp, " }\n");
}
else if (!strcmp(oper->ideal_type(_globalNames), "ConL")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " return (intptr_t)_c0;");
fprintf(fp, " }\n");
fprintf(fp," virtual jlong constantL() const {");
fprintf(fp, " return _c0;");
fprintf(fp, " }\n");
}
else if (!strcmp(oper->ideal_type(_globalNames), "ConF")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " ShouldNotReachHere(); return 0; ");
fprintf(fp, " }\n");
fprintf(fp," virtual jfloat constantF() const {");
fprintf(fp, " return (jfloat)_c0;");
fprintf(fp, " }\n");
}
else if (!strcmp(oper->ideal_type(_globalNames), "ConD")) {
fprintf(fp," virtual intptr_t constant() const {");
fprintf(fp, " ShouldNotReachHere(); return 0; ");
fprintf(fp, " }\n");
fprintf(fp," virtual jdouble constantD() const {");
fprintf(fp, " return _c0;");
fprintf(fp, " }\n");
}
}
else if (oper->_interface->is_RegInterface() != NULL) {
if (oper->_format->_strings.count() != 0 && !oper->is_bound_register()) {
syntax_err(oper->_linenum,
"Only bound registers can have fixed formats: %s\n",
oper->_ident);
}
}
else {
assert( false, "ShouldNotReachHere();");
}
}
fprintf(fp,"\n");
fprintf(fp, "#ifndef PRODUCT\n");
gen_oper_format(fp, _globalNames, *oper);
uint num_consts = oper->num_consts(_globalNames);
if( num_consts > 0 ) {
fprintf(fp, " virtual void dump_spec(outputStream *st) const {\n");
uint i = 0;
const char *type = oper->ideal_type(_globalNames);
Component *comp;
oper->_components.reset();
if ((comp = oper->_components.iter()) == NULL) {
assert(num_consts == 1, "Bad component list detected.\n");
i = dump_spec_constant( fp, type, i, oper );
assert( i != 0, "Non-constant operand lacks component list.");
} // end if NULL
else {
oper->_components.reset();
while((comp = oper->_components.iter()) != NULL) {
type = comp->base_type(_globalNames);
i = dump_spec_constant( fp, type, i, NULL );
}
}
fprintf(fp," }\n");
}
fprintf(fp," virtual const char *Name() const { return \"%s\";}\n",
oper->_ident);
fprintf(fp,"#endif\n");
fprintf(fp,"};\n");
}
fprintf(fp,"\n");
fprintf(fp,"//----------------------------Declare classes for Pipelines-----------------\n");
declare_pipe_classes(fp);
fprintf(fp,"\n");
fprintf(fp,"//----------------------------Declare classes derived from MachNode----------\n");
_instructions.reset();
InstructForm *instr;
for( ; (instr = (InstructForm*)_instructions.iter()) != NULL; ) {
if ( instr->ideal_only() ) continue;
fprintf(fp,"\n");
fprintf(fp,"class %sNode : public %s { \n",
instr->_ident, instr->mach_base_class(_globalNames) );
fprintf(fp,"private:\n");
fprintf(fp," MachOper *_opnd_array[%d];\n", instr->num_opnds() );
if ( instr->is_ideal_jump() ) {
fprintf(fp, " GrowableArray<Label*> _index2label;\n");
}
fprintf(fp, "public:\n");
Attribute *att = instr->_attribs;
while (att != NULL) {
if (strncmp(att->_ident, "ins_field_", 10) == 0) {
const char *field_name = att->_ident+10;
const char *field_type = att->_val;
fprintf(fp, " %s _%s;\n", field_type, field_name);
}
att = (Attribute *)att->_next;
}
fprintf(fp," MachOper *opnd_array(uint operand_index) const {\n");
fprintf(fp," assert(operand_index < _num_opnds, \"invalid _opnd_array index\");\n");
fprintf(fp," return _opnd_array[operand_index];\n");
fprintf(fp," }\n");
fprintf(fp," void set_opnd_array(uint operand_index, MachOper *operand) {\n");
fprintf(fp," assert(operand_index < _num_opnds, \"invalid _opnd_array index\");\n");
fprintf(fp," _opnd_array[operand_index] = operand;\n");
fprintf(fp," }\n");
fprintf(fp,"private:\n");
if ( instr->is_ideal_jump() ) {
fprintf(fp," virtual void add_case_label(int index_num, Label* blockLabel) {\n");
fprintf(fp," _index2label.at_put_grow(index_num, blockLabel);\n");
fprintf(fp," }\n");
}
if( can_cisc_spill() && (instr->cisc_spill_alternate() != NULL) ) {
fprintf(fp," const RegMask *_cisc_RegMask;\n");
}
out_RegMask(fp); // output register mask
fprintf(fp," virtual uint rule() const { return %s_rule; }\n",
instr->_ident);
int label_position = instr->label_position();
if( label_position != -1 ) {
fprintf(fp," virtual void label_set( Label* label, uint block_num );\n");
fprintf(fp," virtual void save_label( Label** label, uint* block_num );\n");
}
int method_position = instr->method_position();
if( method_position != -1 ) {
fprintf(fp," virtual void method_set( intptr_t method );\n");
}
Attribute *attr = instr->_attribs;
Attribute *avoid_back_to_back_attr = NULL;
while (attr != NULL) {
if (strcmp (attr->_ident, "ins_is_TrapBasedCheckNode") == 0) {
fprintf(fp, " virtual bool is_TrapBasedCheckNode() const { return %s; }\n", attr->_val);
} else if (strcmp (attr->_ident, "ins_cost") != 0 &&
strncmp(attr->_ident, "ins_field_", 10) != 0 &&
strcmp (attr->_ident, "ins_is_TrapBasedCheckNode") != 0 &&
strcmp (attr->_ident, "ins_short_branch") != 0) {
fprintf(fp, " virtual int %s() const { return %s; }\n", attr->_ident, attr->_val);
}
if (strcmp(attr->_ident, "ins_avoid_back_to_back") == 0) {
avoid_back_to_back_attr = attr;
}
attr = (Attribute *)attr->_next;
}
if (instr->is_mach_constant()) {
fprintf(fp," virtual void eval_constant(Compile* C);\n");
}
if ( instr->_insencode ) {
if (instr->postalloc_expands()) {
fprintf(fp," virtual bool requires_postalloc_expand() const { return true; }\n");
fprintf(fp," virtual void postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_);\n");
} else {
fprintf(fp," virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;\n");
}
}
if ( instr->_size ) {
fprintf(fp," virtual uint size(PhaseRegAlloc *ra_) const;\n");
}
if ( strcmp("Node", instr->ideal_Opcode(_globalNames)) != 0 ||
strcmp("MachNode", instr->mach_base_class(_globalNames)) != 0 ) {
fprintf(fp," virtual int ideal_Opcode() const { return Op_%s; }\n",
instr->ideal_Opcode(_globalNames) );
}
if (instr->needs_constant_base() &&
!instr->is_mach_constant()) { // These inherit the funcion from MachConstantNode.
fprintf(fp," virtual uint mach_constant_base_node_input() const { ");
if (instr->is_ideal_call() != Form::invalid_type &&
instr->is_ideal_call() != Form::JAVA_LEAF) {
fprintf(fp,"assert(tf() && tf()->domain(), \"\"); return tf()->domain()->cnt();");
} else {
fprintf(fp,"return req()-1;");
}
fprintf(fp," }\n");
}
if( instr->is_ideal_if() ) {
fprintf(fp," virtual void negate() { \n");
int idx = 0;
instr->_components.reset();
for( Component *comp; (comp = instr->_components.iter()) != NULL; ) {
Form *form = (Form*)_globalNames[comp->_type];
OperandForm *opForm = form ? form->is_operand() : NULL;
if( opForm == NULL ) continue;
if( opForm->is_ideal_bool() ) {
idx = instr->operand_position(comp->_name, comp->_usedef);
assert( idx != NameList::Not_in_list, "Did not find component in list that contained it.");
break;
}
}
fprintf(fp," opnd_array(%d)->negate();\n", idx);
fprintf(fp," _prob = 1.0f - _prob;\n");
fprintf(fp," };\n");
}
uint matching_input = instr->two_address(_globalNames);
if( matching_input != 0 ) {
fprintf(fp," virtual uint two_adr() const ");
fprintf(fp,"{ return oper_input_base()");
for( uint i = 2; i <= matching_input; i++ )
fprintf(fp," + opnd_array(%d)->num_edges()",i-1);
fprintf(fp,"; }\n");
}
instr->declare_cisc_version(*this, fp);
if ( instr->peepholes() != NULL ) {
fprintf(fp," virtual MachNode *peephole(Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile *C);\n");
}
if ( instr->reloc(_globalNames) != 0 ) {
fprintf(fp," virtual int reloc() const;\n");
}
if (instr->alignment() != 1) {
fprintf(fp," virtual int alignment_required() const { return %d; }\n", instr->alignment());
fprintf(fp," virtual int compute_padding(int current_offset) const;\n");
}
if ( instr->oper_input_base(_globalNames) != 1 ||
strcmp("MachNode", instr->mach_base_class(_globalNames)) != 0 ) {
fprintf(fp," virtual uint oper_input_base() const { return %d; }\n",
instr->oper_input_base(_globalNames));
}
fprintf(fp,"public:\n");
if ( instr->is_ideal_jump() ) {
fprintf(fp," %sNode() : _index2label(MinJumpTableSize*2) { ", instr->_ident);
} else {
fprintf(fp," %sNode() { ", instr->_ident);
if( can_cisc_spill() && (instr->cisc_spill_alternate() != NULL) ) {
fprintf(fp,"_cisc_RegMask = NULL; ");
}
}
fprintf(fp," _num_opnds = %d; _opnds = _opnd_array; ", instr->num_opnds());
bool node_flags_set = false;
if ( instr->is_ideal_copy() != 0 ) {
fprintf(fp,"init_flags(Flag_is_Copy");
node_flags_set = true;
}
Form::DataType data_type;
const char *opType = NULL;
const char *result = NULL;
data_type = instr->is_chain_of_constant(_globalNames, opType, result);
if ( data_type != Form::none ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_is_Con");
} else {
fprintf(fp,"init_flags(Flag_is_Con");
node_flags_set = true;
}
}
if ( can_cisc_spill() && instr->is_cisc_alternate() ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_is_cisc_alternate");
} else {
fprintf(fp,"init_flags(Flag_is_cisc_alternate");
node_flags_set = true;
}
}
if ( instr->has_short_branch_form() ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_may_be_short_branch");
} else {
fprintf(fp,"init_flags(Flag_may_be_short_branch");
node_flags_set = true;
}
}
if (avoid_back_to_back_attr != NULL) {
if (node_flags_set) {
fprintf(fp," | (%s)", avoid_back_to_back_attr->_val);
} else {
fprintf(fp,"init_flags((%s)", avoid_back_to_back_attr->_val);
node_flags_set = true;
}
}
if ( instr->needs_anti_dependence_check(_globalNames) ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_needs_anti_dependence_check");
} else {
fprintf(fp,"init_flags(Flag_needs_anti_dependence_check");
node_flags_set = true;
}
}
if ( instr->_has_call ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_has_call");
} else {
fprintf(fp,"init_flags(Flag_has_call");
node_flags_set = true;
}
}
if ( node_flags_set ) {
fprintf(fp,"); ");
}
fprintf(fp,"}\n");
fprintf(fp," virtual uint size_of() const {");
fprintf(fp, " return sizeof(%sNode);", instr->_ident);
fprintf(fp, " }\n");
if( instr->expands() || instr->needs_projections() ||
instr->has_temps() ||
instr->is_mach_constant() ||
instr->needs_constant_base() ||
instr->_matrule != NULL &&
instr->num_opnds() != instr->num_unique_opnds() ) {
fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list, Node* mem);\n");
}
if (instr->is_pinned(_globalNames)) {
fprintf(fp," virtual bool pinned() const { return ");
if (instr->is_parm(_globalNames)) {
fprintf(fp,"_in[0]->pinned();");
} else {
fprintf(fp,"true;");
}
fprintf(fp," }\n");
}
if (instr->is_projection(_globalNames)) {
fprintf(fp," virtual const Node *is_block_proj() const { return this; }\n");
}
if ( instr->num_post_match_opnds() != 0
|| instr->is_chain_of_constant(_globalNames) ) {
fprintf(fp," friend MachNode *State::MachNodeGenerator(int opcode, Compile* C);\n");
}
if ( instr->rematerialize(_globalNames, get_registers()) ) {
fprintf(fp," // Rematerialize %s\n", instr->_ident);
}
instr->declare_short_branch_methods(fp);
if (instr->_ins_pipe) {
fprintf(fp," static const Pipeline *pipeline_class();\n");
fprintf(fp," virtual const Pipeline *pipeline() const;\n");
}
if( data_type != Form::none ) {
fprintf(fp," virtual const class Type *bottom_type() const {\n");
switch( data_type ) {
case Form::idealI:
fprintf(fp," return TypeInt::make(opnd_array(1)->constant());\n");
break;
case Form::idealP:
case Form::idealN:
case Form::idealNKlass:
fprintf(fp," return opnd_array(1)->type();\n");
break;
case Form::idealD:
fprintf(fp," return TypeD::make(opnd_array(1)->constantD());\n");
break;
case Form::idealF:
fprintf(fp," return TypeF::make(opnd_array(1)->constantF());\n");
break;
case Form::idealL:
fprintf(fp," return TypeLong::make(opnd_array(1)->constantL());\n");
break;
default:
assert( false, "Unimplemented()" );
break;
}
fprintf(fp," };\n");
}
( strcmp("ConvF2I",instr->_matrule->_rChild->_opType)==0
|| strcmp("ConvD2I",instr->_matrule->_rChild->_opType)==0 ) ) {
fprintf(fp," virtual const class Type *bottom_type() const {");
fprintf(fp, " return TypeInt::INT;");
fprintf(fp, " };\n");
}*/
else if( instr->is_ideal_copy() &&
!strcmp(instr->_matrule->_lChild->_opType,"stackSlotP") ) {
fprintf(fp," const Type *bottom_type() const { return in(1)->bottom_type(); } // Copy?\n");
}
else if( instr->is_ideal_loadPC() ) {
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // LoadPC?\n");
}
else if( instr->is_ideal_box() ) {
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // Box?\n");
}
else if( instr->_matrule && instr->_matrule->_rChild && !strcmp(instr->_matrule->_rChild->_opType,"CMoveP") ) {
int offset = 1;
MatchNode *rl = instr->_matrule->_rChild->_lChild;
if( rl && !strcmp(rl->_opType, "Binary") ) {
MatchNode *rlr = rl->_rChild;
if (rlr && strncmp(rlr->_opType, "Cmp", 3) == 0)
offset = 2;
}
fprintf(fp," const Type *bottom_type() const { const Type *t = in(oper_input_base()+%d)->bottom_type(); return (req() <= oper_input_base()+%d) ? t : t->meet(in(oper_input_base()+%d)->bottom_type()); } // CMoveP\n",
offset, offset+1, offset+1);
}
else if( instr->_matrule && instr->_matrule->_rChild && !strcmp(instr->_matrule->_rChild->_opType,"CMoveN") ) {
int offset = 1;
MatchNode *rl = instr->_matrule->_rChild->_lChild;
if( rl && !strcmp(rl->_opType, "Binary") ) {
MatchNode *rlr = rl->_rChild;
if (rlr && strncmp(rlr->_opType, "Cmp", 3) == 0)
offset = 2;
}
fprintf(fp," const Type *bottom_type() const { const Type *t = in(oper_input_base()+%d)->bottom_type(); return (req() <= oper_input_base()+%d) ? t : t->meet(in(oper_input_base()+%d)->bottom_type()); } // CMoveN\n",
offset, offset+1, offset+1);
}
else if (instr->is_tls_instruction()) {
fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // tlsLoadP\n");
}
else if ( instr->is_ideal_if() ) {
fprintf(fp," const Type *bottom_type() const { return TypeTuple::IFBOTH; } // matched IfNode\n");
}
else if ( instr->is_ideal_membar() ) {
fprintf(fp," const Type *bottom_type() const { return TypeTuple::MEMBAR; } // matched MemBar\n");
}
if ( instr->_matrule && instr->_matrule->_rChild &&
( strcmp("ConvF2I",instr->_matrule->_rChild->_opType)==0
|| strcmp("ConvD2I",instr->_matrule->_rChild->_opType)==0 ) ) {
fprintf(fp," virtual uint ideal_reg() const { return Compile::current()->matcher()->base2reg[Type::Int]; }\n");
}*/
int memory_operand = instr->memory_operand(_globalNames);
if ( instr->is_wide_memory_kill(_globalNames) ) {
memory_operand = InstructForm::MANY_MEMORY_OPERANDS;
}
if ( memory_operand != InstructForm::NO_MEMORY_OPERAND ) {
if( memory_operand == InstructForm::MANY_MEMORY_OPERANDS ) {
fprintf(fp," virtual const TypePtr *adr_type() const;\n");
}
fprintf(fp," virtual const MachOper *memory_operand() const;\n");
}
fprintf(fp, "#ifndef PRODUCT\n");
gen_inst_format(fp, _globalNames,*instr);
fprintf(fp," virtual const char *Name() const { return \"%s\";}\n",
instr->_ident);
fprintf(fp, "#endif\n");
fprintf(fp,"};\n");
};
}
void ArchDesc::defineStateClass(FILE *fp) {
static const char *state__valid = "_valid[((uint)index) >> 5] & (0x1 << (((uint)index) & 0x0001F))";
static const char *state__set_valid= "_valid[((uint)index) >> 5] |= (0x1 << (((uint)index) & 0x0001F))";
fprintf(fp,"\n");
fprintf(fp,"// MACROS to inline and constant fold State::valid(index)...\n");
fprintf(fp,"// when given a constant 'index' in dfa_<arch>.cpp\n");
fprintf(fp,"// uint word = index >> 5; // Shift out bit position\n");
fprintf(fp,"// uint bitpos = index & 0x0001F; // Mask off word bits\n");
fprintf(fp,"#define STATE__VALID(index) ");
fprintf(fp," (%s)\n", state__valid);
fprintf(fp,"\n");
fprintf(fp,"#define STATE__NOT_YET_VALID(index) ");
fprintf(fp," ( (%s) == 0 )\n", state__valid);
fprintf(fp,"\n");
fprintf(fp,"#define STATE__VALID_CHILD(state,index) ");
fprintf(fp," ( state && (state->%s) )\n", state__valid);
fprintf(fp,"\n");
fprintf(fp,"#define STATE__SET_VALID(index) ");
fprintf(fp," (%s)\n", state__set_valid);
fprintf(fp,"\n");
fprintf(fp,
"//---------------------------State-------------------------------------------\n");
fprintf(fp,"// State contains an integral cost vector, indexed by machine operand opcodes,\n");
fprintf(fp,"// a rule vector consisting of machine operand/instruction opcodes, and also\n");
fprintf(fp,"// indexed by machine operand opcodes, pointers to the children in the label\n");
fprintf(fp,"// tree generated by the Label routines in ideal nodes (currently limited to\n");
fprintf(fp,"// two for convenience, but this could change).\n");
fprintf(fp,"class State : public ResourceObj {\n");
fprintf(fp,"public:\n");
fprintf(fp," int _id; // State identifier\n");
fprintf(fp," Node *_leaf; // Ideal (non-machine-node) leaf of match tree\n");
fprintf(fp," State *_kids[2]; // Children of state node in label tree\n");
fprintf(fp," unsigned int _cost[_LAST_MACH_OPER]; // Cost vector, indexed by operand opcodes\n");
fprintf(fp," unsigned int _rule[_LAST_MACH_OPER]; // Rule vector, indexed by operand opcodes\n");
fprintf(fp," unsigned int _valid[(_LAST_MACH_OPER/32)+1]; // Bit Map of valid Cost/Rule entries\n");
fprintf(fp,"\n");
fprintf(fp," State(void); // Constructor\n");
fprintf(fp," DEBUG_ONLY( ~State(void); ) // Destructor\n");
fprintf(fp,"\n");
fprintf(fp," // Methods created by ADLC and invoked by Reduce\n");
fprintf(fp," MachOper *MachOperGenerator( int opcode, Compile* C );\n");
fprintf(fp," MachNode *MachNodeGenerator( int opcode, Compile* C );\n");
fprintf(fp,"\n");
fprintf(fp," // Assign a state to a node, definition of method produced by ADLC\n");
fprintf(fp," bool DFA( int opcode, const Node *ideal );\n");
fprintf(fp,"\n");
fprintf(fp," // Access function for _valid bit vector\n");
fprintf(fp," bool valid(uint index) {\n");
fprintf(fp," return( STATE__VALID(index) != 0 );\n");
fprintf(fp," }\n");
fprintf(fp,"\n");
fprintf(fp," // Set function for _valid bit vector\n");
fprintf(fp," void set_valid(uint index) {\n");
fprintf(fp," STATE__SET_VALID(index);\n");
fprintf(fp," }\n");
fprintf(fp,"\n");
fprintf(fp,"#ifndef PRODUCT\n");
fprintf(fp," void dump(); // Debugging prints\n");
fprintf(fp," void dump(int depth);\n");
fprintf(fp,"#endif\n");
if (_dfa_small) {
for (int i = 1; i < _last_opcode; i++) {
if (_mlistab[i] == NULL) continue;
fprintf(fp, " void _sub_Op_%s(const Node *n);\n", NodeClassNames[i]);
}
}
fprintf(fp,"};\n");
fprintf(fp,"\n");
fprintf(fp,"\n");
}
class OutputMachOperands : public OutputMap {
public:
OutputMachOperands(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)
: OutputMap(hpp, cpp, globals, AD, "MachOperands") {};
void declaration() { }
void definition() { fprintf(_cpp, "enum MachOperands {\n"); }
void closing() { fprintf(_cpp, " _LAST_MACH_OPER\n");
OutputMap::closing();
}
void map(OpClassForm &opc) {
const char* opc_ident_to_upper = _AD.machOperEnum(opc._ident);
fprintf(_cpp, " %s", opc_ident_to_upper);
delete[] opc_ident_to_upper;
}
void map(OperandForm &oper) {
const char* oper_ident_to_upper = _AD.machOperEnum(oper._ident);
fprintf(_cpp, " %s", oper_ident_to_upper);
delete[] oper_ident_to_upper;
}
void map(char *name) {
const char* name_to_upper = _AD.machOperEnum(name);
fprintf(_cpp, " %s", name_to_upper);
delete[] name_to_upper;
}
bool do_instructions() { return false; }
void map(InstructForm &inst){ assert( false, "ShouldNotCallThis()"); }
};
void ArchDesc::buildMachOperEnum(FILE *fp_hpp) {
OutputMachOperands output_mach_operands(fp_hpp, fp_hpp, _globalNames, *this);
build_map(output_mach_operands);
}
class OutputMachOpcodes : public OutputMap {
int begin_inst_chain_rule;
int end_inst_chain_rule;
int begin_rematerialize;
int end_rematerialize;
int end_instructions;
public:
OutputMachOpcodes(FILE *hpp, FILE *cpp, FormDict &globals, ArchDesc &AD)
: OutputMap(hpp, cpp, globals, AD, "MachOpcodes"),
begin_inst_chain_rule(-1), end_inst_chain_rule(-1),
begin_rematerialize(-1), end_rematerialize(-1),
end_instructions(-1)
{};
void declaration() { }
void definition() { fprintf(_cpp, "enum MachOpcodes {\n"); }
void closing() {
if( begin_inst_chain_rule != -1 )
fprintf(_cpp, " _BEGIN_INST_CHAIN_RULE = %d,\n", begin_inst_chain_rule);
if( end_inst_chain_rule != -1 )
fprintf(_cpp, " _END_INST_CHAIN_RULE = %d,\n", end_inst_chain_rule);
if( begin_rematerialize != -1 )
fprintf(_cpp, " _BEGIN_REMATERIALIZE = %d,\n", begin_rematerialize);
if( end_rematerialize != -1 )
fprintf(_cpp, " _END_REMATERIALIZE = %d,\n", end_rematerialize);
fprintf(_cpp, " _last_Mach_Node = %d \n", end_instructions);
OutputMap::closing();
}
void map(OpClassForm &opc) { fprintf(_cpp, " %s_rule", opc._ident ); }
void map(OperandForm &oper) { fprintf(_cpp, " %s_rule", oper._ident ); }
void map(char *name) { if (name) fprintf(_cpp, " %s_rule", name);
else fprintf(_cpp, " 0"); }
void map(InstructForm &inst) {fprintf(_cpp, " %s_rule", inst._ident ); }
void record_position(OutputMap::position place, int idx ) {
switch(place) {
case OutputMap::BEGIN_INST_CHAIN_RULES :
begin_inst_chain_rule = idx;
break;
case OutputMap::END_INST_CHAIN_RULES :
end_inst_chain_rule = idx;
break;
case OutputMap::BEGIN_REMATERIALIZE :
begin_rematerialize = idx;
break;
case OutputMap::END_REMATERIALIZE :
end_rematerialize = idx;
break;
case OutputMap::END_INSTRUCTIONS :
end_instructions = idx;
break;
default:
break;
}
}
};
void ArchDesc::buildMachOpcodesEnum(FILE *fp_hpp) {
OutputMachOpcodes output_mach_opcodes(fp_hpp, fp_hpp, _globalNames, *this);
build_map(output_mach_opcodes);
}
void ArchDesc::build_pipeline_enums(FILE *fp_hpp) {
int stagelen = (int)strlen("undefined");
int stagenum = 0;
if (_pipeline) { // Find max enum string length
const char *stage;
for ( _pipeline->_stages.reset(); (stage = _pipeline->_stages.iter()) != NULL; ) {
int len = (int)strlen(stage);
if (stagelen < len) stagelen = len;
}
}
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "// Pipeline Stages\n");
fprintf(fp_hpp, "enum machPipelineStages {\n");
fprintf(fp_hpp, " stage_%-*s = 0,\n", stagelen, "undefined");
if( _pipeline ) {
const char *stage;
for ( _pipeline->_stages.reset(); (stage = _pipeline->_stages.iter()) != NULL; )
fprintf(fp_hpp, " stage_%-*s = %d,\n", stagelen, stage, ++stagenum);
}
fprintf(fp_hpp, " stage_%-*s = %d\n", stagelen, "count", stagenum);
fprintf(fp_hpp, "};\n");
fprintf(fp_hpp, "\n");
fprintf(fp_hpp, "// Pipeline Resources\n");
fprintf(fp_hpp, "enum machPipelineResources {\n");
int rescount = 0;
if( _pipeline ) {
const char *resource;
int reslen = 0;
for ( _pipeline->_reslist.reset(); (resource = _pipeline->_reslist.iter()) != NULL; ) {
int len = (int)strlen(resource);
if (reslen < len)
reslen = len;
}
for ( _pipeline->_reslist.reset(); (resource = _pipeline->_reslist.iter()) != NULL; ) {
const ResourceForm *resform = _pipeline->_resdict[resource]->is_resource();
int mask = resform->mask();
if ((mask & (mask-1)) == 0)
fprintf(fp_hpp, " resource_%-*s = %d,\n", reslen, resource, rescount++);
}
fprintf(fp_hpp, "\n");
for ( _pipeline->_reslist.reset(); (resource = _pipeline->_reslist.iter()) != NULL; ) {
const ResourceForm *resform = _pipeline->_resdict[resource]->is_resource();
fprintf(fp_hpp, " res_mask_%-*s = 0x%08x,\n", reslen, resource, resform->mask());
}
fprintf(fp_hpp, "\n");
}
fprintf(fp_hpp, " resource_count = %d\n", rescount);
fprintf(fp_hpp, "};\n");
}
C:\hotspot-69087d08d473\src\share\vm/asm/assembler.cpp
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "asm/codeBuffer.hpp"
#include "runtime/atomic.hpp"
#include "runtime/atomic.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/os.hpp"
AbstractAssembler::AbstractAssembler(CodeBuffer* code) {
if (code == NULL) return;
CodeSection* cs = code->insts();
cs->clear_mark(); // new assembler kills old mark
if (cs->start() == NULL) {
vm_exit_out_of_memory(0, OOM_MMAP_ERROR, err_msg("CodeCache: no room for %s",
code->name()));
}
_code_section = cs;
_oop_recorder= code->oop_recorder();
DEBUG_ONLY( _short_branch_delta = 0; )
}
void AbstractAssembler::set_code_section(CodeSection* cs) {
assert(cs->outer() == code_section()->outer(), "sanity");
assert(cs->is_allocated(), "need to pre-allocate this section");
cs->clear_mark(); // new assembly into this section kills old mark
_code_section = cs;
}
address AbstractAssembler::start_a_stub(int required_space) {
CodeBuffer* cb = code();
CodeSection* cs = cb->stubs();
assert(_code_section == cb->insts(), "not in insts?");
if (cs->maybe_expand_to_ensure_remaining(required_space)
&& cb->blob() == NULL) {
return NULL;
}
set_code_section(cs);
return pc();
}
void AbstractAssembler::end_a_stub() {
assert(_code_section == code()->stubs(), "not in stubs?");
set_code_section(code()->insts());
}
address AbstractAssembler::start_a_const(int required_space, int required_align) {
CodeBuffer* cb = code();
CodeSection* cs = cb->consts();
assert(_code_section == cb->insts() || _code_section == cb->stubs(), "not in insts/stubs?");
address end = cs->end();
int pad = -(intptr_t)end & (required_align-1);
if (cs->maybe_expand_to_ensure_remaining(pad + required_space)) {
if (cb->blob() == NULL) return NULL;
end = cs->end(); // refresh pointer
}
if (pad > 0) {
while (--pad >= 0) { *end++ = 0; }
cs->set_end(end);
}
set_code_section(cs);
return end;
}
void AbstractAssembler::end_a_const(CodeSection* cs) {
assert(_code_section == code()->consts(), "not in consts?");
set_code_section(cs);
}
void AbstractAssembler::flush() {
ICache::invalidate_range(addr_at(0), offset());
}
void AbstractAssembler::bind(Label& L) {
if (L.is_bound()) {
guarantee(L.loc() == locator(), "attempt to redefine label");
return;
}
L.bind_loc(locator());
L.patch_instructions((MacroAssembler*)this);
}
void AbstractAssembler::generate_stack_overflow_check( int frame_size_in_bytes) {
if (UseStackBanging) {
const int page_size = os::vm_page_size();
int bang_end = StackShadowPages*page_size;
const int bang_end_safe = bang_end;
if (frame_size_in_bytes > page_size) {
bang_end += frame_size_in_bytes;
}
int bang_offset = bang_end_safe;
while (bang_offset <= bang_end) {
bang_stack_with_offset(bang_offset);
bang_offset += page_size;
}
} // end (UseStackBanging)
}
void Label::add_patch_at(CodeBuffer* cb, int branch_loc) {
assert(_loc == -1, "Label is unbound");
if (_patch_index < PatchCacheSize) {
_patches[_patch_index] = branch_loc;
} else {
if (_patch_overflow == NULL) {
_patch_overflow = cb->create_patch_overflow();
}
_patch_overflow->push(branch_loc);
}
++_patch_index;
}
void Label::patch_instructions(MacroAssembler* masm) {
assert(is_bound(), "Label is bound");
CodeBuffer* cb = masm->code();
int target_sect = CodeBuffer::locator_sect(loc());
address target = cb->locator_address(loc());
while (_patch_index > 0) {
--_patch_index;
int branch_loc;
if (_patch_index >= PatchCacheSize) {
branch_loc = _patch_overflow->pop();
} else {
branch_loc = _patches[_patch_index];
}
int branch_sect = CodeBuffer::locator_sect(branch_loc);
address branch = cb->locator_address(branch_loc);
if (branch_sect == CodeBuffer::SECT_CONSTS) {
continue;
}
#ifdef ASSERT
if (target_sect != branch_sect) {
for (int n = MIN2(target_sect, branch_sect),
nlimit = (target_sect + branch_sect) - n;
n < nlimit; n++) {
CodeSection* cs = cb->code_section(n);
assert(cs->is_frozen(), "cross-section branch needs stable offsets");
}
}
#endif //ASSERT
masm->pd_patch_instruction(branch, target);
}
}
struct DelayedConstant {
typedef void (*value_fn_t)();
BasicType type;
intptr_t value;
value_fn_t value_fn;
enum { DC_LIMIT = 20 };
static DelayedConstant delayed_constants[DC_LIMIT];
static DelayedConstant* add(BasicType type, value_fn_t value_fn);
bool match(BasicType t, value_fn_t cfn) {
return type == t && value_fn == cfn;
}
static void update_all();
};
DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT];
DelayedConstant* DelayedConstant::add(BasicType type,
DelayedConstant::value_fn_t cfn) {
for (int i = 0; i < DC_LIMIT; i++) {
DelayedConstant* dcon = &delayed_constants[i];
if (dcon->match(type, cfn))
return dcon;
if (dcon->value_fn == NULL) {
if (Atomic::cmpxchg_ptr(CAST_FROM_FN_PTR(void*, cfn), &dcon->value_fn, NULL) == NULL) {
dcon->type = type;
return dcon;
}
}
}
guarantee(false, "too many delayed constants");
return NULL;
}
void DelayedConstant::update_all() {
for (int i = 0; i < DC_LIMIT; i++) {
DelayedConstant* dcon = &delayed_constants[i];
if (dcon->value_fn != NULL && dcon->value == 0) {
typedef int (*int_fn_t)();
typedef address (*address_fn_t)();
switch (dcon->type) {
case T_INT: dcon->value = (intptr_t) ((int_fn_t) dcon->value_fn)(); break;
case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break;
}
}
}
}
RegisterOrConstant AbstractAssembler::delayed_value(int(*value_fn)(), Register tmp, int offset) {
intptr_t val = (intptr_t) (*value_fn)();
if (val != 0) return val + offset;
return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
}
RegisterOrConstant AbstractAssembler::delayed_value(address(*value_fn)(), Register tmp, int offset) {
intptr_t val = (intptr_t) (*value_fn)();
if (val != 0) return val + offset;
return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
}
intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) {
DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn);
return &dcon->value;
}
intptr_t* AbstractAssembler::delayed_value_addr(address(*value_fn)()) {
DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn);
return &dcon->value;
}
void AbstractAssembler::update_delayed_values() {
DelayedConstant::update_all();
}
void AbstractAssembler::block_comment(const char* comment) {
if (sect() == CodeBuffer::SECT_INSTS) {
code_section()->outer()->block_comment(offset(), comment);
}
}
const char* AbstractAssembler::code_string(const char* str) {
if (sect() == CodeBuffer::SECT_INSTS || sect() == CodeBuffer::SECT_STUBS) {
return code_section()->outer()->code_string(str);
}
return NULL;
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
#ifdef _LP64
if (UseCompressedOops && Universe::narrow_oop_base() != NULL) {
assert (Universe::heap() != NULL, "java heap should be initialized");
uintptr_t base = (uintptr_t)Universe::narrow_oop_base();
if ((uintptr_t)offset >= base) {
offset = (intptr_t)(pointer_delta((void*)offset, (void*)base, 1));
}
}
#endif
return offset < 0 || os::vm_page_size() <= offset;
}
C:\hotspot-69087d08d473\src\share\vm/asm/assembler.hpp
#ifndef SHARE_VM_ASM_ASSEMBLER_HPP
#define SHARE_VM_ASM_ASSEMBLER_HPP
#include "asm/codeBuffer.hpp"
#include "code/oopRecorder.hpp"
#include "code/relocInfo.hpp"
#include "memory/allocation.hpp"
#include "utilities/debug.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/top.hpp"
#ifdef TARGET_ARCH_x86
# include "register_x86.hpp"
# include "vm_version_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "register_sparc.hpp"
# include "vm_version_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "register_zero.hpp"
# include "vm_version_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "register_arm.hpp"
# include "vm_version_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "register_ppc.hpp"
# include "vm_version_ppc.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "register_aarch64.hpp"
# include "vm_version_aarch64.hpp"
#endif
class MacroAssembler;
class AbstractAssembler;
class Label;
class Label VALUE_OBJ_CLASS_SPEC {
private:
enum { PatchCacheSize = 4 };
int _loc;
int _patches[PatchCacheSize];
int _patch_index;
GrowableArray<int>* _patch_overflow;
Label(const Label&) { ShouldNotReachHere(); }
public:
void bind_loc(int loc) {
assert(loc >= 0, "illegal locator");
assert(_loc == -1, "already bound");
_loc = loc;
}
void bind_loc(int pos, int sect) { bind_loc(CodeBuffer::locator(pos, sect)); }
#ifndef PRODUCT
void print_instructions(MacroAssembler* masm) const;
#endif // PRODUCT
int loc() const {
assert(_loc >= 0, "unbound label");
return _loc;
}
int loc_pos() const { return CodeBuffer::locator_pos(loc()); }
int loc_sect() const { return CodeBuffer::locator_sect(loc()); }
bool is_bound() const { return _loc >= 0; }
bool is_unbound() const { return _loc == -1 && _patch_index > 0; }
bool is_unused() const { return _loc == -1 && _patch_index == 0; }
void add_patch_at(CodeBuffer* cb, int branch_loc);
void patch_instructions(MacroAssembler* masm);
void init() {
_loc = -1;
_patch_index = 0;
_patch_overflow = NULL;
}
Label() {
init();
}
~Label() {
assert(is_bound() || is_unused(), "Label was never bound to a location, but it was used as a jmp target");
}
void reset() {
init(); //leave _patch_overflow because it points to CodeBuffer.
}
};
class RegisterOrConstant VALUE_OBJ_CLASS_SPEC {
private:
Register _r;
intptr_t _c;
public:
RegisterOrConstant(): _r(noreg), _c(0) {}
RegisterOrConstant(Register r): _r(r), _c(0) {}
RegisterOrConstant(intptr_t c): _r(noreg), _c(c) {}
Register as_register() const { assert(is_register(),""); return _r; }
intptr_t as_constant() const { assert(is_constant(),""); return _c; }
Register register_or_noreg() const { return _r; }
intptr_t constant_or_zero() const { return _c; }
bool is_register() const { return _r != noreg; }
bool is_constant() const { return _r == noreg; }
};
class AbstractAssembler : public ResourceObj {
friend class Label;
protected:
CodeSection* _code_section; // section within the code buffer
OopRecorder* _oop_recorder; // support for relocInfo::oop_type
public:
address addr_at(int pos) const { return code_section()->start() + pos; }
protected:
address target(Label& L) { return code_section()->target(L, pc()); }
bool is8bit(int x) const { return -0x80 <= x && x < 0x80; }
bool isByte(int x) const { return 0 <= x && x < 0x100; }
bool isShiftCount(int x) const { return 0 <= x && x < 32; }
class InstructionMark: public StackObj {
private:
AbstractAssembler* _assm;
public:
InstructionMark(AbstractAssembler* assm) : _assm(assm) {
assert(assm->inst_mark() == NULL, "overlapping instructions");
_assm->set_inst_mark();
}
~InstructionMark() {
_assm->clear_inst_mark();
}
};
friend class InstructionMark;
#ifdef ASSERT
static bool pd_check_instruction_mark();
int _short_branch_delta;
int short_branch_delta() const { return _short_branch_delta; }
void set_short_branch_delta() { _short_branch_delta = 32; }
void clear_short_branch_delta() { _short_branch_delta = 0; }
class ShortBranchVerifier: public StackObj {
private:
AbstractAssembler* _assm;
public:
ShortBranchVerifier(AbstractAssembler* assm) : _assm(assm) {
assert(assm->short_branch_delta() == 0, "overlapping instructions");
_assm->set_short_branch_delta();
}
~ShortBranchVerifier() {
_assm->clear_short_branch_delta();
}
};
#else
class ShortBranchVerifier: public StackObj {
public:
ShortBranchVerifier(AbstractAssembler* assm) {}
};
#endif
public:
AbstractAssembler(CodeBuffer* code);
void flush();
void emit_int8( int8_t x) { code_section()->emit_int8( x); }
void emit_int16( int16_t x) { code_section()->emit_int16( x); }
void emit_int32( int32_t x) { code_section()->emit_int32( x); }
void emit_int64( int64_t x) { code_section()->emit_int64( x); }
void emit_float( jfloat x) { code_section()->emit_float( x); }
void emit_double( jdouble x) { code_section()->emit_double( x); }
void emit_address(address x) { code_section()->emit_address(x); }
enum { min_simm10 = -512 };
static bool is_simm(int64_t x, uint w) {
precond(1 < w && w < 64);
int64_t limes = INT64_C(1) << (w - 1);
return -limes <= x && x < limes;
}
static bool is_simm8(int64_t x) { return is_simm(x, 8); }
static bool is_simm9(int64_t x) { return is_simm(x, 9); }
static bool is_simm10(int64_t x) { return is_simm(x, 10); }
static bool is_simm16(int64_t x) { return is_simm(x, 16); }
static bool is_simm32(int64_t x) { return is_simm(x, 32); }
static bool is_uimm(uint64_t x, uint w) {
precond(0 < w && w < 64);
uint64_t limes = UINT64_C(1) << w;
return x < limes;
}
static bool is_uimm12(uint64_t x) { return is_uimm(x, 12); }
CodeSection* code_section() const { return _code_section; }
CodeBuffer* code() const { return code_section()->outer(); }
int sect() const { return code_section()->index(); }
address pc() const { return code_section()->end(); }
int offset() const { return code_section()->size(); }
int locator() const { return CodeBuffer::locator(offset(), sect()); }
OopRecorder* oop_recorder() const { return _oop_recorder; }
void set_oop_recorder(OopRecorder* r) { _oop_recorder = r; }
address inst_mark() const { return code_section()->mark(); }
void set_inst_mark() { code_section()->set_mark(); }
void clear_inst_mark() { code_section()->clear_mark(); }
void relocate(RelocationHolder const& rspec, int format = 0) {
assert(!pd_check_instruction_mark()
|| inst_mark() == NULL || inst_mark() == code_section()->end(),
"call relocate() between instructions");
code_section()->relocate(code_section()->end(), rspec, format);
}
void relocate( relocInfo::relocType rtype, int format = 0) {
code_section()->relocate(code_section()->end(), rtype, format);
}
static int code_fill_byte(); // used to pad out odd-sized code buffers
void block_comment(const char* comment);
const char* code_string(const char* str);
void bind(Label& L); // binds an unbound label L to the current code position
void set_code_section(CodeSection* cs);
address start_a_stub(int required_space);
void end_a_stub();
address start_a_const(int required_space, int required_align = sizeof(double));
void end_a_const(CodeSection* cs); // Pass the codesection to continue in (insts or stubs?).
address long_constant(jlong c) {
CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
emit_int64(c);
end_a_const(c1);
}
return ptr;
}
address double_constant(jdouble c) {
CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
emit_double(c);
end_a_const(c1);
}
return ptr;
}
address float_constant(jfloat c) {
CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
emit_float(c);
end_a_const(c1);
}
return ptr;
}
address address_constant(address c) {
CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
emit_address(c);
end_a_const(c1);
}
return ptr;
}
address address_constant(address c, RelocationHolder const& rspec) {
CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
relocate(rspec);
emit_address(c);
end_a_const(c1);
}
return ptr;
}
RegisterOrConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0);
RegisterOrConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0);
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset) = 0;
static intptr_t* delayed_value_addr(int(*constant_fn)());
static intptr_t* delayed_value_addr(address(*constant_fn)());
static void update_delayed_values();
void generate_stack_overflow_check( int frame_size_in_bytes );
virtual void bang_stack_with_offset(int offset) = 0;
void pd_patch_instruction(address branch, address target);
};
#ifdef TARGET_ARCH_x86
# include "assembler_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "assembler_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "assembler_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "assembler_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "assembler_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "assembler_ppc.hpp"
#endif
#endif // SHARE_VM_ASM_ASSEMBLER_HPP
C:\hotspot-69087d08d473\src\share\vm/asm/assembler.inline.hpp
#ifndef SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
#define SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
#include "asm/assembler.hpp"
#ifdef TARGET_ARCH_x86
# include "assembler_x86.inline.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "assembler_sparc.inline.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "assembler_zero.inline.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "assembler_arm.inline.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "assembler_ppc.inline.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "assembler_aarch64.inline.hpp"
#endif
#endif // SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/asm/codeBuffer.cpp
#include "precompiled.hpp"
#include "asm/codeBuffer.hpp"
#include "compiler/disassembler.hpp"
#include "memory/gcLocker.hpp"
#include "oops/methodData.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/copy.hpp"
#include "utilities/xmlstream.hpp"
typedef CodeBuffer::csize_t csize_t; // file-local definition
CodeBuffer::CodeBuffer(CodeBlob* blob) {
initialize_misc("static buffer");
initialize(blob->content_begin(), blob->content_size());
verify_section_allocation();
}
void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) {
int align = _insts.alignment();
int slop = (int) CodeSection::end_slop();
assert(blob() == NULL, "only once");
set_blob(BufferBlob::create(_name, code_size + (align+slop) * (SECT_LIMIT+1)));
if (blob() == NULL) {
return; // caller must test this
}
initialize(_total_start, _total_size);
assert((uintptr_t)insts_begin() % CodeEntryAlignment == 0, "instruction start not code entry aligned");
pd_initialize();
if (locs_size != 0) {
_insts.initialize_locs(locs_size / sizeof(relocInfo));
}
verify_section_allocation();
}
CodeBuffer::~CodeBuffer() {
verify_section_allocation();
for (CodeBuffer* cb = this; cb != NULL; cb = cb->before_expand()) {
cb->free_blob();
}
delete _overflow_arena;
free_strings();
#ifdef ASSERT
assert(_default_oop_recorder.allocated_on_stack(), "should be embedded object");
ResourceObj::allocation_type at = _default_oop_recorder.get_allocation_type();
Copy::fill_to_bytes(this, sizeof(*this), badResourceValue);
ResourceObj::set_allocation_type((address)(&_default_oop_recorder), at);
#endif
}
void CodeBuffer::initialize_oop_recorder(OopRecorder* r) {
assert(_oop_recorder == &_default_oop_recorder && _default_oop_recorder.is_unused(), "do this once");
DEBUG_ONLY(_default_oop_recorder.freeze()); // force unused OR to be frozen
_oop_recorder = r;
}
void CodeBuffer::initialize_section_size(CodeSection* cs, csize_t size) {
assert(cs != &_insts, "insts is the memory provider, not the consumer");
csize_t slop = CodeSection::end_slop(); // margin between sections
int align = cs->alignment();
assert(is_power_of_2(align), "sanity");
address start = _insts._start;
address limit = _insts._limit;
address middle = limit - size;
middle -= (intptr_t)middle & (align-1); // align the division point downward
guarantee(middle - slop > start, "need enough space to divide up");
_insts._limit = middle - slop; // subtract desired space, plus slop
cs->initialize(middle, limit - middle);
assert(cs->start() == middle, "sanity");
assert(cs->limit() == limit, "sanity");
if (_insts.has_locs()) cs->initialize_locs(1);
}
void CodeBuffer::freeze_section(CodeSection* cs) {
CodeSection* next_cs = (cs == consts())? NULL: code_section(cs->index()+1);
csize_t frozen_size = cs->size();
if (next_cs != NULL) {
frozen_size = next_cs->align_at_start(frozen_size);
}
address old_limit = cs->limit();
address new_limit = cs->start() + frozen_size;
relocInfo* old_locs_limit = cs->locs_limit();
relocInfo* new_locs_limit = cs->locs_end();
cs->_limit = new_limit;
cs->_locs_limit = new_locs_limit;
cs->_frozen = true;
if (!next_cs->is_allocated() && !next_cs->is_frozen()) {
next_cs->initialize(new_limit, old_limit - new_limit);
next_cs->initialize_shared_locs(new_locs_limit,
old_locs_limit - new_locs_limit);
}
}
void CodeBuffer::set_blob(BufferBlob* blob) {
_blob = blob;
if (blob != NULL) {
address start = blob->content_begin();
address end = blob->content_end();
int align = _insts.alignment();
start += (-(intptr_t)start) & (align-1);
_total_start = start;
_total_size = end - start;
} else {
#ifdef ASSERT
_total_start = badAddress;
_consts._start = _consts._end = badAddress;
_insts._start = _insts._end = badAddress;
_stubs._start = _stubs._end = badAddress;
#endif //ASSERT
}
}
void CodeBuffer::free_blob() {
if (_blob != NULL) {
BufferBlob::free(_blob);
set_blob(NULL);
}
}
const char* CodeBuffer::code_section_name(int n) {
#ifdef PRODUCT
return NULL;
#else //PRODUCT
switch (n) {
case SECT_CONSTS: return "consts";
case SECT_INSTS: return "insts";
case SECT_STUBS: return "stubs";
default: return NULL;
}
#endif //PRODUCT
}
int CodeBuffer::section_index_of(address addr) const {
for (int n = 0; n < (int)SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
if (cs->allocates(addr)) return n;
}
return SECT_NONE;
}
int CodeBuffer::locator(address addr) const {
for (int n = 0; n < (int)SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
if (cs->allocates(addr)) {
return locator(addr - cs->start(), n);
}
}
return -1;
}
address CodeBuffer::locator_address(int locator) const {
if (locator < 0) return NULL;
address start = code_section(locator_sect(locator))->start();
return start + locator_pos(locator);
}
bool CodeBuffer::is_backward_branch(Label& L) {
return L.is_bound() && insts_end() <= locator_address(L.loc());
}
address CodeBuffer::decode_begin() {
address begin = _insts.start();
if (_decode_begin != NULL && _decode_begin > begin)
begin = _decode_begin;
return begin;
}
GrowableArray<int>* CodeBuffer::create_patch_overflow() {
if (_overflow_arena == NULL) {
_overflow_arena = new (mtCode) Arena(mtCode);
}
return new (_overflow_arena) GrowableArray<int>(_overflow_arena, 8, 0, 0);
}
address CodeSection::target(Label& L, address branch_pc) {
if (L.is_bound()) {
int loc = L.loc();
if (index() == CodeBuffer::locator_sect(loc)) {
return start() + CodeBuffer::locator_pos(loc);
} else {
return outer()->locator_address(loc);
}
} else {
assert(allocates2(branch_pc), "sanity");
address base = start();
int patch_loc = CodeBuffer::locator(branch_pc - base, index());
L.add_patch_at(outer(), patch_loc);
return branch_pc;
}
}
void CodeSection::relocate(address at, RelocationHolder const& spec, int format) {
Relocation* reloc = spec.reloc();
relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();
if (rtype == relocInfo::none) return;
assert(start() <= at && at <= end()+1,
"cannot relocate data outside code boundaries");
if (!has_locs()) {
assert(rtype == relocInfo::none ||
rtype == relocInfo::runtime_call_type ||
rtype == relocInfo::internal_word_type||
rtype == relocInfo::section_word_type ||
rtype == relocInfo::external_word_type,
"code needs relocation information");
DEBUG_ONLY(_locs_start = _locs_limit = (relocInfo*)badAddress);
return;
}
csize_t offset = at - locs_point();
set_locs_point(at);
relocInfo* end = locs_end();
relocInfo* req = end + relocInfo::length_limit;
if (req >= locs_limit() || offset >= relocInfo::offset_limit()) {
req += (uint)offset / (uint)relocInfo::offset_limit();
if (req >= locs_limit()) {
expand_locs(locs_count() + (req - end));
end = locs_end();
}
}
while (offset >= relocInfo::offset_limit()) {
assert(end < locs_limit(), "adjust previous paragraph of code");
offset -= filler_relocInfo().addr_offset();
}
(*end) = relocInfo(rtype, offset, format);
end->initialize(this, reloc);
}
void CodeSection::initialize_locs(int locs_capacity) {
assert(_locs_start == NULL, "only one locs init step, please");
csize_t min_locs = MAX2(size() / 16, (csize_t)4);
if (locs_capacity < min_locs) locs_capacity = min_locs;
relocInfo* locs_start = NEW_RESOURCE_ARRAY(relocInfo, locs_capacity);
_locs_start = locs_start;
_locs_end = locs_start;
_locs_limit = locs_start + locs_capacity;
_locs_own = true;
}
void CodeSection::initialize_shared_locs(relocInfo* buf, int length) {
assert(_locs_start == NULL, "do this before locs are allocated");
while ((uintptr_t)buf % HeapWordSize != 0 && length > 0) {
++buf; --length;
}
if (length > 0) {
_locs_start = buf;
_locs_end = buf;
_locs_limit = buf + length;
_locs_own = false;
}
}
void CodeSection::initialize_locs_from(const CodeSection* source_cs) {
int lcount = source_cs->locs_count();
if (lcount != 0) {
initialize_shared_locs(source_cs->locs_start(), lcount);
_locs_end = _locs_limit = _locs_start + lcount;
assert(is_allocated(), "must have copied code already");
set_locs_point(start() + source_cs->locs_point_off());
}
assert(this->locs_count() == source_cs->locs_count(), "sanity");
}
void CodeSection::expand_locs(int new_capacity) {
if (_locs_start == NULL) {
initialize_locs(new_capacity);
return;
} else {
int old_count = locs_count();
int old_capacity = locs_capacity();
if (new_capacity < old_capacity * 2)
new_capacity = old_capacity * 2;
relocInfo* locs_start;
if (_locs_own) {
locs_start = REALLOC_RESOURCE_ARRAY(relocInfo, _locs_start, old_capacity, new_capacity);
} else {
locs_start = NEW_RESOURCE_ARRAY(relocInfo, new_capacity);
Copy::conjoint_jbytes(_locs_start, locs_start, old_capacity * sizeof(relocInfo));
_locs_own = true;
}
_locs_start = locs_start;
_locs_end = locs_start + old_count;
_locs_limit = locs_start + new_capacity;
}
}
csize_t CodeBuffer::total_content_size() const {
csize_t size_so_far = 0;
for (int n = 0; n < (int)SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
if (cs->is_empty()) continue; // skip trivial section
size_so_far = cs->align_at_start(size_so_far);
size_so_far += cs->size();
}
return size_so_far;
}
void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
address buf = dest->_total_start;
csize_t buf_offset = 0;
assert(dest->_total_size >= total_content_size(), "must be big enough");
{
int alignSize = MAX2((intx) sizeof(jdouble), CodeEntryAlignment);
assert( (dest->_total_start - _insts.start()) % alignSize == 0, "copy must preserve alignment");
}
const CodeSection* prev_cs = NULL;
CodeSection* prev_dest_cs = NULL;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
csize_t csize = cs->size();
CodeSection* dest_cs = dest->code_section(n);
if (!cs->is_empty()) {
csize_t padding = cs->align_at_start(buf_offset) - buf_offset;
if (padding != 0) {
buf_offset += padding;
assert(prev_dest_cs != NULL, "sanity");
prev_dest_cs->_limit += padding;
}
#ifdef ASSERT
if (prev_cs != NULL && prev_cs->is_frozen() && n < (SECT_LIMIT - 1)) {
address dest_start = buf+buf_offset;
csize_t start2start = cs->start() - prev_cs->start();
csize_t dest_start2start = dest_start - prev_dest_cs->start();
assert(start2start == dest_start2start, "cannot stretch frozen sect");
}
#endif //ASSERT
prev_dest_cs = dest_cs;
prev_cs = cs;
}
debug_only(dest_cs->_start = NULL); // defeat double-initialization assert
dest_cs->initialize(buf+buf_offset, csize);
dest_cs->set_end(buf+buf_offset+csize);
assert(dest_cs->is_allocated(), "must always be allocated");
assert(cs->is_empty() == dest_cs->is_empty(), "sanity");
buf_offset += csize;
}
assert(buf_offset == total_content_size(), "sanity");
dest->verify_section_allocation();
}
static void append_oop_references(GrowableArray<oop>* oops, Klass* k) {
oop cl = k->klass_holder();
if (cl != NULL && !oops->contains(cl)) {
oops->append(cl);
}
}
void CodeBuffer::finalize_oop_references(methodHandle mh) {
No_Safepoint_Verifier nsv;
GrowableArray<oop> oops;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
CodeSection* cs = code_section(n);
if (cs->is_empty()) continue; // skip trivial section
RelocIterator iter(cs);
while (iter.next()) {
if (iter.type() == relocInfo::metadata_type) {
metadata_Relocation* md = iter.metadata_reloc();
if (md->metadata_is_immediate()) {
Metadata* m = md->metadata_value();
if (oop_recorder()->is_real(m)) {
if (m->is_methodData()) {
m = ((MethodData*)m)->method();
}
if (m->is_method()) {
m = ((Method*)m)->method_holder();
}
if (m->is_klass()) {
append_oop_references(&oops, (Klass*)m);
} else {
m->print();
ShouldNotReachHere();
}
}
}
}
}
}
if (!oop_recorder()->is_unused()) {
for (int i = 0; i < oop_recorder()->metadata_count(); i++) {
Metadata* m = oop_recorder()->metadata_at(i);
if (oop_recorder()->is_real(m)) {
if (m->is_methodData()) {
m = ((MethodData*)m)->method();
}
if (m->is_method()) {
m = ((Method*)m)->method_holder();
}
if (m->is_klass()) {
append_oop_references(&oops, (Klass*)m);
} else {
m->print();
ShouldNotReachHere();
}
}
}
}
append_oop_references(&oops, mh->method_holder());
Thread* thread = Thread::current();
for (int i = 0; i < oops.length(); i++) {
oop_recorder()->find_index((jobject)thread->handle_area()->allocate_handle(oops.at(i)));
}
}
csize_t CodeBuffer::total_offset_of(CodeSection* cs) const {
csize_t size_so_far = 0;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
const CodeSection* cur_cs = code_section(n);
if (!cur_cs->is_empty()) {
size_so_far = cur_cs->align_at_start(size_so_far);
}
if (cur_cs->index() == cs->index()) {
return size_so_far;
}
size_so_far += cur_cs->size();
}
ShouldNotReachHere();
return -1;
}
csize_t CodeBuffer::total_relocation_size() const {
csize_t lsize = copy_relocations_to(NULL); // dry run only
csize_t csize = total_content_size();
csize_t total = RelocIterator::locs_and_index_size(csize, lsize);
return (csize_t) align_size_up(total, HeapWordSize);
}
csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const {
address buf = NULL;
csize_t buf_offset = 0;
csize_t buf_limit = 0;
if (dest != NULL) {
buf = (address)dest->relocation_begin();
buf_limit = (address)dest->relocation_end() - buf;
assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned");
assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized");
}
csize_t code_end_so_far = 0;
csize_t code_point_so_far = 0;
for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity");
if (cs->is_empty()) continue; // skip trivial section
relocInfo* lstart = cs->locs_start();
relocInfo* lend = cs->locs_end();
csize_t lsize = (csize_t)( (address)lend - (address)lstart );
csize_t csize = cs->size();
code_end_so_far = cs->align_at_start(code_end_so_far);
if (lsize > 0) {
csize_t new_code_point = code_end_so_far;
for (csize_t jump;
code_point_so_far < new_code_point;
code_point_so_far += jump) {
jump = new_code_point - code_point_so_far;
relocInfo filler = filler_relocInfo();
if (jump >= filler.addr_offset()) {
jump = filler.addr_offset();
} else { // else shrink the filler to fit
filler = relocInfo(relocInfo::none, jump);
}
if (buf != NULL) {
assert(buf_offset + (csize_t)sizeof(filler) <= buf_limit, "filler in bounds");
}
buf_offset += sizeof(filler);
}
csize_t last_code_point = code_end_so_far + cs->locs_point_off();
assert(code_point_so_far <= last_code_point, "sanity");
code_point_so_far = last_code_point; // advance past this guy's relocs
}
code_end_so_far += csize; // advance past this guy's instructions too
if (buf != NULL && lsize != 0) {
assert(buf_offset + lsize <= buf_limit, "target in bounds");
assert((uintptr_t)lstart % HeapWordSize == 0, "sane start");
if (buf_offset % HeapWordSize == 0) {
Copy::disjoint_words((HeapWord*)lstart,
(HeapWord*)(buf+buf_offset),
(lsize + HeapWordSize-1) / HeapWordSize);
} else {
Copy::conjoint_jbytes(lstart, buf+buf_offset, lsize);
}
}
buf_offset += lsize;
}
while (buf_offset % HeapWordSize != 0) {
if (buf != NULL) {
relocInfo padding = relocInfo(relocInfo::none, 0);
assert(buf_offset + (csize_t)sizeof(padding) <= buf_limit, "padding in bounds");
}
buf_offset += sizeof(relocInfo);
}
assert(code_end_so_far == total_content_size(), "sanity");
if (buf != NULL) {
RelocIterator::create_index(dest->relocation_begin(),
buf_offset / sizeof(relocInfo),
dest->relocation_end());
}
return buf_offset;
}
void CodeBuffer::copy_code_to(CodeBlob* dest_blob) {
#ifndef PRODUCT
if (PrintNMethods && (WizardMode || Verbose)) {
tty->print("done with CodeBuffer:");
((CodeBuffer*)this)->print();
}
#endif //PRODUCT
CodeBuffer dest(dest_blob);
assert(dest_blob->content_size() >= total_content_size(), "good sizing");
this->compute_final_layout(&dest);
relocate_code_to(&dest);
dest_blob->set_strings(_code_strings);
assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity");
ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size());
}
void CodeBuffer::relocate_code_to(CodeBuffer* dest) const {
address dest_end = dest->_total_start + dest->_total_size;
address dest_filled = NULL;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
if (cs->is_empty()) continue; // skip trivial section
CodeSection* dest_cs = dest->code_section(n);
assert(cs->size() == dest_cs->size(), "sanity");
csize_t usize = dest_cs->size();
csize_t wsize = align_size_up(usize, HeapWordSize);
assert(dest_cs->start() + wsize <= dest_end, "no overflow");
Copy::disjoint_words((HeapWord*)cs->start(),
(HeapWord*)dest_cs->start(),
wsize / HeapWordSize);
if (dest->blob() == NULL) {
Copy::fill_to_bytes(dest_cs->end(), dest_cs->remaining(),
Assembler::code_fill_byte());
}
dest_filled = MAX2(dest_filled, dest_cs->end() + dest_cs->remaining());
assert(cs->locs_start() != (relocInfo*)badAddress,
"this section carries no reloc storage, but reloc was attempted");
dest_cs->initialize_locs_from(cs);
}
for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) {
const CodeSection* cs = code_section(n);
if (cs->is_empty()) continue; // skip trivial section
CodeSection* dest_cs = dest->code_section(n);
{ // Repair the pc relative information in the code after the move
RelocIterator iter(dest_cs);
while (iter.next()) {
iter.reloc()->fix_relocation_after_move(this, dest);
}
}
}
if (dest->blob() == NULL && dest_filled != NULL) {
Copy::fill_to_bytes(dest_filled, dest_end - dest_filled,
Assembler::code_fill_byte());
}
}
csize_t CodeBuffer::figure_expanded_capacities(CodeSection* which_cs,
csize_t amount,
csize_t* new_capacity) {
csize_t new_total_cap = 0;
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
const CodeSection* sect = code_section(n);
if (!sect->is_empty()) {
csize_t padding = sect->align_at_start(new_total_cap) - new_total_cap;
if (padding != 0) {
new_total_cap += padding;
assert(n - 1 >= SECT_FIRST, "sanity");
new_capacity[n - 1] += padding;
}
}
csize_t exp = sect->size(); // 100% increase
if ((uint)exp < 4*K) exp = 4*K; // minimum initial increase
if (sect == which_cs) {
if (exp < amount) exp = amount;
if (StressCodeBuffers) exp = amount; // expand only slightly
} else if (n == SECT_INSTS) {
exp = 4*K + ((exp - 4*K) >> 2);
if (StressCodeBuffers) exp = amount / 2; // expand only slightly
} else if (sect->is_empty()) {
exp = 0;
}
exp += CodeSection::end_slop();
csize_t new_cap = sect->size() + exp;
if (new_cap < sect->capacity()) {
new_cap = sect->capacity();
}
new_capacity[n] = new_cap;
new_total_cap += new_cap;
}
return new_total_cap;
}
void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) {
#ifndef PRODUCT
if (PrintNMethods && (WizardMode || Verbose)) {
tty->print("expanding CodeBuffer:");
this->print();
}
if (StressCodeBuffers && blob() != NULL) {
static int expand_count = 0;
if (expand_count >= 0) expand_count += 1;
if (expand_count > 100 && is_power_of_2(expand_count)) {
tty->print_cr("StressCodeBuffers: have expanded %d times", expand_count);
free_blob();
}
}
#endif //PRODUCT
{
if (blob() == NULL) return; // caller must check for blob == NULL
for (int n = 0; n < (int)SECT_LIMIT; n++) {
guarantee(!code_section(n)->is_frozen(), "resizing not allowed when frozen");
}
}
csize_t new_capacity[SECT_LIMIT];
csize_t new_total_cap
= figure_expanded_capacities(which_cs, amount, new_capacity);
CodeBuffer cb(name(), new_total_cap, 0);
if (cb.blob() == NULL) {
free_blob();
return;
}
CodeBuffer* bxp = new CodeBuffer(_total_start, _total_size);
bxp->take_over_code_from(this); // remember the old undersized blob
DEBUG_ONLY(this->_blob = NULL); // silence a later assert
bxp->_before_expand = this->_before_expand;
this->_before_expand = bxp;
for (int n = (int)SECT_LIMIT-1; n >= SECT_FIRST; n--) {
CodeSection* cb_sect = cb.code_section(n);
CodeSection* this_sect = code_section(n);
if (new_capacity[n] == 0) continue; // already nulled out
if (n != SECT_INSTS) {
cb.initialize_section_size(cb_sect, new_capacity[n]);
}
assert(cb_sect->capacity() >= new_capacity[n], "big enough");
address cb_start = cb_sect->start();
cb_sect->set_end(cb_start + this_sect->size());
if (this_sect->mark() == NULL) {
cb_sect->clear_mark();
} else {
cb_sect->set_mark(cb_start + this_sect->mark_off());
}
}
relocate_code_to(&cb);
this->take_over_code_from(&cb);
cb.set_blob(NULL);
debug_only(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size,
badCodeHeapFreeVal));
_decode_begin = NULL; // sanity
verify_section_allocation();
#ifndef PRODUCT
if (PrintNMethods && (WizardMode || Verbose)) {
tty->print("expanded CodeBuffer:");
this->print();
}
#endif //PRODUCT
}
void CodeBuffer::take_over_code_from(CodeBuffer* cb) {
assert(blob() == NULL, "must be empty");
#ifdef ASSERT
#endif
set_blob(cb->blob());
for (int n = 0; n < (int)SECT_LIMIT; n++) {
CodeSection* cb_sect = cb->code_section(n);
CodeSection* this_sect = code_section(n);
this_sect->take_over_code_from(cb_sect);
}
_overflow_arena = cb->_overflow_arena;
DEBUG_ONLY(cb->_blob = (BufferBlob*)badAddress);
}
void CodeBuffer::verify_section_allocation() {
address tstart = _total_start;
if (tstart == badAddress) return; // smashed by set_blob(NULL)
address tend = tstart + _total_size;
if (_blob != NULL) {
guarantee(tstart >= _blob->content_begin(), "sanity");
guarantee(tend <= _blob->content_end(), "sanity");
}
for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
CodeSection* sect = code_section(n);
if (!sect->is_allocated() || sect->is_empty()) continue;
guarantee((intptr_t)sect->start() % sect->alignment() == 0
|| sect->is_empty() || _blob == NULL,
"start is aligned");
for (int m = (int) SECT_FIRST; m < (int) SECT_LIMIT; m++) {
CodeSection* other = code_section(m);
if (!other->is_allocated() || other == sect) continue;
guarantee(!other->contains(sect->start() ), "sanity");
guarantee(!other->contains(sect->limit() - 1), "sanity");
}
guarantee(sect->end() <= tend, "sanity");
guarantee(sect->end() <= sect->limit(), "sanity");
}
}
void CodeBuffer::log_section_sizes(const char* name) {
if (xtty != NULL) {
xtty->print_cr("<blob name='%s' size='%d'>", name, _total_size);
for (int n = (int) CodeBuffer::SECT_FIRST; n < (int) CodeBuffer::SECT_LIMIT; n++) {
CodeSection* sect = code_section(n);
if (!sect->is_allocated() || sect->is_empty()) continue;
xtty->print_cr("<sect index='%d' size='" SIZE_FORMAT "' free='" SIZE_FORMAT "'/>",
n, sect->limit() - sect->start(), sect->limit() - sect->end());
}
xtty->print_cr("</blob>");
}
}
#ifndef PRODUCT
void CodeSection::dump() {
address ptr = start();
for (csize_t step; ptr < end(); ptr += step) {
step = end() - ptr;
if (step > jintSize * 4) step = jintSize * 4;
tty->print(INTPTR_FORMAT ": ", p2i(ptr));
while (step > 0) {
tty->print(" " PTR32_FORMAT, *(jint*)ptr);
ptr += jintSize;
}
tty->cr();
}
}
void CodeSection::decode() {
Disassembler::decode(start(), end());
}
void CodeBuffer::block_comment(intptr_t offset, const char * comment) {
_code_strings.add_comment(offset, comment);
}
const char* CodeBuffer::code_string(const char* str) {
return _code_strings.add_string(str);
}
class CodeString: public CHeapObj<mtCode> {
private:
friend class CodeStrings;
const char * _string;
CodeString* _next;
intptr_t _offset;
~CodeString() {
assert(_next == NULL, "wrong interface for freeing list");
os::free((void*)_string, mtCode);
}
bool is_comment() const { return _offset >= 0; }
public:
CodeString(const char * string, intptr_t offset = -1)
: _next(NULL), _offset(offset) {
_string = os::strdup(string, mtCode);
}
const char * string() const { return _string; }
intptr_t offset() const { assert(_offset >= 0, "offset for non comment?"); return _offset; }
CodeString* next() const { return _next; }
void set_next(CodeString* next) { _next = next; }
CodeString* first_comment() {
if (is_comment()) {
return this;
} else {
return next_comment();
}
}
CodeString* next_comment() const {
CodeString* s = _next;
while (s != NULL && !s->is_comment()) {
s = s->_next;
}
return s;
}
};
CodeString* CodeStrings::find(intptr_t offset) const {
CodeString* a = _strings->first_comment();
while (a != NULL && a->offset() != offset) {
a = a->next_comment();
}
return a;
}
CodeString* CodeStrings::find_last(intptr_t offset) const {
CodeString* a = find(offset);
if (a != NULL) {
CodeString* c = NULL;
while (((c = a->next_comment()) != NULL) && (c->offset() == offset)) {
a = c;
}
}
return a;
}
void CodeStrings::add_comment(intptr_t offset, const char * comment) {
check_valid();
CodeString* c = new CodeString(comment, offset);
CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset);
if (inspos) {
c->set_next(inspos->next());
inspos->set_next(c);
} else {
c->set_next(_strings);
_strings = c;
}
}
void CodeStrings::assign(CodeStrings& other) {
other.check_valid();
assert(is_null(), "Cannot assign onto non-empty CodeStrings");
_strings = other._strings;
other.set_null_and_invalidate();
}
void CodeStrings::copy(CodeStrings& other) {
other.check_valid();
check_valid();
assert(is_null(), "Cannot copy onto non-empty CodeStrings");
CodeString* n = other._strings;
CodeString** ps = &_strings;
while (n != NULL) {
ps = &((*ps)->_next);
n = n->next();
}
}
void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
check_valid();
if (_strings != NULL) {
CodeString* c = find(offset);
while (c && c->offset() == offset) {
stream->bol();
stream->print(" ;; ");
stream->print_cr("%s", c->string());
c = c->next_comment();
}
}
}
void CodeStrings::free() {
CodeString* n = _strings;
while (n) {
CodeString* p = n->next();
n->set_next(NULL);
delete n;
n = p;
}
set_null_and_invalidate();
}
const char* CodeStrings::add_string(const char * string) {
check_valid();
CodeString* s = new CodeString(string);
s->set_next(_strings);
_strings = s;
assert(s->string() != NULL, "should have a string");
return s->string();
}
void CodeBuffer::decode() {
ttyLocker ttyl;
Disassembler::decode(decode_begin(), insts_end());
_decode_begin = insts_end();
}
void CodeBuffer::skip_decode() {
_decode_begin = insts_end();
}
void CodeBuffer::decode_all() {
ttyLocker ttyl;
for (int n = 0; n < (int)SECT_LIMIT; n++) {
CodeSection* cs = code_section(n);
tty->print_cr("! %s:", code_section_name(n));
if (cs != consts())
cs->decode();
else
cs->dump();
}
}
void CodeSection::print(const char* name) {
csize_t locs_size = locs_end() - locs_start();
tty->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)%s",
name, p2i(start()), p2i(end()), p2i(limit()), size(), capacity(),
is_frozen()? " [frozen]": "");
tty->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d",
name, p2i(locs_start()), p2i(locs_end()), p2i(locs_limit()), locs_size, locs_capacity(), locs_point_off());
if (PrintRelocations) {
RelocIterator iter(this);
iter.print();
}
}
void CodeBuffer::print() {
if (this == NULL) {
tty->print_cr("NULL CodeBuffer pointer");
return;
}
tty->print_cr("CodeBuffer:");
for (int n = 0; n < (int)SECT_LIMIT; n++) {
CodeSection* cs = code_section(n);
cs->print(code_section_name(n));
}
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/asm/codeBuffer.hpp
#ifndef SHARE_VM_ASM_CODEBUFFER_HPP
#define SHARE_VM_ASM_CODEBUFFER_HPP
#include "code/oopRecorder.hpp"
#include "code/relocInfo.hpp"
#include "utilities/debug.hpp"
class CodeStrings;
class PhaseCFG;
class Compile;
class BufferBlob;
class CodeBuffer;
class Label;
class CodeOffsets: public StackObj {
public:
enum Entries { Entry,
Verified_Entry,
Frame_Complete, // Offset in the code where the frame setup is (for forte stackwalks) is complete
OSR_Entry,
Dtrace_trap = OSR_Entry, // dtrace probes can never have an OSR entry so reuse it
Exceptions, // Offset where exception handler lives
Deopt, // Offset where deopt handler lives
DeoptMH, // Offset where MethodHandle deopt handler lives
UnwindHandler, // Offset to default unwind handler
max_Entries };
enum { frame_never_safe = -1 };
private:
int _values[max_Entries];
public:
CodeOffsets() {
_values[Entry ] = 0;
_values[Verified_Entry] = 0;
_values[Frame_Complete] = frame_never_safe;
_values[OSR_Entry ] = 0;
_values[Exceptions ] = -1;
_values[Deopt ] = -1;
_values[DeoptMH ] = -1;
_values[UnwindHandler ] = -1;
}
int value(Entries e) { return _values[e]; }
void set_value(Entries e, int val) { _values[e] = val; }
};
class CodeSection VALUE_OBJ_CLASS_SPEC {
friend class CodeBuffer;
public:
typedef int csize_t; // code size type; would be size_t except for history
private:
address _start; // first byte of contents (instructions)
address _mark; // user mark, usually an instruction beginning
address _end; // current end address
address _limit; // last possible (allocated) end address
relocInfo* _locs_start; // first byte of relocation information
relocInfo* _locs_end; // first byte after relocation information
relocInfo* _locs_limit; // first byte after relocation information buf
address _locs_point; // last relocated position (grows upward)
bool _locs_own; // did I allocate the locs myself?
bool _frozen; // no more expansion of this section
char _index; // my section number (SECT_INST, etc.)
CodeBuffer* _outer; // enclosing CodeBuffer
CodeSection() {
_start = NULL;
_mark = NULL;
_end = NULL;
_limit = NULL;
_locs_start = NULL;
_locs_end = NULL;
_locs_limit = NULL;
_locs_point = NULL;
_locs_own = false;
_frozen = false;
debug_only(_index = (char)-1);
debug_only(_outer = (CodeBuffer*)badAddress);
}
void initialize_outer(CodeBuffer* outer, int index) {
_outer = outer;
_index = index;
}
void initialize(address start, csize_t size = 0) {
assert(_start == NULL, "only one init step, please");
_start = start;
_mark = NULL;
_end = start;
_limit = start + size;
_locs_point = start;
}
void initialize_locs(int locs_capacity);
void expand_locs(int new_capacity);
void initialize_locs_from(const CodeSection* source_cs);
void take_over_code_from(CodeSection* cs) {
_start = cs->_start;
_mark = cs->_mark;
_end = cs->_end;
_limit = cs->_limit;
_locs_point = cs->_locs_point;
}
public:
address start() const { return _start; }
address mark() const { return _mark; }
address end() const { return _end; }
address limit() const { return _limit; }
csize_t size() const { return (csize_t)(_end - _start); }
csize_t mark_off() const { assert(_mark != NULL, "not an offset");
return (csize_t)(_mark - _start); }
csize_t capacity() const { return (csize_t)(_limit - _start); }
csize_t remaining() const { return (csize_t)(_limit - _end); }
relocInfo* locs_start() const { return _locs_start; }
relocInfo* locs_end() const { return _locs_end; }
int locs_count() const { return (int)(_locs_end - _locs_start); }
relocInfo* locs_limit() const { return _locs_limit; }
address locs_point() const { return _locs_point; }
csize_t locs_point_off() const{ return (csize_t)(_locs_point - _start); }
csize_t locs_capacity() const { return (csize_t)(_locs_limit - _locs_start); }
csize_t locs_remaining()const { return (csize_t)(_locs_limit - _locs_end); }
int index() const { return _index; }
bool is_allocated() const { return _start != NULL; }
bool is_empty() const { return _start == _end; }
bool is_frozen() const { return _frozen; }
bool has_locs() const { return _locs_end != NULL; }
CodeBuffer* outer() const { return _outer; }
bool contains(address pc) const { return pc >= _start && pc < _end; }
bool contains2(address pc) const { return pc >= _start && pc <= _end; }
bool allocates(address pc) const { return pc >= _start && pc < _limit; }
bool allocates2(address pc) const { return pc >= _start && pc <= _limit; }
void set_end(address pc) { assert(allocates2(pc), err_msg("not in CodeBuffer memory: " PTR_FORMAT " <= " PTR_FORMAT " <= " INTPTR_FORMAT, p2i(_start), p2i(pc), p2i(_limit))); _end = pc; }
void set_mark(address pc) { assert(contains2(pc), "not in codeBuffer");
_mark = pc; }
void set_mark_off(int offset) { assert(contains2(offset+_start),"not in codeBuffer");
_mark = offset + _start; }
void set_mark() { _mark = _end; }
void clear_mark() { _mark = NULL; }
void set_locs_end(relocInfo* p) {
assert(p <= locs_limit(), "locs data fits in allocated buffer");
_locs_end = p;
}
void set_locs_point(address pc) {
assert(pc >= locs_point(), "relocation addr may not decrease");
assert(allocates2(pc), "relocation addr must be in this section");
_locs_point = pc;
}
void emit_int8 ( int8_t x) { *((int8_t*) end()) = x; set_end(end() + sizeof(int8_t)); }
void emit_int16( int16_t x) { *((int16_t*) end()) = x; set_end(end() + sizeof(int16_t)); }
void emit_int32( int32_t x) { *((int32_t*) end()) = x; set_end(end() + sizeof(int32_t)); }
void emit_int64( int64_t x) { *((int64_t*) end()) = x; set_end(end() + sizeof(int64_t)); }
void emit_float( jfloat x) { *((jfloat*) end()) = x; set_end(end() + sizeof(jfloat)); }
void emit_double(jdouble x) { *((jdouble*) end()) = x; set_end(end() + sizeof(jdouble)); }
void emit_address(address x) { *((address*) end()) = x; set_end(end() + sizeof(address)); }
void initialize_shared_locs(relocInfo* buf, int length);
address target(Label& L, address branch_pc);
void relocate(address at, RelocationHolder const& rspec, int format = 0);
void relocate(address at, relocInfo::relocType rtype, int format = 0) {
if (rtype != relocInfo::none)
relocate(at, Relocation::spec_simple(rtype), format);
}
int alignment() const { return MAX2((int)sizeof(jdouble), (int)CodeEntryAlignment); }
static csize_t end_slop() { return MAX2((int)sizeof(jdouble), (int)CodeEntryAlignment); }
csize_t align_at_start(csize_t off) const { return (csize_t) align_size_up(off, alignment()); }
inline void freeze(); // { _outer->freeze_section(this); }
bool maybe_expand_to_ensure_remaining(csize_t amount);
#ifndef PRODUCT
void decode();
void dump();
void print(const char* name);
#endif //PRODUCT
};
class CodeString;
class CodeStrings VALUE_OBJ_CLASS_SPEC {
private:
#ifndef PRODUCT
CodeString* _strings;
#ifdef ASSERT
bool _defunct; // Zero bit pattern is "valid", see memset call in decode_env::decode_env
#endif
#endif
CodeString* find(intptr_t offset) const;
CodeString* find_last(intptr_t offset) const;
void set_null_and_invalidate() {
#ifndef PRODUCT
_strings = NULL;
#ifdef ASSERT
_defunct = true;
#endif
#endif
}
public:
CodeStrings() {
#ifndef PRODUCT
_strings = NULL;
#ifdef ASSERT
_defunct = false;
#endif
#endif
}
bool is_null() {
#ifdef ASSERT
return _strings == NULL;
#else
return true;
#endif
}
const char* add_string(const char * string) PRODUCT_RETURN_(return NULL;);
void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN;
void assign(CodeStrings& other) PRODUCT_RETURN;
void copy(CodeStrings& other) PRODUCT_RETURN;
void free() PRODUCT_RETURN;
inline void check_valid() const {
#ifdef ASSERT
assert(!_defunct, "Use of invalid CodeStrings");
#endif
}
};
class CodeBuffer: public StackObj {
friend class CodeSection;
private:
void* operator new(size_t size) throw() { return ResourceObj::operator new(size); }
void operator delete(void* p) { ShouldNotCallThis(); }
public:
typedef int csize_t; // code size type; would be size_t except for history
enum {
SECT_FIRST = 0,
SECT_CONSTS = SECT_FIRST, // Non-instruction data: Floats, jump tables, etc.
SECT_INSTS, // Executable instructions.
SECT_STUBS, // Outbound trampolines for supporting call sites.
SECT_LIMIT, SECT_NONE = -1
};
private:
enum {
sect_bits = 2, // assert (SECT_LIMIT <= (1<<sect_bits))
sect_mask = (1<<sect_bits)-1
};
const char* _name;
CodeSection _consts; // constants, jump tables
CodeSection _insts; // instructions (the main section)
CodeSection _stubs; // stubs (call site support), deopt, exception handling
CodeBuffer* _before_expand; // dead buffer, from before the last expansion
BufferBlob* _blob; // optional buffer in CodeCache for generated code
address _total_start; // first address of combined memory buffer
csize_t _total_size; // size in bytes of combined memory buffer
OopRecorder* _oop_recorder;
CodeStrings _code_strings;
OopRecorder _default_oop_recorder; // override with initialize_oop_recorder
Arena* _overflow_arena;
address _decode_begin; // start address for decode
address decode_begin();
void initialize_misc(const char * name) {
assert(name != NULL, "must have a name");
_name = name;
_before_expand = NULL;
_blob = NULL;
_oop_recorder = NULL;
_decode_begin = NULL;
_overflow_arena = NULL;
}
void initialize(address code_start, csize_t code_size) {
_consts.initialize_outer(this, SECT_CONSTS);
_insts.initialize_outer(this, SECT_INSTS);
_stubs.initialize_outer(this, SECT_STUBS);
_total_start = code_start;
_total_size = code_size;
_insts.initialize(code_start, code_size);
assert(!_stubs.is_allocated(), "no garbage here");
assert(!_consts.is_allocated(), "no garbage here");
_oop_recorder = &_default_oop_recorder;
}
void initialize_section_size(CodeSection* cs, csize_t size);
void freeze_section(CodeSection* cs);
void take_over_code_from(CodeBuffer* cs);
void verify_section_allocation();
csize_t copy_relocations_to(CodeBlob* blob) const;
void copy_code_to(CodeBlob* blob);
void relocate_code_to(CodeBuffer* cb) const;
void compute_final_layout(CodeBuffer* dest) const;
void expand(CodeSection* which_cs, csize_t amount);
csize_t figure_expanded_capacities(CodeSection* which_cs, csize_t amount, csize_t* new_capacity);
public:
CodeBuffer(address code_start, csize_t code_size) {
assert(code_start != NULL, "sanity");
initialize_misc("static buffer");
initialize(code_start, code_size);
verify_section_allocation();
}
CodeBuffer(CodeBlob* blob);
CodeBuffer(const char* name) {
initialize_misc(name);
}
CodeBuffer(const char* name, csize_t code_size, csize_t locs_size) {
initialize_misc(name);
initialize(code_size, locs_size);
}
~CodeBuffer();
void initialize(csize_t code_size, csize_t locs_size);
CodeSection* consts() { return &_consts; }
CodeSection* insts() { return &_insts; }
CodeSection* stubs() { return &_stubs; }
CodeSection* code_section(int n) {
CodeSection* cs = &_consts + n;
assert(cs->index() == n || !cs->is_allocated(), "sanity");
return cs;
}
const CodeSection* code_section(int n) const { // yucky const stuff
return ((CodeBuffer*)this)->code_section(n);
}
static const char* code_section_name(int n);
int section_index_of(address addr) const;
bool contains(address addr) const {
return section_index_of(addr) > SECT_NONE;
}
static int locator_pos(int locator) { return locator >> sect_bits; }
static int locator_sect(int locator) { return locator & sect_mask; }
static int locator(int pos, int sect) { return (pos << sect_bits) | sect; }
int locator(address addr) const;
address locator_address(int locator) const;
bool is_backward_branch(Label& L);
const char* name() const { return _name; }
CodeBuffer* before_expand() const { return _before_expand; }
BufferBlob* blob() const { return _blob; }
void set_blob(BufferBlob* blob);
void free_blob(); // Free the blob, if we own one.
address insts_begin() const { return _insts.start(); }
address insts_end() const { return _insts.end(); }
void set_insts_end(address end) { _insts.set_end(end); }
address insts_limit() const { return _insts.limit(); }
address insts_mark() const { return _insts.mark(); }
void set_insts_mark() { _insts.set_mark(); }
void clear_insts_mark() { _insts.clear_mark(); }
bool is_pure() const { return insts_size() == total_content_size(); }
csize_t insts_size() const { return _insts.size(); }
csize_t pure_insts_size() const { assert(is_pure(), "no non-code");
return insts_size(); }
csize_t insts_capacity() const { return _insts.capacity(); }
csize_t insts_remaining() const { return _insts.remaining(); }
bool insts_contains(address pc) const { return _insts.contains(pc); }
bool insts_contains2(address pc) const { return _insts.contains2(pc); }
void finalize_oop_references(methodHandle method);
csize_t total_content_size() const;
csize_t total_offset_of(CodeSection* cs) const;
csize_t total_relocation_size() const;
csize_t total_oop_size() const {
OopRecorder* recorder = oop_recorder();
return (recorder == NULL)? 0: recorder->oop_size();
}
csize_t total_metadata_size() const {
OopRecorder* recorder = oop_recorder();
return (recorder == NULL)? 0: recorder->metadata_size();
}
void initialize_consts_size(csize_t size) { initialize_section_size(&_consts, size); }
void initialize_stubs_size(csize_t size) { initialize_section_size(&_stubs, size); }
void initialize_oop_recorder(OopRecorder* r);
OopRecorder* oop_recorder() const { return _oop_recorder; }
CodeStrings& strings() { return _code_strings; }
void free_strings() {
if (!_code_strings.is_null()) {
_code_strings.free(); // sets _strings Null as a side-effect.
}
}
void relocate(address at, RelocationHolder const& rspec, int format = 0) {
_insts.relocate(at, rspec, format);
}
void relocate(address at, relocInfo::relocType rtype, int format = 0) {
_insts.relocate(at, rtype, format);
}
GrowableArray<int>* create_patch_overflow();
void copy_code_and_locs_to(CodeBlob* blob) {
assert(blob != NULL, "sane");
copy_relocations_to(blob);
copy_code_to(blob);
}
void copy_values_to(nmethod* nm) {
if (!oop_recorder()->is_unused()) {
oop_recorder()->copy_values_to(nm);
}
}
address transform_address(const CodeBuffer &cb, address addr) const;
void block_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
const char* code_string(const char* str) PRODUCT_RETURN_(return NULL;);
void log_section_sizes(const char* name);
#ifndef PRODUCT
public:
void decode();
void decode_all(); // decodes all the code
void skip_decode(); // sets decode_begin to code_end();
void print();
#endif
#ifdef TARGET_ARCH_x86
# include "codeBuffer_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "codeBuffer_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "codeBuffer_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "codeBuffer_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "codeBuffer_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "codeBuffer_ppc.hpp"
#endif
};
inline void CodeSection::freeze() {
_outer->freeze_section(this);
}
inline bool CodeSection::maybe_expand_to_ensure_remaining(csize_t amount) {
if (remaining() < amount) { _outer->expand(this, amount); return true; }
return false;
}
#endif // SHARE_VM_ASM_CODEBUFFER_HPP
C:\hotspot-69087d08d473\src\share\vm/asm/macroAssembler.hpp
#ifndef SHARE_VM_ASM_MACROASSEMBLER_HPP
#define SHARE_VM_ASM_MACROASSEMBLER_HPP
#include "asm/assembler.hpp"
#ifdef TARGET_ARCH_x86
# include "macroAssembler_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "macroAssembler_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "assembler_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "macroAssembler_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "macroAssembler_ppc.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "macroAssembler_aarch64.hpp"
#endif
#endif // SHARE_VM_ASM_MACROASSEMBLER_HPP
C:\hotspot-69087d08d473\src\share\vm/asm/macroAssembler.inline.hpp
#ifndef SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP
#define SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP
#include "asm/macroAssembler.hpp"
#ifdef TARGET_ARCH_x86
#endif
#ifdef TARGET_ARCH_sparc
# include "macroAssembler_sparc.inline.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "assembler_zero.inline.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "macroAssembler_arm.inline.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "macroAssembler_ppc.inline.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "macroAssembler_aarch64.inline.hpp"
#endif
#endif // SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/asm/register.cpp
#include "precompiled.hpp"
#include "asm/register.hpp"
C:\hotspot-69087d08d473\src\share\vm/asm/register.hpp
#ifndef SHARE_VM_ASM_REGISTER_HPP
#define SHARE_VM_ASM_REGISTER_HPP
#include "utilities/top.hpp"
class AbstractRegisterImpl;
typedef AbstractRegisterImpl* AbstractRegister;
class AbstractRegisterImpl {
protected:
int value() const { return (int)(intx)this; }
};
#define AS_REGISTER(type,name) ((type)name##_##type##EnumValue)
#define CONSTANT_REGISTER_DECLARATION(type, name, value) \
extern const type name; \
enum { name##_##type##EnumValue = (value) }
#define REGISTER_DECLARATION(type, name, value) \
extern const type name; \
enum { name##_##type##EnumValue = value##_##type##EnumValue }
#define REGISTER_DEFINITION(type, name) \
const type name = ((type)name##_##type##EnumValue)
#ifdef TARGET_ARCH_x86
# include "register_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "register_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "register_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "register_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "register_ppc.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "register_aarch64.hpp"
#endif
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b
) {
assert(
a != b,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT "",
p2i(a), p2i(b))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c
) {
assert(
a != b && a != c
&& b != c,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d
) {
assert(
a != b && a != c && a != d
&& b != c && b != d
&& c != d,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e
) {
assert(
a != b && a != c && a != d && a != e
&& b != c && b != d && b != e
&& c != d && c != e
&& d != e,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f
) {
assert(
a != b && a != c && a != d && a != e && a != f
&& b != c && b != d && b != e && b != f
&& c != d && c != e && c != f
&& d != e && d != f
&& e != f,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f,
AbstractRegister g
) {
assert(
a != b && a != c && a != d && a != e && a != f && a != g
&& b != c && b != d && b != e && b != f && b != g
&& c != d && c != e && c != f && c != g
&& d != e && d != f && d != g
&& e != f && e != g
&& f != g,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f,
AbstractRegister g,
AbstractRegister h
) {
assert(
a != b && a != c && a != d && a != e && a != f && a != g && a != h
&& b != c && b != d && b != e && b != f && b != g && b != h
&& c != d && c != e && c != f && c != g && c != h
&& d != e && d != f && d != g && d != h
&& e != f && e != g && e != h
&& f != g && f != h
&& g != h,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f,
AbstractRegister g,
AbstractRegister h,
AbstractRegister i
) {
assert(
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i
&& c != d && c != e && c != f && c != g && c != h && c != i
&& d != e && d != f && d != g && d != h && d != i
&& e != f && e != g && e != h && e != i
&& f != g && f != h && f != i
&& g != h && g != i
&& h != i,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
", i=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f,
AbstractRegister g,
AbstractRegister h,
AbstractRegister i,
AbstractRegister j
) {
assert(
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j
&& c != d && c != e && c != f && c != g && c != h && c != i && c != j
&& d != e && d != f && d != g && d != h && d != i && d != j
&& e != f && e != g && e != h && e != i && e != j
&& f != g && f != h && f != i && f != j
&& g != h && g != i && g != j
&& h != i && h != j
&& i != j,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f,
AbstractRegister g,
AbstractRegister h,
AbstractRegister i,
AbstractRegister j,
AbstractRegister k
) {
assert(
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k
&& c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k
&& d != e && d != f && d != g && d != h && d != i && d != j && d !=k
&& e != f && e != g && e != h && e != i && e != j && e !=k
&& f != g && f != h && f != i && f != j && f !=k
&& g != h && g != i && g != j && g !=k
&& h != i && h != j && h !=k
&& i != j && i !=k
&& j !=k,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k))
);
}
inline void assert_different_registers(
AbstractRegister a,
AbstractRegister b,
AbstractRegister c,
AbstractRegister d,
AbstractRegister e,
AbstractRegister f,
AbstractRegister g,
AbstractRegister h,
AbstractRegister i,
AbstractRegister j,
AbstractRegister k,
AbstractRegister l
) {
assert(
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k && a !=l
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k && b !=l
&& c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k && c !=l
&& d != e && d != f && d != g && d != h && d != i && d != j && d !=k && d !=l
&& e != f && e != g && e != h && e != i && e != j && e !=k && e !=l
&& f != g && f != h && f != i && f != j && f !=k && f !=l
&& g != h && g != i && g != j && g !=k && g !=l
&& h != i && h != j && h !=k && h !=l
&& i != j && i !=k && i !=l
&& j !=k && j !=l
&& k !=l,
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT
", l=" INTPTR_FORMAT "",
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l))
);
}
#endif // SHARE_VM_ASM_REGISTER_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Canonicalizer.cpp
#include "precompiled.hpp"
#include "c1/c1_Canonicalizer.hpp"
#include "c1/c1_InstructionPrinter.hpp"
#include "c1/c1_ValueStack.hpp"
#include "ci/ciArray.hpp"
#include "runtime/sharedRuntime.hpp"
class PrintValueVisitor: public ValueVisitor {
void visit(Value* vp) {
(*vp)->print_line();
}
};
void Canonicalizer::set_canonical(Value x) {
assert(x != NULL, "value must exist");
if (canonical() != x) {
#ifndef PRODUCT
if (!x->has_printable_bci()) {
x->set_printable_bci(bci());
}
#endif
if (PrintCanonicalization) {
PrintValueVisitor do_print_value;
canonical()->input_values_do(&do_print_value);
canonical()->print_line();
tty->print_cr("canonicalized to:");
x->input_values_do(&do_print_value);
x->print_line();
tty->cr();
}
assert(_canonical->type()->tag() == x->type()->tag(), "types must match");
_canonical = x;
}
}
void Canonicalizer::move_const_to_right(Op2* x) {
if (x->x()->type()->is_constant() && x->is_commutative()) x->swap_operands();
}
void Canonicalizer::do_Op2(Op2* x) {
if (x->x() == x->y()) {
switch (x->op()) {
case Bytecodes::_isub: set_constant(0); return;
case Bytecodes::_lsub: set_constant(jlong_cast(0)); return;
case Bytecodes::_iand: // fall through
case Bytecodes::_land: // fall through
case Bytecodes::_ior: // fall through
case Bytecodes::_lor : set_canonical(x->x()); return;
case Bytecodes::_ixor: set_constant(0); return;
case Bytecodes::_lxor: set_constant(jlong_cast(0)); return;
}
}
if (x->x()->type()->is_constant() && x->y()->type()->is_constant()) {
switch (x->type()->tag()) {
case intTag:
{ jint a = x->x()->type()->as_IntConstant()->value();
jint b = x->y()->type()->as_IntConstant()->value();
switch (x->op()) {
case Bytecodes::_iadd: set_constant(a + b); return;
case Bytecodes::_isub: set_constant(a - b); return;
case Bytecodes::_imul: set_constant(a * b); return;
case Bytecodes::_idiv:
if (b != 0) {
if (a == min_jint && b == -1) {
set_constant(min_jint);
} else {
set_constant(a / b);
}
return;
}
break;
case Bytecodes::_irem:
if (b != 0) {
if (a == min_jint && b == -1) {
set_constant(0);
} else {
set_constant(a % b);
}
return;
}
break;
case Bytecodes::_iand: set_constant(a & b); return;
case Bytecodes::_ior : set_constant(a | b); return;
case Bytecodes::_ixor: set_constant(a ^ b); return;
}
}
break;
case longTag:
{ jlong a = x->x()->type()->as_LongConstant()->value();
jlong b = x->y()->type()->as_LongConstant()->value();
switch (x->op()) {
case Bytecodes::_ladd: set_constant(a + b); return;
case Bytecodes::_lsub: set_constant(a - b); return;
case Bytecodes::_lmul: set_constant(a * b); return;
case Bytecodes::_ldiv:
if (b != 0) {
set_constant(SharedRuntime::ldiv(b, a));
return;
}
break;
case Bytecodes::_lrem:
if (b != 0) {
set_constant(SharedRuntime::lrem(b, a));
return;
}
break;
case Bytecodes::_land: set_constant(a & b); return;
case Bytecodes::_lor : set_constant(a | b); return;
case Bytecodes::_lxor: set_constant(a ^ b); return;
}
}
break;
}
}
move_const_to_right(x);
if (x->y()->type()->is_constant()) {
switch (x->type()->tag()) {
case intTag:
if (x->y()->type()->as_IntConstant()->value() == 0) {
switch (x->op()) {
case Bytecodes::_iadd: set_canonical(x->x()); return;
case Bytecodes::_isub: set_canonical(x->x()); return;
case Bytecodes::_imul: set_constant(0); return;
case Bytecodes::_iand: set_constant(0); return;
case Bytecodes::_ior : set_canonical(x->x()); return;
}
}
break;
case longTag:
if (x->y()->type()->as_LongConstant()->value() == (jlong)0) {
switch (x->op()) {
case Bytecodes::_ladd: set_canonical(x->x()); return;
case Bytecodes::_lsub: set_canonical(x->x()); return;
case Bytecodes::_lmul: set_constant((jlong)0); return;
case Bytecodes::_land: set_constant((jlong)0); return;
case Bytecodes::_lor : set_canonical(x->x()); return;
}
}
break;
}
}
}
void Canonicalizer::do_Phi (Phi* x) {}
void Canonicalizer::do_Constant (Constant* x) {}
void Canonicalizer::do_Local (Local* x) {}
void Canonicalizer::do_LoadField (LoadField* x) {}
static bool in_current_block(Value v) {
int max_distance = 4;
while (max_distance > 0 && v != NULL && v->as_BlockEnd() == NULL) {
v = v->next();
max_distance--;
}
return v == NULL;
}
void Canonicalizer::do_StoreField (StoreField* x) {
Convert* conv = x->value()->as_Convert();
if (conv) {
Value value = NULL;
BasicType type = x->field()->type()->basic_type();
switch (conv->op()) {
case Bytecodes::_i2b: if (type == T_BYTE) value = conv->value(); break;
case Bytecodes::_i2s: if (type == T_SHORT || type == T_BYTE) value = conv->value(); break;
case Bytecodes::_i2c: if (type == T_CHAR || type == T_BYTE) value = conv->value(); break;
}
if (value != NULL && in_current_block(conv)) {
set_canonical(new StoreField(x->obj(), x->offset(), x->field(), value, x->is_static(),
x->state_before(), x->needs_patching()));
return;
}
}
}
void Canonicalizer::do_ArrayLength (ArrayLength* x) {
NewArray* array = x->array()->as_NewArray();
if (array != NULL && array->length() != NULL) {
Constant* length = array->length()->as_Constant();
if (length != NULL) {
assert(length->type()->as_IntConstant() != NULL, "array length must be integer");
set_constant(length->type()->as_IntConstant()->value());
}
} else {
LoadField* lf = x->array()->as_LoadField();
if (lf != NULL) {
ciField* field = lf->field();
if (field->is_constant() && field->is_static()) {
ciObject* c = field->constant_value().as_object();
if (c->is_array()) {
ciArray* array = (ciArray*) c;
set_constant(array->length());
}
}
}
}
}
void Canonicalizer::do_LoadIndexed (LoadIndexed* x) {}
void Canonicalizer::do_StoreIndexed (StoreIndexed* x) {
Convert* conv = x->value()->as_Convert();
if (conv) {
Value value = NULL;
BasicType type = x->elt_type();
switch (conv->op()) {
case Bytecodes::_i2b: if (type == T_BYTE) value = conv->value(); break;
case Bytecodes::_i2s: if (type == T_SHORT || type == T_BYTE) value = conv->value(); break;
case Bytecodes::_i2c: if (type == T_CHAR || type == T_BYTE) value = conv->value(); break;
}
if (value != NULL && in_current_block(conv)) {
set_canonical(new StoreIndexed(x->array(), x->index(), x->length(),
x->elt_type(), value, x->state_before(),
x->check_boolean()));
return;
}
}
}
void Canonicalizer::do_NegateOp(NegateOp* x) {
ValueType* t = x->x()->type();
if (t->is_constant()) {
switch (t->tag()) {
case intTag : set_constant(-t->as_IntConstant ()->value()); return;
case longTag : set_constant(-t->as_LongConstant ()->value()); return;
case floatTag : set_constant(-t->as_FloatConstant ()->value()); return;
case doubleTag: set_constant(-t->as_DoubleConstant()->value()); return;
default : ShouldNotReachHere();
}
}
}
void Canonicalizer::do_ArithmeticOp (ArithmeticOp* x) { do_Op2(x); }
void Canonicalizer::do_ShiftOp (ShiftOp* x) {
ValueType* t = x->x()->type();
ValueType* t2 = x->y()->type();
if (t->is_constant()) {
switch (t->tag()) {
case intTag : if (t->as_IntConstant()->value() == 0) { set_constant(0); return; } break;
case longTag : if (t->as_LongConstant()->value() == (jlong)0) { set_constant(jlong_cast(0)); return; } break;
default : ShouldNotReachHere();
}
if (t2->is_constant()) {
if (t->tag() == intTag) {
int value = t->as_IntConstant()->value();
int shift = t2->as_IntConstant()->value() & 31;
jint mask = ~(~0 << (32 - shift));
if (shift == 0) mask = ~0;
switch (x->op()) {
case Bytecodes::_ishl: set_constant(value << shift); return;
case Bytecodes::_ishr: set_constant(value >> shift); return;
case Bytecodes::_iushr: set_constant((value >> shift) & mask); return;
}
} else if (t->tag() == longTag) {
jlong value = t->as_LongConstant()->value();
int shift = t2->as_IntConstant()->value() & 63;
jlong mask = ~(~jlong_cast(0) << (64 - shift));
if (shift == 0) mask = ~jlong_cast(0);
switch (x->op()) {
case Bytecodes::_lshl: set_constant(value << shift); return;
case Bytecodes::_lshr: set_constant(value >> shift); return;
case Bytecodes::_lushr: set_constant((value >> shift) & mask); return;
}
}
}
}
if (t2->is_constant()) {
switch (t2->tag()) {
case intTag : if (t2->as_IntConstant()->value() == 0) set_canonical(x->x()); return;
case longTag : if (t2->as_LongConstant()->value() == (jlong)0) set_canonical(x->x()); return;
default : ShouldNotReachHere();
}
}
}
void Canonicalizer::do_LogicOp (LogicOp* x) { do_Op2(x); }
void Canonicalizer::do_CompareOp (CompareOp* x) {
if (x->x() == x->y()) {
switch (x->x()->type()->tag()) {
case longTag: set_constant(0); break;
case floatTag: {
FloatConstant* fc = x->x()->type()->as_FloatConstant();
if (fc) {
if (g_isnan(fc->value())) {
set_constant(x->op() == Bytecodes::_fcmpl ? -1 : 1);
} else {
set_constant(0);
}
}
break;
}
case doubleTag: {
DoubleConstant* dc = x->x()->type()->as_DoubleConstant();
if (dc) {
if (g_isnan(dc->value())) {
set_constant(x->op() == Bytecodes::_dcmpl ? -1 : 1);
} else {
set_constant(0);
}
}
break;
}
}
} else if (x->x()->type()->is_constant() && x->y()->type()->is_constant()) {
switch (x->x()->type()->tag()) {
case longTag: {
jlong vx = x->x()->type()->as_LongConstant()->value();
jlong vy = x->y()->type()->as_LongConstant()->value();
if (vx == vy)
set_constant(0);
else if (vx < vy)
set_constant(-1);
else
set_constant(1);
break;
}
case floatTag: {
float vx = x->x()->type()->as_FloatConstant()->value();
float vy = x->y()->type()->as_FloatConstant()->value();
if (g_isnan(vx) || g_isnan(vy))
set_constant(x->op() == Bytecodes::_fcmpl ? -1 : 1);
else if (vx == vy)
set_constant(0);
else if (vx < vy)
set_constant(-1);
else
set_constant(1);
break;
}
case doubleTag: {
double vx = x->x()->type()->as_DoubleConstant()->value();
double vy = x->y()->type()->as_DoubleConstant()->value();
if (g_isnan(vx) || g_isnan(vy))
set_constant(x->op() == Bytecodes::_dcmpl ? -1 : 1);
else if (vx == vy)
set_constant(0);
else if (vx < vy)
set_constant(-1);
else
set_constant(1);
break;
}
}
}
}
void Canonicalizer::do_IfInstanceOf(IfInstanceOf* x) {}
void Canonicalizer::do_IfOp(IfOp* x) {
move_const_to_right(x);
}
void Canonicalizer::do_Intrinsic (Intrinsic* x) {
switch (x->id()) {
case vmIntrinsics::_floatToRawIntBits : {
FloatConstant* c = x->argument_at(0)->type()->as_FloatConstant();
if (c != NULL) {
JavaValue v;
v.set_jfloat(c->value());
set_constant(v.get_jint());
}
break;
}
case vmIntrinsics::_intBitsToFloat : {
IntConstant* c = x->argument_at(0)->type()->as_IntConstant();
if (c != NULL) {
JavaValue v;
v.set_jint(c->value());
set_constant(v.get_jfloat());
}
break;
}
case vmIntrinsics::_doubleToRawLongBits : {
DoubleConstant* c = x->argument_at(0)->type()->as_DoubleConstant();
if (c != NULL) {
JavaValue v;
v.set_jdouble(c->value());
set_constant(v.get_jlong());
}
break;
}
case vmIntrinsics::_longBitsToDouble : {
LongConstant* c = x->argument_at(0)->type()->as_LongConstant();
if (c != NULL) {
JavaValue v;
v.set_jlong(c->value());
set_constant(v.get_jdouble());
}
break;
}
case vmIntrinsics::_isInstance : {
assert(x->number_of_arguments() == 2, "wrong type");
InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant();
if (c != NULL && !c->value()->is_null_object()) {
ciType* t = c->value()->as_instance()->java_mirror_type();
if (t->is_klass()) {
InstanceOf* i = new InstanceOf(t->as_klass(), x->argument_at(1), x->state_before());
set_canonical(i);
do_InstanceOf(i);
} else {
assert(t->is_primitive_type(), "should be a primitive type");
set_constant(0);
}
}
break;
}
}
}
void Canonicalizer::do_Convert (Convert* x) {
if (x->value()->type()->is_constant()) {
switch (x->op()) {
case Bytecodes::_i2b: set_constant((int)((x->value()->type()->as_IntConstant()->value() << 24) >> 24)); break;
case Bytecodes::_i2s: set_constant((int)((x->value()->type()->as_IntConstant()->value() << 16) >> 16)); break;
case Bytecodes::_i2c: set_constant((int)(x->value()->type()->as_IntConstant()->value() & ((1<<16)-1))); break;
case Bytecodes::_i2l: set_constant((jlong)(x->value()->type()->as_IntConstant()->value())); break;
case Bytecodes::_i2f: set_constant((float)(x->value()->type()->as_IntConstant()->value())); break;
case Bytecodes::_i2d: set_constant((double)(x->value()->type()->as_IntConstant()->value())); break;
case Bytecodes::_l2i: set_constant((int)(x->value()->type()->as_LongConstant()->value())); break;
case Bytecodes::_l2f: set_constant(SharedRuntime::l2f(x->value()->type()->as_LongConstant()->value())); break;
case Bytecodes::_l2d: set_constant(SharedRuntime::l2d(x->value()->type()->as_LongConstant()->value())); break;
case Bytecodes::_f2d: set_constant((double)(x->value()->type()->as_FloatConstant()->value())); break;
case Bytecodes::_f2i: set_constant(SharedRuntime::f2i(x->value()->type()->as_FloatConstant()->value())); break;
case Bytecodes::_f2l: set_constant(SharedRuntime::f2l(x->value()->type()->as_FloatConstant()->value())); break;
case Bytecodes::_d2f: set_constant((float)(x->value()->type()->as_DoubleConstant()->value())); break;
case Bytecodes::_d2i: set_constant(SharedRuntime::d2i(x->value()->type()->as_DoubleConstant()->value())); break;
case Bytecodes::_d2l: set_constant(SharedRuntime::d2l(x->value()->type()->as_DoubleConstant()->value())); break;
default:
ShouldNotReachHere();
}
}
Value value = x->value();
BasicType type = T_ILLEGAL;
LoadField* lf = value->as_LoadField();
if (lf) {
type = lf->field_type();
} else {
LoadIndexed* li = value->as_LoadIndexed();
if (li) {
type = li->elt_type();
} else {
Convert* conv = value->as_Convert();
if (conv) {
switch (conv->op()) {
case Bytecodes::_i2b: type = T_BYTE; break;
case Bytecodes::_i2s: type = T_SHORT; break;
case Bytecodes::_i2c: type = T_CHAR; break;
}
}
}
}
if (type != T_ILLEGAL) {
switch (x->op()) {
case Bytecodes::_i2b: if (type == T_BYTE) set_canonical(x->value()); break;
case Bytecodes::_i2s: if (type == T_SHORT || type == T_BYTE) set_canonical(x->value()); break;
case Bytecodes::_i2c: if (type == T_CHAR) set_canonical(x->value()); break;
}
} else {
Op2* op2 = x->value()->as_Op2();
if (op2 && op2->op() == Bytecodes::_iand && op2->y()->type()->is_constant()) {
jint safebits = 0;
jint mask = op2->y()->type()->as_IntConstant()->value();
switch (x->op()) {
case Bytecodes::_i2b: safebits = 0x7f; break;
case Bytecodes::_i2s: safebits = 0x7fff; break;
case Bytecodes::_i2c: safebits = 0xffff; break;
}
if (safebits && (mask & ~safebits) == 0) {
set_canonical(x->value());
}
}
}
}
void Canonicalizer::do_NullCheck (NullCheck* x) {
if (x->obj()->as_NewArray() != NULL || x->obj()->as_NewInstance() != NULL) {
set_canonical(x->obj());
} else {
Constant* con = x->obj()->as_Constant();
if (con) {
ObjectType* c = con->type()->as_ObjectType();
if (c && c->is_loaded()) {
ObjectConstant* oc = c->as_ObjectConstant();
if (!oc || !oc->value()->is_null_object()) {
set_canonical(con);
}
}
}
}
}
void Canonicalizer::do_TypeCast (TypeCast* x) {}
void Canonicalizer::do_Invoke (Invoke* x) {}
void Canonicalizer::do_NewInstance (NewInstance* x) {}
void Canonicalizer::do_NewTypeArray (NewTypeArray* x) {}
void Canonicalizer::do_NewObjectArray (NewObjectArray* x) {}
void Canonicalizer::do_NewMultiArray (NewMultiArray* x) {}
void Canonicalizer::do_CheckCast (CheckCast* x) {
if (x->klass()->is_loaded()) {
Value obj = x->obj();
ciType* klass = obj->exact_type();
if (klass == NULL) klass = obj->declared_type();
if (klass != NULL && klass->is_loaded() && klass->is_subtype_of(x->klass())) {
set_canonical(obj);
return;
}
if (obj->as_Constant() && obj->type()->as_ObjectType()->constant_value()->is_null_object()) {
set_canonical(obj);
}
}
}
void Canonicalizer::do_InstanceOf (InstanceOf* x) {
if (x->klass()->is_loaded()) {
Value obj = x->obj();
ciType* exact = obj->exact_type();
if (exact != NULL && exact->is_loaded() && (obj->as_NewInstance() || obj->as_NewArray())) {
set_constant(exact->is_subtype_of(x->klass()) ? 1 : 0);
return;
}
if (obj->as_Constant() && obj->type()->as_ObjectType()->constant_value()->is_null_object()) {
set_constant(0);
}
}
}
void Canonicalizer::do_MonitorEnter (MonitorEnter* x) {}
void Canonicalizer::do_MonitorExit (MonitorExit* x) {}
void Canonicalizer::do_BlockBegin (BlockBegin* x) {}
void Canonicalizer::do_Goto (Goto* x) {}
static bool is_true(jlong x, If::Condition cond, jlong y) {
switch (cond) {
case If::eql: return x == y;
case If::neq: return x != y;
case If::lss: return x < y;
case If::leq: return x <= y;
case If::gtr: return x > y;
case If::geq: return x >= y;
}
ShouldNotReachHere();
return false;
}
static bool is_safepoint(BlockEnd* x, BlockBegin* sux) {
return x->is_safepoint() && (sux->bci() < x->state_before()->bci());
}
void Canonicalizer::do_If(If* x) {
if (x->x()->type()->is_constant()) x->swap_operands();
const Value l = x->x(); ValueType* lt = l->type();
const Value r = x->y(); ValueType* rt = r->type();
if (l == r && !lt->is_float_kind()) {
BlockBegin* sux = NULL;
switch (x->cond()) {
case If::eql: sux = x->sux_for(true); break;
case If::neq: sux = x->sux_for(false); break;
case If::lss: sux = x->sux_for(false); break;
case If::leq: sux = x->sux_for(true); break;
case If::gtr: sux = x->sux_for(false); break;
case If::geq: sux = x->sux_for(true); break;
default: ShouldNotReachHere();
}
set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
return;
}
if (lt->is_constant() && rt->is_constant()) {
if (x->x()->as_Constant() != NULL) {
BlockBegin* sux = x->x()->as_Constant()->compare(x->cond(), x->y(),
x->sux_for(true),
x->sux_for(false));
if (sux != NULL) {
set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
}
}
} else if (rt->as_IntConstant() != NULL) {
const jint rc = rt->as_IntConstant()->value();
if (l->as_CompareOp() != NULL) {
CompareOp* cmp = l->as_CompareOp();
bool unordered_is_less = cmp->op() == Bytecodes::_fcmpl || cmp->op() == Bytecodes::_dcmpl;
BlockBegin* lss_sux = x->sux_for(is_true(-1, x->cond(), rc)); // successor for a < b
BlockBegin* eql_sux = x->sux_for(is_true( 0, x->cond(), rc)); // successor for a = b
BlockBegin* gtr_sux = x->sux_for(is_true(+1, x->cond(), rc)); // successor for a > b
BlockBegin* nan_sux = unordered_is_less ? lss_sux : gtr_sux ; // successor for unordered
if (lss_sux == eql_sux && eql_sux == gtr_sux) {
set_canonical(new Goto(lss_sux, x->state_before(), x->is_safepoint()));
} else {
If::Condition cond = If::eql;
BlockBegin* tsux = NULL;
BlockBegin* fsux = NULL;
if (lss_sux == eql_sux) { cond = If::leq; tsux = lss_sux; fsux = gtr_sux; }
else if (lss_sux == gtr_sux) { cond = If::neq; tsux = lss_sux; fsux = eql_sux; }
else if (eql_sux == gtr_sux) { cond = If::geq; tsux = eql_sux; fsux = lss_sux; }
else { ShouldNotReachHere(); }
If* canon = new If(cmp->x(), cond, nan_sux == tsux, cmp->y(), tsux, fsux, cmp->state_before(), x->is_safepoint());
if (cmp->x() == cmp->y()) {
do_If(canon);
} else {
if (compilation()->profile_branches()) {
switch(cmp->op()) {
case Bytecodes::_fcmpl: case Bytecodes::_fcmpg:
case Bytecodes::_dcmpl: case Bytecodes::_dcmpg:
set_canonical(x);
return;
}
}
set_bci(cmp->state_before()->bci());
set_canonical(canon);
}
}
} else if (l->as_InstanceOf() != NULL) {
return;
InstanceOf* inst = l->as_InstanceOf();
BlockBegin* is_inst_sux = x->sux_for(is_true(1, x->cond(), rc)); // successor for instanceof == 1
BlockBegin* no_inst_sux = x->sux_for(is_true(0, x->cond(), rc)); // successor for instanceof == 0
if (is_inst_sux == no_inst_sux && inst->is_loaded()) {
set_canonical(new Goto(is_inst_sux, x->state_before(), x->is_safepoint()));
} else {
set_canonical(new IfInstanceOf(inst->klass(), inst->obj(), true, inst->state_before()->bci(), is_inst_sux, no_inst_sux));
}
}
} else if (rt == objectNull && (l->as_NewInstance() || l->as_NewArray())) {
if (x->cond() == Instruction::eql) {
BlockBegin* sux = x->fsux();
set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
} else {
assert(x->cond() == Instruction::neq, "only other valid case");
BlockBegin* sux = x->tsux();
set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
}
}
}
void Canonicalizer::do_TableSwitch(TableSwitch* x) {
if (x->tag()->type()->is_constant()) {
int v = x->tag()->type()->as_IntConstant()->value();
BlockBegin* sux = x->default_sux();
if (v >= x->lo_key() && v <= x->hi_key()) {
sux = x->sux_at(v - x->lo_key());
}
set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
} else if (x->number_of_sux() == 1) {
return;
set_canonical(new Goto(x->default_sux(), x->state_before(), x->is_safepoint()));
} else if (x->number_of_sux() == 2) {
return;
assert(x->lo_key() == x->hi_key(), "keys must be the same");
Constant* key = new Constant(new IntConstant(x->lo_key()));
set_canonical(new If(x->tag(), If::eql, true, key, x->sux_at(0), x->default_sux(), x->state_before(), x->is_safepoint()));
}
}
void Canonicalizer::do_LookupSwitch(LookupSwitch* x) {
if (x->tag()->type()->is_constant()) {
int v = x->tag()->type()->as_IntConstant()->value();
BlockBegin* sux = x->default_sux();
for (int i = 0; i < x->length(); i++) {
if (v == x->key_at(i)) {
sux = x->sux_at(i);
}
}
set_canonical(new Goto(sux, x->state_before(), is_safepoint(x, sux)));
} else if (x->number_of_sux() == 1) {
return;
set_canonical(new Goto(x->default_sux(), x->state_before(), x->is_safepoint()));
} else if (x->number_of_sux() == 2) {
return;
assert(x->length() == 1, "length must be the same");
Constant* key = new Constant(new IntConstant(x->key_at(0)));
set_canonical(new If(x->tag(), If::eql, true, key, x->sux_at(0), x->default_sux(), x->state_before(), x->is_safepoint()));
}
}
void Canonicalizer::do_Return (Return* x) {}
void Canonicalizer::do_Throw (Throw* x) {}
void Canonicalizer::do_Base (Base* x) {}
void Canonicalizer::do_OsrEntry (OsrEntry* x) {}
void Canonicalizer::do_ExceptionObject(ExceptionObject* x) {}
static bool match_index_and_scale(Instruction* instr,
Instruction** index,
int* log2_scale) {
#ifndef _LP64
Convert* convert = instr->as_Convert();
if (convert != NULL && convert->op() == Bytecodes::_i2l) {
assert(convert->value()->type() == intType, "invalid input type");
instr = convert->value();
}
#endif
ShiftOp* shift = instr->as_ShiftOp();
if (shift != NULL) {
if (shift->op() == Bytecodes::_lshl) {
assert(shift->x()->type() == longType, "invalid input type");
} else {
#ifndef _LP64
if (shift->op() == Bytecodes::_ishl) {
assert(shift->x()->type() == intType, "invalid input type");
} else {
return false;
}
#else
return false;
#endif
}
Constant* con = shift->y()->as_Constant();
if (con == NULL) return false;
IntConstant* val = con->type()->as_IntConstant();
assert(val != NULL, "Should be an int constant");
int tmp_scale = val->value();
if (tmp_scale >= 0 && tmp_scale < 4) {
return true;
} else {
return false;
}
}
ArithmeticOp* arith = instr->as_ArithmeticOp();
if (arith != NULL) {
Constant* con = arith->x()->as_Constant();
if (con != NULL) {
} else {
con = arith->y()->as_Constant();
if (con == NULL) return false;
}
long const_value;
if (arith->op() == Bytecodes::_lmul) {
assert((*index)->type() == longType, "invalid input type");
LongConstant* val = con->type()->as_LongConstant();
assert(val != NULL, "expecting a long constant");
const_value = val->value();
} else {
#ifndef _LP64
if (arith->op() == Bytecodes::_imul) {
assert((*index)->type() == intType, "invalid input type");
IntConstant* val = con->type()->as_IntConstant();
assert(val != NULL, "expecting an int constant");
const_value = val->value();
} else {
return false;
}
#else
return false;
#endif
}
switch (const_value) {
case 1: *log2_scale = 0; return true;
case 2: *log2_scale = 1; return true;
case 4: *log2_scale = 2; return true;
case 8: *log2_scale = 3; return true;
default: return false;
}
}
return false;
}
static bool match(UnsafeRawOp* x,
Instruction** base,
Instruction** index,
int* log2_scale) {
ArithmeticOp* root = x->base()->as_ArithmeticOp();
if (root == NULL) return false;
if (root->op() != Bytecodes::_ladd) return false;
bool match_found = false;
if (match_index_and_scale(root->y(), index, log2_scale)) {
match_found = true;
} else if (match_index_and_scale(root->x(), index, log2_scale)) {
match_found = true;
} else if (NOT_LP64(root->y()->as_Convert() != NULL) LP64_ONLY(false)) {
Convert* convert = root->y()->as_Convert();
if (convert->op() == Bytecodes::_i2l) {
assert(convert->value()->type() == intType, "should be an int");
match_found = true;
}
}
if (!match_found) {
}
#ifdef AARCH64
if (*log2_scale != 0 &&
(1 << *log2_scale) != type2aelembytes(x->basic_type(), true))
return false;
#endif
return !root->is_pinned();
}
void Canonicalizer::do_UnsafeRawOp(UnsafeRawOp* x) {
Instruction* base = NULL;
Instruction* index = NULL;
int log2_scale;
if (match(x, &base, &index, &log2_scale)) {
x->set_base(base);
x->set_index(index);
x->set_log2_scale(log2_scale);
if (PrintUnsafeOptimization) {
tty->print_cr("Canonicalizer: UnsafeRawOp id %d: base = id %d, index = id %d, log2_scale = %d",
x->id(), x->base()->id(), x->index()->id(), x->log2_scale());
}
}
}
void Canonicalizer::do_RoundFP(RoundFP* x) {}
void Canonicalizer::do_UnsafeGetRaw(UnsafeGetRaw* x) { if (OptimizeUnsafes) do_UnsafeRawOp(x); }
void Canonicalizer::do_UnsafePutRaw(UnsafePutRaw* x) { if (OptimizeUnsafes) do_UnsafeRawOp(x); }
void Canonicalizer::do_UnsafeGetObject(UnsafeGetObject* x) {}
void Canonicalizer::do_UnsafePutObject(UnsafePutObject* x) {}
void Canonicalizer::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
void Canonicalizer::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {}
void Canonicalizer::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {}
void Canonicalizer::do_ProfileCall(ProfileCall* x) {}
void Canonicalizer::do_ProfileReturnType(ProfileReturnType* x) {}
void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {}
void Canonicalizer::do_RuntimeCall(RuntimeCall* x) {}
void Canonicalizer::do_RangeCheckPredicate(RangeCheckPredicate* x) {}
#ifdef ASSERT
void Canonicalizer::do_Assert(Assert* x) {}
#endif
void Canonicalizer::do_MemBar(MemBar* x) {}
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Canonicalizer.hpp
#ifndef SHARE_VM_C1_C1_CANONICALIZER_HPP
#define SHARE_VM_C1_C1_CANONICALIZER_HPP
#include "c1/c1_Instruction.hpp"
class Canonicalizer: InstructionVisitor {
private:
Compilation *_compilation;
Instruction* _canonical;
int _bci;
Compilation *compilation() { return _compilation; }
void set_canonical(Value x);
void set_bci(int bci) { _bci = bci; }
void set_constant(jint x) { set_canonical(new Constant(new IntConstant(x))); }
void set_constant(jlong x) { set_canonical(new Constant(new LongConstant(x))); }
void set_constant(jfloat x) { set_canonical(new Constant(new FloatConstant(x))); }
void set_constant(jdouble x) { set_canonical(new Constant(new DoubleConstant(x))); }
void move_const_to_right(Op2* x);
void do_Op2(Op2* x);
void do_UnsafeRawOp(UnsafeRawOp* x);
void unsafe_raw_match(UnsafeRawOp* x,
Instruction** base,
Instruction** index,
int* scale);
public:
Canonicalizer(Compilation* c, Value x, int bci) : _compilation(c), _canonical(x), _bci(bci) {
NOT_PRODUCT(x->set_printable_bci(bci));
if (CanonicalizeNodes) x->visit(this);
}
Value canonical() const { return _canonical; }
int bci() const { return _bci; }
virtual void do_Phi (Phi* x);
virtual void do_Constant (Constant* x);
virtual void do_Local (Local* x);
virtual void do_LoadField (LoadField* x);
virtual void do_StoreField (StoreField* x);
virtual void do_ArrayLength (ArrayLength* x);
virtual void do_LoadIndexed (LoadIndexed* x);
virtual void do_StoreIndexed (StoreIndexed* x);
virtual void do_NegateOp (NegateOp* x);
virtual void do_ArithmeticOp (ArithmeticOp* x);
virtual void do_ShiftOp (ShiftOp* x);
virtual void do_LogicOp (LogicOp* x);
virtual void do_CompareOp (CompareOp* x);
virtual void do_IfOp (IfOp* x);
virtual void do_IfInstanceOf (IfInstanceOf* x);
virtual void do_Convert (Convert* x);
virtual void do_NullCheck (NullCheck* x);
virtual void do_TypeCast (TypeCast* x);
virtual void do_Invoke (Invoke* x);
virtual void do_NewInstance (NewInstance* x);
virtual void do_NewTypeArray (NewTypeArray* x);
virtual void do_NewObjectArray (NewObjectArray* x);
virtual void do_NewMultiArray (NewMultiArray* x);
virtual void do_CheckCast (CheckCast* x);
virtual void do_InstanceOf (InstanceOf* x);
virtual void do_MonitorEnter (MonitorEnter* x);
virtual void do_MonitorExit (MonitorExit* x);
virtual void do_Intrinsic (Intrinsic* x);
virtual void do_BlockBegin (BlockBegin* x);
virtual void do_Goto (Goto* x);
virtual void do_If (If* x);
virtual void do_TableSwitch (TableSwitch* x);
virtual void do_LookupSwitch (LookupSwitch* x);
virtual void do_Return (Return* x);
virtual void do_Throw (Throw* x);
virtual void do_Base (Base* x);
virtual void do_OsrEntry (OsrEntry* x);
virtual void do_ExceptionObject(ExceptionObject* x);
virtual void do_RoundFP (RoundFP* x);
virtual void do_UnsafeGetRaw (UnsafeGetRaw* x);
virtual void do_UnsafePutRaw (UnsafePutRaw* x);
virtual void do_UnsafeGetObject(UnsafeGetObject* x);
virtual void do_UnsafePutObject(UnsafePutObject* x);
virtual void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x);
virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x);
virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x);
virtual void do_ProfileCall (ProfileCall* x);
virtual void do_ProfileReturnType (ProfileReturnType* x);
virtual void do_ProfileInvoke (ProfileInvoke* x);
virtual void do_RuntimeCall (RuntimeCall* x);
virtual void do_MemBar (MemBar* x);
virtual void do_RangeCheckPredicate(RangeCheckPredicate* x);
#ifdef ASSERT
virtual void do_Assert (Assert* x);
#endif
};
#endif // SHARE_VM_C1_C1_CANONICALIZER_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_CFGPrinter.cpp
#include "precompiled.hpp"
#include "c1/c1_CFGPrinter.hpp"
#include "c1/c1_IR.hpp"
#include "c1/c1_InstructionPrinter.hpp"
#include "c1/c1_LIR.hpp"
#include "c1/c1_LinearScan.hpp"
#include "c1/c1_ValueStack.hpp"
#ifndef PRODUCT
class CFGPrinterOutput : public CHeapObj<mtCompiler> {
private:
outputStream* _output;
Compilation* _compilation;
bool _do_print_HIR;
bool _do_print_LIR;
class PrintBlockClosure: public BlockClosure {
void block_do(BlockBegin* block) { if (block != NULL) CFGPrinter::output()->print_block(block); }
};
outputStream* output() { assert(_output != NULL, ""); return _output; }
void inc_indent();
void dec_indent();
void print(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
void print_begin(const char* tag);
void print_end(const char* tag);
char* method_name(ciMethod* method, bool short_name = false);
public:
CFGPrinterOutput();
void set_compilation(Compilation* compilation) { _compilation = compilation; }
void set_print_flags(bool do_print_HIR, bool do_print_LIR) { _do_print_HIR = do_print_HIR; _do_print_LIR = do_print_LIR; }
void print_compilation();
void print_intervals(IntervalList* intervals, const char* name);
void print_state(BlockBegin* block);
void print_operand(Value instr);
void print_HIR(Value instr);
void print_HIR(BlockBegin* block);
void print_LIR(BlockBegin* block);
void print_block(BlockBegin* block);
void print_cfg(BlockList* blocks, const char* name);
void print_cfg(IR* blocks, const char* name);
};
CFGPrinterOutput* CFGPrinter::_output = NULL;
void CFGPrinter::print_compilation(Compilation* compilation) {
if (_output == NULL) {
_output = new CFGPrinterOutput();
}
output()->set_compilation(compilation);
output()->print_compilation();
}
void CFGPrinter::print_cfg(BlockList* blocks, const char* name, bool do_print_HIR, bool do_print_LIR) {
output()->set_print_flags(do_print_HIR, do_print_LIR);
output()->print_cfg(blocks, name);
}
void CFGPrinter::print_cfg(IR* blocks, const char* name, bool do_print_HIR, bool do_print_LIR) {
output()->set_print_flags(do_print_HIR, do_print_LIR);
output()->print_cfg(blocks, name);
}
void CFGPrinter::print_intervals(IntervalList* intervals, const char* name) {
output()->print_intervals(intervals, name);
}
CFGPrinterOutput::CFGPrinterOutput()
: _output(new(ResourceObj::C_HEAP, mtCompiler) fileStream("output.cfg"))
{
}
void CFGPrinterOutput::inc_indent() {
output()->inc();
output()->inc();
}
void CFGPrinterOutput::dec_indent() {
output()->dec();
output()->dec();
}
void CFGPrinterOutput::print(const char* format, ...) {
output()->indent();
va_list ap;
va_start(ap, format);
output()->vprint_cr(format, ap);
va_end(ap);
}
void CFGPrinterOutput::print_begin(const char* tag) {
output()->indent();
output()->print_cr("begin_%s", tag);
inc_indent();
}
void CFGPrinterOutput::print_end(const char* tag) {
dec_indent();
output()->indent();
output()->print_cr("end_%s", tag);
}
char* CFGPrinterOutput::method_name(ciMethod* method, bool short_name) {
stringStream name;
if (short_name) {
method->print_short_name(&name);
} else {
method->print_name(&name);
}
return name.as_string();
}
void CFGPrinterOutput::print_compilation() {
print_begin("compilation");
print("name \"%s\"", method_name(_compilation->method(), true));
print("method \"%s\"", method_name(_compilation->method()));
print("date " INT64_FORMAT, (int64_t) os::javaTimeMillis());
print_end("compilation");
}
void CFGPrinterOutput::print_state(BlockBegin* block) {
print_begin("states");
InstructionPrinter ip(true, output());
ValueStack* state = block->state();
int index;
Value value;
for_each_state(state) {
print_begin("locals");
print("size %d", state->locals_size());
print("method \"%s\"", method_name(state->scope()->method()));
for_each_local_value(state, index, value) {
ip.print_phi(index, value, block);
print_operand(value);
output()->cr();
}
print_end("locals");
if (state->stack_size() > 0) {
print_begin("stack");
print("size %d", state->stack_size());
print("method \"%s\"", method_name(state->scope()->method()));
for_each_stack_value(state, index, value) {
ip.print_phi(index, value, block);
print_operand(value);
output()->cr();
}
print_end("stack");
}
if (state->locks_size() > 0) {
print_begin("locks");
print("size %d", state->locks_size());
print("method \"%s\"", method_name(state->scope()->method()));
for_each_lock_value(state, index, value) {
ip.print_phi(index, value, block);
print_operand(value);
output()->cr();
}
print_end("locks");
}
}
print_end("states");
}
void CFGPrinterOutput::print_operand(Value instr) {
if (instr->operand()->is_virtual()) {
output()->print(" \"");
instr->operand()->print(output());
output()->print("\" ");
}
}
void CFGPrinterOutput::print_HIR(Value instr) {
InstructionPrinter ip(true, output());
if (instr->is_pinned()) {
output()->put('.');
}
output()->print("%d %d ", instr->printable_bci(), instr->use_count());
print_operand(instr);
ip.print_temp(instr);
output()->print(" ");
ip.print_instr(instr);
output()->print_cr(" <|@");
}
void CFGPrinterOutput::print_HIR(BlockBegin* block) {
print_begin("HIR");
Value cur = block->next();
while (cur != NULL) {
print_HIR(cur);
cur = cur->next();
}
print_end("HIR");
}
void CFGPrinterOutput::print_LIR(BlockBegin* block) {
print_begin("LIR");
for (int i = 0; i < block->lir()->length(); i++) {
block->lir()->at(i)->print_on(output());
output()->print_cr(" <|@ ");
}
print_end("LIR");
}
void CFGPrinterOutput::print_block(BlockBegin* block) {
print_begin("block");
print("name \"B%d\"", block->block_id());
print("from_bci %d", block->bci());
print("to_bci %d", (block->end() == NULL ? -1 : block->end()->printable_bci()));
output()->indent();
output()->print("predecessors ");
int i;
for (i = 0; i < block->number_of_preds(); i++) {
output()->print("\"B%d\" ", block->pred_at(i)->block_id());
}
output()->cr();
output()->indent();
output()->print("successors ");
for (i = 0; i < block->number_of_sux(); i++) {
output()->print("\"B%d\" ", block->sux_at(i)->block_id());
}
output()->cr();
output()->indent();
output()->print("xhandlers");
for (i = 0; i < block->number_of_exception_handlers(); i++) {
output()->print("\"B%d\" ", block->exception_handler_at(i)->block_id());
}
output()->cr();
output()->indent();
output()->print("flags ");
if (block->is_set(BlockBegin::std_entry_flag)) output()->print("\"std\" ");
if (block->is_set(BlockBegin::osr_entry_flag)) output()->print("\"osr\" ");
if (block->is_set(BlockBegin::exception_entry_flag)) output()->print("\"ex\" ");
if (block->is_set(BlockBegin::subroutine_entry_flag)) output()->print("\"sr\" ");
if (block->is_set(BlockBegin::backward_branch_target_flag)) output()->print("\"bb\" ");
if (block->is_set(BlockBegin::parser_loop_header_flag)) output()->print("\"plh\" ");
if (block->is_set(BlockBegin::critical_edge_split_flag)) output()->print("\"ces\" ");
if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) output()->print("\"llh\" ");
if (block->is_set(BlockBegin::linear_scan_loop_end_flag)) output()->print("\"lle\" ");
output()->cr();
if (block->dominator() != NULL) {
print("dominator \"B%d\"", block->dominator()->block_id());
}
if (block->loop_index() != -1) {
print("loop_index %d", block->loop_index());
print("loop_depth %d", block->loop_depth());
}
if (block->first_lir_instruction_id() != -1) {
print("first_lir_id %d", block->first_lir_instruction_id());
print("last_lir_id %d", block->last_lir_instruction_id());
}
if (_do_print_HIR) {
print_state(block);
print_HIR(block);
}
if (_do_print_LIR) {
print_LIR(block);
}
print_end("block");
}
void CFGPrinterOutput::print_cfg(BlockList* blocks, const char* name) {
print_begin("cfg");
print("name \"%s\"", name);
PrintBlockClosure print_block;
blocks->iterate_forward(&print_block);
print_end("cfg");
output()->flush();
}
void CFGPrinterOutput::print_cfg(IR* blocks, const char* name) {
print_begin("cfg");
print("name \"%s\"", name);
PrintBlockClosure print_block;
blocks->iterate_preorder(&print_block);
print_end("cfg");
output()->flush();
}
void CFGPrinterOutput::print_intervals(IntervalList* intervals, const char* name) {
print_begin("intervals");
print("name \"%s\"", name);
for (int i = 0; i < intervals->length(); i++) {
if (intervals->at(i) != NULL) {
intervals->at(i)->print(output());
}
}
print_end("intervals");
output()->flush();
}
#endif
C:\hotspot-69087d08d473\src\share\vm/c1/c1_CFGPrinter.hpp
#ifndef SHARE_VM_C1_C1_CFGPRINTER_HPP
#define SHARE_VM_C1_C1_CFGPRINTER_HPP
#include "c1/c1_Compilation.hpp"
#include "c1/c1_Instruction.hpp"
#ifndef PRODUCT
class CFGPrinterOutput;
class IntervalList;
class CFGPrinter : public AllStatic {
private:
static CFGPrinterOutput* _output;
public:
static CFGPrinterOutput* output() { assert(_output != NULL, ""); return _output; }
static void print_compilation(Compilation* compilation);
static void print_cfg(BlockList* blocks, const char* name, bool do_print_HIR, bool do_print_LIR);
static void print_cfg(IR* blocks, const char* name, bool do_print_HIR, bool do_print_LIR);
static void print_intervals(IntervalList* intervals, const char* name);
};
#endif
#endif // SHARE_VM_C1_C1_CFGPRINTER_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_CodeStubs.hpp
#ifndef SHARE_VM_C1_C1_CODESTUBS_HPP
#define SHARE_VM_C1_C1_CODESTUBS_HPP
#include "c1/c1_FrameMap.hpp"
#include "c1/c1_IR.hpp"
#include "c1/c1_Instruction.hpp"
#include "c1/c1_LIR.hpp"
#include "c1/c1_Runtime1.hpp"
#include "utilities/array.hpp"
#include "utilities/macros.hpp"
class CodeEmitInfo;
class LIR_Assembler;
class LIR_OpVisitState;
class CodeStub: public CompilationResourceObj {
protected:
Label _entry; // label at the stub entry point
Label _continuation; // label where stub continues, if any
public:
CodeStub() {}
void assert_no_unbound_labels() { assert(!_entry.is_unbound() && !_continuation.is_unbound(), "unbound label"); }
virtual void emit_code(LIR_Assembler* e) = 0;
virtual CodeEmitInfo* info() const { return NULL; }
virtual bool is_exception_throw_stub() const { return false; }
virtual bool is_range_check_stub() const { return false; }
virtual bool is_divbyzero_stub() const { return false; }
virtual bool is_simple_exception_stub() const { return false; }
#ifndef PRODUCT
virtual void print_name(outputStream* out) const = 0;
#endif
Label* entry() { return &_entry; }
Label* continuation() { return &_continuation; }
virtual void visit(LIR_OpVisitState* visit) {
#ifndef PRODUCT
if (LIRTracePeephole && Verbose) {
tty->print("no visitor for ");
print_name(tty);
tty->cr();
}
#endif
}
};
define_array(CodeStubArray, CodeStub*)
define_stack(_CodeStubList, CodeStubArray)
class CodeStubList: public _CodeStubList {
public:
CodeStubList(): _CodeStubList() {}
void append(CodeStub* stub) {
if (!contains(stub)) {
_CodeStubList::append(stub);
}
}
};
class CounterOverflowStub: public CodeStub {
private:
CodeEmitInfo* _info;
int _bci;
LIR_Opr _method;
public:
CounterOverflowStub(CodeEmitInfo* info, int bci, LIR_Opr method) : _info(info), _bci(bci), _method(method) {
}
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
visitor->do_input(_method);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("CounterOverflowStub"); }
#endif // PRODUCT
};
class ConversionStub: public CodeStub {
private:
Bytecodes::Code _bytecode;
LIR_Opr _input;
LIR_Opr _result;
static float float_zero;
static double double_zero;
public:
ConversionStub(Bytecodes::Code bytecode, LIR_Opr input, LIR_Opr result)
: _bytecode(bytecode), _input(input), _result(result) {
}
Bytecodes::Code bytecode() { return _bytecode; }
LIR_Opr input() { return _input; }
LIR_Opr result() { return _result; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case();
visitor->do_input(_input);
visitor->do_output(_result);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("ConversionStub"); }
#endif // PRODUCT
};
class RangeCheckStub: public CodeStub {
private:
CodeEmitInfo* _info;
LIR_Opr _index;
bool _throw_index_out_of_bounds_exception;
public:
RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, bool throw_index_out_of_bounds_exception = false);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual bool is_exception_throw_stub() const { return true; }
virtual bool is_range_check_stub() const { return true; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
visitor->do_input(_index);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("RangeCheckStub"); }
#endif // PRODUCT
};
class PredicateFailedStub: public CodeStub {
private:
CodeEmitInfo* _info;
public:
PredicateFailedStub(CodeEmitInfo* info);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("PredicateFailedStub"); }
#endif // PRODUCT
};
class DivByZeroStub: public CodeStub {
private:
CodeEmitInfo* _info;
int _offset;
public:
DivByZeroStub(CodeEmitInfo* info)
: _info(info), _offset(-1) {
}
DivByZeroStub(int offset, CodeEmitInfo* info)
: _info(info), _offset(offset) {
}
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual bool is_exception_throw_stub() const { return true; }
virtual bool is_divbyzero_stub() const { return true; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("DivByZeroStub"); }
#endif // PRODUCT
};
class ImplicitNullCheckStub: public CodeStub {
private:
CodeEmitInfo* _info;
int _offset;
public:
ImplicitNullCheckStub(int offset, CodeEmitInfo* info)
: _offset(offset), _info(info) {
}
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual bool is_exception_throw_stub() const { return true; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("ImplicitNullCheckStub"); }
#endif // PRODUCT
};
class NewInstanceStub: public CodeStub {
private:
ciInstanceKlass* _klass;
LIR_Opr _klass_reg;
LIR_Opr _result;
CodeEmitInfo* _info;
Runtime1::StubID _stub_id;
public:
NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
visitor->do_input(_klass_reg);
visitor->do_output(_result);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("NewInstanceStub"); }
#endif // PRODUCT
};
class NewTypeArrayStub: public CodeStub {
private:
LIR_Opr _klass_reg;
LIR_Opr _length;
LIR_Opr _result;
CodeEmitInfo* _info;
public:
NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
visitor->do_input(_klass_reg);
visitor->do_input(_length);
assert(_result->is_valid(), "must be valid"); visitor->do_output(_result);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("NewTypeArrayStub"); }
#endif // PRODUCT
};
class NewObjectArrayStub: public CodeStub {
private:
LIR_Opr _klass_reg;
LIR_Opr _length;
LIR_Opr _result;
CodeEmitInfo* _info;
public:
NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
visitor->do_input(_klass_reg);
visitor->do_input(_length);
assert(_result->is_valid(), "must be valid"); visitor->do_output(_result);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("NewObjectArrayStub"); }
#endif // PRODUCT
};
class MonitorAccessStub: public CodeStub {
protected:
LIR_Opr _obj_reg;
LIR_Opr _lock_reg;
public:
MonitorAccessStub(LIR_Opr obj_reg, LIR_Opr lock_reg) {
_obj_reg = obj_reg;
_lock_reg = lock_reg;
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("MonitorAccessStub"); }
#endif // PRODUCT
};
class MonitorEnterStub: public MonitorAccessStub {
private:
CodeEmitInfo* _info;
public:
MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_input(_obj_reg);
visitor->do_input(_lock_reg);
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("MonitorEnterStub"); }
#endif // PRODUCT
};
class MonitorExitStub: public MonitorAccessStub {
private:
bool _compute_lock;
int _monitor_ix;
public:
MonitorExitStub(LIR_Opr lock_reg, bool compute_lock, int monitor_ix)
: MonitorAccessStub(LIR_OprFact::illegalOpr, lock_reg),
_compute_lock(compute_lock), _monitor_ix(monitor_ix) { }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
assert(_obj_reg->is_illegal(), "unused");
if (_compute_lock) {
visitor->do_temp(_lock_reg);
} else {
visitor->do_input(_lock_reg);
}
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("MonitorExitStub"); }
#endif // PRODUCT
};
class PatchingStub: public CodeStub {
public:
enum PatchID {
access_field_id,
load_klass_id,
load_mirror_id,
load_appendix_id
};
enum constants {
patch_info_size = 3
};
private:
PatchID _id;
address _pc_start;
int _bytes_to_copy;
Label _patched_code_entry;
Label _patch_site_entry;
Label _patch_site_continuation;
Register _obj;
CodeEmitInfo* _info;
int _index; // index of the patchable oop or Klass* in nmethod oop or metadata table if needed
static int _patch_info_offset;
void align_patch_site(MacroAssembler* masm);
public:
static int patch_info_offset() { return _patch_info_offset; }
PatchingStub(MacroAssembler* masm, PatchID id, int index = -1):
_id(id)
, _info(NULL)
, _index(index) {
if (os::is_MP()) {
align_patch_site(masm);
}
_pc_start = masm->pc();
masm->bind(_patch_site_entry);
}
void install(MacroAssembler* masm, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info) {
_info = info;
_obj = obj;
masm->bind(_patch_site_continuation);
_bytes_to_copy = masm->pc() - pc_start();
if (_id == PatchingStub::access_field_id) {
int field_offset = 0;
switch (patch_code) {
case lir_patch_low: field_offset = lo_word_offset_in_bytes; break;
case lir_patch_high: field_offset = hi_word_offset_in_bytes; break;
case lir_patch_normal: field_offset = 0; break;
default: ShouldNotReachHere();
}
NativeMovRegMem* n_move = nativeMovRegMem_at(pc_start());
n_move->set_offset(field_offset);
} else if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
assert(_obj != noreg, "must have register object for load_klass/load_mirror");
#ifdef ASSERT
nativeMovConstReg_at(pc_start());
#endif
} else {
ShouldNotReachHere();
}
assert(_bytes_to_copy <= (masm->pc() - pc_start()), "not enough bytes");
}
address pc_start() const { return _pc_start; }
PatchID id() const { return _id; }
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("PatchingStub"); }
#endif // PRODUCT
};
class DeoptimizeStub : public CodeStub {
private:
CodeEmitInfo* _info;
public:
DeoptimizeStub(CodeEmitInfo* info) : _info(new CodeEmitInfo(info)) {}
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual bool is_exception_throw_stub() const { return true; }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("DeoptimizeStub"); }
#endif // PRODUCT
};
class SimpleExceptionStub: public CodeStub {
private:
LIR_Opr _obj;
Runtime1::StubID _stub;
CodeEmitInfo* _info;
public:
SimpleExceptionStub(Runtime1::StubID stub, LIR_Opr obj, CodeEmitInfo* info):
_obj(obj), _info(info), _stub(stub) {
}
void set_obj(LIR_Opr obj) {
_obj = obj;
}
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual bool is_exception_throw_stub() const { return true; }
virtual bool is_simple_exception_stub() const { return true; }
virtual void visit(LIR_OpVisitState* visitor) {
if (_obj->is_valid()) visitor->do_input(_obj);
visitor->do_slow_case(_info);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("SimpleExceptionStub"); }
#endif // PRODUCT
};
class ArrayStoreExceptionStub: public SimpleExceptionStub {
private:
CodeEmitInfo* _info;
public:
ArrayStoreExceptionStub(LIR_Opr obj, CodeEmitInfo* info): SimpleExceptionStub(Runtime1::throw_array_store_exception_id, obj, info) {}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("ArrayStoreExceptionStub"); }
#endif // PRODUCT
};
class ArrayCopyStub: public CodeStub {
private:
LIR_OpArrayCopy* _op;
public:
ArrayCopyStub(LIR_OpArrayCopy* op): _op(op) { }
LIR_Opr src() const { return _op->src(); }
LIR_Opr src_pos() const { return _op->src_pos(); }
LIR_Opr dst() const { return _op->dst(); }
LIR_Opr dst_pos() const { return _op->dst_pos(); }
LIR_Opr length() const { return _op->length(); }
LIR_Opr tmp() const { return _op->tmp(); }
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _op->info(); }
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case();
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("ArrayCopyStub"); }
#endif // PRODUCT
};
#if INCLUDE_ALL_GCS
class G1PreBarrierStub: public CodeStub {
private:
bool _do_load;
LIR_Opr _addr;
LIR_Opr _pre_val;
LIR_PatchCode _patch_code;
CodeEmitInfo* _info;
public:
G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) :
_addr(addr), _pre_val(pre_val), _do_load(true),
_patch_code(patch_code), _info(info)
{
assert(_pre_val->is_register(), "should be temporary register");
assert(_addr->is_address(), "should be the address of the field");
}
G1PreBarrierStub(LIR_Opr pre_val) :
_addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false),
_patch_code(lir_patch_none), _info(NULL)
{
assert(_pre_val->is_register(), "should be a register");
}
LIR_Opr addr() const { return _addr; }
LIR_Opr pre_val() const { return _pre_val; }
LIR_PatchCode patch_code() const { return _patch_code; }
CodeEmitInfo* info() const { return _info; }
bool do_load() const { return _do_load; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
if (_do_load) {
if (_info != NULL)
visitor->do_slow_case(_info);
else
visitor->do_slow_case();
visitor->do_input(_addr);
visitor->do_temp(_pre_val);
} else {
visitor->do_slow_case();
visitor->do_input(_pre_val);
}
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); }
#endif // PRODUCT
};
class G1PostBarrierStub: public CodeStub {
private:
LIR_Opr _addr;
LIR_Opr _new_val;
static jbyte* _byte_map_base;
static jbyte* byte_map_base_slow();
static jbyte* byte_map_base() {
if (_byte_map_base == NULL) {
_byte_map_base = byte_map_base_slow();
}
return _byte_map_base;
}
public:
G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { }
LIR_Opr addr() const { return _addr; }
LIR_Opr new_val() const { return _new_val; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
visitor->do_slow_case();
visitor->do_input(_addr);
visitor->do_input(_new_val);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PostBarrierStub"); }
#endif // PRODUCT
};
#endif // INCLUDE_ALL_GCS
#endif // SHARE_VM_C1_C1_CODESTUBS_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Compilation.cpp
#include "precompiled.hpp"
#include "c1/c1_CFGPrinter.hpp"
#include "c1/c1_Compilation.hpp"
#include "c1/c1_IR.hpp"
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_LinearScan.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_ValueMap.hpp"
#include "c1/c1_ValueStack.hpp"
#include "code/debugInfoRec.hpp"
#include "compiler/compileLog.hpp"
#include "c1/c1_RangeCheckElimination.hpp"
typedef enum {
_t_compile,
_t_setup,
_t_buildIR,
_t_optimize_blocks,
_t_optimize_null_checks,
_t_rangeCheckElimination,
_t_emit_lir,
_t_linearScan,
_t_lirGeneration,
_t_lir_schedule,
_t_codeemit,
_t_codeinstall,
max_phase_timers
} TimerName;
static const char * timer_name[] = {
"compile",
"setup",
"buildIR",
"optimize_blocks",
"optimize_null_checks",
"rangeCheckElimination",
"emit_lir",
"linearScan",
"lirGeneration",
"lir_schedule",
"codeemit",
"codeinstall"
};
static elapsedTimer timers[max_phase_timers];
static int totalInstructionNodes = 0;
class PhaseTraceTime: public TraceTime {
private:
JavaThread* _thread;
CompileLog* _log;
TimerName _timer;
public:
PhaseTraceTime(TimerName timer)
: TraceTime("", &timers[timer], CITime || CITimeEach, Verbose),
_log(NULL), _timer(timer)
{
if (Compilation::current() != NULL) {
_log = Compilation::current()->log();
}
if (_log != NULL) {
_log->begin_head("phase name='%s'", timer_name[_timer]);
_log->stamp();
_log->end_head();
}
}
~PhaseTraceTime() {
if (_log != NULL)
_log->done("phase name='%s'", timer_name[_timer]);
}
};
#ifndef PRODUCT
void Compilation::maybe_print_current_instruction() {
if (_current_instruction != NULL && _last_instruction_printed != _current_instruction) {
_last_instruction_printed = _current_instruction;
_current_instruction->print_line();
}
}
#endif // PRODUCT
DebugInformationRecorder* Compilation::debug_info_recorder() const {
return _env->debug_info();
}
Dependencies* Compilation::dependency_recorder() const {
return _env->dependencies();
}
void Compilation::initialize() {
OopRecorder* ooprec = new OopRecorder(_env->arena());
_env->set_oop_recorder(ooprec);
_env->set_debug_info(new DebugInformationRecorder(ooprec));
debug_info_recorder()->set_oopmaps(new OopMapSet());
_env->set_dependencies(new Dependencies(_env));
}
void Compilation::build_hir() {
CHECK_BAILOUT();
CompileLog* log = this->log();
if (log != NULL) {
log->begin_head("parse method='%d' ",
log->identify(_method));
log->stamp();
log->end_head();
}
_hir = new IR(this, method(), osr_bci());
if (log) log->done("parse");
if (!_hir->is_valid()) {
bailout("invalid parsing");
return;
}
#ifndef PRODUCT
if (PrintCFGToFile) {
CFGPrinter::print_cfg(_hir, "After Generation of HIR", true, false);
}
#endif
#ifndef PRODUCT
if (PrintCFG || PrintCFG0) { tty->print_cr("CFG after parsing"); _hir->print(true); }
if (PrintIR || PrintIR0 ) { tty->print_cr("IR after parsing"); _hir->print(false); }
#endif
_hir->verify();
if (UseC1Optimizations) {
NEEDS_CLEANUP
PhaseTraceTime timeit(_t_optimize_blocks);
_hir->optimize_blocks();
}
_hir->verify();
_hir->split_critical_edges();
#ifndef PRODUCT
if (PrintCFG || PrintCFG1) { tty->print_cr("CFG after optimizations"); _hir->print(true); }
if (PrintIR || PrintIR1 ) { tty->print_cr("IR after optimizations"); _hir->print(false); }
#endif
_hir->verify();
_hir->compute_code();
if (UseGlobalValueNumbering) {
int instructions = Instruction::number_of_instructions();
GlobalValueNumbering gvn(_hir);
assert(instructions == Instruction::number_of_instructions(),
"shouldn't have created an instructions");
}
_hir->verify();
#ifndef PRODUCT
if (PrintCFGToFile) {
CFGPrinter::print_cfg(_hir, "Before RangeCheckElimination", true, false);
}
#endif
if (RangeCheckElimination) {
if (_hir->osr_entry() == NULL) {
PhaseTraceTime timeit(_t_rangeCheckElimination);
RangeCheckElimination::eliminate(_hir);
}
}
#ifndef PRODUCT
if (PrintCFGToFile) {
CFGPrinter::print_cfg(_hir, "After RangeCheckElimination", true, false);
}
#endif
if (UseC1Optimizations) {
NEEDS_CLEANUP
PhaseTraceTime timeit(_t_optimize_null_checks);
_hir->eliminate_null_checks();
}
_hir->verify();
_hir->compute_use_counts();
#ifndef PRODUCT
if (PrintCFG || PrintCFG2) { tty->print_cr("CFG before code generation"); _hir->code()->print(true); }
if (PrintIR || PrintIR2 ) { tty->print_cr("IR before code generation"); _hir->code()->print(false, true); }
#endif
_hir->verify();
}
void Compilation::emit_lir() {
CHECK_BAILOUT();
LIRGenerator gen(this, method());
{
PhaseTraceTime timeit(_t_lirGeneration);
hir()->iterate_linear_scan_order(&gen);
}
CHECK_BAILOUT();
{
PhaseTraceTime timeit(_t_linearScan);
LinearScan* allocator = new LinearScan(hir(), &gen, frame_map());
set_allocator(allocator);
allocator->do_linear_scan();
CHECK_BAILOUT();
_max_spills = allocator->max_spills();
}
if (BailoutAfterLIR) {
if (PrintLIR && !bailed_out()) {
print_LIR(hir()->code());
}
bailout("Bailing out because of -XX:+BailoutAfterLIR");
}
}
void Compilation::emit_code_epilog(LIR_Assembler* assembler) {
CHECK_BAILOUT();
CodeOffsets* code_offsets = assembler->offsets();
assembler->emit_slow_case_stubs();
CHECK_BAILOUT();
assembler->emit_exception_entries(exception_info_list());
CHECK_BAILOUT();
code_offsets->set_value(CodeOffsets::Exceptions, assembler->emit_exception_handler());
CHECK_BAILOUT();
code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler());
CHECK_BAILOUT();
if (has_method_handle_invokes()) {
code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler());
CHECK_BAILOUT();
}
offsets()->set_value(CodeOffsets::UnwindHandler, assembler->emit_unwind_handler());
masm()->flush();
}
bool Compilation::setup_code_buffer(CodeBuffer* code, int call_stub_estimate) {
int locs_buffer_size = 20 * (relocInfo::length_limit + sizeof(relocInfo));
char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size);
code->insts()->initialize_shared_locs((relocInfo*)locs_buffer,
locs_buffer_size / sizeof(relocInfo));
code->initialize_consts_size(Compilation::desired_max_constant_size());
int stub_size = (call_stub_estimate * LIR_Assembler::call_stub_size) +
LIR_Assembler::exception_handler_size +
(2 * LIR_Assembler::deopt_handler_size);
if (stub_size >= code->insts_capacity()) return false;
code->initialize_stubs_size(stub_size);
return true;
}
int Compilation::emit_code_body() {
if (!setup_code_buffer(code(), allocator()->num_calls())) {
BAILOUT_("size requested greater than avail code buffer size", 0);
}
code()->initialize_oop_recorder(env()->oop_recorder());
_masm = new C1_MacroAssembler(code());
_masm->set_oop_recorder(env()->oop_recorder());
LIR_Assembler lir_asm(this);
lir_asm.emit_code(hir()->code());
CHECK_BAILOUT_(0);
emit_code_epilog(&lir_asm);
CHECK_BAILOUT_(0);
generate_exception_handler_table();
#ifndef PRODUCT
if (PrintExceptionHandlers && Verbose) {
exception_handler_table()->print();
}
#endif /* PRODUCT */
return frame_map()->framesize();
}
int Compilation::compile_java_method() {
assert(!method()->is_native(), "should not reach here");
if (BailoutOnExceptionHandlers) {
if (method()->has_exception_handlers()) {
bailout("linear scan can't handle exception handlers");
}
}
CHECK_BAILOUT_(no_frame_size);
if (is_profiling() && !method()->ensure_method_data()) {
BAILOUT_("mdo allocation failed", no_frame_size);
}
{
PhaseTraceTime timeit(_t_buildIR);
build_hir();
}
if (BailoutAfterHIR) {
BAILOUT_("Bailing out because of -XX:+BailoutAfterHIR", no_frame_size);
}
{
PhaseTraceTime timeit(_t_emit_lir);
_frame_map = new FrameMap(method(), hir()->number_of_locks(), MAX2(4, hir()->max_stack()));
emit_lir();
}
CHECK_BAILOUT_(no_frame_size);
{
PhaseTraceTime timeit(_t_codeemit);
return emit_code_body();
}
}
void Compilation::install_code(int frame_size) {
assert(frame_size == frame_map()->framesize(), "must match");
assert(in_bytes(frame_map()->framesize_in_bytes()) % sizeof(intptr_t) == 0, "must be at least pointer aligned");
_env->register_method(
method(),
osr_bci(),
&_offsets,
in_bytes(_frame_map->sp_offset_for_orig_pc()),
code(),
in_bytes(frame_map()->framesize_in_bytes()) / sizeof(intptr_t),
debug_info_recorder()->_oopmaps,
exception_handler_table(),
implicit_exception_table(),
compiler(),
_env->comp_level(),
has_unsafe_access(),
SharedRuntime::is_wide_vector(max_vector_size())
);
}
void Compilation::compile_method() {
initialize();
if (!method()->can_be_compiled()) {
bailout("Bailing out because method is not compilable");
return;
}
if (_env->jvmti_can_hotswap_or_post_breakpoint()) {
dependency_recorder()->assert_evol_method(method());
}
if (method()->break_at_execute()) {
BREAKPOINT;
}
#ifndef PRODUCT
if (PrintCFGToFile) {
CFGPrinter::print_compilation(this);
}
#endif
int frame_size = compile_java_method();
CHECK_BAILOUT();
if (InstallMethods) {
PhaseTraceTime timeit(_t_codeinstall);
install_code(frame_size);
}
if (log() != NULL) // Print code cache state into compiler log
log()->code_cache_state();
totalInstructionNodes += Instruction::number_of_instructions();
}
void Compilation::generate_exception_handler_table() {
ExceptionInfoList* info_list = exception_info_list();
if (info_list->length() == 0) {
return;
}
const int num_handlers = 5;
GrowableArray<intptr_t>* bcis = new GrowableArray<intptr_t>(num_handlers);
GrowableArray<intptr_t>* scope_depths = new GrowableArray<intptr_t>(num_handlers);
GrowableArray<intptr_t>* pcos = new GrowableArray<intptr_t>(num_handlers);
for (int i = 0; i < info_list->length(); i++) {
ExceptionInfo* info = info_list->at(i);
XHandlers* handlers = info->exception_handlers();
bcis->trunc_to(0);
scope_depths->trunc_to(0);
pcos->trunc_to(0);
for (int i = 0; i < handlers->length(); i++) {
XHandler* handler = handlers->handler_at(i);
assert(handler->entry_pco() != -1, "must have been generated");
int e = bcis->find(handler->handler_bci());
if (e >= 0 && scope_depths->at(e) == handler->scope_count()) {
continue;
}
bcis->append(handler->handler_bci());
if (handler->handler_bci() == -1) {
scope_depths->append(0);
} else {
scope_depths->append(handler->scope_count());
}
pcos->append(handler->entry_pco());
if (handler->is_catch_all()) {
assert(i == handlers->length() - 1, "catch all must be last handler");
}
}
exception_handler_table()->add_subtable(info->pco(), bcis, scope_depths, pcos);
}
}
Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method,
int osr_bci, BufferBlob* buffer_blob)
: _compiler(compiler)
, _env(env)
, _log(env->log())
, _method(method)
, _osr_bci(osr_bci)
, _hir(NULL)
, _max_spills(-1)
, _frame_map(NULL)
, _masm(NULL)
, _has_exception_handlers(false)
, _has_fpu_code(true) // pessimistic assumption
, _would_profile(false)
, _has_unsafe_access(false)
, _has_method_handle_invokes(false)
, _bailout_msg(NULL)
, _exception_info_list(NULL)
, _allocator(NULL)
, _next_id(0)
, _next_block_id(0)
, _code(buffer_blob)
, _has_access_indexed(false)
, _current_instruction(NULL)
, _interpreter_frame_size(0)
#ifndef PRODUCT
, _last_instruction_printed(NULL)
#endif // PRODUCT
{
PhaseTraceTime timeit(_t_compile);
_arena = Thread::current()->resource_area();
_env->set_compiler_data(this);
_exception_info_list = new ExceptionInfoList();
_implicit_exception_table.set_size(0);
compile_method();
if (bailed_out()) {
_env->record_method_not_compilable(bailout_msg(), !TieredCompilation);
if (is_profiling()) {
_method->ensure_method_data();
}
} else if (is_profiling()) {
ciMethodData *md = method->method_data_or_null();
if (md != NULL) {
md->set_would_profile(_would_profile);
}
}
}
Compilation::~Compilation() {
_env->set_compiler_data(NULL);
}
void Compilation::add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers) {
#ifndef PRODUCT
if (PrintExceptionHandlers && Verbose) {
tty->print_cr(" added exception scope for pco %d", pco);
}
#endif
exception_info_list()->push(new ExceptionInfo(pco, exception_handlers));
}
void Compilation::notice_inlined_method(ciMethod* method) {
_env->notice_inlined_method(method);
}
void Compilation::bailout(const char* msg) {
assert(msg != NULL, "bailout message must exist");
if (!bailed_out()) {
if (PrintCompilation || PrintBailouts) tty->print_cr("compilation bailout: %s", msg);
_bailout_msg = msg;
}
}
ciKlass* Compilation::cha_exact_type(ciType* type) {
if (type != NULL && type->is_loaded() && type->is_instance_klass()) {
ciInstanceKlass* ik = type->as_instance_klass();
assert(ik->exact_klass() == NULL, "no cha for final klass");
if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) {
dependency_recorder()->assert_leaf_type(ik);
return ik;
}
}
return NULL;
}
void Compilation::print_timers() {
float total = timers[_t_setup].seconds() + timers[_t_buildIR].seconds() + timers[_t_emit_lir].seconds() + timers[_t_lir_schedule].seconds() + timers[_t_codeemit].seconds() + timers[_t_codeinstall].seconds();
tty->print_cr(" Detailed C1 Timings");
tty->print_cr(" Setup time: %6.3f s (%4.1f%%)", timers[_t_setup].seconds(), (timers[_t_setup].seconds() / total) * 100.0);
tty->print_cr(" Build IR: %6.3f s (%4.1f%%)", timers[_t_buildIR].seconds(), (timers[_t_buildIR].seconds() / total) * 100.0);
float t_optimizeIR = timers[_t_optimize_blocks].seconds() + timers[_t_optimize_null_checks].seconds();
tty->print_cr(" Optimize: %6.3f s (%4.1f%%)", t_optimizeIR, (t_optimizeIR / total) * 100.0);
tty->print_cr(" RCE: %6.3f s (%4.1f%%)", timers[_t_rangeCheckElimination].seconds(), (timers[_t_rangeCheckElimination].seconds() / total) * 100.0);
tty->print_cr(" Emit LIR: %6.3f s (%4.1f%%)", timers[_t_emit_lir].seconds(), (timers[_t_emit_lir].seconds() / total) * 100.0);
tty->print_cr(" LIR Gen: %6.3f s (%4.1f%%)", timers[_t_lirGeneration].seconds(), (timers[_t_lirGeneration].seconds() / total) * 100.0);
tty->print_cr(" Linear Scan: %6.3f s (%4.1f%%)", timers[_t_linearScan].seconds(), (timers[_t_linearScan].seconds() / total) * 100.0);
NOT_PRODUCT(LinearScan::print_timers(timers[_t_linearScan].seconds()));
tty->print_cr(" LIR Schedule: %6.3f s (%4.1f%%)", timers[_t_lir_schedule].seconds(), (timers[_t_lir_schedule].seconds() / total) * 100.0);
tty->print_cr(" Code Emission: %6.3f s (%4.1f%%)", timers[_t_codeemit].seconds(), (timers[_t_codeemit].seconds() / total) * 100.0);
tty->print_cr(" Code Installation: %6.3f s (%4.1f%%)", timers[_t_codeinstall].seconds(), (timers[_t_codeinstall].seconds() / total) * 100.0);
tty->print_cr(" Instruction Nodes: %6d nodes", totalInstructionNodes);
NOT_PRODUCT(LinearScan::print_statistics());
}
#ifndef PRODUCT
void Compilation::compile_only_this_method() {
ResourceMark rm;
fileStream stream(fopen("c1_compile_only", "wt"));
stream.print_cr("# c1 compile only directives");
compile_only_this_scope(&stream, hir()->top_scope());
}
void Compilation::compile_only_this_scope(outputStream* st, IRScope* scope) {
st->print("CompileOnly=");
scope->method()->holder()->name()->print_symbol_on(st);
st->print(".");
scope->method()->name()->print_symbol_on(st);
st->cr();
}
void Compilation::exclude_this_method() {
fileStream stream(fopen(".hotspot_compiler", "at"));
stream.print("exclude ");
method()->holder()->name()->print_symbol_on(&stream);
stream.print(" ");
method()->name()->print_symbol_on(&stream);
stream.cr();
stream.cr();
}
#endif
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Compilation.hpp
#ifndef SHARE_VM_C1_C1_COMPILATION_HPP
#define SHARE_VM_C1_C1_COMPILATION_HPP
#include "ci/ciEnv.hpp"
#include "ci/ciMethodData.hpp"
#include "code/exceptionHandlerTable.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/deoptimization.hpp"
class CompilationResourceObj;
class XHandlers;
class ExceptionInfo;
class DebugInformationRecorder;
class FrameMap;
class IR;
class IRScope;
class Instruction;
class LinearScan;
class OopMap;
class LIR_Emitter;
class LIR_Assembler;
class CodeEmitInfo;
class ciEnv;
class ciMethod;
class ValueStack;
class LIR_OprDesc;
class C1_MacroAssembler;
class CFGPrinter;
typedef LIR_OprDesc* LIR_Opr;
define_array(BasicTypeArray, BasicType)
define_stack(BasicTypeList, BasicTypeArray)
define_array(ExceptionInfoArray, ExceptionInfo*)
define_stack(ExceptionInfoList, ExceptionInfoArray)
class Compilation: public StackObj {
friend class CompilationResourceObj;
private:
Arena* _arena;
int _next_id;
int _next_block_id;
AbstractCompiler* _compiler;
ciEnv* _env;
CompileLog* _log;
ciMethod* _method;
int _osr_bci;
IR* _hir;
int _max_spills;
FrameMap* _frame_map;
C1_MacroAssembler* _masm;
bool _has_exception_handlers;
bool _has_fpu_code;
bool _has_unsafe_access;
bool _would_profile;
bool _has_method_handle_invokes; // True if this method has MethodHandle invokes.
const char* _bailout_msg;
ExceptionInfoList* _exception_info_list;
ExceptionHandlerTable _exception_handler_table;
ImplicitExceptionTable _implicit_exception_table;
LinearScan* _allocator;
CodeOffsets _offsets;
CodeBuffer _code;
bool _has_access_indexed;
int _interpreter_frame_size; // Stack space needed in case of a deoptimization
void initialize();
void build_hir();
void emit_lir();
void emit_code_epilog(LIR_Assembler* assembler);
int emit_code_body();
int compile_java_method();
void install_code(int frame_size);
void compile_method();
void generate_exception_handler_table();
ExceptionInfoList* exception_info_list() const { return _exception_info_list; }
ExceptionHandlerTable* exception_handler_table() { return &_exception_handler_table; }
LinearScan* allocator() { return _allocator; }
void set_allocator(LinearScan* allocator) { _allocator = allocator; }
Instruction* _current_instruction; // the instruction currently being processed
#ifndef PRODUCT
Instruction* _last_instruction_printed; // the last instruction printed during traversal
#endif // PRODUCT
public:
Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method,
int osr_bci, BufferBlob* buffer_blob);
~Compilation();
static Compilation* current() {
return (Compilation*) ciEnv::current()->compiler_data();
}
ciEnv* env() const { return _env; }
CompileLog* log() const { return _log; }
AbstractCompiler* compiler() const { return _compiler; }
bool has_exception_handlers() const { return _has_exception_handlers; }
bool has_fpu_code() const { return _has_fpu_code; }
bool has_unsafe_access() const { return _has_unsafe_access; }
int max_vector_size() const { return 0; }
ciMethod* method() const { return _method; }
int osr_bci() const { return _osr_bci; }
bool is_osr_compile() const { return osr_bci() >= 0; }
IR* hir() const { return _hir; }
int max_spills() const { return _max_spills; }
FrameMap* frame_map() const { return _frame_map; }
CodeBuffer* code() { return &_code; }
C1_MacroAssembler* masm() const { return _masm; }
CodeOffsets* offsets() { return &_offsets; }
Arena* arena() { return _arena; }
bool has_access_indexed() { return _has_access_indexed; }
int get_next_id() { return _next_id++; }
int number_of_instructions() const { return _next_id; }
int get_next_block_id() { return _next_block_id++; }
int number_of_blocks() const { return _next_block_id; }
void set_has_exception_handlers(bool f) { _has_exception_handlers = f; }
void set_has_fpu_code(bool f) { _has_fpu_code = f; }
void set_has_unsafe_access(bool f) { _has_unsafe_access = f; }
void set_would_profile(bool f) { _would_profile = f; }
void set_has_access_indexed(bool f) { _has_access_indexed = f; }
void add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers);
void notice_inlined_method(ciMethod* method);
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
DebugInformationRecorder* debug_info_recorder() const; // = _env->debug_info();
Dependencies* dependency_recorder() const; // = _env->dependencies()
ImplicitExceptionTable* implicit_exception_table() { return &_implicit_exception_table; }
Instruction* current_instruction() const { return _current_instruction; }
Instruction* set_current_instruction(Instruction* instr) {
Instruction* previous = _current_instruction;
_current_instruction = instr;
return previous;
}
#ifndef PRODUCT
void maybe_print_current_instruction();
#endif // PRODUCT
void bailout(const char* msg);
bool bailed_out() const { return _bailout_msg != NULL; }
const char* bailout_msg() const { return _bailout_msg; }
static int desired_max_code_buffer_size() {
#ifndef PPC
return (int) NMethodSizeLimit; // default 256K or 512K
#else
return MIN2((unsigned int)NMethodSizeLimit,32*K);
#endif
}
static int desired_max_constant_size() {
return desired_max_code_buffer_size() / 10;
}
static bool setup_code_buffer(CodeBuffer* cb, int call_stub_estimate);
static void print_timers();
#ifndef PRODUCT
void compile_only_this_method();
void compile_only_this_scope(outputStream* st, IRScope* scope);
void exclude_this_method();
#endif // PRODUCT
bool is_profiling() {
return env()->comp_level() == CompLevel_full_profile ||
env()->comp_level() == CompLevel_limited_profile;
}
bool count_invocations() { return is_profiling(); }
bool count_backedges() { return is_profiling(); }
bool profile_branches() {
return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && C1ProfileBranches;
}
bool profile_calls() {
return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && C1ProfileCalls;
}
bool profile_inlined_calls() {
return profile_calls() && C1ProfileInlinedCalls;
}
bool profile_checkcasts() {
return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && C1ProfileCheckcasts;
}
bool profile_parameters() {
return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && MethodData::profile_parameters();
}
bool profile_arguments() {
return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && MethodData::profile_arguments();
}
bool profile_return() {
return env()->comp_level() == CompLevel_full_profile &&
C1UpdateMethodData && MethodData::profile_return();
}
bool is_optimistic() const {
return !TieredCompilation &&
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
}
ciKlass* cha_exact_type(ciType* type);
void dump_inline_data(outputStream* out) { /* do nothing now */ }
void update_interpreter_frame_size(int size) {
if (_interpreter_frame_size < size) {
_interpreter_frame_size = size;
}
}
int interpreter_frame_size() const {
return _interpreter_frame_size;
}
};
#define BAILOUT(msg) { bailout(msg); return; }
#define BAILOUT_(msg, res) { bailout(msg); return res; }
#define CHECK_BAILOUT() { if (bailed_out()) return; }
#define CHECK_BAILOUT_(res) { if (bailed_out()) return res; }
class InstructionMark: public StackObj {
private:
Compilation* _compilation;
Instruction* _previous;
public:
InstructionMark(Compilation* compilation, Instruction* instr) {
_compilation = compilation;
_previous = _compilation->set_current_instruction(instr);
}
~InstructionMark() {
_compilation->set_current_instruction(_previous);
}
};
class CompilationResourceObj ALLOCATION_SUPER_CLASS_SPEC {
public:
void* operator new(size_t size) throw() { return Compilation::current()->arena()->Amalloc(size); }
void* operator new(size_t size, Arena* arena) throw() {
return arena->Amalloc(size);
}
void operator delete(void* p) {} // nothing to do
};
class ExceptionInfo: public CompilationResourceObj {
private:
int _pco; // PC of potentially exception-throwing instruction
XHandlers* _exception_handlers; // flat list of exception handlers covering this PC
public:
ExceptionInfo(int pco, XHandlers* exception_handlers)
: _pco(pco)
, _exception_handlers(exception_handlers)
{ }
int pco() { return _pco; }
XHandlers* exception_handlers() { return _exception_handlers; }
};
#endif // SHARE_VM_C1_C1_COMPILATION_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Compiler.cpp
#include "precompiled.hpp"
#include "c1/c1_Compilation.hpp"
#include "c1/c1_Compiler.hpp"
#include "c1/c1_FrameMap.hpp"
#include "c1/c1_GraphBuilder.hpp"
#include "c1/c1_LinearScan.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_Runtime1.hpp"
#include "c1/c1_ValueType.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerOracle.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/arguments.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
Compiler::Compiler () {}
void Compiler::init_c1_runtime() {
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
Arena* arena = new (mtCompiler) Arena(mtCompiler);
Runtime1::initialize(buffer_blob);
FrameMap::initialize();
ValueType::initialize(arena);
GraphBuilder::initialize();
Interval::initialize(arena);
}
void Compiler::initialize() {
BufferBlob* buffer_blob = init_buffer_blob();
if (should_perform_init()) {
if (buffer_blob == NULL) {
set_state(failed);
} else {
init_c1_runtime();
set_state(initialized);
}
}
}
BufferBlob* Compiler::init_buffer_blob() {
assert (CompilerThread::current()->get_buffer_blob() == NULL, "Should initialize only once");
int code_buffer_size = Compilation::desired_max_code_buffer_size() +
Compilation::desired_max_constant_size();
BufferBlob* buffer_blob = BufferBlob::create("C1 temporary CodeBuffer", code_buffer_size);
if (buffer_blob != NULL) {
CompilerThread::current()->set_buffer_blob(buffer_blob);
}
return buffer_blob;
}
void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) {
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
assert(buffer_blob != NULL, "Must exist");
{
ResourceMark rm;
Compilation c(this, env, method, entry_bci, buffer_blob);
}
}
void Compiler::print_timers() {
Compilation::print_timers();
}
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Compiler.hpp
#ifndef SHARE_VM_C1_C1_COMPILER_HPP
#define SHARE_VM_C1_C1_COMPILER_HPP
#include "compiler/abstractCompiler.hpp"
class Compiler: public AbstractCompiler {
private:
static void init_c1_runtime();
BufferBlob* init_buffer_blob();
public:
Compiler();
~Compiler();
virtual const char* name() { return "C1"; }
virtual bool is_c1() { return true; };
virtual bool supports_native() { return true; }
virtual bool supports_osr () { return true; }
virtual void initialize();
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
virtual void print_timers();
};
#endif // SHARE_VM_C1_C1_COMPILER_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Defs.cpp
#include "precompiled.hpp"
#include "c1/c1_Defs.hpp"
C:\hotspot-69087d08d473\src\share\vm/c1/c1_Defs.hpp
#ifndef SHARE_VM_C1_C1_DEFS_HPP
#define SHARE_VM_C1_C1_DEFS_HPP
#include "utilities/globalDefinitions.hpp"
#ifdef TARGET_ARCH_x86
# include "register_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "register_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "register_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "register_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "register_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "register_ppc.hpp"
#endif
enum {
no_frame_size = -1
};
#ifdef TARGET_ARCH_x86
# include "c1_Defs_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "c1_Defs_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "c1_Defs_sparc.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "c1_Defs_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "c1_Defs_ppc.hpp"
#endif
enum {
lo_word_offset_in_bytes = pd_lo_word_offset_in_bytes,
hi_word_offset_in_bytes = pd_hi_word_offset_in_bytes
};
enum {
strict_fp_requires_explicit_rounding = pd_strict_fp_requires_explicit_rounding
};
enum {
float_saved_as_double = pd_float_saved_as_double
};
#endif // SHARE_VM_C1_C1_DEFS_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_FpuStackSim.hpp
#ifndef SHARE_VM_C1_C1_FPUSTACKSIM_HPP
#define SHARE_VM_C1_C1_FPUSTACKSIM_HPP
#include "c1/c1_FrameMap.hpp"
#include "memory/allocation.hpp"
class FpuStackSim;
ssssssss3
最新推荐文章于 2024-09-08 10:25:07 发布