1 /* 2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "JavaVirtualMachine.h" 27 #include "Platform.h" 28 #include "PlatformString.h" 29 #include "FilePath.h" 30 #include "Package.h" 31 #include "JavaTypes.h" 32 #include "Helpers.h" 33 #include "Messages.h" 34 #include "Macros.h" 35 #include "PlatformThread.h" 36 37 #include "jni.h" 38 39 #include <map> 40 #include <list> 41 #include <sstream> 42 43 44 bool RunVM() { 45 JavaVirtualMachine javavm; 46 47 bool result = javavm.StartJVM(); 48 49 if (!result) { 50 Platform& platform = Platform::GetInstance(); 51 platform.ShowMessage(_T("Failed to launch JVM\n")); 52 } 53 54 return result; 55 } 56 57 JavaLibrary::JavaLibrary() : Library(), FCreateProc(NULL) { 58 } 59 60 bool JavaLibrary::JavaVMCreate(size_t argc, char *argv[]) { 61 if (FCreateProc == NULL) { 62 FCreateProc = (JVM_CREATE)GetProcAddress(LAUNCH_FUNC); 63 } 64 65 if (FCreateProc == NULL) { 66 Platform& platform = Platform::GetInstance(); 67 Messages& messages = Messages::GetInstance(); 68 platform.ShowMessage( 69 messages.GetMessage(FAILED_LOCATING_JVM_ENTRY_POINT)); 70 return false; 71 } 72 73 return FCreateProc((int)argc, argv, 74 0, NULL, 75 0, NULL, 76 "", 77 "", 78 "java", 79 "java", 80 false, 81 false, 82 false, 83 0) == 0; 84 } 85 86 //---------------------------------------------------------------------------- 87 88 JavaOptions::JavaOptions(): FOptions(NULL) { 89 } 90 91 JavaOptions::~JavaOptions() { 92 if (FOptions != NULL) { 93 for (unsigned int index = 0; index < GetCount(); index++) { 94 delete[] FOptions[index].optionString; 95 } 96 97 delete[] FOptions; 98 } 99 } 100 101 void JavaOptions::AppendValue(const TString Key, TString Value, void* Extra) { 102 JavaOptionItem item; 103 item.name = Key; 104 item.value = Value; 105 item.extraInfo = Extra; 106 FItems.push_back(item); 107 } 108 109 void JavaOptions::AppendValue(const TString Key, TString Value) { 110 AppendValue(Key, Value, NULL); 111 } 112 113 void JavaOptions::AppendValue(const TString Key) { 114 AppendValue(Key, _T(""), NULL); 115 } 116 117 void JavaOptions::AppendValues(OrderedMap<TString, TString> Values) { 118 std::vector<TString> orderedKeys = Values.GetKeys(); 119 120 for (std::vector<TString>::const_iterator iterator = orderedKeys.begin(); 121 iterator != orderedKeys.end(); iterator++) { 122 TString name = *iterator; 123 TString value; 124 125 if (Values.GetValue(name, value) == true) { 126 AppendValue(name, value); 127 } 128 } 129 } 130 131 void JavaOptions::ReplaceValue(const TString Key, TString Value) { 132 for (std::list<JavaOptionItem>::iterator iterator = FItems.begin(); 133 iterator != FItems.end(); iterator++) { 134 135 TString lkey = iterator->name; 136 137 if (lkey == Key) { 138 JavaOptionItem item = *iterator; 139 item.value = Value; 140 iterator = FItems.erase(iterator); 141 FItems.insert(iterator, item); 142 break; 143 } 144 } 145 } 146 147 std::list<TString> JavaOptions::ToList() { 148 std::list<TString> result; 149 Macros& macros = Macros::GetInstance(); 150 151 for (std::list<JavaOptionItem>::const_iterator iterator = FItems.begin(); 152 iterator != FItems.end(); iterator++) { 153 TString key = iterator->name; 154 TString value = iterator->value; 155 TString option = Helpers::NameValueToString(key, value); 156 option = macros.ExpandMacros(option); 157 result.push_back(option); 158 } 159 160 return result; 161 } 162 163 size_t JavaOptions::GetCount() { 164 return FItems.size(); 165 } 166 167 //---------------------------------------------------------------------------- 168 169 JavaVirtualMachine::JavaVirtualMachine() { 170 } 171 172 JavaVirtualMachine::~JavaVirtualMachine(void) { 173 } 174 175 bool JavaVirtualMachine::StartJVM() { 176 Platform& platform = Platform::GetInstance(); 177 Package& package = Package::GetInstance(); 178 179 TString classpath = package.GetClassPath(); 180 TString modulepath = package.GetModulePath(); 181 JavaOptions options; 182 183 if (modulepath.empty() == false) { 184 options.AppendValue(_T("-Djava.module.path"), modulepath); 185 } 186 187 options.AppendValue(_T("-Djava.library.path"), 188 package.GetPackageAppDirectory() + FilePath::PathSeparator() 189 + package.GetPackageLauncherDirectory()); 190 options.AppendValue( 191 _T("-Djava.launcher.path"), package.GetPackageLauncherDirectory()); 192 options.AppendValue(_T("-Dapp.preferences.id"), package.GetAppID()); 193 options.AppendValues(package.GetJVMArgs()); 194 195 #ifdef DEBUG 196 if (package.Debugging() == dsJava) { 197 options.AppendValue(_T("-Xdebug"), _T("")); 198 options.AppendValue( 199 _T("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:5005"), 200 _T("")); 201 platform.ShowMessage(_T("localhost:5005")); 202 } 203 #endif // DEBUG 204 205 TString maxHeapSizeOption; 206 TString minHeapSizeOption; 207 208 209 if (package.GetMemoryState() == PackageBootFields::msAuto) { 210 TPlatformNumber memorySize = package.GetMemorySize(); 211 TString memory = 212 PlatformString((size_t)memorySize).toString() + _T("m"); 213 maxHeapSizeOption = TString(_T("-Xmx")) + memory; 214 options.AppendValue(maxHeapSizeOption, _T("")); 215 216 if (memorySize > 256) 217 minHeapSizeOption = _T("-Xms256m"); 218 else 219 minHeapSizeOption = _T("-Xms") + memory; 220 221 options.AppendValue(minHeapSizeOption, _T("")); 222 } 223 224 TString mainClassName = package.GetMainClassName(); 225 TString mainModule = package.GetMainModule(); 226 227 if (mainClassName.empty() == true && mainModule.empty() == true) { 228 Messages& messages = Messages::GetInstance(); 229 platform.ShowMessage(messages.GetMessage(NO_MAIN_CLASS_SPECIFIED)); 230 return false; 231 } 232 233 configureLibrary(); 234 235 // Initialize the arguments to JLI_Launch() 236 // 237 // On Mac OS X JLI_Launch spawns a new thread that actually starts the JVM. 238 // This new thread simply re-runs main(argc, argv). Therefore we do not 239 // want to add new args if we are still in the original main thread so we 240 // will treat them as command line args provided by the user ... 241 // Only propagate original set of args first time. 242 243 options.AppendValue(_T("-classpath")); 244 options.AppendValue(classpath); 245 246 std::list<TString> vmargs; 247 vmargs.push_back(package.GetCommandName()); 248 249 if (package.HasSplashScreen() == true) { 250 options.AppendValue(TString(_T("-splash:")) 251 + package.GetSplashScreenFileName(), _T("")); 252 } 253 254 if (mainModule.empty() == true) { 255 options.AppendValue(Helpers::ConvertJavaPathToId(mainClassName), 256 _T("")); 257 } else { 258 options.AppendValue(_T("-m")); 259 options.AppendValue(mainModule); 260 } 261 262 return launchVM(options, vmargs); 263 } 264 265 void JavaVirtualMachine::configureLibrary() { 266 Platform& platform = Platform::GetInstance(); 267 Package& package = Package::GetInstance(); 268 // TODO: Clean this up. Because of bug JDK-8131321 the opening of the 269 // PE file ails in WindowsPlatform.cpp on the check to 270 // if (pNTHeader->Signature == IMAGE_NT_SIGNATURE) 271 TString libName = package.GetJVMLibraryFileName(); 272 #ifdef _WIN64 273 if (FilePath::FileExists(_T("msvcr100.dll")) == true) { 274 javaLibrary.AddDependency(_T("msvcr100.dll")); 275 } 276 277 TString runtimeBin = platform.GetPackageRuntimeBinDirectory(); 278 SetDllDirectory(runtimeBin.c_str()); 279 #else 280 javaLibrary.AddDependencies( 281 platform.FilterOutRuntimeDependenciesForPlatform( 282 platform.GetLibraryImports(libName))); 283 #endif 284 javaLibrary.Load(libName); 285 } 286 287 bool JavaVirtualMachine::launchVM(JavaOptions& options, 288 std::list<TString>& vmargs) { 289 Platform& platform = Platform::GetInstance(); 290 Package& package = Package::GetInstance(); 291 292 #ifdef MAC 293 // Mac adds a ProcessSerialNumber to args when launched from .app 294 // filter out the psn since they it's not expected in the app 295 if (platform.IsMainThread() == false) { 296 std::list<TString> loptions = options.ToList(); 297 vmargs.splice(vmargs.end(), loptions, 298 loptions.begin(), loptions.end()); 299 } 300 #else 301 std::list<TString> loptions = options.ToList(); 302 vmargs.splice(vmargs.end(), loptions, loptions.begin(), loptions.end()); 303 #endif 304 305 std::list<TString> largs = package.GetArgs(); 306 vmargs.splice(vmargs.end(), largs, largs.begin(), largs.end()); 307 308 size_t argc = vmargs.size(); 309 DynamicBuffer<char*> argv(argc + 1); 310 if (argv.GetData() == NULL) { 311 return false; 312 } 313 314 unsigned int index = 0; 315 for (std::list<TString>::const_iterator iterator = vmargs.begin(); 316 iterator != vmargs.end(); iterator++) { 317 TString item = *iterator; 318 std::string arg = PlatformString(item).toStdString(); 319 #ifdef DEBUG 320 printf("%i %s\n", index, arg.c_str()); 321 #endif // DEBUG 322 argv[index] = PlatformString::duplicate(arg.c_str()); 323 index++; 324 } 325 326 argv[argc] = NULL; 327 328 // On Mac we can only free the boot fields if the calling thread is 329 // not the main thread. 330 #ifdef MAC 331 if (platform.IsMainThread() == false) { 332 package.FreeBootFields(); 333 } 334 #else 335 package.FreeBootFields(); 336 #endif // MAC 337 338 if (javaLibrary.JavaVMCreate(argc, argv.GetData()) == true) { 339 return true; 340 } 341 342 for (index = 0; index < argc; index++) { 343 if (argv[index] != NULL) { 344 delete[] argv[index]; 345 } 346 } 347 348 return false; 349 }