aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm
diff options
context:
space:
mode:
authortwisti <none@none>2010-12-03 01:34:31 -0800
committertwisti <none@none>2010-12-03 01:34:31 -0800
commit7519ccef5207260cf08b6719d6f15a0dec23f01a (patch)
tree18754063293c32ad2ef1540da2417c0327196480 /src/share/vm
parent8d885e9a6cc86571bcf87be42bcabcfe9f4a60fd (diff)
6961690: load oops from constant table on SPARC
Summary: oops should be loaded from the constant table of an nmethod instead of materializing them with a long code sequence. Reviewed-by: never, kvn
Diffstat (limited to 'src/share/vm')
-rw-r--r--src/share/vm/adlc/adlparse.cpp266
-rw-r--r--src/share/vm/adlc/adlparse.hpp9
-rw-r--r--src/share/vm/adlc/archDesc.hpp14
-rw-r--r--src/share/vm/adlc/formssel.cpp29
-rw-r--r--src/share/vm/adlc/formssel.hpp11
-rw-r--r--src/share/vm/adlc/output_c.cpp162
-rw-r--r--src/share/vm/adlc/output_h.cpp28
-rw-r--r--src/share/vm/asm/assembler.hpp22
-rw-r--r--src/share/vm/asm/assembler.inline.hpp28
-rw-r--r--src/share/vm/compiler/disassembler.cpp13
-rw-r--r--src/share/vm/opto/c2_globals.hpp3
-rw-r--r--src/share/vm/opto/compile.cpp252
-rw-r--r--src/share/vm/opto/compile.hpp98
-rw-r--r--src/share/vm/opto/gcm.cpp2
-rw-r--r--src/share/vm/opto/machnode.cpp14
-rw-r--r--src/share/vm/opto/machnode.hpp62
-rw-r--r--src/share/vm/opto/matcher.hpp4
-rw-r--r--src/share/vm/opto/node.hpp14
-rw-r--r--src/share/vm/opto/output.cpp84
-rw-r--r--src/share/vm/opto/postaloc.cpp13
-rw-r--r--src/share/vm/utilities/debug.cpp10
21 files changed, 959 insertions, 179 deletions
diff --git a/src/share/vm/adlc/adlparse.cpp b/src/share/vm/adlc/adlparse.cpp
index bd37af19a..c2d9ee0ab 100644
--- a/src/share/vm/adlc/adlparse.cpp
+++ b/src/share/vm/adlc/adlparse.cpp
@@ -95,7 +95,7 @@ void ADLParser::parse() {
if (ident == NULL) { // Empty line
continue; // Get the next line
}
- if (!strcmp(ident, "instruct")) instr_parse();
+ if (!strcmp(ident, "instruct")) instr_parse();
else if (!strcmp(ident, "operand")) oper_parse();
else if (!strcmp(ident, "opclass")) opclass_parse();
else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();
@@ -216,24 +216,23 @@ void ADLParser::instr_parse(void) {
else if (!strcmp(ident, "encode")) {
parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
}
- else if (!strcmp(ident, "ins_encode"))
- instr->_insencode = ins_encode_parse(*instr);
- else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
- else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
- else if (!strcmp(ident, "effect")) effect_parse(instr);
- else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
- else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
+ else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);
+ else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
+ else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
+ else if (!strcmp(ident, "effect")) effect_parse(instr);
+ else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
+ else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
else if (!strcmp(ident, "constraint")) {
parse_err(SYNERR, "Instructions do not specify a constraint\n");
}
else if (!strcmp(ident, "construct")) {
parse_err(SYNERR, "Instructions do not specify a construct\n");
}
- else if (!strcmp(ident, "format")) instr->_format = format_parse();
+ else if (!strcmp(ident, "format")) instr->_format = format_parse();
else if (!strcmp(ident, "interface")) {
parse_err(SYNERR, "Instructions do not specify an interface\n");
}
- else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);
+ else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);
else { // Done with staticly defined parts of instruction definition
// Check identifier to see if it is the name of an attribute
const Form *form = _globalNames[ident];
@@ -323,7 +322,8 @@ void ADLParser::adjust_set_rule(InstructForm *instr) {
const char *optype2 = NULL;
// Can not have additional base operands in right side of match!
if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) {
- assert( instr->_predicate == NULL, "ADLC does not support instruction chain rules with predicates");
+ if (instr->_predicate != NULL)
+ parse_err(SYNERR, "ADLC does not support instruction chain rules with predicates");
// Chain from input _ideal_operand_type_,
// Needed for shared roots of match-trees
ChainList *lst = (ChainList *)_AD._chainRules[optype];
@@ -935,9 +935,9 @@ void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {
// (2)
// If we are at a replacement variable,
// copy it and record in EncClass
- if ( _curchar == '$' ) {
+ if (_curchar == '$') {
// Found replacement Variable
- char *rep_var = get_rep_var_ident_dup();
+ char* rep_var = get_rep_var_ident_dup();
// Add flag to _strings list indicating we should check _rep_vars
encoding->add_rep_var(rep_var);
}
@@ -2774,47 +2774,122 @@ Predicate *ADLParser::pred_parse(void) {
//------------------------------ins_encode_parse_block-------------------------
// Parse the block form of ins_encode. See ins_encode_parse for more details
-InsEncode *ADLParser::ins_encode_parse_block(InstructForm &inst) {
+void ADLParser::ins_encode_parse_block(InstructForm& inst) {
// Create a new encoding name based on the name of the instruction
// definition, which should be unique.
- const char * prefix = "__enc_";
- char* ec_name = (char*)malloc(strlen(inst._ident) + strlen(prefix) + 1);
+ const char* prefix = "__ins_encode_";
+ char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
sprintf(ec_name, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
- EncClass *encoding = _AD._encode->add_EncClass(ec_name);
+ EncClass* encoding = _AD._encode->add_EncClass(ec_name);
encoding->_linenum = linenum();
// synthesize the arguments list for the enc_class from the
// arguments to the instruct definition.
- const char * param = NULL;
+ const char* param = NULL;
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
- OperandForm *opForm = (OperandForm*)inst._localNames[param];
+ OperandForm* opForm = (OperandForm*) inst._localNames[param];
encoding->add_parameter(opForm->_ident, param);
}
- // Add the prologue to create the MacroAssembler
- encoding->add_code("\n"
- " // Define a MacroAssembler instance for use by the encoding. The\n"
- " // name is chosen to match the __ idiom used for assembly in other\n"
- " // parts of hotspot and assumes the existence of the standard\n"
- " // #define __ _masm.\n"
- " MacroAssembler _masm(&cbuf);\n");
+ // Define a MacroAssembler instance for use by the encoding. The
+ // name is chosen to match the __ idiom used for assembly in other
+ // parts of hotspot and assumes the existence of the standard
+ // #define __ _masm.
+ encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
// Parse the following %{ }% block
- enc_class_parse_block(encoding, ec_name);
+ ins_encode_parse_block_impl(inst, encoding, ec_name);
// Build an encoding rule which invokes the encoding rule we just
// created, passing all arguments that we received.
- InsEncode *encrule = new InsEncode(); // Encode class for instruction
- NameAndList *params = encrule->add_encode(ec_name);
+ InsEncode* encrule = new InsEncode(); // Encode class for instruction
+ NameAndList* params = encrule->add_encode(ec_name);
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
params->add_entry(param);
}
- return encrule;
+ // Set encode class of this instruction.
+ inst._insencode = encrule;
+}
+
+
+void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) {
+ skipws_no_preproc(); // Skip leading whitespace
+ // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
+ if (_AD._adlocation_debug) {
+ encoding->add_code(get_line_string());
+ }
+
+ // Collect the parts of the encode description
+ // (1) strings that are passed through to output
+ // (2) replacement/substitution variable, preceeded by a '$'
+ while ((_curchar != '%') && (*(_ptr+1) != '}')) {
+
+ // (1)
+ // Check if there is a string to pass through to output
+ char *start = _ptr; // Record start of the next string
+ while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
+ // If at the start of a comment, skip past it
+ if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
+ skipws_no_preproc();
+ } else {
+ // ELSE advance to the next character, or start of the next line
+ next_char_or_line();
+ }
+ }
+ // If a string was found, terminate it and record in EncClass
+ if (start != _ptr) {
+ *_ptr = '\0'; // Terminate the string
+ encoding->add_code(start);
+ }
+
+ // (2)
+ // If we are at a replacement variable,
+ // copy it and record in EncClass
+ if (_curchar == '$') {
+ // Found replacement Variable
+ char* rep_var = get_rep_var_ident_dup();
+
+ // Add flag to _strings list indicating we should check _rep_vars
+ encoding->add_rep_var(rep_var);
+
+ skipws();
+
+ // Check if this instruct is a MachConstantNode.
+ if (strcmp(rep_var, "constanttablebase") == 0) {
+ // This instruct is a MachConstantNode.
+ inst.set_is_mach_constant(true);
+
+ if (_curchar == '(') {
+ parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument (only constantaddress and constantoffset)", ec_name);
+ return;
+ }
+ }
+ else if ((strcmp(rep_var, "constantaddress") == 0) ||
+ (strcmp(rep_var, "constantoffset") == 0)) {
+ // This instruct is a MachConstantNode.
+ inst.set_is_mach_constant(true);
+
+ // If the constant keyword has an argument, parse it.
+ if (_curchar == '(') constant_parse(inst);
+ }
+ }
+ } // end while part of format description
+ next_char(); // Skip '%'
+ next_char(); // Skip '}'
+
+ skipws();
+
+ if (_AD._adlocation_debug) {
+ encoding->add_code(end_line_marker());
+ }
+
+ // Debug Stuff
+ if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
}
@@ -2838,7 +2913,7 @@ InsEncode *ADLParser::ins_encode_parse_block(InstructForm &inst) {
//
// making it more compact to take advantage of the MacroAssembler and
// placing the assembly closer to it's use by instructions.
-InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
+void ADLParser::ins_encode_parse(InstructForm& inst) {
// Parse encode class name
skipws(); // Skip whitespace
@@ -2849,11 +2924,12 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
next_char(); // Skip '{'
// Parse the block form of ins_encode
- return ins_encode_parse_block(inst);
+ ins_encode_parse_block(inst);
+ return;
}
parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n");
- return NULL;
+ return;
}
next_char(); // move past '('
skipws();
@@ -2866,7 +2942,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
ec_name = get_ident();
if (ec_name == NULL) {
parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");
- return NULL;
+ return;
}
// Check that encoding is defined in the encode section
EncClass *encode_class = _AD._encode->encClass(ec_name);
@@ -2898,7 +2974,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
- return NULL;
+ return;
}
params->add_entry(param);
@@ -2915,7 +2991,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
// Only ',' or ')' are valid after a parameter name
parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",
ec_name);
- return NULL;
+ return;
}
} else {
@@ -2923,11 +2999,11 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
// Did not find a parameter
if (_curchar == ',') {
parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
- return NULL;
+ return;
}
if (_curchar != ')') {
parse_err(SYNERR, "Expected ')' after encode parameters.\n");
- return NULL;
+ return;
}
}
} // WHILE loop collecting parameters
@@ -2944,7 +3020,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
else if ( _curchar != ')' ) {
// If not a ',' then only a ')' is allowed
parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);
- return NULL;
+ return;
}
// Check for ',' separating parameters
@@ -2956,14 +3032,14 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
} // done parsing ins_encode methods and their parameters
if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");
- return NULL;
+ return;
}
next_char(); // move past ')'
skipws(); // Skip leading whitespace
if ( _curchar != ';' ) {
parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");
- return NULL;
+ return;
}
next_char(); // move past ';'
skipws(); // be friendly to oper_parse()
@@ -2971,7 +3047,113 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
// Debug Stuff
if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);
- return encrule;
+ // Set encode class of this instruction.
+ inst._insencode = encrule;
+}
+
+
+//------------------------------constant_parse---------------------------------
+// Parse a constant expression.
+void ADLParser::constant_parse(InstructForm& inst) {
+ // Create a new encoding name based on the name of the instruction
+ // definition, which should be unique.
+ const char* prefix = "__constant_";
+ char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
+ sprintf(ec_name, "%s%s", prefix, inst._ident);
+
+ assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
+ EncClass* encoding = _AD._encode->add_EncClass(ec_name);
+ encoding->_linenum = linenum();
+
+ // synthesize the arguments list for the enc_class from the
+ // arguments to the instruct definition.
+ const char* param = NULL;
+ inst._parameters.reset();
+ while ((param = inst._parameters.iter()) != NULL) {
+ OperandForm* opForm = (OperandForm*) inst._localNames[param];
+ encoding->add_parameter(opForm->_ident, param);
+ }
+
+ // Parse the following ( ) expression.
+ constant_parse_expression(encoding, ec_name);
+
+ // Build an encoding rule which invokes the encoding rule we just
+ // created, passing all arguments that we received.
+ InsEncode* encrule = new InsEncode(); // Encode class for instruction
+ NameAndList* params = encrule->add_encode(ec_name);
+ inst._parameters.reset();
+ while ((param = inst._parameters.iter()) != NULL) {
+ params->add_entry(param);
+ }
+
+ // Set encode class of this instruction.
+ inst._constant = encrule;
+}
+
+
+//------------------------------constant_parse_expression----------------------
+void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
+ skipws();
+
+ // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
+ if (_AD._adlocation_debug) {
+ encoding->add_code(get_line_string());
+ }
+
+ // Start code line.
+ encoding->add_code(" _constant = C->constant_table().add");
+
+ // Parse everything in ( ) expression.
+ encoding->add_code("(");
+ next_char(); // Skip '('
+ int parens_depth = 1;
+
+ // Collect the parts of the constant expression.
+ // (1) strings that are passed through to output
+ // (2) replacement/substitution variable, preceeded by a '$'
+ while (parens_depth > 0) {
+ if (_curchar == '(') {
+ parens_depth++;
+ encoding->add_code("(");
+ next_char();
+ }
+ else if (_curchar == ')') {
+ parens_depth--;
+ encoding->add_code(")");
+ next_char();
+ }
+ else {
+ // (1)
+ // Check if there is a string to pass through to output
+ char *start = _ptr; // Record start of the next string
+ while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) {
+ next_char();
+ }
+ // If a string was found, terminate it and record in EncClass
+ if (start != _ptr) {
+ *_ptr = '\0'; // Terminate the string
+ encoding->add_code(start);
+ }
+
+ // (2)
+ // If we are at a replacement variable, copy it and record in EncClass.
+ if (_curchar == '$') {
+ // Found replacement Variable
+ char* rep_var = get_rep_var_ident_dup();
+ encoding->add_rep_var(rep_var);
+ }
+ }
+ }
+
+ // Finish code line.
+ encoding->add_code(";");
+
+ if (_AD._adlocation_debug) {
+ encoding->add_code(end_line_marker());
+ }
+
+ // Debug Stuff
+ if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
}
diff --git a/src/share/vm/adlc/adlparse.hpp b/src/share/vm/adlc/adlparse.hpp
index 1ebb3e325..ee33b88ef 100644
--- a/src/share/vm/adlc/adlparse.hpp
+++ b/src/share/vm/adlc/adlparse.hpp
@@ -156,8 +156,13 @@ protected:
Attribute *attr_parse(char *ident);// Parse instr/operand attribute rule
// Parse instruction encode rule
- InsEncode *ins_encode_parse(InstructForm &inst);
- InsEncode *ins_encode_parse_block(InstructForm &inst);
+ void ins_encode_parse(InstructForm &inst);
+ void ins_encode_parse_block(InstructForm &inst);
+ void ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name);
+
+ void constant_parse(InstructForm& inst);
+ void constant_parse_expression(EncClass* encoding, char* ec_name);
+
Opcode *opcode_parse(InstructForm *insr); // Parse instruction opcode
char *size_parse(InstructForm *insr); // Parse instruction size
Interface *interface_parse(); // Parse operand interface rule
diff --git a/src/share/vm/adlc/archDesc.hpp b/src/share/vm/adlc/archDesc.hpp
index 7a2ff93af..ad8f454be 100644
--- a/src/share/vm/adlc/archDesc.hpp
+++ b/src/share/vm/adlc/archDesc.hpp
@@ -126,7 +126,6 @@ private:
void chain_rule(FILE *fp, const char *indent, const char *ideal,
const Expr *icost, const char *irule,
Dict &operands_chained_from, ProductionState &status);
- void chain_rule_c(FILE *fp, char *indent, char *ideal, char *irule); // %%%%% TODO: remove this
void expand_opclass(FILE *fp, const char *indent, const Expr *cost,
const char *result_type, ProductionState &status);
Expr *calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status);
@@ -301,13 +300,18 @@ public:
void buildMachNodeGenerator(FILE *fp_cpp);
// Generator for Expand methods for instructions with expand rules
- void defineExpand(FILE *fp, InstructForm *node);
+ void defineExpand (FILE *fp, InstructForm *node);
// Generator for Peephole methods for instructions with peephole rules
- void definePeephole(FILE *fp, InstructForm *node);
+ void definePeephole (FILE *fp, InstructForm *node);
// Generator for Size methods for instructions
- void defineSize(FILE *fp, InstructForm &node);
+ void defineSize (FILE *fp, InstructForm &node);
+
+public:
+ // Generator for EvalConstantValue methods for instructions
+ void defineEvalConstant(FILE *fp, InstructForm &node);
// Generator for Emit methods for instructions
- void defineEmit(FILE *fp, InstructForm &node);
+ void defineEmit (FILE *fp, InstructForm &node);
+
// Define a MachOper encode method
void define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,
const char *name, const char *encoding);
diff --git a/src/share/vm/adlc/formssel.cpp b/src/share/vm/adlc/formssel.cpp
index 5011b505c..c659cdb88 100644
--- a/src/share/vm/adlc/formssel.cpp
+++ b/src/share/vm/adlc/formssel.cpp
@@ -30,11 +30,14 @@
InstructForm::InstructForm(const char *id, bool ideal_only)
: _ident(id), _ideal_only(ideal_only),
_localNames(cmpstr, hashstr, Form::arena),
- _effects(cmpstr, hashstr, Form::arena) {
+ _effects(cmpstr, hashstr, Form::arena),
+ _is_mach_constant(false)
+{
_ftype = Form::INS;
_matrule = NULL;
_insencode = NULL;
+ _constant = NULL;
_opcode = NULL;
_size = NULL;
_attribs = NULL;
@@ -58,11 +61,14 @@ InstructForm::InstructForm(const char *id, bool ideal_only)
InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
: _ident(id), _ideal_only(false),
_localNames(instr->_localNames),
- _effects(instr->_effects) {
+ _effects(instr->_effects),
+ _is_mach_constant(false)
+{
_ftype = Form::INS;
_matrule = rule;
_insencode = instr->_insencode;
+ _constant = instr->_constant;
_opcode = instr->_opcode;
_size = instr->_size;
_attribs = instr->_attribs;
@@ -1094,6 +1100,9 @@ const char *InstructForm::mach_base_class(FormDict &globals) const {
else if (is_ideal_nop()) {
return "MachNopNode";
}
+ else if (is_mach_constant()) {
+ return "MachConstantNode";
+ }
else if (captures_bottom_type(globals)) {
return "MachTypeNode";
} else {
@@ -1190,6 +1199,21 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch
//
// Generate the format call for the replacement variable
void InstructForm::rep_var_format(FILE *fp, const char *rep_var) {
+ // Handle special constant table variables.
+ if (strcmp(rep_var, "constanttablebase") == 0) {
+ fprintf(fp, "char reg[128]; ra->dump_register(in(mach_constant_base_node_input()), reg);\n");
+ fprintf(fp, "st->print(\"%%s\");\n");
+ return;
+ }
+ if (strcmp(rep_var, "constantoffset") == 0) {
+ fprintf(fp, "st->print(\"#%%d\", constant_offset());\n");
+ return;
+ }
+ if (strcmp(rep_var, "constantaddress") == 0) {
+ fprintf(fp, "st->print(\"constant table base + #%%d\", constant_offset());\n");
+ return;
+ }
+
// Find replacement variable's type
const Form *form = _localNames[rep_var];
if (form == NULL) {
@@ -1348,6 +1372,7 @@ void InstructForm::output(FILE *fp) {
fprintf(fp,"\nInstruction: %s\n", (_ident?_ident:""));
if (_matrule) _matrule->output(fp);
if (_insencode) _insencode->output(fp);
+ if (_constant) _constant->output(fp);
if (_opcode) _opcode->output(fp);
if (_attribs) _attribs->output(fp);
if (_predicate) _predicate->output(fp);
diff --git a/src/share/vm/adlc/formssel.hpp b/src/share/vm/adlc/formssel.hpp
index 285eacd0a..88ba70267 100644
--- a/src/share/vm/adlc/formssel.hpp
+++ b/src/share/vm/adlc/formssel.hpp
@@ -74,15 +74,16 @@ class ArchDesc;
//------------------------------InstructForm-----------------------------------
class InstructForm : public Form {
private:
- bool _ideal_only; // Not a user-defined instruction
+ bool _ideal_only; // Not a user-defined instruction
// Members used for tracking CISC-spilling
- uint _cisc_spill_operand;// Which operand may cisc-spill
+ uint _cisc_spill_operand;// Which operand may cisc-spill
void set_cisc_spill_operand(uint op_index) { _cisc_spill_operand = op_index; }
- bool _is_cisc_alternate;
+ bool _is_cisc_alternate;
InstructForm *_cisc_spill_alternate;// cisc possible replacement
const char *_cisc_reg_mask_name;
InstructForm *_short_branch_form;
bool _is_short_branch;
+ bool _is_mach_constant; // true if Node is a MachConstantNode
uint _alignment;
public:
@@ -94,6 +95,7 @@ public:
Opcode *_opcode; // Encoding of the opcode for instruction
char *_size; // Size of instruction
InsEncode *_insencode; // Encoding class instruction belongs to
+ InsEncode *_constant; // Encoding class constant value belongs to
Attribute *_attribs; // List of Attribute rules
Predicate *_predicate; // Predicate test for this instruction
FormDict _effects; // Dictionary of effect rules
@@ -251,6 +253,9 @@ public:
bool is_short_branch() { return _is_short_branch; }
void set_short_branch(bool val) { _is_short_branch = val; }
+ bool is_mach_constant() const { return _is_mach_constant; }
+ void set_is_mach_constant(bool x) { _is_mach_constant = x; }
+
InstructForm *short_branch_form() { return _short_branch_form; }
bool has_short_branch_form() { return _short_branch_form != NULL; }
// Output short branch prototypes and method bodies
diff --git a/src/share/vm/adlc/output_c.cpp b/src/share/vm/adlc/output_c.cpp
index 75cdcacb9..776c486f1 100644
--- a/src/share/vm/adlc/output_c.cpp
+++ b/src/share/vm/adlc/output_c.cpp
@@ -1496,8 +1496,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
unsigned i;
// Generate Expand function header
- fprintf(fp,"MachNode *%sNode::Expand(State *state, Node_List &proj_list, Node* mem) {\n", node->_ident);
- fprintf(fp,"Compile* C = Compile::current();\n");
+ fprintf(fp, "MachNode* %sNode::Expand(State* state, Node_List& proj_list, Node* mem) {\n", node->_ident);
+ fprintf(fp, " Compile* C = Compile::current();\n");
// Generate expand code
if( node->expands() ) {
const char *opid;
@@ -1818,6 +1818,12 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
}
}
+ // If the node is a MachConstantNode, insert the MachConstantBaseNode edge.
+ // NOTE: this edge must be the last input (see MachConstantNode::mach_constant_base_node_input).
+ if (node->is_mach_constant()) {
+ fprintf(fp," add_req(C->mach_constant_base_node());\n");
+ }
+
fprintf(fp,"\n");
if( node->expands() ) {
fprintf(fp," return result;\n");
@@ -1924,7 +1930,17 @@ public:
// No state needed.
assert( _opclass == NULL,
"'primary', 'secondary' and 'tertiary' don't follow operand.");
- } else {
+ }
+ else if ((strcmp(rep_var, "constanttablebase") == 0) ||
+ (strcmp(rep_var, "constantoffset") == 0) ||
+ (strcmp(rep_var, "constantaddress") == 0)) {
+ if (!_inst.is_mach_constant()) {
+ _AD.syntax_err(_encoding._linenum,
+ "Replacement variable %s not allowed in instruct %s (only in MachConstantNode).\n",
+ rep_var, _encoding._name);
+ }
+ }
+ else {
// Lookup its position in parameter list
int param_no = _encoding.rep_var_index(rep_var);
if ( param_no == -1 ) {
@@ -2380,6 +2396,15 @@ private:
rep_var, _inst._ident, _encoding._name);
}
}
+ else if (strcmp(rep_var, "constanttablebase") == 0) {
+ fprintf(_fp, "as_Register(ra_->get_encode(in(mach_constant_base_node_input())))");
+ }
+ else if (strcmp(rep_var, "constantoffset") == 0) {
+ fprintf(_fp, "constant_offset()");
+ }
+ else if (strcmp(rep_var, "constantaddress") == 0) {
+ fprintf(_fp, "InternalAddress(__ code()->consts()->start() + constant_offset())");
+ }
else {
// Lookup its position in parameter list
int param_no = _encoding.rep_var_index(rep_var);
@@ -2465,37 +2490,39 @@ void ArchDesc::defineSize(FILE *fp, InstructForm &inst) {
fprintf(fp,"}\n");
}
-void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
- InsEncode *ins_encode = inst._insencode;
+// defineEmit -----------------------------------------------------------------
+void ArchDesc::defineEmit(FILE* fp, InstructForm& inst) {
+ InsEncode* encode = inst._insencode;
// (1)
// Output instruction's emit prototype
- fprintf(fp,"void %sNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {\n",
- inst._ident);
+ fprintf(fp, "void %sNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {\n", inst._ident);
// If user did not define an encode section,
// provide stub that does not generate any machine code.
- if( (_encode == NULL) || (ins_encode == NULL) ) {
+ if( (_encode == NULL) || (encode == NULL) ) {
fprintf(fp, " // User did not define an encode section.\n");
- fprintf(fp,"}\n");
+ fprintf(fp, "}\n");
return;
}
// Save current instruction's starting address (helps with relocation).
- fprintf(fp, " cbuf.set_insts_mark();\n");
+ fprintf(fp, " cbuf.set_insts_mark();\n");
- // // // idx0 is only needed for syntactic purposes and only by "storeSSI"
- // fprintf( fp, " unsigned idx0 = 0;\n");
+ // For MachConstantNodes which are ideal jump nodes, fill the jump table.
+ if (inst.is_mach_constant() && inst.is_ideal_jump()) {
+ fprintf(fp, " ra_->C->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");
+ }
// Output each operand's offset into the array of registers.
- inst.index_temps( fp, _globalNames );
+ inst.index_temps(fp, _globalNames);
// Output this instruction's encodings
const char *ec_name;
bool user_defined = false;
- ins_encode->reset();
- while ( (ec_name = ins_encode->encode_class_iter()) != NULL ) {
- fprintf(fp, " {");
+ encode->reset();
+ while ((ec_name = encode->encode_class_iter()) != NULL) {
+ fprintf(fp, " {\n");
// Output user-defined encoding
user_defined = true;
@@ -2507,25 +2534,25 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
abort();
}
- if (ins_encode->current_encoding_num_args() != encoding->num_args()) {
- globalAD->syntax_err(ins_encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
- inst._ident, ins_encode->current_encoding_num_args(),
+ if (encode->current_encoding_num_args() != encoding->num_args()) {
+ globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
+ inst._ident, encode->current_encoding_num_args(),
ec_name, encoding->num_args());
}
- DefineEmitState pending(fp, *this, *encoding, *ins_encode, inst );
+ DefineEmitState pending(fp, *this, *encoding, *encode, inst);
encoding->_code.reset();
encoding->_rep_vars.reset();
// Process list of user-defined strings,
// and occurrences of replacement variables.
// Replacement Vars are pushed into a list and then output
- while ( (ec_code = encoding->_code.iter()) != NULL ) {
- if ( ! encoding->_code.is_signal( ec_code ) ) {
+ while ((ec_code = encoding->_code.iter()) != NULL) {
+ if (!encoding->_code.is_signal(ec_code)) {
// Emit pending code
pending.emit();
pending.clear();
// Emit this code section
- fprintf(fp,"%s", ec_code);
+ fprintf(fp, "%s", ec_code);
} else {
// A replacement variable or one of its subfields
// Obtain replacement variable from list
@@ -2536,7 +2563,7 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
// Emit pending code
pending.emit();
pending.clear();
- fprintf(fp, "}\n");
+ fprintf(fp, " }\n");
} // end while instruction's encodings
// Check if user stated which encoding to user
@@ -2545,7 +2572,86 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
}
// (3) and (4)
- fprintf(fp,"}\n");
+ fprintf(fp, "}\n");
+}
+
+// defineEvalConstant ---------------------------------------------------------
+void ArchDesc::defineEvalConstant(FILE* fp, InstructForm& inst) {
+ InsEncode* encode = inst._constant;
+
+ // (1)
+ // Output instruction's emit prototype
+ fprintf(fp, "void %sNode::eval_constant(Compile* C) {\n", inst._ident);
+
+ // For ideal jump nodes, allocate a jump table.
+ if (inst.is_ideal_jump()) {
+ fprintf(fp, " _constant = C->constant_table().allocate_jump_table(this);\n");
+ }
+
+ // If user did not define an encode section,
+ // provide stub that does not generate any machine code.
+ if ((_encode == NULL) || (encode == NULL)) {
+ fprintf(fp, " // User did not define an encode section.\n");
+ fprintf(fp, "}\n");
+ return;
+ }
+
+ // Output this instruction's encodings
+ const char *ec_name;
+ bool user_defined = false;
+ encode->reset();
+ while ((ec_name = encode->encode_class_iter()) != NULL) {
+ fprintf(fp, " {\n");
+ // Output user-defined encoding
+ user_defined = true;
+
+ const char *ec_code = NULL;
+ const char *ec_rep_var = NULL;
+ EncClass *encoding = _encode->encClass(ec_name);
+ if (encoding == NULL) {
+ fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);
+ abort();
+ }
+
+ if (encode->current_encoding_num_args() != encoding->num_args()) {
+ globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
+ inst._ident, encode->current_encoding_num_args(),
+ ec_name, encoding->num_args());
+ }
+
+ DefineEmitState pending(fp, *this, *encoding, *encode, inst);
+ encoding->_code.reset();
+ encoding->_rep_vars.reset();
+ // Process list of user-defined strings,
+ // and occurrences of replacement variables.
+ // Replacement Vars are pushed into a list and then output
+ while ((ec_code = encoding->_code.iter()) != NULL) {
+ if (!encoding->_code.is_signal(ec_code)) {
+ // Emit pending code
+ pending.emit();
+ pending.clear();
+ // Emit this code section
+ fprintf(fp, "%s", ec_code);
+ } else {
+ // A replacement variable or one of its subfields
+ // Obtain replacement variable from list
+ ec_rep_var = encoding->_rep_vars.iter();
+ pending.add_rep_var(ec_rep_var);
+ }
+ }
+ // Emit pending code
+ pending.emit();
+ pending.clear();
+ fprintf(fp, " }\n");
+ } // end while instruction's encodings
+
+ // Check if user stated which encoding to user
+ if (user_defined == false) {
+ fprintf(fp, " // User did not define which encode class to use.\n");
+ }
+
+ // (3) and (4)
+ fprintf(fp, "}\n");
}
// ---------------------------------------------------------------------------
@@ -2952,6 +3058,7 @@ void ArchDesc::defineClasses(FILE *fp) {
// If there are multiple defs/kills, or an explicit expand rule, build rule
if( instr->expands() || instr->needs_projections() ||
instr->has_temps() ||
+ instr->is_mach_constant() ||
instr->_matrule != NULL &&
instr->num_opnds() != instr->num_unique_opnds() )
defineExpand(_CPP_EXPAND_file._fp, instr);
@@ -3032,8 +3139,9 @@ void ArchDesc::defineClasses(FILE *fp) {
// Ensure this is a machine-world instruction
if ( instr->ideal_only() ) continue;
- if (instr->_insencode) defineEmit(fp, *instr);
- if (instr->_size) defineSize(fp, *instr);
+ if (instr->_insencode) defineEmit (fp, *instr);
+ if (instr->is_mach_constant()) defineEvalConstant(fp, *instr);
+ if (instr->_size) defineSize (fp, *instr);
// side-call to generate output that used to be in the header file:
extern void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &oper, bool for_c_file);
diff --git a/src/share/vm/adlc/output_h.cpp b/src/share/vm/adlc/output_h.cpp
index 1bae8b1fd..08e8ca6bf 100644
--- a/src/share/vm/adlc/output_h.cpp
+++ b/src/share/vm/adlc/output_h.cpp
@@ -1550,7 +1550,12 @@ void ArchDesc::declareClasses(FILE *fp) {
}
// virtual functions for encode and format
- //
+
+ // Virtual function for evaluating the constant.
+ if (instr->is_mach_constant()) {
+ fprintf(fp," virtual void eval_constant(Compile* C);\n");
+ }
+
// Output the opcode function and the encode function here using the
// encoding class information in the _insencode slot.
if ( instr->_insencode ) {
@@ -1559,7 +1564,7 @@ void ArchDesc::declareClasses(FILE *fp) {
// virtual function for getting the size of an instruction
if ( instr->_size ) {
- fprintf(fp," virtual uint size(PhaseRegAlloc *ra_) const;\n");
+ fprintf(fp," virtual uint size(PhaseRegAlloc *ra_) const;\n");
}
// Return the top-level ideal opcode.
@@ -1752,6 +1757,7 @@ void ArchDesc::declareClasses(FILE *fp) {
// Virtual methods which are only generated to override base class
if( instr->expands() || instr->needs_projections() ||
instr->has_temps() ||
+ instr->is_mach_constant() ||
instr->_matrule != NULL &&
instr->num_opnds() != instr->num_unique_opnds() ) {
fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list, Node* mem);\n");
@@ -1780,24 +1786,6 @@ void ArchDesc::declareClasses(FILE *fp) {
// Declare short branch methods, if applicable
instr->declare_short_branch_methods(fp);
- // Instructions containing a constant that will be entered into the
- // float/double table redefine the base virtual function
-#ifdef SPARC
- // Sparc doubles entries in the constant table require more space for
- // alignment. (expires 9/98)
- int table_entries = (3 * instr->num_consts( _globalNames, Form::idealD ))
- + instr->num_consts( _globalNames, Form::idealF );
-#else
- int table_entries = instr->num_consts( _globalNames, Form::idealD )
- + instr->num_consts( _globalNames, Form::idealF );
-#endif
- if( table_entries != 0 ) {
- fprintf(fp," virtual int const_size() const {");
- fprintf(fp, " return %d;", table_entries);
- fprintf(fp, " }\n");
- }
-
-
// See if there is an "ins_pipe" declaration for this instruction
if (instr->_ins_pipe) {
fprintf(fp," static const Pipeline *pipeline_class();\n");
diff --git a/src/share/vm/asm/assembler.hpp b/src/share/vm/asm/assembler.hpp
index 04d84c437..0b3544e69 100644
--- a/src/share/vm/asm/assembler.hpp
+++ b/src/share/vm/asm/assembler.hpp
@@ -292,7 +292,16 @@ class AbstractAssembler : public ResourceObj {
address start_a_const(int required_space, int required_align = sizeof(double));
void end_a_const();
- // fp constants support
+ // constants support
+ address long_constant(jlong c) {
+ address ptr = start_a_const(sizeof(c), sizeof(c));
+ if (ptr != NULL) {
+ *(jlong*)ptr = c;
+ _code_pos = ptr + sizeof(c);
+ end_a_const();
+ }
+ return ptr;
+ }
address double_constant(jdouble c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
@@ -311,6 +320,15 @@ class AbstractAssembler : public ResourceObj {
}
return ptr;
}
+ address address_constant(address c) {
+ address ptr = start_a_const(sizeof(c), sizeof(c));
+ if (ptr != NULL) {
+ *(address*)ptr = c;
+ _code_pos = ptr + sizeof(c);
+ end_a_const();
+ }
+ return ptr;
+ }
address address_constant(address c, RelocationHolder const& rspec) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
@@ -321,8 +339,6 @@ class AbstractAssembler : public ResourceObj {
}
return ptr;
}
- inline address address_constant(Label& L);
- inline address address_table_constant(GrowableArray<Label*> label);
// Bootstrapping aid to cope with delayed determination of constants.
// Returns a static address which will eventually contain the constant.
diff --git a/src/share/vm/asm/assembler.inline.hpp b/src/share/vm/asm/assembler.inline.hpp
index a42b6d3ab..6eede4445 100644
--- a/src/share/vm/asm/assembler.inline.hpp
+++ b/src/share/vm/asm/assembler.inline.hpp
@@ -114,32 +114,4 @@ inline void Label::bind_loc(int pos, int sect) {
bind_loc(CodeBuffer::locator(pos, sect));
}
-address AbstractAssembler::address_constant(Label& L) {
- address c = NULL;
- address ptr = start_a_const(sizeof(c), sizeof(c));
- if (ptr != NULL) {
- relocate(Relocation::spec_simple(relocInfo::internal_word_type));
- *(address*)ptr = c = code_section()->target(L, ptr);
- _code_pos = ptr + sizeof(c);
- end_a_const();
- }
- return ptr;
-}
-
-address AbstractAssembler::address_table_constant(GrowableArray<Label*> labels) {
- int addressSize = sizeof(address);
- int sizeLabel = addressSize * labels.length();
- address ptr = start_a_const(sizeLabel, addressSize);
-
- if (ptr != NULL) {
- address *labelLoc = (address*)ptr;
- for (int i=0; i < labels.length(); i++) {
- emit_address(code_section()->target(*labels.at(i), (address)&labelLoc[i]));
- code_section()->relocate((address)&labelLoc[i], relocInfo::internal_word_type);
- }
- end_a_const();
- }
- return ptr;
-}
-
#endif // SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
diff --git a/src/share/vm/compiler/disassembler.cpp b/src/share/vm/compiler/disassembler.cpp
index b63b55649..61c3fb1a2 100644
--- a/src/share/vm/compiler/disassembler.cpp
+++ b/src/share/vm/compiler/disassembler.cpp
@@ -467,5 +467,18 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
env.set_total_ticks(total_bucket_count);
}
+ // Print constant table.
+ if (nm->consts_size() > 0) {
+ nm->print_nmethod_labels(env.output(), nm->consts_begin());
+ int offset = 0;
+ for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
+ if ((offset % 8) == 0) {
+ env.output()->print_cr(" " INTPTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, (intptr_t) p, offset, *((int32_t*) p), *((int64_t*) p));
+ } else {
+ env.output()->print_cr(" " INTPTR_FORMAT " (offset: %4d): " PTR32_FORMAT, (intptr_t) p, offset, *((int32_t*) p));
+ }
+ }
+ }
+
env.decode_instructions(p, end);
}
diff --git a/src/share/vm/opto/c2_globals.hpp b/src/share/vm/opto/c2_globals.hpp
index 2bdc1a04a..fe516dff5 100644
--- a/src/share/vm/opto/c2_globals.hpp
+++ b/src/share/vm/opto/c2_globals.hpp
@@ -284,6 +284,9 @@
develop(bool, SparcV9RegsHiBitsZero, true, \
"Assume Sparc V9 I&L registers on V8+ systems are zero-extended") \
\
+ product(bool, UseRDPCForConstantTableBase, false, \
+ "Use Sparc RDPC instruction for the constant table base.") \
+ \
develop(intx, PrintIdealGraphLevel, 0, \
"Print ideal graph to XML file / network interface. " \
"By default attempts to connect to the visualizer on a socket.") \
diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
index 972cc34ae..0ca15e168 100644
--- a/src/share/vm/opto/compile.cpp
+++ b/src/share/vm/opto/compile.cpp
@@ -75,6 +75,18 @@
# include "adfiles/ad_zero.hpp"
#endif
+
+// -------------------- Compile::mach_constant_base_node -----------------------
+// Constant table base node singleton.
+MachConstantBaseNode* Compile::mach_constant_base_node() {
+ if (_mach_constant_base_node == NULL) {
+ _mach_constant_base_node = new (C) MachConstantBaseNode();
+ _mach_constant_base_node->add_req(C->root());
+ }
+ return _mach_constant_base_node;
+}
+
+
/// Support for intrinsics.
// Return the index at which m must be inserted (or already exists).
@@ -432,13 +444,14 @@ void Compile::print_compile_messages() {
}
-void Compile::init_scratch_buffer_blob() {
- if( scratch_buffer_blob() != NULL ) return;
+void Compile::init_scratch_buffer_blob(int const_size) {
+ if (scratch_buffer_blob() != NULL) return;
// Construct a temporary CodeBuffer to have it construct a BufferBlob
// Cache this BufferBlob for this compile.
ResourceMark rm;
- int size = (MAX_inst_size + MAX_stubs_size + MAX_const_size);
+ _scratch_const_size = const_size;
+ int size = (MAX_inst_size + MAX_stubs_size + _scratch_const_size);
BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size);
// Record the buffer blob for next time.
set_scratch_buffer_blob(blob);
@@ -455,9 +468,19 @@ void Compile::init_scratch_buffer_blob() {
}
+void Compile::clear_scratch_buffer_blob() {
+ assert(scratch_buffer_blob(), "no BufferBlob set");
+ set_scratch_buffer_blob(NULL);
+ set_scratch_locs_memory(NULL);
+}
+
+
//-----------------------scratch_emit_size-------------------------------------
// Helper function that computes size by emitting code
uint Compile::scratch_emit_size(const Node* n) {
+ // Start scratch_emit_size section.
+ set_in_scratch_emit_size(true);
+
// Emit into a trash buffer and count bytes emitted.
// This is a pretty expensive way to compute a size,
// but it works well enough if seldom used.
@@ -476,13 +499,20 @@ uint Compile::scratch_emit_size(const Node* n) {
address blob_end = (address)locs_buf;
assert(blob->content_contains(blob_end), "sanity");
CodeBuffer buf(blob_begin, blob_end - blob_begin);
- buf.initialize_consts_size(MAX_const_size);
+ buf.initialize_consts_size(_scratch_const_size);
buf.initialize_stubs_size(MAX_stubs_size);
assert(locs_buf != NULL, "sanity");
- int lsize = MAX_locs_size / 2;
- buf.insts()->initialize_shared_locs(&locs_buf[0], lsize);
- buf.stubs()->initialize_shared_locs(&locs_buf[lsize], lsize);
+ int lsize = MAX_locs_size / 3;
+ buf.consts()->initialize_shared_locs(&locs_buf[lsize * 0], lsize);
+ buf.insts()->initialize_shared_locs( &locs_buf[lsize * 1], lsize);
+ buf.stubs()->initialize_shared_locs( &locs_buf[lsize * 2], lsize);
+
+ // Do the emission.
n->emit(buf, this->regalloc());
+
+ // End scratch_emit_size section.
+ set_in_scratch_emit_size(false);
+
return buf.insts_size();
}
@@ -516,10 +546,13 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
_orig_pc_slot(0),
_orig_pc_slot_offset_in_bytes(0),
_has_method_handle_invokes(false),
+ _mach_constant_base_node(NULL),
_node_bundling_limit(0),
_node_bundling_base(NULL),
_java_calls(0),
_inner_loops(0),
+ _scratch_const_size(-1),
+ _in_scratch_emit_size(false),
#ifndef PRODUCT
_trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")),
_printer(IdealGraphPrinter::printer()),
@@ -783,6 +816,7 @@ Compile::Compile( ciEnv* ci_env,
_failure_reason(NULL),
_code_buffer("Compile::Fill_buffer"),
_has_method_handle_invokes(false),
+ _mach_constant_base_node(NULL),
_node_bundling_limit(0),
_node_bundling_base(NULL),
_java_calls(0),
@@ -2862,3 +2896,207 @@ Compile::TracePhase::~TracePhase() {
_log->done("phase nodes='%d'", C->unique());
}
}
+
+//=============================================================================
+// Two Constant's are equal when the type and the value are equal.
+bool Compile::Constant::operator==(const Constant& other) {
+ if (type() != other.type() ) return false;
+ if (can_be_reused() != other.can_be_reused()) return false;
+ // For floating point values we compare the bit pattern.
+ switch (type()) {
+ case T_FLOAT: return (_value.i == other._value.i);
+ case T_LONG:
+ case T_DOUBLE: return (_value.j == other._value.j);
+ case T_OBJECT:
+ case T_ADDRESS: return (_value.l == other._value.l);
+ case T_VOID: return (_value.l == other._value.l); // jump-table entries
+ default: ShouldNotReachHere();
+ }
+ return false;
+}
+
+// Emit constants grouped in the following order:
+static BasicType type_order[] = {
+ T_FLOAT, // 32-bit
+ T_OBJECT, // 32 or 64-bit
+ T_ADDRESS, // 32 or 64-bit
+ T_DOUBLE, // 64-bit
+ T_LONG, // 64-bit
+ T_VOID, // 32 or 64-bit (jump-tables are at the end of the constant table for code emission reasons)
+ T_ILLEGAL
+};
+
+static int type_to_size_in_bytes(BasicType t) {
+ switch (t) {
+ case T_LONG: return sizeof(jlong );
+ case T_FLOAT: return sizeof(jfloat );
+ case T_DOUBLE: return sizeof(jdouble);
+ // We use T_VOID as marker for jump-table entries (labels) which
+ // need an interal word relocation.
+ case T_VOID:
+ case T_ADDRESS:
+ case T_OBJECT: return sizeof(jobject);
+ }
+
+ ShouldNotReachHere();
+ return -1;
+}
+
+void Compile::ConstantTable::calculate_offsets_and_size() {
+ int size = 0;
+ for (int t = 0; type_order[t] != T_ILLEGAL; t++) {
+ BasicType type = type_order[t];
+
+ for (int i = 0; i < _constants.length(); i++) {
+ Constant con = _constants.at(i);
+ if (con.type() != type) continue; // Skip other types.
+
+ // Align size for type.
+ int typesize = type_to_size_in_bytes(con.type());
+ size = align_size_up(size, typesize);
+
+ // Set offset.
+ con.set_offset(size);
+ _constants.at_put(i, con);
+
+ // Add type size.
+ size = size + typesize;
+ }
+ }
+
+ // Align size up to the next section start (which is insts; see
+ // CodeBuffer::align_at_start).
+ assert(_size == -1, "already set?");
+ _size = align_size_up(size, CodeEntryAlignment);
+
+ if (Matcher::constant_table_absolute_addressing) {
+ set_table_base_offset(0); // No table base offset required
+ } else {
+ if (UseRDPCForConstantTableBase) {
+ // table base offset is set in MachConstantBaseNode::emit
+ } else {
+ // When RDPC is not used, the table base is set into the middle of
+ // the constant table.
+ int half_size = _size / 2;
+ assert(half_size * 2 == _size, "sanity");
+ set_table_base_offset(-half_size);
+ }
+ }
+}
+
+void Compile::ConstantTable::emit(CodeBuffer& cb) {
+ MacroAssembler _masm(&cb);
+ for (int t = 0; type_order[t] != T_ILLEGAL; t++) {
+ BasicType type = type_order[t];
+
+ for (int i = 0; i < _constants.length(); i++) {
+ Constant con = _constants.at(i);
+ if (con.type() != type) continue; // Skip other types.
+
+ address constant_addr;
+ switch (con.type()) {
+ case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break;
+ case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break;
+ case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break;
+ case T_OBJECT: {
+ jobject obj = con.get_jobject();
+ int oop_index = _masm.oop_recorder()->find_index(obj);
+ constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index));
+ break;
+ }
+ case T_ADDRESS: {
+ address addr = (address) con.get_jobject();
+ constant_addr = _masm.address_constant(addr);
+ break;
+ }
+ // We use T_VOID as marker for jump-table entries (labels) which
+ // need an interal word relocation.
+ case T_VOID: {
+ // Write a dummy word. The real value is filled in later
+ // in fill_jump_table_in_constant_table.
+ address addr = (address) con.get_jobject();
+ constant_addr = _masm.address_constant(addr);
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+ assert(constant_addr != NULL, "consts section too small");
+ assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset()));
+ }
+ }
+}
+
+int Compile::ConstantTable::find_offset(Constant& con) const {
+ int idx = _constants.find(con);
+ assert(idx != -1, "constant must be in constant table");
+ int offset = _constants.at(idx).offset();
+ assert(offset != -1, "constant table not emitted yet?");
+ return offset;
+}
+
+void Compile::ConstantTable::add(Constant& con) {
+ if (con.can_be_reused()) {
+ int idx = _constants.find(con);
+ if (idx != -1 && _constants.at(idx).can_be_reused()) {
+ return;
+ }
+ }
+ (void) _constants.append(con);
+}
+
+Compile::Constant Compile::ConstantTable::add(BasicType type, jvalue value) {
+ Constant con(type, value);
+ add(con);
+ return con;
+}
+
+Compile::Constant Compile::ConstantTable::add(MachOper* oper) {
+ jvalue value;
+ BasicType type = oper->type()->basic_type();
+ switch (type) {
+ case T_LONG: value.j = oper->constantL(); break;
+ case T_FLOAT: value.f = oper->constantF(); break;
+ case T_DOUBLE: value.d = oper->constantD(); break;
+ case T_OBJECT:
+ case T_ADDRESS: value.l = (jobject) oper->constant(); break;
+ default: ShouldNotReachHere();
+ }
+ return add(type, value);
+}
+
+Compile::Constant Compile::ConstantTable::allocate_jump_table(MachConstantNode* n) {
+ jvalue value;
+ // We can use the node pointer here to identify the right jump-table
+ // as this method is called from Compile::Fill_buffer right before
+ // the MachNodes are emitted and the jump-table is filled (means the
+ // MachNode pointers do not change anymore).
+ value.l = (jobject) n;
+ Constant con(T_VOID, value, false); // Labels of a jump-table cannot be reused.
+ for (uint i = 0; i < n->outcnt(); i++) {
+ add(con);
+ }
+ return con;
+}
+
+void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const {
+ // If called from Compile::scratch_emit_size do nothing.
+ if (Compile::current()->in_scratch_emit_size()) return;
+
+ assert(labels.is_nonempty(), "must be");
+ assert((uint) labels.length() == n->outcnt(), err_msg("must be equal: %d == %d", labels.length(), n->outcnt()));
+
+ // Since MachConstantNode::constant_offset() also contains
+ // table_base_offset() we need to subtract the table_base_offset()
+ // to get the plain offset into the constant table.
+ int offset = n->constant_offset() - table_base_offset();
+
+ MacroAssembler _masm(&cb);
+ address* jump_table_base = (address*) (_masm.code()->consts()->start() + offset);
+
+ for (int i = 0; i < labels.length(); i++) {
+ address* constant_addr = &jump_table_base[i];
+ assert(*constant_addr == (address) n, "all jump-table entries must contain node pointer");
+ *constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr);
+ cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type);
+ }
+}
diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
index 9ec26ac70..36d09aca4 100644
--- a/src/share/vm/opto/compile.hpp
+++ b/src/share/vm/opto/compile.hpp
@@ -48,7 +48,10 @@ class ConnectionGraph;
class InlineTree;
class Int_Array;
class Matcher;
+class MachConstantNode;
+class MachConstantBaseNode;
class MachNode;
+class MachOper;
class MachSafePointNode;
class Node;
class Node_Array;
@@ -139,6 +142,81 @@ class Compile : public Phase {
trapHistLength = methodDataOopDesc::_trap_hist_limit
};
+ // Constant entry of the constant table.
+ class Constant {
+ private:
+ BasicType _type;
+ jvalue _value;
+ int _offset; // offset of this constant (in bytes) relative to the constant table base.
+ bool _can_be_reused; // true (default) if the value can be shared with other users.
+
+ public:
+ Constant() : _type(T_ILLEGAL), _offset(-1), _can_be_reused(true) { _value.l = 0; }
+ Constant(BasicType type, jvalue value, bool can_be_reused = true) :
+ _type(type),
+ _value(value),
+ _offset(-1),
+ _can_be_reused(can_be_reused)
+ {}
+
+ bool operator==(const Constant& other);
+
+ BasicType type() const { return _type; }
+
+ jlong get_jlong() const { return _value.j; }
+ jfloat get_jfloat() const { return _value.f; }
+ jdouble get_jdouble() const { return _value.d; }
+ jobject get_jobject() const { return _value.l; }
+
+ int offset() const { return _offset; }
+ void set_offset(int offset) { _offset = offset; }
+
+ bool can_be_reused() const { return _can_be_reused; }
+ };
+
+ // Constant table.
+ class ConstantTable {
+ private:
+ GrowableArray<Constant> _constants; // Constants of this table.
+ int _size; // Size in bytes the emitted constant table takes (including padding).
+ int _table_base_offset; // Offset of the table base that gets added to the constant offsets.
+
+ public:
+ ConstantTable() :
+ _size(-1),
+ _table_base_offset(-1) // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit).
+ {}
+
+ int size() const { assert(_size != -1, "size not yet calculated"); return _size; }
+
+ void set_table_base_offset(int x) { assert(_table_base_offset == -1, "set only once"); _table_base_offset = x; }
+ int table_base_offset() const { assert(_table_base_offset != -1, "table base offset not yet set"); return _table_base_offset; }
+
+ void emit(CodeBuffer& cb);
+
+ // Returns the offset of the last entry (the top) of the constant table.
+ int top_offset() const { assert(_constants.top().offset() != -1, "constant not yet bound"); return _constants.top().offset(); }
+
+ void calculate_offsets_and_size();
+ int find_offset(Constant& con) const;
+
+ void add(Constant& con);
+ Constant add(BasicType type, jvalue value);
+ Constant add(MachOper* oper);
+ Constant add(jfloat f) {
+ jvalue value; value.f = f;
+ return add(T_FLOAT, value);
+ }
+ Constant add(jdouble d) {
+ jvalue value; value.d = d;
+ return add(T_DOUBLE, value);
+ }
+
+ // Jump table
+ Constant allocate_jump_table(MachConstantNode* n);
+ void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const;
+ };
+
private:
// Fixed parameters to this compilation.
const int _compile_id;
@@ -212,6 +290,11 @@ class Compile : public Phase {
Node* _recent_alloc_obj;
Node* _recent_alloc_ctl;
+ // Constant table
+ ConstantTable _constant_table; // The constant table for this compile.
+ MachConstantBaseNode* _mach_constant_base_node; // Constant table base node singleton.
+
+
// Blocked array of debugging and profiling information,
// tracked per node.
enum { _log2_node_notes_block_size = 8,
@@ -272,6 +355,8 @@ class Compile : public Phase {
static int _CompiledZap_count; // counter compared against CompileZap[First/Last]
BufferBlob* _scratch_buffer_blob; // For temporary code buffers.
relocInfo* _scratch_locs_memory; // For temporary code buffers.
+ int _scratch_const_size; // For temporary code buffers.
+ bool _in_scratch_emit_size; // true when in scratch_emit_size.
public:
// Accessors
@@ -454,6 +539,12 @@ class Compile : public Phase {
_recent_alloc_obj = obj;
}
+ // Constant table
+ ConstantTable& constant_table() { return _constant_table; }
+
+ MachConstantBaseNode* mach_constant_base_node();
+ bool has_mach_constant_base_node() const { return _mach_constant_base_node != NULL; }
+
// Handy undefined Node
Node* top() const { return _top; }
@@ -605,13 +696,16 @@ class Compile : public Phase {
Dependencies* dependencies() { return env()->dependencies(); }
static int CompiledZap_count() { return _CompiledZap_count; }
BufferBlob* scratch_buffer_blob() { return _scratch_buffer_blob; }
- void init_scratch_buffer_blob();
+ void init_scratch_buffer_blob(int const_size);
+ void clear_scratch_buffer_blob();
void set_scratch_buffer_blob(BufferBlob* b) { _scratch_buffer_blob = b; }
relocInfo* scratch_locs_memory() { return _scratch_locs_memory; }
void set_scratch_locs_memory(relocInfo* b) { _scratch_locs_memory = b; }
// emit to scratch blob, report resulting size
uint scratch_emit_size(const Node* n);
+ void set_in_scratch_emit_size(bool x) { _in_scratch_emit_size = x; }
+ bool in_scratch_emit_size() const { return _in_scratch_emit_size; }
enum ScratchBufferBlob {
MAX_inst_size = 1024,
@@ -692,7 +786,7 @@ class Compile : public Phase {
void Fill_buffer();
// Determine which variable sized branches can be shortened
- void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size, int& const_size);
+ void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size);
// Compute the size of first NumberOfLoopInstrToAlign instructions
// at the head of a loop.
diff --git a/src/share/vm/opto/gcm.cpp b/src/share/vm/opto/gcm.cpp
index 6a6a18e73..1a0116445 100644
--- a/src/share/vm/opto/gcm.cpp
+++ b/src/share/vm/opto/gcm.cpp
@@ -89,7 +89,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) {
assert(in0 != NULL, "Only control-dependent");
const Node *p = in0->is_block_proj();
if (p != NULL && p != n) { // Control from a block projection?
- assert(!n->pinned() || n->is_SafePointScalarObject(), "only SafePointScalarObject pinned node is expected here");
+ assert(!n->pinned() || n->is_MachConstantBase() || n->is_SafePointScalarObject(), "only pinned MachConstantBase or SafePointScalarObject node is expected here");
// Find trailing Region
Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block
uint j = 0;
diff --git a/src/share/vm/opto/machnode.cpp b/src/share/vm/opto/machnode.cpp
index 179116287..6242c66aa 100644
--- a/src/share/vm/opto/machnode.cpp
+++ b/src/share/vm/opto/machnode.cpp
@@ -489,6 +489,20 @@ void MachTypeNode::dump_spec(outputStream *st) const {
}
#endif
+
+//=============================================================================
+int MachConstantNode::constant_offset() {
+ int offset = _constant.offset();
+ // Bind the offset lazily.
+ if (offset == -1) {
+ Compile::ConstantTable& constant_table = Compile::current()->constant_table();
+ offset = constant_table.table_base_offset() + constant_table.find_offset(_constant);
+ _constant.set_offset(offset);
+ }
+ return offset;
+}
+
+
//=============================================================================
#ifndef PRODUCT
void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
diff --git a/src/share/vm/opto/machnode.hpp b/src/share/vm/opto/machnode.hpp
index 633a9b143..d947bb871 100644
--- a/src/share/vm/opto/machnode.hpp
+++ b/src/share/vm/opto/machnode.hpp
@@ -231,9 +231,6 @@ public:
// Return number of relocatable values contained in this instruction
virtual int reloc() const { return 0; }
- // Return number of words used for double constants in this instruction
- virtual int const_size() const { return 0; }
-
// Hash and compare over operands. Used to do GVN on machine Nodes.
virtual uint hash() const;
virtual uint cmp( const Node &n ) const;
@@ -348,6 +345,65 @@ public:
#endif
};
+//------------------------------MachConstantBaseNode--------------------------
+// Machine node that represents the base address of the constant table.
+class MachConstantBaseNode : public MachIdealNode {
+public:
+ static const RegMask& _out_RegMask; // We need the out_RegMask statically in MachConstantNode::in_RegMask().
+
+public:
+ MachConstantBaseNode() : MachIdealNode() {
+ init_class_id(Class_MachConstantBase);
+ }
+ virtual const class Type* bottom_type() const { return TypeRawPtr::NOTNULL; }
+ virtual uint ideal_reg() const { return Op_RegP; }
+ virtual uint oper_input_base() const { return 1; }
+
+ virtual void emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const;
+ virtual uint size(PhaseRegAlloc* ra_) const;
+ virtual bool pinned() const { return UseRDPCForConstantTableBase; }
+
+ static const RegMask& static_out_RegMask() { return _out_RegMask; }
+ virtual const RegMask& out_RegMask() const { return static_out_RegMask(); }
+
+#ifndef PRODUCT
+ virtual const char* Name() const { return "MachConstantBaseNode"; }
+ virtual void format(PhaseRegAlloc*, outputStream* st) const;
+#endif
+};
+
+//------------------------------MachConstantNode-------------------------------
+// Machine node that holds a constant which is stored in the constant table.
+class MachConstantNode : public MachNode {
+protected:
+ Compile::Constant _constant; // This node's constant.
+
+public:
+ MachConstantNode() : MachNode() {
+ init_class_id(Class_MachConstant);
+ }
+
+ virtual void eval_constant(Compile* C) {
+#ifdef ASSERT
+ tty->print("missing MachConstantNode eval_constant function: ");
+ dump();
+#endif
+ ShouldNotCallThis();
+ }
+
+ virtual const RegMask &in_RegMask(uint idx) const {
+ if (idx == mach_constant_base_node_input())
+ return MachConstantBaseNode::static_out_RegMask();
+ return MachNode::in_RegMask(idx);
+ }
+
+ // Input edge of MachConstantBaseNode.
+ uint mach_constant_base_node_input() const { return req() - 1; }
+
+ int constant_offset();
+ int constant_offset() const { return ((MachConstantNode*) this)->constant_offset(); }
+};
+
//------------------------------MachUEPNode-----------------------------------
// Machine Unvalidated Entry Point Node
class MachUEPNode : public MachIdealNode {
diff --git a/src/share/vm/opto/matcher.hpp b/src/share/vm/opto/matcher.hpp
index 6e8f04c5c..c1627c60f 100644
--- a/src/share/vm/opto/matcher.hpp
+++ b/src/share/vm/opto/matcher.hpp
@@ -365,6 +365,10 @@ public:
// registers? True for Intel but false for most RISCs
static const bool clone_shift_expressions;
+ // Should constant table entries be accessed with loads using
+ // absolute addressing? True for x86 but false for most RISCs.
+ static const bool constant_table_absolute_addressing;
+
static bool narrow_oop_use_complex_address();
// Generate implicit null check for narrow oops if it can fold
diff --git a/src/share/vm/opto/node.hpp b/src/share/vm/opto/node.hpp
index c1aaf3600..67bcf90f2 100644
--- a/src/share/vm/opto/node.hpp
+++ b/src/share/vm/opto/node.hpp
@@ -81,6 +81,8 @@ class MachCallLeafNode;
class MachCallNode;
class MachCallRuntimeNode;
class MachCallStaticJavaNode;
+class MachConstantBaseNode;
+class MachConstantNode;
class MachIfNode;
class MachNode;
class MachNullCheckNode;
@@ -566,10 +568,12 @@ public:
DEFINE_CLASS_ID(MachCallDynamicJava, MachCallJava, 1)
DEFINE_CLASS_ID(MachCallRuntime, MachCall, 1)
DEFINE_CLASS_ID(MachCallLeaf, MachCallRuntime, 0)
- DEFINE_CLASS_ID(MachSpillCopy, Mach, 1)
- DEFINE_CLASS_ID(MachNullCheck, Mach, 2)
- DEFINE_CLASS_ID(MachIf, Mach, 3)
- DEFINE_CLASS_ID(MachTemp, Mach, 4)
+ DEFINE_CLASS_ID(MachSpillCopy, Mach, 1)
+ DEFINE_CLASS_ID(MachNullCheck, Mach, 2)
+ DEFINE_CLASS_ID(MachIf, Mach, 3)
+ DEFINE_CLASS_ID(MachTemp, Mach, 4)
+ DEFINE_CLASS_ID(MachConstantBase, Mach, 5)
+ DEFINE_CLASS_ID(MachConstant, Mach, 6)
DEFINE_CLASS_ID(Proj, Node, 2)
DEFINE_CLASS_ID(CatchProj, Proj, 0)
@@ -734,6 +738,8 @@ public:
DEFINE_CLASS_QUERY(MachCallLeaf)
DEFINE_CLASS_QUERY(MachCallRuntime)
DEFINE_CLASS_QUERY(MachCallStaticJava)
+ DEFINE_CLASS_QUERY(MachConstantBase)
+ DEFINE_CLASS_QUERY(MachConstant)
DEFINE_CLASS_QUERY(MachIf)
DEFINE_CLASS_QUERY(MachNullCheck)
DEFINE_CLASS_QUERY(MachReturn)
diff --git a/src/share/vm/opto/output.cpp b/src/share/vm/opto/output.cpp
index 015b8f69a..e2ddd974f 100644
--- a/src/share/vm/opto/output.cpp
+++ b/src/share/vm/opto/output.cpp
@@ -61,11 +61,6 @@ void Compile::Output() {
// RootNode goes
assert( _cfg->_broot->_nodes.size() == 0, "" );
- // Initialize the space for the BufferBlob used to find and verify
- // instruction size in MachNode::emit_size()
- init_scratch_buffer_blob();
- if (failing()) return; // Out of memory
-
// The number of new nodes (mostly MachNop) is proportional to
// the number of java calls and inner loops which are aligned.
if ( C->check_node_count((NodeLimitFudgeFactor + C->java_calls()*3 +
@@ -333,7 +328,7 @@ void Compile::compute_loop_first_inst_sizes() {
//----------------------Shorten_branches---------------------------------------
// The architecture description provides short branch variants for some long
// branch instructions. Replace eligible long branches with short branches.
-void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size, int& const_size) {
+void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size) {
// fill in the nop array for bundling computations
MachNode *_nop_list[Bundle::_nop_count];
@@ -353,12 +348,11 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
// Size in bytes of all relocation entries, including those in local stubs.
// Start with 2-bytes of reloc info for the unvalidated entry point
reloc_size = 1; // Number of relocation entries
- const_size = 0; // size of fp constants in words
// Make three passes. The first computes pessimistic blk_starts,
- // relative jmp_end, reloc_size and const_size information.
- // The second performs short branch substitution using the pessimistic
- // sizing. The third inserts nops where needed.
+ // relative jmp_end and reloc_size information. The second performs
+ // short branch substitution using the pessimistic sizing. The
+ // third inserts nops where needed.
Node *nj; // tmp
@@ -381,7 +375,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
MachNode *mach = nj->as_Mach();
blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding
reloc_size += mach->reloc();
- const_size += mach->const_size();
if( mach->is_MachCall() ) {
MachCallNode *mcall = mach->as_MachCall();
// This destination address is NOT PC-relative
@@ -398,10 +391,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
if (min_offset_from_last_call == 0) {
blk_size += nop_size;
}
- } else if (mach->ideal_Opcode() == Op_Jump) {
- const_size += b->_num_succs; // Address table size
- // The size is valid even for 64 bit since it is
- // multiplied by 2*jintSize on this method exit.
}
}
min_offset_from_last_call += inst_size;
@@ -562,10 +551,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
// a relocation index.
// The CodeBuffer will expand the locs array if this estimate is too low.
reloc_size *= 10 / sizeof(relocInfo);
-
- // Adjust const_size to number of bytes
- const_size *= 2*jintSize; // both float and double take two words per entry
-
}
//------------------------------FillLocArray-----------------------------------
@@ -1102,10 +1087,39 @@ void Compile::Fill_buffer() {
blk_labels[i].init();
}
+ if (has_mach_constant_base_node()) {
+ // Fill the constant table.
+ // Note: This must happen before Shorten_branches.
+ for (i = 0; i < _cfg->_num_blocks; i++) {
+ Block* b = _cfg->_blocks[i];
+
+ for (uint j = 0; j < b->_nodes.size(); j++) {
+ Node* n = b->_nodes[j];
+
+ // If the node is a MachConstantNode evaluate the constant
+ // value section.
+ if (n->is_MachConstant()) {
+ MachConstantNode* machcon = n->as_MachConstant();
+ machcon->eval_constant(C);
+ }
+ }
+ }
+
+ // Calculate the offsets of the constants and the size of the
+ // constant table (including the padding to the next section).
+ constant_table().calculate_offsets_and_size();
+ const_req = constant_table().size();
+ }
+
+ // Initialize the space for the BufferBlob used to find and verify
+ // instruction size in MachNode::emit_size()
+ init_scratch_buffer_blob(const_req);
+ if (failing()) return; // Out of memory
+
// If this machine supports different size branch offsets, then pre-compute
// the length of the blocks
if( _matcher->is_short_branch_offset(-1, 0) ) {
- Shorten_branches(blk_labels, code_req, locs_req, stub_req, const_req);
+ Shorten_branches(blk_labels, code_req, locs_req, stub_req);
labels_not_set = false;
}
@@ -1121,12 +1135,12 @@ void Compile::Fill_buffer() {
code_req = const_req = stub_req = exception_handler_req = deopt_handler_req = 0x10; // force expansion
int total_req =
+ const_req +
code_req +
pad_req +
stub_req +
exception_handler_req +
- deopt_handler_req + // deopt handler
- const_req;
+ deopt_handler_req; // deopt handler
if (has_method_handle_invokes())
total_req += deopt_handler_req; // deopt MH handler
@@ -1180,6 +1194,11 @@ void Compile::Fill_buffer() {
NonSafepointEmitter non_safepoints(this); // emit non-safepoints lazily
+ // Emit the constant table.
+ if (has_mach_constant_base_node()) {
+ constant_table().emit(*cb);
+ }
+
// ------------------
// Now fill in the code buffer
Node *delay_slot = NULL;
@@ -1196,12 +1215,13 @@ void Compile::Fill_buffer() {
cb->flush_bundle(true);
// Define the label at the beginning of the basic block
- if( labels_not_set )
- MacroAssembler(cb).bind( blk_labels[b->_pre_order] );
-
- else
- assert( blk_labels[b->_pre_order].loc_pos() == cb->insts_size(),
- "label position does not match code offset" );
+ if (labels_not_set) {
+ MacroAssembler(cb).bind(blk_labels[b->_pre_order]);
+ } else {
+ assert(blk_labels[b->_pre_order].loc_pos() == cb->insts_size(),
+ err_msg("label position does not match code offset: %d != %d",
+ blk_labels[b->_pre_order].loc_pos(), cb->insts_size()));
+ }
uint last_inst = b->_nodes.size();
@@ -1718,9 +1738,17 @@ void Compile::ScheduleAndBundle() {
// Create a data structure for all the scheduling information
Scheduling scheduling(Thread::current()->resource_area(), *this);
+ // Initialize the space for the BufferBlob used to find and verify
+ // instruction size in MachNode::emit_size()
+ init_scratch_buffer_blob(MAX_const_size);
+ if (failing()) return; // Out of memory
+
// Walk backwards over each basic block, computing the needed alignment
// Walk over all the basic blocks
scheduling.DoScheduling();
+
+ // Clear the BufferBlob used for scheduling.
+ clear_scratch_buffer_blob();
}
//------------------------------ComputeLocalLatenciesForward-------------------
diff --git a/src/share/vm/opto/postaloc.cpp b/src/share/vm/opto/postaloc.cpp
index c901f611f..897d5102c 100644
--- a/src/share/vm/opto/postaloc.cpp
+++ b/src/share/vm/opto/postaloc.cpp
@@ -200,6 +200,19 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v
// then reloaded BUT survives in a register the whole way.
Node *val = skip_copies(n->in(k));
+ if (val == x && nk_idx != 0 &&
+ regnd[nk_reg] != NULL && regnd[nk_reg] != x &&
+ n2lidx(x) == n2lidx(regnd[nk_reg])) {
+ // When rematerialzing nodes and stretching lifetimes, the
+ // allocator will reuse the original def for multidef LRG instead
+ // of the current reaching def because it can't know it's safe to
+ // do so. After allocation completes if they are in the same LRG
+ // then it should use the current reaching def instead.
+ n->set_req(k, regnd[nk_reg]);
+ blk_adjust += yank_if_dead(val, current_block, &value, &regnd);
+ val = skip_copies(n->in(k));
+ }
+
if( val == x ) return blk_adjust; // No progress?
bool single = is_single_register(val->ideal_reg());
diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp
index 66edcaa37..484dcf581 100644
--- a/src/share/vm/utilities/debug.cpp
+++ b/src/share/vm/utilities/debug.cpp
@@ -399,8 +399,14 @@ extern "C" void nm(intptr_t p) {
extern "C" void disnm(intptr_t p) {
Command c("disnm");
CodeBlob* cb = CodeCache::find_blob((address) p);
- cb->print();
- Disassembler::decode(cb);
+ nmethod* nm = cb->as_nmethod_or_null();
+ if (nm) {
+ nm->print();
+ Disassembler::decode(nm);
+ } else {
+ cb->print();
+ Disassembler::decode(cb);
+ }
}