fe9f804547
I happened to notice while stepping through the StackUnwindingWin64 test that it never actually encounters a runtime-compiled function despite using %OptimizeFunctionOnNextCall. V8 compiles the function on the subsequent call as requested, but the compiled function isn't very good because there was no feedback data, and it immediately deopts. To fix, we can call the function once between %PrepareFunctionForOptimization and %OptimizeFunctionOnNextCall. Change-Id: Icb25f16d43a60c36a1f85d15e2ce4535e08d1076 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2472780 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Cr-Commit-Position: refs/heads/master@{#70633}
118 lines
4.0 KiB
C++
118 lines
4.0 KiB
C++
// Copyright 2019 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/base/win32-headers.h"
|
|
#include "src/init/v8.h"
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#if defined(V8_OS_WIN_X64)
|
|
#define CONTEXT_PC(context) (context.Rip)
|
|
#elif defined(V8_OS_WIN_ARM64)
|
|
#define CONTEXT_PC(context) (context.Pc)
|
|
#endif
|
|
|
|
class UnwindingWin64Callbacks {
|
|
public:
|
|
UnwindingWin64Callbacks() = default;
|
|
|
|
static void Getter(v8::Local<v8::String> name,
|
|
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
// Expects to find at least 15 stack frames in the call stack.
|
|
// The stack walking should fail on stack frames for builtin functions if
|
|
// stack unwinding data has not been correctly registered.
|
|
int stack_frames = CountCallStackFrames(15);
|
|
CHECK_GE(stack_frames, 15);
|
|
}
|
|
static void Setter(v8::Local<v8::String> name, v8::Local<v8::Value> value,
|
|
const v8::PropertyCallbackInfo<void>& info) {}
|
|
|
|
private:
|
|
// Windows-specific code to walk the stack starting from the current
|
|
// instruction pointer.
|
|
static int CountCallStackFrames(int max_frames) {
|
|
CONTEXT context_record;
|
|
::RtlCaptureContext(&context_record);
|
|
|
|
int iframe = 0;
|
|
while (++iframe < max_frames) {
|
|
uint64_t image_base;
|
|
PRUNTIME_FUNCTION function_entry = ::RtlLookupFunctionEntry(
|
|
CONTEXT_PC(context_record), &image_base, nullptr);
|
|
if (!function_entry) break;
|
|
|
|
void* handler_data;
|
|
uint64_t establisher_frame;
|
|
::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base,
|
|
CONTEXT_PC(context_record), function_entry,
|
|
&context_record, &handler_data, &establisher_frame,
|
|
NULL);
|
|
}
|
|
return iframe;
|
|
}
|
|
};
|
|
|
|
// Verifies that stack unwinding data has been correctly registered on Win64.
|
|
UNINITIALIZED_TEST(StackUnwindingWin64) {
|
|
#ifdef V8_WIN64_UNWINDING_INFO
|
|
|
|
static const char* unwinding_win64_test_source =
|
|
"function start(count) {\n"
|
|
" for (var i = 0; i < count; i++) {\n"
|
|
" var o = instance.foo;\n"
|
|
" instance.foo = o + 1;\n"
|
|
" }\n"
|
|
"};\n"
|
|
"%PrepareFunctionForOptimization(start);\n";
|
|
|
|
// This test may fail on Windows 7
|
|
if (!::IsWindows8OrGreater()) {
|
|
return;
|
|
}
|
|
|
|
i::FLAG_allow_natives_syntax = true;
|
|
i::FLAG_win64_unwinding_info = true;
|
|
|
|
v8::Isolate::CreateParams create_params;
|
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
|
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
|
isolate->Enter();
|
|
{
|
|
v8::HandleScope scope(isolate);
|
|
LocalContext env(isolate);
|
|
|
|
v8::Local<v8::FunctionTemplate> func_template =
|
|
v8::FunctionTemplate::New(isolate);
|
|
v8::Local<v8::ObjectTemplate> instance_template =
|
|
func_template->InstanceTemplate();
|
|
|
|
UnwindingWin64Callbacks accessors;
|
|
v8::Local<v8::External> data = v8::External::New(isolate, &accessors);
|
|
instance_template->SetAccessor(v8_str("foo"),
|
|
&UnwindingWin64Callbacks::Getter,
|
|
&UnwindingWin64Callbacks::Setter, data);
|
|
v8::Local<v8::Function> func =
|
|
func_template->GetFunction(env.local()).ToLocalChecked();
|
|
v8::Local<v8::Object> instance =
|
|
func->NewInstance(env.local()).ToLocalChecked();
|
|
env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
|
|
|
|
CompileRun(unwinding_win64_test_source);
|
|
v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
|
|
env->Global()->Get(env.local(), v8_str("start")).ToLocalChecked());
|
|
|
|
CompileRun("start(1); %OptimizeFunctionOnNextCall(start);");
|
|
|
|
int32_t repeat_count = 100;
|
|
v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
|
|
function->Call(env.local(), env.local()->Global(), arraysize(args), args)
|
|
.ToLocalChecked();
|
|
}
|
|
isolate->Exit();
|
|
isolate->Dispose();
|
|
|
|
#endif // V8_WIN64_UNWINDING_INFO
|
|
}
|
|
|
|
#undef CONTEXT_PC
|