1// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/ffi_callback_trampolines.h"
6
7#if !defined(DART_PRECOMPILED_RUNTIME)
8#include "vm/code_comments.h"
9#include "vm/code_observers.h"
10#include "vm/compiler/assembler/assembler.h"
11#include "vm/compiler/assembler/disassembler.h"
12#include "vm/exceptions.h"
13#endif // !defined(DART_PRECOMPILED_RUNTIME)
14
15namespace dart {
16
17DECLARE_FLAG(bool, disassemble_stubs);
18
19#if !defined(DART_PRECOMPILED_RUNTIME)
20uword NativeCallbackTrampolines::TrampolineForId(int32_t callback_id) {
21#if defined(DART_PRECOMPILER)
22 ASSERT(!Enabled());
23 UNREACHABLE();
24#else
25 const intptr_t trampolines_per_page = NumCallbackTrampolinesPerPage();
26 const intptr_t page_index = callback_id / trampolines_per_page;
27 const uword entry_point = trampoline_pages_[page_index]->start();
28
29 return entry_point +
30 (callback_id % trampolines_per_page) *
31 compiler::StubCodeCompiler::kNativeCallbackTrampolineSize;
32#endif
33}
34
35void NativeCallbackTrampolines::AllocateTrampoline() {
36#if defined(DART_PRECOMPILER)
37 ASSERT(!Enabled());
38 UNREACHABLE();
39#else
40
41 // Callback IDs are limited to 32-bits for trampoline compactness.
42 if (kWordSize == 8 &&
43 !Utils::IsInt(32, next_callback_id_ + NumCallbackTrampolinesPerPage())) {
44 Exceptions::ThrowOOM();
45 }
46
47 if (trampolines_left_on_page_ == 0) {
48 VirtualMemory* const memory = VirtualMemory::AllocateAligned(
49 /*size=*/VirtualMemory::PageSize(),
50 /*alignment=*/VirtualMemory::PageSize(),
51 /*is_executable=*/false, /*name=*/"Dart VM FFI callback trampolines");
52
53 if (memory == nullptr) {
54 Exceptions::ThrowOOM();
55 }
56
57 trampoline_pages_.Add(memory);
58
59 compiler::Assembler assembler(/*object_pool_builder=*/nullptr);
60 compiler::StubCodeCompiler::GenerateJITCallbackTrampolines(
61 &assembler, next_callback_id_);
62
63 MemoryRegion region(memory->address(), memory->size());
64 assembler.FinalizeInstructions(region);
65
66 memory->Protect(VirtualMemory::kReadExecute);
67
68#if !defined(PRODUCT)
69 const char* name = "FfiJitCallbackTrampolines";
70 ASSERT(!Thread::Current()->IsAtSafepoint());
71 if (CodeObservers::AreActive()) {
72 const auto& comments = CreateCommentsFrom(&assembler);
73 CodeCommentsWrapper wrapper(comments);
74 CodeObservers::NotifyAll(name,
75 /*base=*/memory->start(),
76 /*prologue_offset=*/0,
77 /*size=*/assembler.CodeSize(),
78 /*optimized=*/false, // not really relevant
79 &wrapper);
80 }
81#endif
82#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
83 if (FLAG_disassemble_stubs && FLAG_support_disassembler) {
84 DisassembleToStdout formatter;
85 THR_Print(
86 "Code for native callback trampolines "
87 "[%" Pd " -> %" Pd "]: {\n",
88 next_callback_id_,
89 next_callback_id_ + NumCallbackTrampolinesPerPage() - 1);
90 const auto& comments = CreateCommentsFrom(&assembler);
91 Disassembler::Disassemble(memory->start(),
92 memory->start() + assembler.CodeSize(),
93 &formatter, &comments);
94 }
95#endif
96
97 trampolines_left_on_page_ = NumCallbackTrampolinesPerPage();
98 }
99
100 trampolines_left_on_page_--;
101 next_callback_id_++;
102#endif // defined(DART_PRECOMPILER)
103}
104#endif // !defined(DART_PRECOMPILED_RUNTIME)
105
106} // namespace dart
107