jdk

Форк
0
/
os_windows_x86.cpp 
576 строк · 18.7 Кб
1
/*
2
 * Copyright (c) 1999, 2023, 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.
8
 *
9
 * This code is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 * version 2 for more details (a copy is included in the LICENSE file that
13
 * accompanied this code).
14
 *
15
 * You should have received a copy of the GNU General Public License version
16
 * 2 along with this work; if not, write to the Free Software Foundation,
17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
 * or visit www.oracle.com if you need additional information or have any
21
 * questions.
22
 *
23
 */
24

25
// no precompiled headers
26
#include "asm/macroAssembler.hpp"
27
#include "classfile/vmSymbols.hpp"
28
#include "code/vtableStubs.hpp"
29
#include "interpreter/interpreter.hpp"
30
#include "jvm.h"
31
#include "memory/allocation.inline.hpp"
32
#include "memory/resourceArea.hpp"
33
#include "nativeInst_x86.hpp"
34
#include "os_windows.hpp"
35
#include "prims/jniFastGetField.hpp"
36
#include "prims/jvm_misc.hpp"
37
#include "runtime/arguments.hpp"
38
#include "runtime/frame.inline.hpp"
39
#include "runtime/interfaceSupport.inline.hpp"
40
#include "runtime/java.hpp"
41
#include "runtime/javaCalls.hpp"
42
#include "runtime/javaThread.hpp"
43
#include "runtime/mutexLocker.hpp"
44
#include "runtime/os.inline.hpp"
45
#include "runtime/osThread.hpp"
46
#include "runtime/sharedRuntime.hpp"
47
#include "runtime/stubRoutines.hpp"
48
#include "runtime/timer.hpp"
49
#include "symbolengine.hpp"
50
#include "unwind_windows_x86.hpp"
51
#include "utilities/events.hpp"
52
#include "utilities/vmError.hpp"
53
#include "windbghelp.hpp"
54

55

56
#undef REG_SP
57
#undef REG_FP
58
#undef REG_PC
59
#ifdef AMD64
60
#define REG_SP Rsp
61
#define REG_FP Rbp
62
#define REG_PC Rip
63
#else
64
#define REG_SP Esp
65
#define REG_FP Ebp
66
#define REG_PC Eip
67
#endif // AMD64
68

69
JNIEXPORT
70
extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* );
71

72
// Install a win32 structured exception handler around thread.
73
void os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandle& method, JavaCallArguments* args, JavaThread* thread) {
74
  __try {
75

76
#ifndef AMD64
77
    // We store the current thread in this wrapperthread location
78
    // and determine how far away this address is from the structured
79
    // exception pointer that FS:[0] points to.  This get_thread
80
    // code can then get the thread pointer via FS.
81
    //
82
    // Warning:  This routine must NEVER be inlined since we'd end up with
83
    //           multiple offsets.
84
    //
85
    volatile Thread* wrapperthread = thread;
86

87
    if (os::win32::get_thread_ptr_offset() == 0) {
88
      int thread_ptr_offset;
89
      __asm {
90
        lea eax, dword ptr wrapperthread;
91
        sub eax, dword ptr FS:[0H];
92
        mov thread_ptr_offset, eax
93
      };
94
      os::win32::set_thread_ptr_offset(thread_ptr_offset);
95
    }
96
#ifdef ASSERT
97
    // Verify that the offset hasn't changed since we initially captured
98
    // it. This might happen if we accidentally ended up with an
99
    // inlined version of this routine.
100
    else {
101
      int test_thread_ptr_offset;
102
      __asm {
103
        lea eax, dword ptr wrapperthread;
104
        sub eax, dword ptr FS:[0H];
105
        mov test_thread_ptr_offset, eax
106
      };
107
      assert(test_thread_ptr_offset == os::win32::get_thread_ptr_offset(),
108
             "thread pointer offset from SEH changed");
109
    }
110
#endif // ASSERT
111
#endif // !AMD64
112

113
    f(value, method, args, thread);
114
  } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) {
115
      // Nothing to do.
116
  }
117
}
118

119
#ifdef AMD64
120

121
// This is the language specific handler for exceptions
122
// originating from dynamically generated code.
123
// We call the standard structured exception handler
124
// We only expect Continued Execution since we cannot unwind
125
// from generated code.
126
LONG HandleExceptionFromCodeCache(
127
  IN PEXCEPTION_RECORD ExceptionRecord,
128
  IN ULONG64 EstablisherFrame,
129
  IN OUT PCONTEXT ContextRecord,
130
  IN OUT PDISPATCHER_CONTEXT DispatcherContext) {
131
  EXCEPTION_POINTERS ep;
132
  LONG result;
133

134
  ep.ExceptionRecord = ExceptionRecord;
135
  ep.ContextRecord = ContextRecord;
136

137
  result = topLevelExceptionFilter(&ep);
138

139
  // We better only get a CONTINUE_EXECUTION from our handler
140
  // since we don't have unwind information registered.
141

142
  guarantee( result == EXCEPTION_CONTINUE_EXECUTION,
143
             "Unexpected result from topLevelExceptionFilter");
144

145
  return(ExceptionContinueExecution);
146
}
147

148

149
// Structure containing the Windows Data Structures required
150
// to register our Code Cache exception handler.
151
// We put these in the CodeCache since the API requires
152
// all addresses in these structures are relative to the Code
153
// area registered with RtlAddFunctionTable.
154
typedef struct {
155
  char ExceptionHandlerInstr[16];  // jmp HandleExceptionFromCodeCache
156
  RUNTIME_FUNCTION rt;
157
  UNWIND_INFO_EH_ONLY unw;
158
} DynamicCodeData, *pDynamicCodeData;
159

160
#endif // AMD64
161
//
162
// Register our CodeCache area with the OS so it will dispatch exceptions
163
// to our topLevelExceptionFilter when we take an exception in our
164
// dynamically generated code.
165
//
166
// Arguments:  low and high are the address of the full reserved
167
// codeCache area
168
//
169
bool os::win32::register_code_area(char *low, char *high) {
170
#ifdef AMD64
171

172
  ResourceMark rm;
173

174
  pDynamicCodeData pDCD;
175
  PRUNTIME_FUNCTION prt;
176
  PUNWIND_INFO_EH_ONLY punwind;
177

178
  BufferBlob* blob = BufferBlob::create("CodeCache Exception Handler", sizeof(DynamicCodeData));
179
  CodeBuffer cb(blob);
180
  MacroAssembler* masm = new MacroAssembler(&cb);
181
  pDCD = (pDynamicCodeData) masm->pc();
182

183
  masm->jump(ExternalAddress((address)&HandleExceptionFromCodeCache), rscratch1);
184
  masm->flush();
185

186
  // Create an Unwind Structure specifying no unwind info
187
  // other than an Exception Handler
188
  punwind = &pDCD->unw;
189
  punwind->Version = 1;
190
  punwind->Flags = UNW_FLAG_EHANDLER;
191
  punwind->SizeOfProlog = 0;
192
  punwind->CountOfCodes = 0;
193
  punwind->FrameRegister = 0;
194
  punwind->FrameOffset = 0;
195
  punwind->ExceptionHandler = (char *)(&(pDCD->ExceptionHandlerInstr[0])) -
196
                              (char*)low;
197
  punwind->ExceptionData[0] = 0;
198

199
  // This structure describes the covered dynamic code area.
200
  // Addresses are relative to the beginning on the code cache area
201
  prt = &pDCD->rt;
202
  prt->BeginAddress = 0;
203
  prt->EndAddress = (ULONG)(high - low);
204
  prt->UnwindData = ((char *)punwind - low);
205

206
  guarantee(RtlAddFunctionTable(prt, 1, (ULONGLONG)low),
207
            "Failed to register Dynamic Code Exception Handler with RtlAddFunctionTable");
208

209
#endif // AMD64
210
  return true;
211
}
212

213
#ifdef HAVE_PLATFORM_PRINT_NATIVE_STACK
214
/*
215
 * Windows/x64 does not use stack frames the way expected by Java:
216
 * [1] in most cases, there is no frame pointer. All locals are addressed via RSP
217
 * [2] in rare cases, when alloca() is used, a frame pointer is used, but this may
218
 *     not be RBP.
219
 * See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx
220
 *
221
 * So it's not possible to print the native stack using the
222
 *     while (...) {...  fr = os::get_sender_for_C_frame(&fr); }
223
 * loop in vmError.cpp. We need to roll our own loop.
224
 */
225
bool os::win32::platform_print_native_stack(outputStream* st, const void* context,
226
                                            char *buf, int buf_size, address& lastpc)
227
{
228
  CONTEXT ctx;
229
  if (context != nullptr) {
230
    memcpy(&ctx, context, sizeof(ctx));
231
  } else {
232
    RtlCaptureContext(&ctx);
233
  }
234

235
  st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
236

237
  STACKFRAME stk;
238
  memset(&stk, 0, sizeof(stk));
239
  stk.AddrStack.Offset    = ctx.Rsp;
240
  stk.AddrStack.Mode      = AddrModeFlat;
241
  stk.AddrFrame.Offset    = ctx.Rbp;
242
  stk.AddrFrame.Mode      = AddrModeFlat;
243
  stk.AddrPC.Offset       = ctx.Rip;
244
  stk.AddrPC.Mode         = AddrModeFlat;
245

246
  // Ensure we consider dynamically loaded dll's
247
  SymbolEngine::refreshModuleList();
248

249
  int count = 0;
250
  address lastpc_internal = 0;
251
  while (count++ < StackPrintLimit) {
252
    intptr_t* sp = (intptr_t*)stk.AddrStack.Offset;
253
    intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp!
254
    address pc = (address)stk.AddrPC.Offset;
255

256
    if (pc != nullptr) {
257
      if (count == 2 && lastpc_internal == pc) {
258
        // Skip it -- StackWalk64() may return the same PC
259
        // (but different SP) on the first try.
260
      } else {
261
        // Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame
262
        // may not contain what Java expects, and may cause the frame() constructor
263
        // to crash. Let's just print out the symbolic address.
264
        frame::print_C_frame(st, buf, buf_size, pc);
265
        // print source file and line, if available
266
        char buf[128];
267
        int line_no;
268
        if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) {
269
          st->print("  (%s:%d)", buf, line_no);
270
        } else {
271
          st->print("  (no source info available)");
272
        }
273
        st->cr();
274
      }
275
      lastpc_internal = pc;
276
    }
277

278
    PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
279
    if (!p) {
280
      // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
281
      lastpc = lastpc_internal;
282
      break;
283
    }
284

285
    BOOL result = WindowsDbgHelp::stackWalk64(
286
        IMAGE_FILE_MACHINE_AMD64,  // __in      DWORD MachineType,
287
        GetCurrentProcess(),       // __in      HANDLE hProcess,
288
        GetCurrentThread(),        // __in      HANDLE hThread,
289
        &stk,                      // __inout   LP STACKFRAME64 StackFrame,
290
        &ctx);                     // __inout   PVOID ContextRecord,
291

292
    if (!result) {
293
      break;
294
    }
295
  }
296
  if (count > StackPrintLimit) {
297
    st->print_cr("...<more frames>...");
298
  }
299
  st->cr();
300

301
  return true;
302
}
303
#endif // HAVE_PLATFORM_PRINT_NATIVE_STACK
304

305
address os::fetch_frame_from_context(const void* ucVoid,
306
                    intptr_t** ret_sp, intptr_t** ret_fp) {
307

308
  address  epc;
309
  CONTEXT* uc = (CONTEXT*)ucVoid;
310

311
  if (uc != nullptr) {
312
    epc = (address)uc->REG_PC;
313
    if (ret_sp) *ret_sp = (intptr_t*)uc->REG_SP;
314
    if (ret_fp) *ret_fp = (intptr_t*)uc->REG_FP;
315
  } else {
316
    epc = nullptr;
317
    if (ret_sp) *ret_sp = (intptr_t *)nullptr;
318
    if (ret_fp) *ret_fp = (intptr_t *)nullptr;
319
  }
320

321
  return epc;
322
}
323

324
frame os::fetch_frame_from_context(const void* ucVoid) {
325
  intptr_t* sp;
326
  intptr_t* fp;
327
  address epc = fetch_frame_from_context(ucVoid, &sp, &fp);
328
  if (!is_readable_pointer(epc)) {
329
    // Try to recover from calling into bad memory
330
    // Assume new frame has not been set up, the same as
331
    // compiled frame stack bang
332
    return frame(sp + 1, fp, (address)*sp);
333
  }
334
  return frame(sp, fp, epc);
335
}
336

337
#ifndef AMD64
338
// Ignore "C4172: returning address of local variable or temporary" on 32bit
339
PRAGMA_DIAG_PUSH
340
PRAGMA_DISABLE_MSVC_WARNING(4172)
341
// Returns an estimate of the current stack pointer. Result must be guaranteed
342
// to point into the calling threads stack, and be no lower than the current
343
// stack pointer.
344
address os::current_stack_pointer() {
345
  int dummy;
346
  address sp = (address)&dummy;
347
  return sp;
348
}
349
PRAGMA_DIAG_POP
350
#else
351
// Returns the current stack pointer. Accurate value needed for
352
// os::verify_stack_alignment().
353
address os::current_stack_pointer() {
354
  typedef address get_sp_func();
355
  get_sp_func* func = CAST_TO_FN_PTR(get_sp_func*,
356
                                     StubRoutines::x86::get_previous_sp_entry());
357
  return (*func)();
358
}
359
#endif
360

361
bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread,
362
        struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) {
363
  PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
364
  address addr = (address) exceptionRecord->ExceptionInformation[1];
365
  if (Interpreter::contains(pc)) {
366
    *fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord);
367
    if (!fr->is_first_java_frame()) {
368
      // get_frame_at_stack_banging_point() is only called when we
369
      // have well defined stacks so java_sender() calls do not need
370
      // to assert safe_for_sender() first.
371
      *fr = fr->java_sender();
372
    }
373
  } else {
374
    // more complex code with compiled code
375
    assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
376
    CodeBlob* cb = CodeCache::find_blob(pc);
377
    if (cb == nullptr || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
378
      // Not sure where the pc points to, fallback to default
379
      // stack overflow handling
380
      return false;
381
    } else {
382
      // in compiled code, the stack banging is performed just after the return pc
383
      // has been pushed on the stack
384
      intptr_t* fp = (intptr_t*)exceptionInfo->ContextRecord->REG_FP;
385
      intptr_t* sp = (intptr_t*)exceptionInfo->ContextRecord->REG_SP;
386
      *fr = frame(sp + 1, fp, (address)*sp);
387
      if (!fr->is_java_frame()) {
388
        // See java_sender() comment above.
389
        *fr = fr->java_sender();
390
      }
391
    }
392
  }
393
  assert(fr->is_java_frame(), "Safety check");
394
  return true;
395
}
396

397

398
// VC++ does not save frame pointer on stack in optimized build. It
399
// can be turned off by /Oy-. If we really want to walk C frames,
400
// we can use the StackWalk() API.
401
frame os::get_sender_for_C_frame(frame* fr) {
402
  ShouldNotReachHere();
403
  return frame();
404
}
405

406
frame os::current_frame() {
407
  return frame();  // cannot walk Windows frames this way.  See os::get_native_stack
408
                   // and os::platform_print_native_stack
409
}
410

