# HG changeset patch # User Doug Simon # Date 1348748584 -7200 # Node ID 3bba61323b38db30426b316e1dfcbebbb08655d7 # Parent a89a18a57617ec797c2582808eab5dda75823e5a added VMErrorNode intrinsic to support handling fatal errors in snippets diff -r a89a18a57617 -r 3bba61323b38 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Sep 26 21:48:07 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Sep 27 14:23:04 2012 +0200 @@ -180,6 +180,7 @@ public long fastMonitorEnterStub; public long fastMonitorExitStub; public long verifyOopStub; + public long vmErrorStub; // special registers public final Register threadRegister = AMD64.r15; diff -r a89a18a57617 -r 3bba61323b38 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Thu Sep 27 14:23:04 2012 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.snippets.*; + +/** + * Causes the VM to exit with a description of the current Java location + * and an optional {@linkplain Log#printf(String, long) formatted} error message specified. + */ +public final class VMErrorNode extends FixedWithNextNode implements LIRGenLowerable { + + @Input private ValueNode format; + @Input private ValueNode value; + + public VMErrorNode(ValueNode format, ValueNode value) { + super(StampFactory.forVoid()); + this.format = format; + this.value = value; + } + + @Override + public void generate(LIRGenerator gen) { + long vmErrorStub = HotSpotGraalRuntime.getInstance().getConfig().vmErrorStub; + LIRFrameState state = gen.state(); + BytecodePosition pos = state.topFrame; + String where = CodeUtil.append(new StringBuilder(100), pos).toString(); + Kind[] signature = new Kind[] {Kind.Object, Kind.Object, Kind.Long}; + gen.emitCall(vmErrorStub, Kind.Void, signature, true, Constant.forObject(where), gen.operand(format), gen.operand(value)); + } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static void vmError(String format, long value) { + throw new GraalInternalError(""); + } +} diff -r a89a18a57617 -r 3bba61323b38 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Wed Sep 26 21:48:07 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Thu Sep 27 14:23:04 2012 +0200 @@ -25,6 +25,7 @@ import static com.oracle.graal.hotspot.nodes.BeginLockScopeNode.*; import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*; +import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; import static com.oracle.graal.snippets.nodes.DirectObjectStoreNode.*; @@ -69,7 +70,7 @@ */ private static final String TRACE_METHOD_FILTER = System.getProperty("graal.monitors.trace.methodFilter"); - public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalance"); + public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced"); @Snippet public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { @@ -380,9 +381,7 @@ final Word counter = MonitorCounterNode.counter(wordKind()); final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int); if (count != 0) { - Log.print(errMsg); - Log.println(count); - DirectObjectStoreNode.storeInt(Word.zero(), 0, 0, count + 1); + vmError(errMsg, count); } } @@ -519,7 +518,7 @@ List rets = graph.getNodes().filter(ReturnNode.class).snapshot(); for (ReturnNode ret : rets) { returnType = checkCounter.signature().returnType(checkCounter.holder()); - ConstantNode errMsg = ConstantNode.forObject("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()), runtime, graph); + ConstantNode errMsg = ConstantNode.forObject("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d", runtime, graph); callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter, new ValueNode[] {errMsg}, returnType)); invoke = graph.add(new InvokeNode(callTarget, 0, -1)); List stack = Collections.emptyList(); diff -r a89a18a57617 -r 3bba61323b38 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java Wed Sep 26 21:48:07 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java Thu Sep 27 14:23:04 2012 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.snippets; +import java.io.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; @@ -31,7 +33,7 @@ //JaCoCo Exclude /** - * Provides printf-like debug facility. This should only be used in {@linkplain Snippet snippets}. + * Provides {@link PrintStream}-like logging facility. This should only be used in {@linkplain Snippet snippets}. */ public final class Log { @@ -83,7 +85,10 @@ } /** - * @param format a C style printf format value - must be between 0 and 1024 characters + * Prints a formatted string to the log stream. + * + * @param format a C style printf format value that can contain at most one conversion specifier (i.e., a sequence + * of characters starting with '%'). */ public static void printf(String format, long value) { printf(RuntimeCall.LogPrintf, format, value); diff -r a89a18a57617 -r 3bba61323b38 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Sep 26 21:48:07 2012 +0200 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Sep 27 14:23:04 2012 +0200 @@ -1917,6 +1917,18 @@ break; } + case graal_vm_error_id: { + __ enter(); + oop_maps = new OopMapSet(); + OopMap* oop_map = save_live_registers(sasm, 0); + int call_offset = __ call_RT(noreg, noreg, (address)graal_vm_error, j_rarg0, j_rarg1, j_rarg2); + oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers(sasm); + __ leave(); + __ ret(0); + break; + } + case graal_log_printf_id: { __ enter(); oop_maps = new OopMapSet(); diff -r a89a18a57617 -r 3bba61323b38 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Wed Sep 26 21:48:07 2012 +0200 +++ b/src/share/vm/c1/c1_Runtime1.cpp Thu Sep 27 14:23:04 2012 +0200 @@ -761,68 +761,40 @@ bool newline = flags & LOG_OBJECT_NEWLINE; if (!string) { if (!address && obj->is_oop_or_null(true)) { - char buf[400]; - tty->print("%s@%p", obj->klass()->klass_part()->name()->as_C_string(buf, 400), obj); + char buf[O_BUFLEN]; + tty->print("%s@%p", obj->klass()->klass_part()->name()->as_C_string(buf, O_BUFLEN), obj); } else { tty->print("%p", obj); } } else { + ResourceMark rm; assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); - - typeArrayOop value = java_lang_String::value(obj); - int offset = java_lang_String::offset(obj); - int length = java_lang_String::length(obj); - - if (length != 0) { - int printLength = MIN2(length, 1024); - if (value == NULL) { - // This can happen if, e.g., printing a String - // object before its initializer has been called - tty->print("null"); - } else if (printLength < 256 - 1) { - // Use an intermediate buffer to try and prevent interlacing of multi-threaded output - char buf[256]; - for (int index = 0; index < printLength; index++) { - buf[index] = value->char_at(index + offset); - } - buf[printLength] = 0; - tty->print("%s", buf); - if (printLength < length) { - tty->print("... (%d more)", length - printLength); - } - } else { - for (int index = 0; index < printLength; index++) { - tty->print("%c", value->char_at(index + offset)); - } - if (printLength < length) { - tty->print("... (%d more)", length - printLength); - } - } - } + char *buf = java_lang_String::as_utf8_string(obj); + tty->print(buf); } if (newline) { tty->cr(); } JRT_END -JRT_ENTRY(void, Runtime1::graal_log_printf(JavaThread* thread, oop format, jlong val)) - char buf[1025]; - assert(format != NULL && java_lang_String::is_instance(format), "must be"); - - typeArrayOop value = java_lang_String::value(format); - int offset = java_lang_String::offset(format); - int length = java_lang_String::length(format); +JRT_ENTRY(void, Runtime1::graal_vm_error(JavaThread* thread, oop where, oop format, jlong value)) + ResourceMark rm; + assert(where == NULL || java_lang_String::is_instance(where), "must be"); + const char *error_msg = where == NULL ? "" : java_lang_String::as_utf8_string(where); + char *detail_msg = NULL; + if (format != NULL) { + const char* buf = java_lang_String::as_utf8_string(format); + int detail_msg_length = strlen(buf) * 2; + detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); + jio_snprintf(detail_msg, detail_msg_length, buf, value); + } + report_vm_error(__FILE__, __LINE__, error_msg, detail_msg); +JRT_END - assert(value != NULL, "fmtString must be a literal"); - assert(length >= 0 && length <= 1024, "format must be between 0 and 1024 characters"); - length = MIN2(length, 1024); - - int index = 0; - while (index < length) { - buf[index] = value->char_at(index + offset); - index++; - } - buf[index++] = 0; +JRT_ENTRY(void, Runtime1::graal_log_printf(JavaThread* thread, oop format, jlong val)) + ResourceMark rm; + assert(format != NULL && java_lang_String::is_instance(format), "must be"); + char *buf = java_lang_String::as_utf8_string(format); tty->print(buf, val); JRT_END diff -r a89a18a57617 -r 3bba61323b38 src/share/vm/c1/c1_Runtime1.hpp --- a/src/share/vm/c1/c1_Runtime1.hpp Wed Sep 26 21:48:07 2012 +0200 +++ b/src/share/vm/c1/c1_Runtime1.hpp Thu Sep 27 14:23:04 2012 +0200 @@ -76,7 +76,8 @@ stub(graal_arithmetic_drem) \ stub(graal_monitorenter) \ stub(graal_monitorexit) \ - stub(graal_verify_oop) \ + stub(graal_verify_oop) \ + stub(graal_vm_error) \ stub(graal_set_deopt_info) \ stub(graal_create_null_pointer_exception) \ stub(graal_create_out_of_bounds_exception) \ @@ -207,6 +208,7 @@ static void graal_generic_callback(JavaThread* thread, oop _callback, oop _argument); static void graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); static void graal_monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void graal_vm_error(JavaThread* thread, oop where, oop format, jlong value); static void graal_log_printf(JavaThread* thread, oop format, jlong value); static void graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline);