b89d4249c0
This migrates the JSEntryStub to three dedicated builtins: JSEntry JSConstructEntry JSRunMicrotasksEntry Drive-by: Tweaks to make the code isolate-independent (e.g. using the correct macro assembler method to load and store external references through the kRootRegister). Drive-by: The context slot on x64/ia32 must be set up after kRootRegister is initialized, so we first reserve the slot and later load its value. Drive-by: Update all remaining comments referencing JSEntryStub. Bug: v8:7777 Change-Id: Ie3ba17ffb3bde6f18ec1d26d778b258719b2d4ef Reviewed-on: https://chromium-review.googlesource.com/c/1365275 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#58088}
99 lines
3.4 KiB
C++
99 lines
3.4 KiB
C++
// Copyright 2018 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 "include/v8.h"
|
|
#include "src/frame-constants.h"
|
|
#include "src/globals.h"
|
|
|
|
namespace v8 {
|
|
|
|
namespace {
|
|
|
|
bool PCIsInCodeRange(const v8::MemoryRange& code_range, void* pc) {
|
|
// Given that the length of the memory range is in bytes and it is not
|
|
// necessarily aligned, we need to do the pointer arithmetic in byte* here.
|
|
const i::byte* pc_as_byte = reinterpret_cast<i::byte*>(pc);
|
|
const i::byte* start = reinterpret_cast<const i::byte*>(code_range.start);
|
|
const i::byte* end = start + code_range.length_in_bytes;
|
|
return pc_as_byte >= start && pc_as_byte < end;
|
|
}
|
|
|
|
bool IsInUnsafeJSEntryRange(const v8::JSEntryStub& js_entry_stub, void* pc) {
|
|
return PCIsInCodeRange(js_entry_stub.code, pc);
|
|
|
|
// TODO(petermarshall): We can be more precise by checking whether we are
|
|
// in JSEntry but after frame setup and before frame teardown, in which case
|
|
// we are safe to unwind the stack. For now, we bail out if the PC is anywhere
|
|
// within JSEntry.
|
|
}
|
|
|
|
i::Address Load(i::Address address) {
|
|
return *reinterpret_cast<i::Address*>(address);
|
|
}
|
|
|
|
void* GetReturnAddressFromFP(void* fp) {
|
|
return reinterpret_cast<void*>(
|
|
Load(reinterpret_cast<i::Address>(fp) +
|
|
i::CommonFrameConstants::kCallerPCOffset));
|
|
}
|
|
|
|
void* GetCallerFPFromFP(void* fp) {
|
|
return reinterpret_cast<void*>(
|
|
Load(reinterpret_cast<i::Address>(fp) +
|
|
i::CommonFrameConstants::kCallerFPOffset));
|
|
}
|
|
|
|
void* GetCallerSPFromFP(void* fp) {
|
|
return reinterpret_cast<void*>(reinterpret_cast<i::Address>(fp) +
|
|
i::CommonFrameConstants::kCallerSPOffset);
|
|
}
|
|
|
|
bool AddressIsInStack(const void* address, const void* stack_base,
|
|
const void* stack_top) {
|
|
return address <= stack_base && address >= stack_top;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool Unwinder::TryUnwindV8Frames(const UnwindState& unwind_state,
|
|
RegisterState* register_state,
|
|
const void* stack_base) {
|
|
const void* stack_top = register_state->sp;
|
|
|
|
void* pc = register_state->pc;
|
|
if (PCIsInV8(unwind_state, pc) &&
|
|
!IsInUnsafeJSEntryRange(unwind_state.js_entry_stub, pc)) {
|
|
void* current_fp = register_state->fp;
|
|
if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false;
|
|
|
|
// Peek at the return address that the caller pushed. If it's in V8, then we
|
|
// assume the caller frame is a JS frame and continue to unwind.
|
|
void* next_pc = GetReturnAddressFromFP(current_fp);
|
|
while (PCIsInV8(unwind_state, next_pc)) {
|
|
current_fp = GetCallerFPFromFP(current_fp);
|
|
if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false;
|
|
next_pc = GetReturnAddressFromFP(current_fp);
|
|
}
|
|
|
|
void* final_sp = GetCallerSPFromFP(current_fp);
|
|
if (!AddressIsInStack(final_sp, stack_base, stack_top)) return false;
|
|
register_state->sp = final_sp;
|
|
|
|
void* final_fp = GetCallerFPFromFP(current_fp);
|
|
if (!AddressIsInStack(final_fp, stack_base, stack_top)) return false;
|
|
register_state->fp = final_fp;
|
|
|
|
register_state->pc = next_pc;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Unwinder::PCIsInV8(const UnwindState& unwind_state, void* pc) {
|
|
return pc && (PCIsInCodeRange(unwind_state.code_range, pc) ||
|
|
PCIsInCodeRange(unwind_state.embedded_code_range, pc));
|
|
}
|
|
|
|
} // namespace v8
|