411
void os::print_context(outputStream *st, const void *context) {
412
  if (context == nullptr) return;
413

414
  const CONTEXT* uc = (const CONTEXT*)context;
415

416
  st->print_cr("Registers:");
417
#ifdef AMD64
418
  st->print(  "RAX=" INTPTR_FORMAT, uc->Rax);
419
  st->print(", RBX=" INTPTR_FORMAT, uc->Rbx);
420
  st->print(", RCX=" INTPTR_FORMAT, uc->Rcx);
421
  st->print(", RDX=" INTPTR_FORMAT, uc->Rdx);
422
  st->cr();
423
  st->print(  "RSP=" INTPTR_FORMAT, uc->Rsp);
424
  st->print(", RBP=" INTPTR_FORMAT, uc->Rbp);
425
  st->print(", RSI=" INTPTR_FORMAT, uc->Rsi);
426
  st->print(", RDI=" INTPTR_FORMAT, uc->Rdi);
427
  st->cr();
428
  st->print(  "R8 =" INTPTR_FORMAT, uc->R8);
429
  st->print(", R9 =" INTPTR_FORMAT, uc->R9);
430
  st->print(", R10=" INTPTR_FORMAT, uc->R10);
431
  st->print(", R11=" INTPTR_FORMAT, uc->R11);
432
  st->cr();
433
  st->print(  "R12=" INTPTR_FORMAT, uc->R12);
434
  st->print(", R13=" INTPTR_FORMAT, uc->R13);
435
  st->print(", R14=" INTPTR_FORMAT, uc->R14);
436
  st->print(", R15=" INTPTR_FORMAT, uc->R15);
437
  st->cr();
438
  st->print(  "RIP=" INTPTR_FORMAT, uc->Rip);
439
  st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags);
440
#else
441
  st->print(  "EAX=" INTPTR_FORMAT, uc->Eax);
442
  st->print(", EBX=" INTPTR_FORMAT, uc->Ebx);
443
  st->print(", ECX=" INTPTR_FORMAT, uc->Ecx);
444
  st->print(", EDX=" INTPTR_FORMAT, uc->Edx);
445
  st->cr();
446
  st->print(  "ESP=" INTPTR_FORMAT, uc->Esp);
447
  st->print(", EBP=" INTPTR_FORMAT, uc->Ebp);
448
  st->print(", ESI=" INTPTR_FORMAT, uc->Esi);
449
  st->print(", EDI=" INTPTR_FORMAT, uc->Edi);
450
  st->cr();
451
  st->print(  "EIP=" INTPTR_FORMAT, uc->Eip);
452
  st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags);
453
#endif // AMD64
454
  st->cr();
455
  st->cr();
456
}
457

458
void os::print_tos_pc(outputStream *st, const void *context) {
459
  if (context == nullptr) return;
460

461
  const CONTEXT* uc = (const CONTEXT*)context;
462

463
  address sp = (address)uc->REG_SP;
464
  print_tos(st, sp);
465
  st->cr();
466

467
  // Note: it may be unsafe to inspect memory near pc. For example, pc may
468
  // point to garbage if entry point in an nmethod is corrupted. Leave
469
  // this at the end, and hope for the best.
470
  address pc = os::fetch_frame_from_context(uc).pc();
471
  print_instructions(st, pc);
472
  st->cr();
473
}
474

