This commit is contained in:
Jesper Wilhelmsson 2022-06-21 22:26:26 +00:00
commit 2bf5c9a687
31 changed files with 260 additions and 166 deletions

View file

@ -59,7 +59,7 @@ static const char* reference_type_name(ReferenceType type) {
default: default:
ShouldNotReachHere(); ShouldNotReachHere();
return NULL; return "Unknown";
} }
} }

View file

@ -1732,8 +1732,13 @@ void PhaseChaitin::fixup_spills() {
// instructions which have "stackSlotX" parameter instead of "memory". // instructions which have "stackSlotX" parameter instead of "memory".
// For example, "MoveF2I_stack_reg". We always need a memory edge from // For example, "MoveF2I_stack_reg". We always need a memory edge from
// src to cisc, else we might schedule cisc before src, loading from a // src to cisc, else we might schedule cisc before src, loading from a
// spill location before storing the spill. // spill location before storing the spill. On some platforms, we land
assert(cisc->memory_operand() == nullptr, "no memory operand, only stack"); // in this else case because mach->oper_input_base() > 1, i.e. we have
// multiple inputs. In some rare cases there are even multiple memory
// operands, before and after spilling.
// (e.g. spilling "addFPR24_reg_mem" to "addFPR24_mem_cisc")
// In either case, there is no space in the inputs for the memory edge
// so we add an additional precedence / memory edge.
cisc->add_prec(src); cisc->add_prec(src);
} }
block->map_node(cisc, j); // Insert into basic block block->map_node(cisc, j); // Insert into basic block

View file

@ -1965,6 +1965,10 @@ inline void ThawBase::patch(frame& f, const frame& caller, bool bottom) {
if (bottom) { if (bottom) {
ContinuationHelper::Frame::patch_pc(caller, _cont.is_empty() ? caller.pc() ContinuationHelper::Frame::patch_pc(caller, _cont.is_empty() ? caller.pc()
: StubRoutines::cont_returnBarrier()); : StubRoutines::cont_returnBarrier());
} else {
// caller might have been deoptimized during thaw but we've overwritten the return address when copying f from the heap.
// If the caller is not deoptimized, pc is unchanged.
ContinuationHelper::Frame::patch_pc(caller, caller.raw_pc());
} }
patch_pd(f, caller); patch_pd(f, caller);
@ -2061,6 +2065,9 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n
_align_size += frame::align_wiggle; // we add one whether or not we've aligned because we add it in freeze_interpreted_frame _align_size += frame::align_wiggle; // we add one whether or not we've aligned because we add it in freeze_interpreted_frame
} }
// new_stack_frame must construct the resulting frame using hf.pc() rather than hf.raw_pc() because the frame is not
// yet laid out in the stack, and so the original_pc is not stored in it.
// As a result, f.is_deoptimized_frame() is always false and we must test hf to know if the frame is deoptimized.
frame f = new_stack_frame<ContinuationHelper::CompiledFrame>(hf, caller, is_bottom_frame); frame f = new_stack_frame<ContinuationHelper::CompiledFrame>(hf, caller, is_bottom_frame);
intptr_t* const stack_frame_top = f.sp(); intptr_t* const stack_frame_top = f.sp();
intptr_t* const heap_frame_top = hf.unextended_sp(); intptr_t* const heap_frame_top = hf.unextended_sp();
@ -2082,7 +2089,9 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n
patch(f, caller, is_bottom_frame); patch(f, caller, is_bottom_frame);
if (f.is_deoptimized_frame()) { // f.is_deoptimized_frame() is always false and we must test hf.is_deoptimized_frame() (see comment above)
assert(!f.is_deoptimized_frame(), "");
if (hf.is_deoptimized_frame()) {
maybe_set_fastpath(f.sp()); maybe_set_fastpath(f.sp());
} else if (_thread->is_interp_only_mode() } else if (_thread->is_interp_only_mode()
|| (_cont.is_preempted() && f.cb()->as_compiled_method()->is_marked_for_deoptimization())) { || (_cont.is_preempted() && f.cb()->as_compiled_method()->is_marked_for_deoptimization())) {

View file

@ -996,11 +996,12 @@ JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* current,
JRT_END JRT_END
jlong SharedRuntime::get_java_tid(Thread* thread) { jlong SharedRuntime::get_java_tid(Thread* thread) {
if (thread != NULL) { if (thread != NULL && thread->is_Java_thread()) {
if (thread->is_Java_thread()) { Thread* current = Thread::current();
oop obj = JavaThread::cast(thread)->threadObj(); guarantee(current != thread || JavaThread::cast(thread)->is_oop_safe(),
return (obj == NULL) ? 0 : java_lang_Thread::thread_id(obj); "current cannot touch oops after its GC barrier is detached.");
} oop obj = JavaThread::cast(thread)->threadObj();
return (obj == NULL) ? 0 : java_lang_Thread::thread_id(obj);
} }
return 0; return 0;
} }

View file

@ -123,6 +123,7 @@
#include "services/attachListener.hpp" #include "services/attachListener.hpp"
#include "services/management.hpp" #include "services/management.hpp"
#include "services/memTracker.hpp" #include "services/memTracker.hpp"
#include "services/threadIdTable.hpp"
#include "services/threadService.hpp" #include "services/threadService.hpp"
#include "utilities/align.hpp" #include "utilities/align.hpp"
#include "utilities/copy.hpp" #include "utilities/copy.hpp"
@ -3594,11 +3595,24 @@ void Threads::remove(JavaThread* p, bool is_daemon) {
// that we do not remove thread without safepoint code notice // that we do not remove thread without safepoint code notice
{ MonitorLocker ml(Threads_lock); { MonitorLocker ml(Threads_lock);
if (ThreadIdTable::is_initialized()) {
// This cleanup must be done before the current thread's GC barrier
// is detached since we need to touch the threadObj oop.
jlong tid = SharedRuntime::get_java_tid(p);
ThreadIdTable::remove_thread(tid);
}
// BarrierSet state must be destroyed after the last thread transition // BarrierSet state must be destroyed after the last thread transition
// before the thread terminates. Thread transitions result in calls to // before the thread terminates. Thread transitions result in calls to
// StackWatermarkSet::on_safepoint(), which performs GC processing, // StackWatermarkSet::on_safepoint(), which performs GC processing,
// requiring the GC state to be alive. // requiring the GC state to be alive.
BarrierSet::barrier_set()->on_thread_detach(p); BarrierSet::barrier_set()->on_thread_detach(p);
if (p->is_exiting()) {
// If we got here via JavaThread::exit(), then we remember that the
// thread's GC barrier has been detached. We don't do this when we get
// here from another path, e.g., cleanup_failed_attach_current_thread().
p->set_terminated(JavaThread::_thread_gc_barrier_detached);
}
assert(ThreadsSMRSupport::get_java_thread_list()->includes(p), "p must be present"); assert(ThreadsSMRSupport::get_java_thread_list()->includes(p), "p must be present");

View file

@ -904,8 +904,9 @@ class JavaThread: public Thread {
// JavaThread termination support // JavaThread termination support
public: public:
enum TerminatedTypes { enum TerminatedTypes {
_not_terminated = 0xDEAD - 2, _not_terminated = 0xDEAD - 3,
_thread_exiting, // JavaThread::exit() has been called for this thread _thread_exiting, // JavaThread::exit() has been called for this thread
_thread_gc_barrier_detached, // thread's GC barrier has been detached
_thread_terminated, // JavaThread is removed from thread list _thread_terminated, // JavaThread is removed from thread list
_vm_exited // JavaThread is still executing native code, but VM is terminated _vm_exited // JavaThread is still executing native code, but VM is terminated
// only VM_Exit can set _vm_exited // only VM_Exit can set _vm_exited
@ -914,10 +915,14 @@ class JavaThread: public Thread {
private: private:
// In general a JavaThread's _terminated field transitions as follows: // In general a JavaThread's _terminated field transitions as follows:
// //
// _not_terminated => _thread_exiting => _thread_terminated // _not_terminated => _thread_exiting => _thread_gc_barrier_detached => _thread_terminated
// //
// _vm_exited is a special value to cover the case of a JavaThread // _vm_exited is a special value to cover the case of a JavaThread
// executing native code after the VM itself is terminated. // executing native code after the VM itself is terminated.
//
// A JavaThread that fails to JNI attach has these _terminated field transitions:
// _not_terminated => _thread_terminated
//
volatile TerminatedTypes _terminated; volatile TerminatedTypes _terminated;
jint _in_deopt_handler; // count of deoptimization jint _in_deopt_handler; // count of deoptimization
@ -1172,13 +1177,17 @@ private:
bool on_thread_list() const { return _on_thread_list; } bool on_thread_list() const { return _on_thread_list; }
void set_on_thread_list() { _on_thread_list = true; } void set_on_thread_list() { _on_thread_list = true; }
// thread has called JavaThread::exit() or is terminated // thread has called JavaThread::exit(), thread's GC barrier is detached
// or thread is terminated
bool is_exiting() const; bool is_exiting() const;
// thread's GC barrier is NOT detached and thread is NOT terminated
bool is_oop_safe() const;
// thread is terminated (no longer on the threads list); we compare // thread is terminated (no longer on the threads list); we compare
// against the two non-terminated values so that a freed JavaThread // against the three non-terminated values so that a freed JavaThread
// will also be considered terminated. // will also be considered terminated.
bool check_is_terminated(TerminatedTypes l_terminated) const { bool check_is_terminated(TerminatedTypes l_terminated) const {
return l_terminated != _not_terminated && l_terminated != _thread_exiting; return l_terminated != _not_terminated && l_terminated != _thread_exiting &&
l_terminated != _thread_gc_barrier_detached;
} }
bool is_terminated() const; bool is_terminated() const;
void set_terminated(TerminatedTypes t); void set_terminated(TerminatedTypes t);

View file

@ -147,6 +147,12 @@ class AsyncExceptionHandshake : public AsyncHandshakeClosure {
} }
~AsyncExceptionHandshake() { ~AsyncExceptionHandshake() {
Thread* current = Thread::current();
// Can get here from the VMThread via install_async_exception() bail out.
if (current->is_Java_thread()) {
guarantee(JavaThread::cast(current)->is_oop_safe(),
"JavaThread cannot touch oops after its GC barrier is detached.");
}
assert(!_exception.is_empty(), "invariant"); assert(!_exception.is_empty(), "invariant");
_exception.release(Universe::vm_global()); _exception.release(Universe::vm_global());
} }
@ -260,21 +266,24 @@ inline void JavaThread::set_done_attaching_via_jni() {
} }
inline bool JavaThread::is_exiting() const { inline bool JavaThread::is_exiting() const {
// Use load-acquire so that setting of _terminated by
// JavaThread::exit() is seen more quickly.
TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated); TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated);
return l_terminated == _thread_exiting || check_is_terminated(l_terminated); return l_terminated == _thread_exiting ||
l_terminated == _thread_gc_barrier_detached ||
check_is_terminated(l_terminated);
}
inline bool JavaThread::is_oop_safe() const {
TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated);
return l_terminated != _thread_gc_barrier_detached &&
!check_is_terminated(l_terminated);
} }
inline bool JavaThread::is_terminated() const { inline bool JavaThread::is_terminated() const {
// Use load-acquire so that setting of _terminated by
// JavaThread::exit() is seen more quickly.
TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated); TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated);
return check_is_terminated(l_terminated); return check_is_terminated(l_terminated);
} }
inline void JavaThread::set_terminated(TerminatedTypes t) { inline void JavaThread::set_terminated(TerminatedTypes t) {
// use release-store so the setting of _terminated is seen more quickly
Atomic::release_store(&_terminated, t); Atomic::release_store(&_terminated, t);
} }

View file

@ -716,7 +716,7 @@ JavaThread* ThreadsList::find_JavaThread_from_java_tid(jlong java_tid) const {
if (tobj != NULL && java_tid == java_lang_Thread::thread_id(tobj)) { if (tobj != NULL && java_tid == java_lang_Thread::thread_id(tobj)) {
MutexLocker ml(Threads_lock); MutexLocker ml(Threads_lock);
// Must be inside the lock to ensure that we don't add a thread to the table // Must be inside the lock to ensure that we don't add a thread to the table
// that has just passed the removal point in ThreadsSMRSupport::remove_thread() // that has just passed the removal point in Threads::remove().
if (!thread->is_exiting()) { if (!thread->is_exiting()) {
ThreadIdTable::add_thread(java_tid, thread); ThreadIdTable::add_thread(java_tid, thread);
return thread; return thread;
@ -1000,12 +1000,6 @@ void ThreadsSMRSupport::release_stable_list_wake_up(bool is_nested) {
} }
void ThreadsSMRSupport::remove_thread(JavaThread *thread) { void ThreadsSMRSupport::remove_thread(JavaThread *thread) {
if (ThreadIdTable::is_initialized()) {
jlong tid = SharedRuntime::get_java_tid(thread);
ThreadIdTable::remove_thread(tid);
}
ThreadsList *new_list = ThreadsList::remove_thread(ThreadsSMRSupport::get_java_thread_list(), thread); ThreadsList *new_list = ThreadsList::remove_thread(ThreadsSMRSupport::get_java_thread_list(), thread);
if (EnableThreadSMRStatistics) { if (EnableThreadSMRStatistics) {
ThreadsSMRSupport::inc_java_thread_list_alloc_cnt(); ThreadsSMRSupport::inc_java_thread_list_alloc_cnt();

View file

@ -108,7 +108,7 @@ void ThreadIdTable::lazy_initialize(const ThreadsList *threads) {
MutexLocker ml(Threads_lock); MutexLocker ml(Threads_lock);
if (!thread->is_exiting()) { if (!thread->is_exiting()) {
// Must be inside the lock to ensure that we don't add a thread to the table // Must be inside the lock to ensure that we don't add a thread to the table
// that has just passed the removal point in ThreadsSMRSupport::remove_thread() // that has just passed the removal point in Threads::remove().
add_thread(java_tid, thread); add_thread(java_tid, thread);
} }
} }

View file

@ -163,7 +163,8 @@ void ThreadService::remove_thread(JavaThread* thread, bool daemon) {
assert(!thread->is_terminated(), "must not be terminated"); assert(!thread->is_terminated(), "must not be terminated");
if (!thread->is_exiting()) { if (!thread->is_exiting()) {
// JavaThread::exit() skipped calling current_thread_exiting() // We did not get here via JavaThread::exit() so current_thread_exiting()
// was not called, e.g., JavaThread::cleanup_failed_attach_current_thread().
decrement_thread_counts(thread, daemon); decrement_thread_counts(thread, daemon);
} }

View file

@ -883,9 +883,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemorySegment.class, "ofAddress"); Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemorySegment.class, "ofAddress");
Objects.requireNonNull(address); Objects.requireNonNull(address);
Objects.requireNonNull(session); Objects.requireNonNull(session);
if (bytesSize < 0) { Utils.checkAllocationSizeAndAlign(bytesSize, 1);
throw new IllegalArgumentException("Invalid size : " + bytesSize);
}
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address, bytesSize, session); return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address, bytesSize, session);
} }
@ -957,15 +955,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
*/ */
static MemorySegment allocateNative(long bytesSize, long alignmentBytes, MemorySession session) { static MemorySegment allocateNative(long bytesSize, long alignmentBytes, MemorySession session) {
Objects.requireNonNull(session); Objects.requireNonNull(session);
if (bytesSize < 0) { Utils.checkAllocationSizeAndAlign(bytesSize, alignmentBytes);
throw new IllegalArgumentException("Invalid allocation size : " + bytesSize);
}
if (alignmentBytes <= 0 ||
((alignmentBytes & (alignmentBytes - 1)) != 0L)) {
throw new IllegalArgumentException("Invalid alignment constraint : " + alignmentBytes);
}
return NativeMemorySegmentImpl.makeNativeSegment(bytesSize, alignmentBytes, session); return NativeMemorySegmentImpl.makeNativeSegment(bytesSize, alignmentBytes, session);
} }

View file

@ -153,10 +153,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegm
@Override @Override
public MemorySegment allocate(long bytesSize, long bytesAlignment) { public MemorySegment allocate(long bytesSize, long bytesAlignment) {
if (bytesAlignment <= 0 || Utils.checkAllocationSizeAndAlign(bytesSize, bytesAlignment);
((bytesAlignment & (bytesAlignment - 1)) != 0L)) {
throw new IllegalArgumentException("Invalid alignment constraint : " + bytesAlignment);
}
return asSlice(0, bytesSize); return asSlice(0, bytesSize);
} }

View file

@ -71,6 +71,7 @@ public final class ArenaAllocator implements SegmentAllocator {
@Override @Override
public MemorySegment allocate(long bytesSize, long bytesAlignment) { public MemorySegment allocate(long bytesSize, long bytesAlignment) {
Utils.checkAllocationSizeAndAlign(bytesSize, bytesAlignment);
// try to slice from current segment first... // try to slice from current segment first...
MemorySegment slice = trySlice(bytesSize, bytesAlignment); MemorySegment slice = trySlice(bytesSize, bytesAlignment);
if (slice != null) { if (slice != null) {

View file

@ -162,4 +162,17 @@ public final class Utils {
throw new IllegalArgumentException(msg); throw new IllegalArgumentException(msg);
} }
} }
public static void checkAllocationSizeAndAlign(long bytesSize, long alignmentBytes) {
// size should be >= 0
if (bytesSize < 0) {
throw new IllegalArgumentException("Invalid allocation size : " + bytesSize);
}
// alignment should be > 0, and power of two
if (alignmentBytes <= 0 ||
((alignmentBytes & (alignmentBytes - 1)) != 0L)) {
throw new IllegalArgumentException("Invalid alignment constraint : " + alignmentBytes);
}
}
} }

View file

@ -614,7 +614,8 @@ public class Navigation {
Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links"); Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links");
String toggleNavLinks = configuration.getDocResources().getText("doclet.Toggle_navigation_links"); String toggleNavLinks = configuration.getDocResources().getText("doclet.Toggle_navigation_links");
navigationBar.add(MarkerComments.START_OF_TOP_NAVBAR); navigationBar.add(MarkerComments.START_OF_TOP_NAVBAR);
HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyle.navBarToggleIcon).addUnchecked(Text.EMPTY); // The mobile menu button uses three empty spans to produce its animated icon
HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyle.navBarToggleIcon).add(Entity.NO_BREAK_SPACE);
navDiv.setStyle(HtmlStyle.topNav) navDiv.setStyle(HtmlStyle.topNav)
.setId(HtmlIds.NAVBAR_TOP) .setId(HtmlIds.NAVBAR_TOP)
.add(new HtmlTree(TagName.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON) .add(new HtmlTree(TagName.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON)

View file

@ -62,9 +62,9 @@ h5 {
h6 { h6 {
font-size:13px; font-size:13px;
} }
/* Disable font boosting */ /* Disable font boosting for selected elements */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6, div.member-signature {
max-height: 2em; max-height: 1000em;
} }
ul { ul {
list-style-type:disc; list-style-type:disc;

View file

@ -140,14 +140,9 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler {
SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
// if signing bundle with app-image, warn user if app-image // if signing bundle with app-image, warn user if app-image
// is not already signed. // is not already signed.
try { if (!(AppImageFile.load(applicationImage).isSigned())) {
if (!(AppImageFile.load(applicationImage).isSigned())) { Log.info(MessageFormat.format(I18N.getString(
Log.info(MessageFormat.format(I18N.getString( "warning.unsigned.app.image"), getID()));
"warning.unsigned.app.image"), getID()));
}
} catch (IOException ioe) {
// Ignore - In case of a forign or tampered with app-image,
// user is notified of this when the name is extracted.
} }
} }
} else { } else {

View file

@ -73,14 +73,47 @@ public final class AppImageFile {
Platform.LINUX, "linux", Platform.WINDOWS, "windows", Platform.MAC, Platform.LINUX, "linux", Platform.WINDOWS, "windows", Platform.MAC,
"macOS"); "macOS");
private AppImageFile(Path appImageDir, String launcherName, String mainClass,
private AppImageFile() {
this(null, null, null, null, null, null, null);
}
private AppImageFile(String launcherName, String mainClass,
List<LauncherInfo> launcherInfos, String creatorVersion, List<LauncherInfo> launcherInfos, String creatorVersion,
String creatorPlatform, String signedStr, String appStoreStr) { String creatorPlatform, String signedStr, String appStoreStr) {
boolean isValid = true;
if (!Objects.equals(getVersion(), creatorVersion)) {
isValid = false;
}
if (!Objects.equals(getPlatform(), creatorPlatform)) {
isValid = false;
}
if (launcherName == null || launcherName.length() == 0) {
isValid = false;
}
if (mainClass == null || mainClass.length() == 0) {
isValid = false;
}
for (var launcher : launcherInfos) {
if ("".equals(launcher.getName())) {
isValid = false;
}
}
if (signedStr == null ||
!("true".equals(signedStr) || "false".equals(signedStr))) {
isValid = false;
}
if (appStoreStr == null ||
!("true".equals(appStoreStr) || "false".equals(appStoreStr))) {
isValid = false;
}
if (!isValid) {
throw new RuntimeException(MessageFormat.format(I18N.getString(
"error.invalid-app-image"), appImageDir));
}
this.launcherName = launcherName; this.launcherName = launcherName;
this.mainClass = mainClass; this.mainClass = mainClass;
this.addLauncherInfos = launcherInfos; this.addLauncherInfos = launcherInfos;
@ -121,10 +154,6 @@ public final class AppImageFile {
return appStore; return appStore;
} }
void verifyCompatible() throws ConfigException {
// Just do nothing for now.
}
/** /**
* Returns path to application image info file. * Returns path to application image info file.
* @param appImageDir - path to application image * @param appImageDir - path to application image
@ -189,7 +218,7 @@ public final class AppImageFile {
* @return valid info about application image or null * @return valid info about application image or null
* @throws IOException * @throws IOException
*/ */
static AppImageFile load(Path appImageDir) throws IOException { static AppImageFile load(Path appImageDir) {
try { try {
Document doc = readXml(appImageDir); Document doc = readXml(appImageDir);
@ -197,17 +226,9 @@ public final class AppImageFile {
String mainLauncher = xpathQueryNullable(xPath, String mainLauncher = xpathQueryNullable(xPath,
"/jpackage-state/main-launcher/text()", doc); "/jpackage-state/main-launcher/text()", doc);
if (mainLauncher == null) {
// No main launcher, this is fatal.
return new AppImageFile();
}
String mainClass = xpathQueryNullable(xPath, String mainClass = xpathQueryNullable(xPath,
"/jpackage-state/main-class/text()", doc); "/jpackage-state/main-class/text()", doc);
if (mainClass == null) {
// No main class, this is fatal.
return new AppImageFile();
}
List<LauncherInfo> launcherInfos = new ArrayList<>(); List<LauncherInfo> launcherInfos = new ArrayList<>();
@ -231,15 +252,17 @@ public final class AppImageFile {
launcherInfos.add(new LauncherInfo(launcherNodes.item(i))); launcherInfos.add(new LauncherInfo(launcherNodes.item(i)));
} }
AppImageFile file = new AppImageFile(mainLauncher, mainClass, return new AppImageFile(appImageDir, mainLauncher, mainClass,
launcherInfos, version, platform, signedStr, appStoreStr); launcherInfos, version, platform, signedStr, appStoreStr);
if (!file.isValid()) {
file = new AppImageFile();
}
return file;
} catch (XPathExpressionException ex) { } catch (XPathExpressionException ex) {
// This should never happen as XPath expressions should be correct // This should never happen as XPath expressions should be correct
throw new RuntimeException(ex); throw new RuntimeException(ex);
} catch (NoSuchFileException nsfe) {
// non jpackage generated app-image (no app/.jpackage.xml)
throw new RuntimeException(MessageFormat.format(I18N.getString(
"error.foreign-app-image"), appImageDir));
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} }
} }
@ -275,23 +298,11 @@ public final class AppImageFile {
Map<String, Object> params) { Map<String, Object> params) {
List<LauncherInfo> launchers = new ArrayList<>(); List<LauncherInfo> launchers = new ArrayList<>();
if (appImageDir != null) { if (appImageDir != null) {
try { AppImageFile appImageInfo = AppImageFile.load(appImageDir);
AppImageFile appImageInfo = AppImageFile.load(appImageDir); launchers.add(new LauncherInfo(
if (appImageInfo != null) { appImageInfo.getLauncherName(), params));
launchers.add(new LauncherInfo(
appImageInfo.getLauncherName(), params));
launchers.addAll(appImageInfo.getAddLaunchers()); launchers.addAll(appImageInfo.getAddLaunchers());
return launchers; return launchers;
}
} catch (NoSuchFileException nsfe) {
// non jpackage generated app-image (no app/.jpackage.xml)
Log.info(MessageFormat.format(I18N.getString(
"warning.foreign-app-image"), appImageDir));
} catch (IOException ioe) {
Log.verbose(ioe);
Log.info(MessageFormat.format(I18N.getString(
"warning.invalid-app-image"), appImageDir));
}
} }
launchers.add(new LauncherInfo(params)); launchers.add(new LauncherInfo(params));
@ -302,23 +313,11 @@ public final class AppImageFile {
} }
public static String extractAppName(Path appImageDir) { public static String extractAppName(Path appImageDir) {
try { return AppImageFile.load(appImageDir).getLauncherName();
return AppImageFile.load(appImageDir).getLauncherName();
} catch (IOException ioe) {
Log.verbose(MessageFormat.format(I18N.getString(
"warning.foreign-app-image"), appImageDir));
return null;
}
} }
public static String extractMainClass(Path appImageDir) { public static String extractMainClass(Path appImageDir) {
try { return AppImageFile.load(appImageDir).getMainClass();
return AppImageFile.load(appImageDir).getMainClass();
} catch (IOException ioe) {
Log.verbose(MessageFormat.format(I18N.getString(
"warning.foreign-app-image"), appImageDir));
return null;
}
} }
private static String xpathQueryNullable(XPath xPath, String xpathExpr, private static String xpathQueryNullable(XPath xPath, String xpathExpr,
@ -331,36 +330,14 @@ public final class AppImageFile {
return null; return null;
} }
static String getVersion() { public static String getVersion() {
return "1.0"; return System.getProperty("java.version");
} }
static String getPlatform() { public static String getPlatform() {
return PLATFORM_LABELS.get(Platform.getPlatform()); return PLATFORM_LABELS.get(Platform.getPlatform());
} }
private boolean isValid() {
if (launcherName == null || launcherName.length() == 0) {
return false;
}
for (var launcher : addLauncherInfos) {
if ("".equals(launcher.getName())) {
return false;
}
}
if (!Objects.equals(getVersion(), creatorVersion)) {
return false;
}
if (!Objects.equals(getPlatform(), creatorPlatform)) {
return false;
}
return true;
}
static class LauncherInfo { static class LauncherInfo {
private final String name; private final String name;
private final boolean shortcut; private final boolean shortcut;

View file

@ -531,12 +531,8 @@ class StandardBundlerParam<T> extends BundlerParamInfo<T> {
Boolean.class, Boolean.class,
params -> { params -> {
if (hasPredefinedAppImage(params)) { if (hasPredefinedAppImage(params)) {
try { return AppImageFile.load(getPredefinedAppImage(params))
return AppImageFile.load(getPredefinedAppImage(params)) .isAppStore();
.isAppStore();
} catch (IOException ex) {
return false;
}
} }
return false; return false;
}, },

View file

@ -77,8 +77,9 @@ error.blocked.option=jlink option [{0}] is not permitted in --jlink-options
error.no.name=Name not specified with --name and cannot infer one from app-image error.no.name=Name not specified with --name and cannot infer one from app-image
warning.no.jdk.modules.found=Warning: No JDK Modules found warning.no.jdk.modules.found=Warning: No JDK Modules found
warning.foreign-app-image=Warning: app-image dir ({0}) not generated by jpackage.
warning.invalid-app-image=Warning: cannot parse .jpackage.xml in app-image dir ({0}) error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir ({0})
error.invalid-app-image=Error: app-image dir ({0}) generated by another jpackage version or malformed .jpackage.xml
MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package
MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\ MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\

View file

@ -75,8 +75,9 @@ error.blocked.option=jlink-Option [{0}] ist in --jlink-options nicht zul\u00E4ss
error.no.name=Name nicht mit --name angegeben. Es kann auch kein Name aus app-image abgeleitet werden error.no.name=Name nicht mit --name angegeben. Es kann auch kein Name aus app-image abgeleitet werden
warning.no.jdk.modules.found=Warnung: Keine JDK-Module gefunden warning.no.jdk.modules.found=Warnung: Keine JDK-Module gefunden
warning.foreign-app-image=Warnung: app-image-Verzeichnis ({0}) wurde von jpackage nicht generiert.
warning.invalid-app-image=Warnung: .jpackage.xml kann in app-image-Verzeichnis ({0}) nicht geparst werden error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir ({0})
error.invalid-app-image=Error: app-image dir ({0}) generated by another jpackage version or malformed .jpackage.xml
MSG_BundlerFailed=Fehler: Bundler "{1}" ({0}) konnte kein Package generieren MSG_BundlerFailed=Fehler: Bundler "{1}" ({0}) konnte kein Package generieren
MSG_BundlerConfigException=Bundler {0} aufgrund eines Konfigurationsproblems \u00FCbersprungen: {1} \nEmpfehlung zur Behebung: {2} MSG_BundlerConfigException=Bundler {0} aufgrund eines Konfigurationsproblems \u00FCbersprungen: {1} \nEmpfehlung zur Behebung: {2}

View file

@ -75,8 +75,9 @@ error.blocked.option=jlink\u30AA\u30D7\u30B7\u30E7\u30F3[{0}]\u306F--jlink-optio
error.no.name=\u540D\u524D\u304C--name\u3067\u6307\u5B9A\u3055\u308C\u3066\u304A\u3089\u305A\u3001app-image\u304B\u3089\u63A8\u8AD6\u3067\u304D\u307E\u305B\u3093 error.no.name=\u540D\u524D\u304C--name\u3067\u6307\u5B9A\u3055\u308C\u3066\u304A\u3089\u305A\u3001app-image\u304B\u3089\u63A8\u8AD6\u3067\u304D\u307E\u305B\u3093
warning.no.jdk.modules.found=\u8B66\u544A: JDK\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 warning.no.jdk.modules.found=\u8B66\u544A: JDK\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
warning.foreign-app-image=\u8B66\u544A: app-image\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA({0})\u306Fjpackage\u3067\u751F\u6210\u3055\u308C\u307E\u305B\u3093\u3002
warning.invalid-app-image=\u8B66\u544A: app-image\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA({0})\u306E.jpackage.xml\u3092\u89E3\u6790\u3067\u304D\u307E\u305B\u3093 error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir ({0})
error.invalid-app-image=Error: app-image dir ({0}) generated by another jpackage version or malformed .jpackage.xml
MSG_BundlerFailed=\u30A8\u30E9\u30FC: \u30D0\u30F3\u30C9\u30E9"{1}" ({0})\u304C\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F MSG_BundlerFailed=\u30A8\u30E9\u30FC: \u30D0\u30F3\u30C9\u30E9"{1}" ({0})\u304C\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F
MSG_BundlerConfigException=\u69CB\u6210\u306E\u554F\u984C\u306E\u305F\u3081\u3001\u30D0\u30F3\u30C9\u30E9{0}\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F: {1} \n\u6B21\u306E\u4FEE\u6B63\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044: {2} MSG_BundlerConfigException=\u69CB\u6210\u306E\u554F\u984C\u306E\u305F\u3081\u3001\u30D0\u30F3\u30C9\u30E9{0}\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F: {1} \n\u6B21\u306E\u4FEE\u6B63\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044: {2}

View file

@ -75,8 +75,9 @@ error.blocked.option=\u4E0D\u5141\u8BB8\u5728 --jlink-options \u4E2D\u4F7F\u7528
error.no.name=\u672A\u4F7F\u7528 --name \u6307\u5B9A\u540D\u79F0\uFF0C\u65E0\u6CD5\u4ECE app-image \u63A8\u65AD\u540D\u79F0 error.no.name=\u672A\u4F7F\u7528 --name \u6307\u5B9A\u540D\u79F0\uFF0C\u65E0\u6CD5\u4ECE app-image \u63A8\u65AD\u540D\u79F0
warning.no.jdk.modules.found=\u8B66\u544A: \u672A\u627E\u5230 JDK \u6A21\u5757 warning.no.jdk.modules.found=\u8B66\u544A: \u672A\u627E\u5230 JDK \u6A21\u5757
warning.foreign-app-image=\u8B66\u544A\uFF1Ajpackage \u672A\u751F\u6210 app-image \u76EE\u5F55 ({0})\u3002
warning.invalid-app-image=\u8B66\u544A\uFF1A\u65E0\u6CD5\u89E3\u6790 app-image \u76EE\u5F55 ({0}) \u4E2D\u7684 .jpackage.xml error.foreign-app-image=Error: Missing .jpackage.xml file in app-image dir ({0})
error.invalid-app-image=Error: app-image dir ({0}) generated by another jpackage version or malformed .jpackage.xml
MSG_BundlerFailed=\u9519\u8BEF\uFF1A\u6253\u5305\u7A0B\u5E8F "{1}" ({0}) \u65E0\u6CD5\u751F\u6210\u7A0B\u5E8F\u5305 MSG_BundlerFailed=\u9519\u8BEF\uFF1A\u6253\u5305\u7A0B\u5E8F "{1}" ({0}) \u65E0\u6CD5\u751F\u6210\u7A0B\u5E8F\u5305
MSG_BundlerConfigException=\u7531\u4E8E\u914D\u7F6E\u95EE\u9898, \u8DF3\u8FC7\u4E86\u6253\u5305\u7A0B\u5E8F{0}: {1} \n\u4FEE\u590D\u5EFA\u8BAE: {2} MSG_BundlerConfigException=\u7531\u4E8E\u914D\u7F6E\u95EE\u9898, \u8DF3\u8FC7\u4E86\u6253\u5305\u7A0B\u5E8F{0}: {1} \n\u4FEE\u590D\u5EFA\u8BAE: {2}

View file

@ -31,9 +31,6 @@ vmTestbase/nsk/jvmti/AttachOnDemand/attach022/TestDescription.java 8277573 gener
vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001/TestDescription.java 8205957 generic-all vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001/TestDescription.java 8205957 generic-all
serviceability/jvmti/vthread/ContFramePopTest/ContFramePopTest.java 8278053 generic-all
serviceability/jvmti/vthread/ContStackDepthTest/ContStackDepthTest.java 8278053 generic-all
serviceability/sa/TestJhsdbJstackMixed.java 8248675 linux-aarch64 serviceability/sa/TestJhsdbJstackMixed.java 8248675 linux-aarch64
vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t002/TestDescription.java 8245680 windows-x64 vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t002/TestDescription.java 8245680 windows-x64

View file

@ -23,7 +23,7 @@
/** /**
* @test * @test
* @bug 8167108 8266130 8283467 8284632 * @bug 8167108 8266130 8283467 8284632 8286830
* @summary Stress test JVM/TI StopThread() at thread exit. * @summary Stress test JVM/TI StopThread() at thread exit.
* @requires vm.jvmti * @requires vm.jvmti
* @run main/othervm/native -agentlib:StopAtExit StopAtExit * @run main/othervm/native -agentlib:StopAtExit StopAtExit
@ -72,6 +72,8 @@ public class StopAtExit extends Thread {
usage(); usage();
} }
} }
timeMax /= 2; // Split time between the two sub-tests.
test(timeMax); test(timeMax);
// Fire-up deamon that just creates new threads. This generates contention on // Fire-up deamon that just creates new threads. This generates contention on

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/** /**
* @test * @test
* @bug 8167108 8265240 * @bug 8167108 8265240 8286830
* @summary Stress test SuspendThread at thread exit. * @summary Stress test SuspendThread at thread exit.
* @requires vm.jvmti * @requires vm.jvmti
* @run main/othervm/native -agentlib:SuspendAtExit SuspendAtExit * @run main/othervm/native -agentlib:SuspendAtExit SuspendAtExit
@ -78,6 +78,8 @@ public class SuspendAtExit extends Thread {
usage(); usage();
} }
} }
timeMax /= 2; // Split time between the two sub-tests.
test(timeMax); test(timeMax);
// Fire-up deamon that just creates new threads. This generates contention on // Fire-up deamon that just creates new threads. This generates contention on

View file

@ -139,6 +139,26 @@ public class TestSegmentAllocators {
SegmentAllocator.newNativeArena( -1, MemorySession.global()); SegmentAllocator.newNativeArena( -1, MemorySession.global());
} }
@Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class)
public void testBadAllocationSize(SegmentAllocator allocator) {
allocator.allocate(-1);
}
@Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class)
public void testBadAllocationAlignZero(SegmentAllocator allocator) {
allocator.allocate(1, 0);
}
@Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class)
public void testBadAllocationAlignNeg(SegmentAllocator allocator) {
allocator.allocate(1, -1);
}
@Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class)
public void testBadAllocationAlignNotPowerTwo(SegmentAllocator allocator) {
allocator.allocate(1, 3);
}
@Test(dataProvider = "arrayAllocations") @Test(dataProvider = "arrayAllocations")
public <Z> void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object, ValueLayout> allocationFunction, ToArrayHelper<Z> arrayHelper) { public <Z> void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object, ValueLayout> allocationFunction, ToArrayHelper<Z> arrayHelper) {
Z arr = arrayHelper.array(); Z arr = arrayHelper.array();
@ -444,4 +464,13 @@ public class TestSegmentAllocators {
} }
}; };
} }
@DataProvider(name = "allocators")
static Object[][] allocators() {
return new Object[][] {
{ SegmentAllocator.implicitAllocator() },
{ SegmentAllocator.newNativeArena(MemorySession.global()) },
{ SegmentAllocator.prefixAllocator(MemorySegment.allocateNative(10, MemorySession.global())) },
};
}
} }

View file

@ -45,6 +45,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.jpackage.internal.IOUtils;
import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.AppImageFile;
import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.internal.ApplicationLayout;
import jdk.jpackage.internal.PackageFile; import jdk.jpackage.internal.PackageFile;
@ -298,6 +299,42 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
return this; return this;
} }
public void createJPackageXMLFile(String mainLauncher, String mainClass)
throws IOException {
Path jpackageXMLFile = AppImageFile.getPathInAppImage(
Optional.ofNullable(getArgumentValue("--app-image")).map(
Path::of).orElseThrow(() -> {
return new RuntimeException(
"Error: --app-image expected");
}));
IOUtils.createXml(jpackageXMLFile, xml -> {
xml.writeStartElement("jpackage-state");
xml.writeAttribute("version", AppImageFile.getVersion());
xml.writeAttribute("platform", AppImageFile.getPlatform());
xml.writeStartElement("app-version");
xml.writeCharacters("1.0");
xml.writeEndElement();
xml.writeStartElement("main-launcher");
xml.writeCharacters(mainLauncher);
xml.writeEndElement();
xml.writeStartElement("main-class");
xml.writeCharacters(mainClass);
xml.writeEndElement();
xml.writeStartElement("signed");
xml.writeCharacters("false");
xml.writeEndElement();
xml.writeStartElement("app-store");
xml.writeCharacters("false");
xml.writeEndElement();
});
}
JPackageCommand addPrerequisiteAction(ThrowingConsumer<JPackageCommand> action) { JPackageCommand addPrerequisiteAction(ThrowingConsumer<JPackageCommand> action) {
verifyMutable(); verifyMutable();
prerequisiteActions.add(action); prerequisiteActions.add(action);

View file

@ -35,6 +35,7 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.junit.function.ThrowingRunnable;
public class AppImageFileTest { public class AppImageFileTest {
@ -74,19 +75,19 @@ public class AppImageFileTest {
@Test @Test
public void testInavlidXml() throws IOException { public void testInavlidXml() throws IOException {
assertInvalid(createFromXml("<foo/>")); assertInvalid(() -> createFromXml("<foo/>"));
assertInvalid(createFromXml("<jpackage-state/>")); assertInvalid(() -> createFromXml("<jpackage-state/>"));
assertInvalid(createFromXml(JPACKAGE_STATE_OPEN, "</jpackage-state>")); assertInvalid(() -> createFromXml(JPACKAGE_STATE_OPEN, "</jpackage-state>"));
assertInvalid(createFromXml( assertInvalid(() -> createFromXml(
JPACKAGE_STATE_OPEN, JPACKAGE_STATE_OPEN,
"<main-launcher></main-launcher>", "<main-launcher></main-launcher>",
"</jpackage-state>")); "</jpackage-state>"));
assertInvalid(createFromXml( assertInvalid(() -> createFromXml(
JPACKAGE_STATE_OPEN, JPACKAGE_STATE_OPEN,
"<main-launcher>Foo</main-launcher>", "<main-launcher>Foo</main-launcher>",
"<main-class></main-class>", "<main-class></main-class>",
"</jpackage-state>")); "</jpackage-state>"));
assertInvalid(createFromXml( assertInvalid(() -> createFromXml(
JPACKAGE_STATE_OPEN, JPACKAGE_STATE_OPEN,
"<launcher>A</launcher>", "<launcher>A</launcher>",
"<launcher>B</launcher>", "<launcher>B</launcher>",
@ -99,6 +100,8 @@ public class AppImageFileTest {
JPACKAGE_STATE_OPEN, JPACKAGE_STATE_OPEN,
"<main-launcher>Foo</main-launcher>", "<main-launcher>Foo</main-launcher>",
"<main-class>main.Class</main-class>", "<main-class>main.Class</main-class>",
"<signed>false</signed>",
"<app-store>false</app-store>",
"</jpackage-state>")).getLauncherName()); "</jpackage-state>")).getLauncherName());
Assert.assertEquals("Boo", (createFromXml( Assert.assertEquals("Boo", (createFromXml(
@ -106,12 +109,16 @@ public class AppImageFileTest {
"<main-launcher>Boo</main-launcher>", "<main-launcher>Boo</main-launcher>",
"<main-launcher>Bar</main-launcher>", "<main-launcher>Bar</main-launcher>",
"<main-class>main.Class</main-class>", "<main-class>main.Class</main-class>",
"<signed>false</signed>",
"<app-store>false</app-store>",
"</jpackage-state>")).getLauncherName()); "</jpackage-state>")).getLauncherName());
var file = createFromXml( var file = createFromXml(
JPACKAGE_STATE_OPEN, JPACKAGE_STATE_OPEN,
"<main-launcher>Foo</main-launcher>", "<main-launcher>Foo</main-launcher>",
"<main-class>main.Class</main-class>", "<main-class>main.Class</main-class>",
"<signed>false</signed>",
"<app-store>false</app-store>",
"<launcher></launcher>", "<launcher></launcher>",
"</jpackage-state>"); "</jpackage-state>");
Assert.assertEquals("Foo", file.getLauncherName()); Assert.assertEquals("Foo", file.getLauncherName());
@ -199,9 +206,10 @@ public class AppImageFileTest {
return AppImageFile.load(tempFolder.getRoot().toPath()); return AppImageFile.load(tempFolder.getRoot().toPath());
} }
private void assertInvalid(AppImageFile file) { private void assertInvalid(ThrowingRunnable action) {
Assert.assertNull(file.getLauncherName()); Exception ex = Assert.assertThrows(RuntimeException.class, action);
Assert.assertNull(file.getAddLaunchers()); Assert.assertTrue(ex instanceof RuntimeException);
Assert.assertTrue(ex.getMessage().contains("malformed .jpackage.xml"));
} }
private AppImageFile createFromXml(String... xmlData) throws IOException { private AppImageFile createFromXml(String... xmlData) throws IOException {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -87,6 +87,7 @@ public class AppImagePackageTest {
cmd.addArguments("--icon", iconPath("icon")); cmd.addArguments("--icon", iconPath("icon"));
} }
cmd.removeArgumentWithValue("--input"); cmd.removeArgumentWithValue("--input");
cmd.createJPackageXMLFile("EmptyAppImagePackageTest", "Hello");
// on mac, with --app-image and without --mac-package-identifier, // on mac, with --app-image and without --mac-package-identifier,
// will try to infer it from the image, so foreign image needs it. // will try to infer it from the image, so foreign image needs it.
@ -101,4 +102,5 @@ public class AppImagePackageTest {
return TKit.TEST_SRC_ROOT.resolve(Path.of("resources", name return TKit.TEST_SRC_ROOT.resolve(Path.of("resources", name
+ TKit.ICON_SUFFIX)); + TKit.ICON_SUFFIX));
} }
} }

View file

@ -113,6 +113,7 @@ public final class PredefinedAppImageErrorTest {
Files.createFile(dummyAppFile); Files.createFile(dummyAppFile);
cmd.addArguments("--app-image", dummyAppFolder.toString()); cmd.addArguments("--app-image", dummyAppFolder.toString());
cmd.createJPackageXMLFile("PredefinedAppImageErrorTest", "Hello");
} }
} }