475
void os::print_register_info(outputStream *st, const void *context, int& continuation) {
476
  const int register_count = AMD64_ONLY(16) NOT_AMD64(8);
477
  int n = continuation;
478
  assert(n >= 0 && n <= register_count, "Invalid continuation value");
479
  if (context == nullptr || n == register_count) {
480
    return;
481
  }
482

483
  const CONTEXT* uc = (const CONTEXT*)context;
484
  while (n < register_count) {
485
    // Update continuation with next index before printing location
486
    continuation = n + 1;
487
# define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->id);
488
    switch (n) {
489
#ifdef AMD64
490
    CASE_PRINT_REG( 0, "RAX=", Rax); break;
491
    CASE_PRINT_REG( 1, "RBX=", Rbx); break;
492
    CASE_PRINT_REG( 2, "RCX=", Rcx); break;
493
    CASE_PRINT_REG( 3, "RDX=", Rdx); break;
494
    CASE_PRINT_REG( 4, "RSP=", Rsp); break;
495
    CASE_PRINT_REG( 5, "RBP=", Rbp); break;
496
    CASE_PRINT_REG( 6, "RSI=", Rsi); break;
497
    CASE_PRINT_REG( 7, "RDI=", Rdi); break;
498
    CASE_PRINT_REG( 8, "R8 =", R8); break;
499
    CASE_PRINT_REG( 9, "R9 =", R9); break;
500
    CASE_PRINT_REG(10, "R10=", R10); break;
501
    CASE_PRINT_REG(11, "R11=", R11); break;
502
    CASE_PRINT_REG(12, "R12=", R12); break;
503
    CASE_PRINT_REG(13, "R13=", R13); break;
504
    CASE_PRINT_REG(14, "R14=", R14); break;
505
    CASE_PRINT_REG(15, "R15=", R15); break;
506
#else
507
    CASE_PRINT_REG(0, "EAX=", Eax); break;
508
    CASE_PRINT_REG(1, "EBX=", Ebx); break;
509
    CASE_PRINT_REG(2, "ECX=", Ecx); break;
510
    CASE_PRINT_REG(3, "EDX=", Edx); break;
511
    CASE_PRINT_REG(4, "ESP=", Esp); break;
512
    CASE_PRINT_REG(5, "EBP=", Ebp); break;
513
    CASE_PRINT_REG(6, "ESI=", Esi); break;
514
    CASE_PRINT_REG(7, "EDI=", Edi); break;
515
#endif // AMD64
516
    }
517
# undef CASE_PRINT_REG
518
    ++n;
519
  }
520
}
521

522
extern "C" int SpinPause () {
523
#ifdef AMD64
524
   return 0 ;
525
#else
526
   // pause == rep:nop
527
   // On systems that don't support pause a rep:nop
528
   // is executed as a nop.  The rep: prefix is ignored.
529
   _asm {
530
      pause ;
531
   };
532
   return 1 ;
533
#endif // AMD64
534
}
535

536
juint os::cpu_microcode_revision() {
537
  juint result = 0;
538
  BYTE data[8] = {0};
539
  HKEY key;
540
  DWORD status = RegOpenKey(HKEY_LOCAL_MACHINE,
541
               "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);
542
  if (status == ERROR_SUCCESS) {
543
    DWORD size = sizeof(data);
544
    status = RegQueryValueEx(key, "Update Revision", nullptr, nullptr, data, &size);
545
    if (status == ERROR_SUCCESS) {
546
      if (size == 4) result = *((juint*)data);
547
      if (size == 8) result = *((juint*)data + 1); // upper 32-bits
548
    }
549
    RegCloseKey(key);
550
  }
551
  return result;
552
}
553

554
void os::setup_fpu() {
555
#ifndef AMD64
556
  int fpu_cntrl_word = StubRoutines::x86::fpu_cntrl_wrd_std();
557
  __asm fldcw fpu_cntrl_word;
558
#endif // !AMD64
559
}
560

561
#ifndef PRODUCT
562
void os::verify_stack_alignment() {
563
#ifdef AMD64
564
  // The current_stack_pointer() calls generated get_previous_sp stub routine.
565
  // Only enable the assert after the routine becomes available.
566
  if (StubRoutines::initial_stubs_code() != nullptr) {
567
    assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
568
  }
569
#endif
570
}
571
#endif
572

573
int os::extra_bang_size_in_bytes() {
574
  // JDK-8050147 requires the full cache line bang for x86.
575
  return VM_Version::L1_line_size();
576
}
577

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.