diff --git a/doc/panama_ffi.html b/doc/panama_ffi.html
deleted file mode 100644
index 35b934b2c20..00000000000
--- a/doc/panama_ffi.html
+++ /dev/null
@@ -1,693 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>
-
-<link href='https://fonts.loli.net/css?family=Open+Sans:400italic,700italic,700,400&subset=latin,latin-ext' rel='stylesheet' type='text/css' /><style type='text/css'>html {overflow-x: initial !important;}:root { --bg-color:#ffffff; --text-color:#333333; --select-text-bg-color:#B5D6FC; --select-text-font-color:auto; --monospace:"Lucida Console",Consolas,"Courier",monospace; --title-bar-height:20px; }
-.mac-os-11 { --title-bar-height:28px; }
-html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
-body { margin: 0px; padding: 0px; height: auto; inset: 0px; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; tab-size: 4; }
-iframe { margin: auto; }
-a.url { word-break: break-all; }
-a:active, a:hover { outline: 0px; }
-.in-text-selection, ::selection { text-shadow: none; background: var(--select-text-bg-color); color: var(--select-text-font-color); }
-#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; overflow-wrap: break-word; position: relative; white-space: normal; overflow-x: visible; padding-top: 36px; }
-#write.first-line-indent p { text-indent: 2em; }
-#write.first-line-indent li p, #write.first-line-indent p * { text-indent: 0px; }
-#write.first-line-indent li { margin-left: 2em; }
-.for-image #write { padding-left: 8px; padding-right: 8px; }
-body.typora-export { padding-left: 30px; padding-right: 30px; }
-.typora-export .footnote-line, .typora-export li, .typora-export p { white-space: pre-wrap; }
-.typora-export .task-list-item input { pointer-events: none; }
-@media screen and (max-width: 500px) {
-  body.typora-export { padding-left: 0px; padding-right: 0px; }
-  #write { padding-left: 20px; padding-right: 20px; }
-}
-#write li > figure:last-child { margin-bottom: 0.5rem; }
-#write ol, #write ul { position: relative; }
-img { max-width: 100%; vertical-align: middle; image-orientation: from-image; }
-button, input, select, textarea { color: inherit; font: inherit; }
-input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
-*, ::after, ::before { box-sizing: border-box; }
-#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
-#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; }
-p { line-height: inherit; }
-h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 4; }
-p { orphans: 4; }
-h1 { font-size: 2rem; }
-h2 { font-size: 1.8rem; }
-h3 { font-size: 1.6rem; }
-h4 { font-size: 1.4rem; }
-h5 { font-size: 1.2rem; }
-h6 { font-size: 1rem; }
-.md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; }
-.hidden { display: none; }
-.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
-a { cursor: pointer; }
-sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-radius: 4px; cursor: pointer; }
-sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; }
-#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
-figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; }
-figure > table { margin: 0px; }
-thead, tr { break-inside: avoid; break-after: auto; }
-thead { display: table-header-group; }
-table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
-table.md-table td { min-width: 32px; }
-.CodeMirror-gutters { border-right: 0px; background-color: inherit; }
-.CodeMirror-linenumber { user-select: none; }
-.CodeMirror { text-align: left; }
-.CodeMirror-placeholder { opacity: 0.3; }
-.CodeMirror pre { padding: 0px 4px; }
-.CodeMirror-lines { padding: 0px; }
-div.hr:focus { cursor: none; }
-#write pre { white-space: pre-wrap; }
-#write.fences-no-line-wrapping pre { white-space: pre; }
-#write pre.ty-contain-cm { white-space: normal; }
-.CodeMirror-gutters { margin-right: 4px; }
-.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
-.md-fences-adv-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
-#write .md-fences.mock-cm { white-space: pre-wrap; }
-.md-fences.md-fences-with-lineno { padding-left: 0px; }
-#write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; }
-.md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; }
-.CodeMirror-line, twitterwidget { break-inside: avoid; }
-svg { break-inside: avoid; }
-.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
-.footnotes + .footnotes { margin-top: 0px; }
-.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: 0px 0px; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; }
-li div { padding-top: 0px; }
-blockquote { margin: 1rem 0px; }
-li .mathjax-block, li p { margin: 0.5rem 0px; }
-li blockquote { margin: 1rem 0px; }
-li { margin: 0px; position: relative; }
-blockquote > :last-child { margin-bottom: 0px; }
-blockquote > :first-child, li > :first-child { margin-top: 0px; }
-.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; }
-#write .footnote-line { white-space: pre-wrap; }
-@media print {
-  body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; font-variant-ligatures: no-common-ligatures; }
-  #write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; padding-bottom: 0px !important; }
-  .typora-export * { -webkit-print-color-adjust: exact; }
-  .typora-export #write { break-after: avoid; }
-  .typora-export #write::after { height: 0px; }
-  .is-mac table { break-inside: avoid; }
-  .typora-export-show-outline .typora-export-sidebar { display: none; }
-}
-.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
-a img, img a { cursor: pointer; }
-pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
-p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; }
-#write.first-line-indent p > .md-image:only-child:not(.md-img-error) img { left: -2em; position: relative; }
-p > .md-image:only-child { display: inline-block; width: 100%; }
-#write .MathJax_Display { margin: 0.8em 0px 0px; }
-.md-math-block { width: 100%; }
-.md-math-block:not(:empty)::after { display: none; }
-.MathJax_ref { fill: currentcolor; }
-[contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus { outline: 0px; box-shadow: none; }
-.md-task-list-item { position: relative; list-style-type: none; }
-.task-list-item.md-task-list-item { padding-left: 0px; }
-.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; }
-.math { font-size: 1rem; }
-.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
-.md-toc-content { position: relative; margin-left: 0px; }
-.md-toc-content::after, .md-toc::after { display: none; }
-.md-toc-item { display: block; color: rgb(65, 131, 196); }
-.md-toc-item a { text-decoration: none; }
-.md-toc-inner:hover { text-decoration: underline; }
-.md-toc-inner { display: inline-block; cursor: pointer; }
-.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
-.md-toc-h2 .md-toc-inner { margin-left: 2em; }
-.md-toc-h3 .md-toc-inner { margin-left: 4em; }
-.md-toc-h4 .md-toc-inner { margin-left: 6em; }
-.md-toc-h5 .md-toc-inner { margin-left: 8em; }
-.md-toc-h6 .md-toc-inner { margin-left: 10em; }
-@media screen and (max-width: 48em) {
-  .md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
-  .md-toc-h4 .md-toc-inner { margin-left: 5em; }
-  .md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
-  .md-toc-h6 .md-toc-inner { margin-left: 8em; }
-}
-a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
-.footnote-line a:not(.reversefootnote) { color: inherit; }
-.reversefootnote { font-family: ui-monospace, sans-serif; }
-.md-attr { display: none; }
-.md-fn-count::after { content: "."; }
-code, pre, samp, tt { font-family: var(--monospace); }
-kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; }
-.md-comment { color: rgb(162, 127, 3); opacity: 0.6; font-family: var(--monospace); }
-code { text-align: left; vertical-align: initial; }
-a.md-print-anchor { white-space: pre !important; border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; background: 0px 0px !important; text-decoration: initial !important; text-shadow: initial !important; }
-.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
-.md-diagram-panel > svg { max-width: 100%; }
-[lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; height: auto; }
-[lang="mermaid"] .node text { font-size: 1rem; }
-table tr th { border-bottom: 0px; }
-video { max-width: 100%; display: block; margin: 0px auto; }
-iframe { max-width: 100%; width: 100%; border: none; }
-.highlight td, .highlight tr { border: 0px; }
-mark { background: rgb(255, 255, 0); color: rgb(0, 0, 0); }
-.md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong { color: inherit; }
-.md-expand mark .md-meta { opacity: 0.3 !important; }
-mark .md-meta { color: rgb(0, 0, 0); }
-@media print {
-  .typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 { break-inside: avoid; }
-}
-.md-diagram-panel .messageText { stroke: none !important; }
-.md-diagram-panel .start-state { fill: var(--node-fill); }
-.md-diagram-panel .edgeLabel rect { opacity: 1 !important; }
-.md-fences.md-fences-math { font-size: 1em; }
-.md-fences-advanced:not(.md-focus) { padding: 0px; white-space: nowrap; border: 0px; }
-.md-fences-advanced:not(.md-focus) { background: inherit; }
-.typora-export-show-outline .typora-export-content { max-width: 1440px; margin: auto; display: flex; flex-direction: row; }
-.typora-export-sidebar { width: 300px; font-size: 0.8rem; margin-top: 80px; margin-right: 18px; }
-.typora-export-show-outline #write { --webkit-flex:2; flex: 2 1 0%; }
-.typora-export-sidebar .outline-content { position: fixed; top: 0px; max-height: 100%; overflow: hidden auto; padding-bottom: 30px; padding-top: 60px; width: 300px; }
-@media screen and (max-width: 1024px) {
-  .typora-export-sidebar, .typora-export-sidebar .outline-content { width: 240px; }
-}
-@media screen and (max-width: 800px) {
-  .typora-export-sidebar { display: none; }
-}
-.outline-content li, .outline-content ul { margin-left: 0px; margin-right: 0px; padding-left: 0px; padding-right: 0px; list-style: none; }
-.outline-content ul { margin-top: 0px; margin-bottom: 0px; }
-.outline-content strong { font-weight: 400; }
-.outline-expander { width: 1rem; height: 1.42857rem; position: relative; display: table-cell; vertical-align: middle; cursor: pointer; padding-left: 4px; }
-.outline-expander::before { content: ""; position: relative; font-family: Ionicons; display: inline-block; font-size: 8px; vertical-align: middle; }
-.outline-item { padding-top: 3px; padding-bottom: 3px; cursor: pointer; }
-.outline-expander:hover::before { content: ""; }
-.outline-h1 > .outline-item { padding-left: 0px; }
-.outline-h2 > .outline-item { padding-left: 1em; }
-.outline-h3 > .outline-item { padding-left: 2em; }
-.outline-h4 > .outline-item { padding-left: 3em; }
-.outline-h5 > .outline-item { padding-left: 4em; }
-.outline-h6 > .outline-item { padding-left: 5em; }
-.outline-label { cursor: pointer; display: table-cell; vertical-align: middle; text-decoration: none; color: inherit; }
-.outline-label:hover { text-decoration: underline; }
-.outline-item:hover { border-color: rgb(245, 245, 245); background-color: var(--item-hover-bg-color); }
-.outline-item:hover { margin-left: -28px; margin-right: -28px; border-left: 28px solid transparent; border-right: 28px solid transparent; }
-.outline-item-single .outline-expander::before, .outline-item-single .outline-expander:hover::before { display: none; }
-.outline-item-open > .outline-item > .outline-expander::before { content: ""; }
-.outline-children { display: none; }
-.info-panel-tab-wrapper { display: none; }
-.outline-item-open > .outline-children { display: block; }
-.typora-export .outline-item { padding-top: 1px; padding-bottom: 1px; }
-.typora-export .outline-item:hover { margin-right: -8px; border-right: 8px solid transparent; }
-.typora-export .outline-expander::before { content: "+"; font-family: inherit; top: -1px; }
-.typora-export .outline-expander:hover::before, .typora-export .outline-item-open > .outline-item > .outline-expander::before { content: "−"; }
-.typora-export-collapse-outline .outline-children { display: none; }
-.typora-export-collapse-outline .outline-item-open > .outline-children, .typora-export-no-collapse-outline .outline-children { display: block; }
-.typora-export-no-collapse-outline .outline-expander::before { content: "" !important; }
-.typora-export-show-outline .outline-item-active > .outline-item .outline-label { font-weight: 700; }
-.md-inline-math-container mjx-container { zoom: 0.95; }
-mjx-container { break-inside: avoid; }
-
-
-.CodeMirror { height: auto; }
-.CodeMirror.cm-s-inner { background: inherit; }
-.CodeMirror-scroll { overflow: auto hidden; z-index: 3; }
-.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); }
-.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background: inherit; white-space: nowrap; }
-.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
-.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
-.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
-.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
-.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
-.cm-s-inner .cm-variable { color: rgb(0, 0, 0); }
-.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
-.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
-.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
-.cm-s-inner .cm-property { color: rgb(0, 0, 0); }
-.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
-.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
-.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
-.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
-.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
-.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
-.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
-.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
-.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
-.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); }
-.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
-.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
-.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
-.cm-negative { color: rgb(221, 68, 68); }
-.cm-positive { color: rgb(34, 153, 34); }
-.cm-header, .cm-strong { font-weight: 700; }
-.cm-del { text-decoration: line-through; }
-.cm-em { font-style: italic; }
-.cm-link { text-decoration: underline; }
-.cm-error { color: red; }
-.cm-invalidchar { color: red; }
-.cm-constant { color: rgb(38, 139, 210); }
-.cm-defined { color: rgb(181, 137, 0); }
-div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
-div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
-.cm-s-inner .CodeMirror-activeline-background { background: inherit; }
-.CodeMirror { position: relative; overflow: hidden; }
-.CodeMirror-scroll { height: 100%; outline: 0px; position: relative; box-sizing: content-box; background: inherit; }
-.CodeMirror-sizer { position: relative; }
-.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; outline: 0px; }
-.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow: hidden; }
-.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow: auto hidden; }
-.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
-.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
-.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 10px; z-index: 3; overflow-y: hidden; }
-.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
-.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: 0px 0px !important; border: none !important; }
-.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; }
-.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
-.CodeMirror-lines { cursor: text; }
-.CodeMirror pre { border-radius: 0px; border-width: 0px; background: 0px 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; overflow-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }
-.CodeMirror-wrap pre { overflow-wrap: break-word; white-space: pre-wrap; word-break: normal; }
-.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }
-.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }
-.CodeMirror-linebackground { position: absolute; inset: 0px; z-index: 0; }
-.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
-.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
-.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
-.CodeMirror-measure pre { position: static; }
-.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; }
-.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
-.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
-.cm-searching { background: rgba(255, 255, 0, 0.4); }
-span.cm-underlined { text-decoration: underline; }
-span.cm-strikethrough { text-decoration: line-through; }
-.cm-tw-syntaxerror { color: rgb(255, 255, 255); background-color: rgb(153, 0, 0); }
-.cm-tw-deleted { text-decoration: line-through; }
-.cm-tw-header5 { font-weight: 700; }
-.cm-tw-listitem:first-child { padding-left: 10px; }
-.cm-tw-box { border-style: solid; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-color: inherit; border-top-width: 0px !important; }
-.cm-tw-underline { text-decoration: underline; }
-@media print {
-  .CodeMirror div.CodeMirror-cursor { visibility: hidden; }
-}
-
-
-:root {
-    --side-bar-bg-color: #fafafa;
-    --control-text-color: #777;
-}
-
-@include-when-export url(https://fonts.loli.net/css?family=Open+Sans:400italic,700italic,700,400&subset=latin,latin-ext);
-
-/* open-sans-regular - latin-ext_latin */
-  /* open-sans-italic - latin-ext_latin */
-    /* open-sans-700 - latin-ext_latin */
-    /* open-sans-700italic - latin-ext_latin */
-  html {
-    font-size: 16px;
-    -webkit-font-smoothing: antialiased;
-}
-
-body {
-    font-family: "Open Sans","Clear Sans", "Helvetica Neue", Helvetica, Arial, 'Segoe UI Emoji', sans-serif;
-    color: rgb(51, 51, 51);
-    line-height: 1.6;
-}
-
-#write {
-    max-width: 860px;
-  	margin: 0 auto;
-  	padding: 30px;
-    padding-bottom: 100px;
-}
-
-@media only screen and (min-width: 1400px) {
-	#write {
-		max-width: 1024px;
-	}
-}
-
-@media only screen and (min-width: 1800px) {
-	#write {
-		max-width: 1200px;
-	}
-}
-
-#write > ul:first-child,
-#write > ol:first-child{
-    margin-top: 30px;
-}
-
-a {
-    color: #4183C4;
-}
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
-    position: relative;
-    margin-top: 1rem;
-    margin-bottom: 1rem;
-    font-weight: bold;
-    line-height: 1.4;
-    cursor: text;
-}
-h1:hover a.anchor,
-h2:hover a.anchor,
-h3:hover a.anchor,
-h4:hover a.anchor,
-h5:hover a.anchor,
-h6:hover a.anchor {
-    text-decoration: none;
-}
-h1 tt,
-h1 code {
-    font-size: inherit;
-}
-h2 tt,
-h2 code {
-    font-size: inherit;
-}
-h3 tt,
-h3 code {
-    font-size: inherit;
-}
-h4 tt,
-h4 code {
-    font-size: inherit;
-}
-h5 tt,
-h5 code {
-    font-size: inherit;
-}
-h6 tt,
-h6 code {
-    font-size: inherit;
-}
-h1 {
-    font-size: 2.25em;
-    line-height: 1.2;
-    border-bottom: 1px solid #eee;
-}
-h2 {
-    font-size: 1.75em;
-    line-height: 1.225;
-    border-bottom: 1px solid #eee;
-}
-
-/*@media print {
-    .typora-export h1,
-    .typora-export h2 {
-        border-bottom: none;
-        padding-bottom: initial;
-    }
-
-    .typora-export h1::after,
-    .typora-export h2::after {
-        content: "";
-        display: block;
-        height: 100px;
-        margin-top: -96px;
-        border-top: 1px solid #eee;
-    }
-}*/
-
-h3 {
-    font-size: 1.5em;
-    line-height: 1.43;
-}
-h4 {
-    font-size: 1.25em;
-}
-h5 {
-    font-size: 1em;
-}
-h6 {
-   font-size: 1em;
-    color: #777;
-}
-p,
-blockquote,
-ul,
-ol,
-dl,
-table{
-    margin: 0.8em 0;
-}
-li>ol,
-li>ul {
-    margin: 0 0;
-}
-hr {
-    height: 2px;
-    padding: 0;
-    margin: 16px 0;
-    background-color: #e7e7e7;
-    border: 0 none;
-    overflow: hidden;
-    box-sizing: content-box;
-}
-
-li p.first {
-    display: inline-block;
-}
-ul,
-ol {
-    padding-left: 30px;
-}
-ul:first-child,
-ol:first-child {
-    margin-top: 0;
-}
-ul:last-child,
-ol:last-child {
-    margin-bottom: 0;
-}
-blockquote {
-    border-left: 4px solid #dfe2e5;
-    padding: 0 15px;
-    color: #777777;
-}
-blockquote blockquote {
-    padding-right: 0;
-}
-table {
-    padding: 0;
-    word-break: initial;
-}
-table tr {
-    border: 1px solid #dfe2e5;
-    margin: 0;
-    padding: 0;
-}
-table tr:nth-child(2n),
-thead {
-    background-color: #f8f8f8;
-}
-table th {
-    font-weight: bold;
-    border: 1px solid #dfe2e5;
-    border-bottom: 0;
-    margin: 0;
-    padding: 6px 13px;
-}
-table td {
-    border: 1px solid #dfe2e5;
-    margin: 0;
-    padding: 6px 13px;
-}
-table th:first-child,
-table td:first-child {
-    margin-top: 0;
-}
-table th:last-child,
-table td:last-child {
-    margin-bottom: 0;
-}
-
-.CodeMirror-lines {
-    padding-left: 4px;
-}
-
-.code-tooltip {
-    box-shadow: 0 1px 1px 0 rgba(0,28,36,.3);
-    border-top: 1px solid #eef2f2;
-}
-
-.md-fences,
-code,
-tt {
-    border: 1px solid #e7eaed;
-    background-color: #f8f8f8;
-    border-radius: 3px;
-    padding: 0;
-    padding: 2px 4px 0px 4px;
-    font-size: 0.9em;
-}
-
-code {
-    background-color: #f3f4f4;
-    padding: 0 2px 0 2px;
-}
-
-.md-fences {
-    margin-bottom: 15px;
-    margin-top: 15px;
-    padding-top: 8px;
-    padding-bottom: 6px;
-}
-
-
-.md-task-list-item > input {
-  margin-left: -1.3em;
-}
-
-@media print {
-    html {
-        font-size: 13px;
-    }
-    pre {
-        page-break-inside: avoid;
-        word-wrap: break-word;
-    }
-}
-
-.md-fences {
-	background-color: #f8f8f8;
-}
-#write pre.md-meta-block {
-	padding: 1rem;
-    font-size: 85%;
-    line-height: 1.45;
-    background-color: #f7f7f7;
-    border: 0;
-    border-radius: 3px;
-    color: #777777;
-    margin-top: 0 !important;
-}
-
-.mathjax-block>.code-tooltip {
-	bottom: .375rem;
-}
-
-.md-mathjax-midline {
-    background: #fafafa;
-}
-
-#write>h3.md-focus:before{
-	left: -1.5625rem;
-	top: .375rem;
-}
-#write>h4.md-focus:before{
-	left: -1.5625rem;
-	top: .285714286rem;
-}
-#write>h5.md-focus:before{
-	left: -1.5625rem;
-	top: .285714286rem;
-}
-#write>h6.md-focus:before{
-	left: -1.5625rem;
-	top: .285714286rem;
-}
-.md-image>.md-meta {
-    /*border: 1px solid #ddd;*/
-    border-radius: 3px;
-    padding: 2px 0px 0px 4px;
-    font-size: 0.9em;
-    color: inherit;
-}
-
-.md-tag {
-    color: #a7a7a7;
-    opacity: 1;
-}
-
-.md-toc { 
-    margin-top:20px;
-    padding-bottom:20px;
-}
-
-.sidebar-tabs {
-    border-bottom: none;
-}
-
-#typora-quick-open {
-    border: 1px solid #ddd;
-    background-color: #f8f8f8;
-}
-
-#typora-quick-open-item {
-    background-color: #FAFAFA;
-    border-color: #FEFEFE #e5e5e5 #e5e5e5 #eee;
-    border-style: solid;
-    border-width: 1px;
-}
-
-/** focus mode */
-.on-focus-mode blockquote {
-    border-left-color: rgba(85, 85, 85, 0.12);
-}
-
-header, .context-menu, .megamenu-content, footer{
-    font-family: "Segoe UI", "Arial", sans-serif;
-}
-
-.file-node-content:hover .file-node-icon,
-.file-node-content:hover .file-node-open-state{
-    visibility: visible;
-}
-
-.mac-seamless-mode #typora-sidebar {
-    background-color: #fafafa;
-    background-color: var(--side-bar-bg-color);
-}
-
-.md-lang {
-    color: #b4654d;
-}
-
-/*.html-for-mac {
-    --item-hover-bg-color: #E6F0FE;
-}*/
-
-#md-notification .btn {
-    border: 0;
-}
-
-.dropdown-menu .divider {
-    border-color: #e5e5e5;
-    opacity: 0.4;
-}
-
-.ty-preferences .window-content {
-    background-color: #fafafa;
-}
-
-.ty-preferences .nav-group-item.active {
-    color: white;
-    background: #999;
-}
-
-.menu-item-container a.menu-style-btn {
-    background-color: #f5f8fa;
-    background-image: linear-gradient( 180deg , hsla(0, 0%, 100%, 0.8), hsla(0, 0%, 100%, 0)); 
-}
-
-
-
-</style><title>panama_ffi</title>
-</head>
-<body class='typora-export'><div class='typora-export-content'>
-<div id='write'  class=''><h2 id='state-of-foreign-function-support'><span>State of foreign function support</span></h2><p><strong><span>January 2023</span></strong></p><p><strong><span>Maurizio Cimadamore</span></strong></p><p><span>The Foreign Function &amp; Memory API (FFM API in short) provides access to foreign functions through the </span><code>Linker</code><span> interface, which has been available as an </span><a href='https://openjdk.java.net/jeps/11'><span>incubating</span></a><span> API since Java </span><a href='https://openjdk.java.net/jeps/389'><span>16</span></a><span>. A linker allows clients to construct </span><em><span>downcall</span></em><span> method handles — that is, method handles whose invocation targets a native function defined in some native library. In other words, FFM API&#39;s foreign function support is completely expressed in terms of Java code and no intermediate native code is required.</span></p><h3 id='zero-length-memory-segments'><span>Zero-length memory segments</span></h3><p><span>Before we dive into the specifics of the foreign function support, it would be useful to briefly recap some of the main concepts we have learned when exploring the </span><a href='panama_memaccess.md'><span>foreign memory access support</span></a><span>. The Foreign Memory Access API allows client to create and manipulate </span><em><span>memory segments</span></em><span>. A memory segment is a view over a memory source (either on- or off-heap) which is spatially bounded, temporally bounded and thread-confined. The guarantees ensure that dereferencing a segment that has been created by Java code is always </span><em><span>safe</span></em><span>, and can never result in a VM crash, or, worse, in silent memory corruption.</span></p><p><span>Now, in the case of memory segments, the above properties (spatial bounds, temporal bounds and confinement) can be known </span><em><span>in full</span></em><span> when the segment is created. But when we interact with native libraries we often receive </span><em><span>raw</span></em><span> pointers; such pointers have no spatial bounds (does a </span><code>char*</code><span> in C refer to one </span><code>char</code><span>, or a </span><code>char</code><span> array of a given size?), no notion of temporal bounds, nor thread-confinement. Raw addresses in the FFM API are modelled using </span><em><span>zero-length memory segments</span></em><span>.</span></p><p><span>If clients want to dereference a zero-length memory segment, they can do so </span><em><span>unsafely</span></em><span> in two ways. First, the client can create a new memory segment from the zero-length memory segment </span><em><span>unsafely</span></em><span>, using the </span><code>MemorySegment::ofAddress</code><span> factory. This method is </span><em><span>restricted</span></em><span> and will generate runtime warnings if called without specifying the </span><code>--enable-native-access</code><span> command-line flag. By calling </span><code>MemorySegment::ofAddress</code><span> a client inject extra knowledge about spatial bounds which might be available in the native library the client is interacting with:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 758.438px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MemorySegment</span> <span class="cm-variable">raw</span> <span class="cm-operator">=</span> ... <span class="cm-comment">//obtain address from native code</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">segment</span> <span class="cm-operator">=</span> <span class="cm-variable">MemorySegment</span>.<span class="cm-variable">ofAddress</span>(<span class="cm-variable">raw</span>.<span class="cm-variable">address</span>(), <span class="cm-number">100</span>, <span class="cm-variable">arena</span>.<span class="cm-variable">scope</span>());</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable-3">int</span> <span class="cm-variable">x</span> <span class="cm-operator">=</span> <span class="cm-variable">segment</span>.<span class="cm-variable">get</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 115px;"></div><div class="CodeMirror-gutters" style="display: none; height: 115px;"></div></div></div></pre><p><span>Alternatively, clients can obtain an </span><em><span>unbounded</span></em><span> address value layout. This is done using the </span><code>ValueLayout.OfAddress::asUnbounded</code><span> method (which is also a restricted method). When an access operation uses an unbounded address value layouts, the runtime will wrap any corresponding raw addresses with native segments with </span><em><span>maximal</span></em><span> size (i.e. </span><code>Long.MAX_VALUE</code><span>). As such, these segments can be accessed directly, as follows:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 1138.39px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MemorySegment</span> <span class="cm-variable">foreign</span> <span class="cm-operator">=</span> <span class="cm-variable">someSegment</span>.<span class="cm-variable">get</span>(<span class="cm-variable">ValueLayout</span>.<span class="cm-variable">ADDRESS</span>.<span class="cm-variable">asUnbounded</span>(), <span class="cm-number">0</span>); <span class="cm-comment">// wrap address into segment (size = Long.MAX_VALUE)</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">int</span> <span class="cm-variable">x</span> <span class="cm-operator">=</span> <span class="cm-variable">foreign</span>.<span class="cm-variable">get</span>(<span class="cm-variable">ValueLayout</span>.<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>); <span class="cm-comment">//ok</span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 46px;"></div><div class="CodeMirror-gutters" style="display: none; height: 46px;"></div></div></div></pre><p><span>Which approach is taken largely depends on the information that a client has available when obtaining a memory segment wrapping a native pointer. For instance, if such pointer points to a C struct, the client might prefer to resize the segment unsafely, to match the size of the struct (so that out-of-bounds access will be detected by the API). In other instances, however, there will be no, or little information as to what spatial and/or temporal bounds should be associated with a given native pointer. In these cases using an unbounded address layout might be preferable.</span></p><h3 id='segment-allocators'><span>Segment allocators</span></h3><p><span>Idiomatic C code implicitly relies on stack allocation to allow for concise variable declarations; consider this example:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="c"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="c"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 267.219px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 266.219px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre>x</pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">int</span> <span class="cm-variable">arr</span>[] <span class="cm-operator">=</span> { <span class="cm-number">0</span>, <span class="cm-number">1</span>, <span class="cm-number">2</span>, <span class="cm-number">3</span>, <span class="cm-number">4</span> };</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 23px;"></div><div class="CodeMirror-gutters" style="display: none; height: 23px;"></div></div></div></pre><p><span>A variable initializer such as the one above can be implemented as follows, using the Foreign Memory Access API:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 957.078px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span> <span class="cm-def">openConfined</span>()) {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">arr</span> <span class="cm-operator">=</span> <span class="cm-variable">MemorySegment</span>.<span class="cm-variable">allocateNative</span>(<span class="cm-variable">MemoryLayout</span>.<span class="cm-variable">sequenceLayout</span>(<span class="cm-number">5</span>, <span class="cm-variable">JAVA_INT</span>), <span class="cm-variable">arena</span>.<span class="cm-variable">scope</span>());</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">for</span> (<span class="cm-variable-3">int</span> <span class="cm-variable">i</span> <span class="cm-operator">=</span> <span class="cm-number">0</span> ; <span class="cm-variable">i</span> <span class="cm-operator">&lt;</span> <span class="cm-number">5</span> ; <span class="cm-variable">i</span><span class="cm-operator">++</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">arr</span>.<span class="cm-variable">setAtIndex</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">i</span>, <span class="cm-variable">i</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 138px;"></div><div class="CodeMirror-gutters" style="display: none; height: 138px;"></div></div></div></pre><p><span>There are a number of issues with the above code snippet:</span></p><ul><li><span>compared to the C code, it is more verbose — the native array has to be initialized </span><em><span>element by element</span></em></li><li><span>allocation is very slow compared to C; allocating the </span><code>arr</code><span> variable now takes a full </span><code>malloc</code><span>, while in C the variable was simply stack-allocated</span></li><li><span>when having multiple declarations like the one above, it might become increasingly harder to manage the lifecycle of the various segments</span></li></ul><p><span>To address these problems, the FFM API provides a </span><code>SegmentAllocator</code><span> abstraction, a functional interface which provides methods to allocate commonly used values. Since </span><code>Arena</code><span> implements the </span><code>SegmentAllocator</code><span> interface, the above code can be rewritten conveniently as follows:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 55.6172px; left: 241.188px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 603.016px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre>x</pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">arr</span> <span class="cm-operator">=</span> <span class="cm-variable">arena</span>.<span class="cm-variable">allocateArray</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>, <span class="cm-number">1</span>, <span class="cm-number">2</span>, <span class="cm-number">3</span>, <span class="cm-number">4</span>);</span></pre><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">} <span class="cm-comment">// 'arr' is released here</span></span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 69px;"></div><div class="CodeMirror-gutters" style="display: none; height: 69px;"></div></div></div></pre><p><span>In the above code, the arena acts as a </span><em><span>native</span></em><span> allocator (that is, an allocator built on top of </span><code>MemorySegment::allocateNative</code><span>). The arena is then used to create a native array, initialized to the values </span><code>0, 1, 2, 3, 4</code><span>.  The array initialization is more efficient, compared to the previous snippet, as the Java array is copied </span><em><span>in bulk</span></em><span> into the memory region associated with the newly allocated memory segment. The returned segment is associated with the scope of the arena which performed the allocation, meaning that the segment will no longer be accessible after the try-with-resource construct.</span></p><p><span>Custom segment allocators are also critical to achieve optimal allocation performance; for this reason, a number of predefined allocators are available via factories in the </span><code>SegmentAllocator</code><span> interface. For example, the following code creates a </span><em><span>slicing</span></em><span> allocator and uses it to allocate a segment whose content is initialized from a Java </span><code>int</code><span> array:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 170.852px; left: 379.359px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 784.406px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre>x</pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">SegmentAllocator</span> <span class="cm-variable">allocator</span> <span class="cm-operator">=</span> <span class="cm-variable">SegmentAllocator</span>.<span class="cm-variable">slicingAllocator</span>(<span class="cm-variable">arena</span>.<span class="cm-variable">allocate</span>(<span class="cm-number">1024</span>));</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">for</span> (<span class="cm-variable-3">int</span> <span class="cm-variable">i</span> <span class="cm-operator">=</span> <span class="cm-number">0</span> ; <span class="cm-variable">i</span> <span class="cm-operator">&lt;</span> <span class="cm-number">10</span> ; <span class="cm-variable">i</span><span class="cm-operator">++</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">MemorySegment</span> <span class="cm-variable">s</span> <span class="cm-operator">=</span> <span class="cm-variable">allocator</span>.<span class="cm-variable">allocateArray</span>(<span class="cm-variable">JAVA_INT</span>,  <span class="cm-keyword">new</span> <span class="cm-variable-3">int</span>[] { <span class="cm-number">1</span>, <span class="cm-number">2</span>, <span class="cm-number">3</span>, <span class="cm-number">4</span>, <span class="cm-number">5</span> });</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        ...</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    ...</span></pre><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> } <span class="cm-comment">// all memory allocated is released here</span></span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 184px;"></div><div class="CodeMirror-gutters" style="display: none; height: 184px;"></div></div></div></pre><p><span>This code creates a native segment whose size is 1024 bytes. The segment is then used to create a slicing allocator, which responds to  allocation requests by returning slices of that pre-allocated segment.  If the current segment does not have sufficient space to accommodate an  allocation request, an exception is thrown. All of the memory associated with the segments created by the allocator (i.e., in the body of the  for loop) is deallocated atomically when the arena is closed. This  technique combines the advantages of deterministic deallocation,  provided by the </span><code>Arena</code><span> abstraction, with a more flexible and scalable allocation scheme. It can be very useful when writing code  which manages a large number of off-heap segments.</span></p><p><span>All the methods in the FFM API which </span><em><span>produce</span></em><span> memory segments (see </span><code>VaList::nextVarg</code><span> and downcall method handles), allow for an allocator parameter to be provided — this is key in ensuring that an application using the FFM API achieves optimal allocation performances, especially in non-trivial use cases.</span></p><h3 id='symbol-lookups'><span>Symbol lookups</span></h3><p><span>The first ingredient of any foreign function support is a mechanism to lookup symbols in native libraries. In traditional Java/JNI, this is done via the </span><code>System::loadLibrary</code><span> and </span><code>System::load</code><span> methods. Unfortunately, these methods do not provide a way for clients to obtain the </span><em><span>address</span></em><span> associated with a given library symbol. For this reason, the Foreign Linker API introduces a new abstraction, namely </span><code>SymbolLookup</code><span> (similar in spirit to a method handle lookup), which provides capabilities to lookup named symbols; we can obtain a symbol lookup in 3 different ways:</span></p><ul><li><code>SymbolLookup::libraryLookup(String, SegmentScope)</code><span> — creates a symbol lookup which can be used to search symbol in a library with the given name. The provided segment scope parameter controls the library lifecycle: that is, when the scope is not longer alive, the library referred to by the lookup will also be closed;</span></li><li><code>SymbolLookup::loaderLookup</code><span> — creates a symbol lookup which can be used to search symbols in all the libraries loaded by the caller&#39;s classloader (e.g. using </span><code>System::loadLibrary</code><span> or </span><code>System::load</code><span>)</span></li><li><code>Linker::defaultLookup</code><span> — returns the default symbol lookup associated with a </span><code>Linker</code><span> instance. For instance, the default lookup of the native linker (see </span><code>Linker::nativeLinker</code><span>) can be used to look up platform-specific symbols in the standard C library (such as </span><code>strlen</code><span>, or </span><code>getpid</code><span>).</span></li></ul><p><span>Once a lookup has been obtained, a client can use it to retrieve handles to library symbols (either global variables or functions) using the </span><code>find(String)</code><span> method, which returns an </span><code>Optional&lt;MemorySegment&gt;</code><span>.  The memory segments returned by the </span><code>lookup</code><span> are zero-length segments, whose base address is the address of the function or variable in the library.</span></p><p><span>For instance, the following code can be used to look up the </span><code>clang_getClangVersion</code><span> function provided by the </span><code>clang</code><span> library; it does so by creating a </span><em><span>library lookup</span></em><span> whose lifecycle is associated to that of a confined arena.</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 741.141px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">SymbolLookup</span> <span class="cm-variable">libclang</span> <span class="cm-operator">=</span> <span class="cm-variable">SymbolLookup</span>.<span class="cm-variable">libraryLookup</span>(<span class="cm-string">"libclang.so"</span>, <span class="cm-variable">arena</span>.<span class="cm-variable">scope</span>());</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">clangVersion</span> <span class="cm-operator">=</span> <span class="cm-variable">libclang</span>.<span class="cm-variable">find</span>(<span class="cm-string">"clang_getClangVersion"</span>).<span class="cm-variable">get</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 92px;"></div><div class="CodeMirror-gutters" style="display: none; height: 92px;"></div></div></div></pre><h3 id='linker'><span>Linker</span></h3><p><span>At the core of the FFM API&#39;s foreign function support we find the </span><code>Linker</code><span> abstraction. This abstraction plays a dual role: first, for downcalls, it allows modelling foreign function calls as plain </span><code>MethodHandle</code><span> calls (see </span><code>Linker::downcallHandle</code><span>); second, for upcalls, it allows to convert an existing </span><code>MethodHandle</code><span> (which might point to some Java method) into a </span><code>MemorySegment</code><span> which could then be passed to foreign functions as a function pointer (see </span><code>Linker::upcallStub</code><span>):</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 862.062px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><span><span>​</span>x</span></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">interface</span> <span class="cm-def">Linker</span> {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MethodHandle</span> <span class="cm-variable">downcallHandle</span>(<span class="cm-variable">Addressable</span> <span class="cm-variable">symbol</span>, <span class="cm-variable">FunctionDescriptor</span> <span class="cm-variable">function</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">upcallStub</span>(<span class="cm-variable">MethodHandle</span> <span class="cm-variable">target</span>, <span class="cm-variable">FunctionDescriptor</span> <span class="cm-variable">function</span>, <span class="cm-variable">SegmentScope</span> <span class="cm-variable">scope</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    ... <span class="cm-comment">// some overloads omitted here</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">static</span> <span class="cm-variable">Linker</span> <span class="cm-variable">nativeLinker</span>() { ... }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 161px;"></div><div class="CodeMirror-gutters" style="display: none; height: 161px;"></div></div></div></pre><p><span>Both functions take a </span><code>FunctionDescriptor</code><span> instance — essentially an aggregate of memory layouts which is used to describe the argument and return types of a foreign function in full. Supported layouts are </span><em><span>value layouts</span></em><span> (for scalars and pointers) and </span><em><span>group layouts</span></em><span> (for structs/unions). Each layout in a function descriptor is associated with a carrier Java type (see table below); together, all the carrier types associated with layouts in a function descriptor will determine a unique Java </span><code>MethodType</code><span>  — that is, the Java signature that clients will be using when interacting with said downcall handles, or upcall stubs.</span></p><p><span>The </span><code>Linker::nativeLinker</code><span> factory is used to obtain a </span><code>Linker</code><span> implementation for the ABI associated with the OS and processor where the Java runtime is currently executing. As such, the native linker can be used to call C functions. The following table shows the mapping between C types, layouts and Java carriers under the Linux/macOS native linker implementation; note that the mappings can be platform dependent: on Windows/x64, the C type </span><code>long</code><span> is 32-bit, so the </span><code>JAVA_INT</code><span> layout (and the Java carrier </span><code>int.class</code><span>) would have to be used instead:</span></p><figure><table><thead><tr><th><span>C type</span></th><th><span>Layout</span></th><th><span>Java carrier</span></th></tr></thead><tbody><tr><td><code>bool</code></td><td><code>JAVA_BOOLEAN</code></td><td><code>byte</code></td></tr><tr><td><code>char</code></td><td><code>JAVA_BYTE</code></td><td><code>byte</code></td></tr><tr><td><code>short</code></td><td><code>JAVA_SHORT</code></td><td><code>short</code><span>, </span><code>char</code></td></tr><tr><td><code>int</code></td><td><code>JAVA_INT</code></td><td><code>int</code></td></tr><tr><td><code>long</code></td><td><code>JAVA_LONG</code></td><td><code>long</code></td></tr><tr><td><code>long long</code></td><td><code>JAVA_LONG</code></td><td><code>long</code></td></tr><tr><td><code>float</code></td><td><code>JAVA_FLOAT</code></td><td><code>float</code></td></tr><tr><td><code>double</code></td><td><code>JAVA_DOUBLE</code></td><td><code>double</code></td></tr><tr><td><code>char*</code><br><code>int**</code><br><span> ...</span></td><td><code>ADDRESS</code></td><td><code>MemorySegment</code></td></tr><tr><td><code>struct Point { int x; int y; };</code><br><code>union Choice { float a; int b; };</code><br><span>...</span></td><td><code>MemoryLayout.structLayout(...)</code><br><code>MemoryLayout.unionLayout(...)</code><br></td><td><code>MemorySegment</code></td></tr></tbody></table></figure><p><span>Both C structs/unions and pointers are modelled using the </span><code>MemorySegment</code><span> carrier type. However, C structs/unions are modelled in function descriptors with memory layouts of type </span><code>GroupLayout</code><span>, whereas pointers are modelled using the </span><code>ADDRESS</code><span> value layout constant (whose size is platform-specific). Moreover, the behavior of a downcall method handle returning a struct/union type is radically different from that of a downcall method handle returning a C pointer:</span></p><ul><li><span>downcall method handles returning C pointers will wrap the pointer address into a fresh zero-length memory segment (unless an unbounded address layout is specified);</span></li><li><span>downcall method handles returning a C struct/union type will return a </span><em><span>new</span></em><span> segment, of given size (the size of the struct/union). The segment is allocated using a user-provided </span><code>SegmentAllocator</code><span>, which is provided using an additional prefix parameter inserted in the downcall method handle signature.</span></li></ul><p><span>A tool, such as </span><code>jextract</code><span>, will generate all the required C layouts (for scalars and structs/unions) </span><em><span>automatically</span></em><span>, so that clients do not have to worry about platform-dependent details such as sizes, alignment constraints and padding.</span></p><h3 id='downcalls'><span>Downcalls</span></h3><p><span>We will now look at how foreign functions can be called from Java using the native linker. Assume we wanted to call the following function from the standard C library:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="c"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="c"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 257.516px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">size_t</span> <span class="cm-def">strlen</span>(<span class="cm-keyword">const</span> <span class="cm-variable-3">char</span> <span class="cm-variable-3">*</span><span class="cm-variable">s</span>);</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 23px;"></div><div class="CodeMirror-gutters" style="display: none; height: 23px;"></div></div></div></pre><p><span>In order to do that, we have to:</span></p><ul><li><span>lookup the </span><code>strlen</code><span> symbol</span></li><li><span>describe the signature of the C function using a function descriptor</span></li><li><span>create a </span><em><span>downcall</span></em><span> native method handle with the above information, using the native linker</span></li></ul><p><span>Here&#39;s an example of how we might want to do that (a full listing of all the examples in this and subsequent sections will be provided in the </span><a href='#appendix-full-source-code'><span>appendix</span></a><span>):</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 456.156px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">Linker</span> <span class="cm-variable">linker</span> <span class="cm-operator">=</span> <span class="cm-variable">Linker</span>.<span class="cm-variable">nativeLinker</span>();</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MethodHandle</span> <span class="cm-variable">strlen</span> <span class="cm-operator">=</span> <span class="cm-variable">linker</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">linker</span>.<span class="cm-variable">defaultLookup</span>().<span class="cm-variable">find</span>(<span class="cm-string">"strlen"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">ADDRESS</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">);</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 115px;"></div><div class="CodeMirror-gutters" style="display: none; height: 115px;"></div></div></div></pre><p><span>Note that, since the function </span><code>strlen</code><span> is part of the standard C library, which is loaded with the VM, we can just use the default lookup of the native linker to look it up. The rest is pretty straightforward — the only tricky detail is how to model </span><code>size_t</code><span>: typically this type has the size of a pointer, so we can use </span><code>JAVA_LONG</code><span> both Linux and Windows. On the Java side, we model the </span><code>size_t</code><span> using a </span><code>long</code><span> and the pointer is modelled using an </span><code>Addressable</code><span> parameter.</span></p><p><span>Once we have obtained the downcall method handle, we can just use it as any other method handle</span><a href="#2"><sup><span>1</span></sup></a><span>:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 602.984px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable-3">long</span> <span class="cm-variable">len</span> <span class="cm-operator">=</span> <span class="cm-variable">strlen</span>.<span class="cm-variable">invoke</span>(<span class="cm-variable">arena</span>.<span class="cm-variable">allocateUtf8String</span>(<span class="cm-string">"Hello"</span>)); <span class="cm-comment">// 5</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 69px;"></div><div class="CodeMirror-gutters" style="display: none; height: 69px;"></div></div></div></pre><p><span>Here we are using a confined arena to convert a Java string into an off-heap memory segment which contains a </span><code>NULL</code><span> terminated C string. We then pass that segment to the method handle and retrieve our result in a Java </span><code>long</code><span>. Note how all this is possible </span><em><span>without</span></em><span> any piece of intervening native code — all the interop code can be expressed in (low level) Java. Note also how we use an arena to control the lifecycle of the allocated C string, which ensures timely deallocation of the memory segment holding the native string.</span></p><p><span>The </span><code>Linker</code><span> interface also supports linking of native functions without an address known at link time; when that happens, an address (of type </span><code>MemorySegment</code><span>) must be provided when the method handle returned by the linker is invoked — this is very useful to support </span><em><span>virtual calls</span></em><span>. For instance, the above code can be rewritten as follows:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 715.219px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MethodHandle</span> <span class="cm-variable">strlen_virtual</span> <span class="cm-operator">=</span> <span class="cm-variable">linker</span>.<span class="cm-variable">downcallHandle</span>( <span class="cm-comment">// address parameter missing!</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">ADDRESS</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span> <span class="cm-def">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable-3">long</span> <span class="cm-variable">len</span> <span class="cm-operator">=</span> <span class="cm-variable">strlen_virtual</span>.<span class="cm-variable">invoke</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">linker</span>.<span class="cm-variable">defaultLookup</span>().<span class="cm-variable">find</span>(<span class="cm-string">"strlen"</span>).<span class="cm-variable">get</span>() <span class="cm-comment">// address provided here!</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">arena</span>.<span class="cm-variable">allocateUtf8String</span>(<span class="cm-string">"Hello"</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    ); <span class="cm-comment">// 5</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 230px;"></div><div class="CodeMirror-gutters" style="display: none; height: 230px;"></div></div></div></pre><p><span>It is important to note that, albeit the interop code is written in Java, the above code can </span><em><span>not</span></em><span> be considered 100% safe. There are many arbitrary decisions to be made when setting up downcall method handles such as the one above, some of which might be obvious to us (e.g. how many parameters does the function take), but which cannot ultimately be verified by the Java runtime. After all, a symbol in a dynamic library is nothing but a numeric offset and, unless we are using a shared library with debugging information, no type information is attached to a given library symbol. This means that the Java runtime has to </span><em><span>trust</span></em><span> the function descriptor passed in</span><a href="#2"><sup><span>2</span></sup></a><span>; for this reason, the </span><code>Linker::nativeLinker</code><span> factory is also a restricted method.</span></p><p><span>When working with shared arenas, it is always possible for the arena associated with a memory segment passed </span><em><span>by reference</span></em><span> to a native function to be closed (by another thread) </span><em><span>while</span></em><span> the native function is executing. When this happens, the native code is at risk of dereferencing already-freed memory, which might trigger a JVM crash, or even result in silent memory corruption. For this reason, the </span><code>Linker</code><span> API provides some basic temporal safety guarantees: any </span><code>MemorySegment</code><span> instance passed by reference to a downcall method handle will be </span><em><span>kept alive</span></em><span> for the entire duration of the call. In other words, it&#39;s as if the call to the downcall method handle occurred inside an invisible call to </span><code>SegmentScope::whileAlive</code><span>.</span></p><p><span>Performance-wise, the reader might ask how efficient calling a foreign function using a native method handle is; the answer is </span><em><span>very</span></em><span>. The JVM comes with some special support for native method handles, so that, if a give method handle is invoked many times (e.g, inside a </span><em><span>hot</span></em><span> loop), the JIT compiler might decide to generate a snippet of assembly code required to call the native function, and execute that directly. In most cases, invoking native function this way is as efficient as doing so through JNI.</span></p><h3 id='upcalls'><span>Upcalls</span></h3><p><span>Sometimes, it is useful to pass Java code as a function pointer to some native function; we can achieve that by using foreign linker support for upcalls. To demonstrate this, let&#39;s consider the following function from the C standard library:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="c"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="c"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 473.469px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">void</span> <span class="cm-def">qsort</span>(<span class="cm-variable-3">void</span> <span class="cm-variable-3">*</span><span class="cm-variable">base</span>, <span class="cm-variable-3">size_t</span> <span class="cm-variable">nmemb</span>, <span class="cm-variable-3">size_t</span> <span class="cm-variable">size</span>,</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">           <span class="cm-variable-3">int</span> (<span class="cm-operator">*</span><span class="cm-variable">compar</span>)(<span class="cm-keyword">const</span> <span class="cm-variable-3">void</span> <span class="cm-variable-3">*</span>, <span class="cm-keyword">const</span> <span class="cm-variable-3">void</span> <span class="cm-variable-3">*</span>));</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 46px;"></div><div class="CodeMirror-gutters" style="display: none; height: 46px;"></div></div></div></pre><p><span>The </span><code>qsort</code><span> function can be used to sort the contents of an array, using a custom comparator function — </span><code>compar</code><span> — which is passed as a function pointer. To be able to call the </span><code>qsort</code><span> function from Java we have first to create a downcall method handle for it:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 637.516px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">Linker</span> <span class="cm-variable">linker</span> <span class="cm-operator">=</span> <span class="cm-variable">Linker</span>.<span class="cm-variable">nativeLinker</span>();</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MethodHandle</span> <span class="cm-variable">qsort</span> <span class="cm-operator">=</span> <span class="cm-variable">linker</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-variable">linker</span>.<span class="cm-variable">defaultLookup</span>().<span class="cm-variable">lookup</span>(<span class="cm-string">"qsort"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">ofVoid</span>(<span class="cm-variable">ADDRESS</span>, <span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">ADDRESS</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">);</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 115px;"></div><div class="CodeMirror-gutters" style="display: none; height: 115px;"></div></div></div></pre><p><span>As before, we use </span><code>JAVA_LONG</code><span> and </span><code>long.class</code><span> to map the C </span><code>size_t</code><span> type, and </span><code>ADDRESS</code><span> for both the first pointer parameter (the array pointer) and the last parameter (the function pointer).</span></p><p><span>This time, in order to invoke the </span><code>qsort</code><span> downcall handle, we need a </span><em><span>function pointer</span></em><span> to be passed as the last parameter; this is where the upcall support in foreign linker comes in handy, as it allows us to create a function pointer out of an existing method handle. First, let&#39;s write a function that can compare two int elements (passed as pointers):</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 620.25px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">class</span> <span class="cm-def">Qsort</span> {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-keyword">static</span> <span class="cm-variable-3">int</span> <span class="cm-variable">qsortCompare</span>(<span class="cm-variable">MemoryAddress</span> <span class="cm-variable">addr1</span>, <span class="cm-variable">MemoryAddress</span> <span class="cm-variable">addr2</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-keyword">return</span> <span class="cm-variable">addr1</span>.<span class="cm-variable">get</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>) <span class="cm-operator">-</span> <span class="cm-variable">addr2</span>.<span class="cm-variable">get</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tab" role="presentation" cm-text="	">    </span>}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 115px;"></div><div class="CodeMirror-gutters" style="display: none; height: 115px;"></div></div></div></pre><p><span>Here we can see that the function is performing some </span><em><span>unsafe</span></em><span> dereference of the pointer contents.</span></p><p><span>Now let&#39;s create a method handle pointing to the comparator function above:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 741.078px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">FunctionDescriptor</span> <span class="cm-variable">comparDesc</span> <span class="cm-operator">=</span> <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">ADDRESS</span>, <span class="cm-variable">ADDRESS</span>);</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MethodHandle</span> <span class="cm-variable">comparHandle</span> <span class="cm-operator">=</span> <span class="cm-variable">MethodHandles</span>.<span class="cm-variable">lookup</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                                         .<span class="cm-variable">findStatic</span>(<span class="cm-variable">Qsort</span>.<span class="cm-keyword">class</span>, <span class="cm-string">"qsortCompare"</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                                                     <span class="cm-variable">CLinker</span>.<span class="cm-variable">upcallType</span>(<span class="cm-variable">comparDesc</span>));</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 92px;"></div><div class="CodeMirror-gutters" style="display: none; height: 92px;"></div></div></div></pre><p><span>To do that, we first create a function descriptor for the function pointer type, and then we use the </span><code>CLinker::upcallType</code><span> to turn that function descriptor into a suitable </span><code>MethodType</code><span> instance to be used in a method handle lookup. Now that we have a method handle for our Java comparator function, we finally have all the ingredients to create an upcall stub, and pass it to the </span><code>qsort</code><span> downcall handle:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 732.5px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">comparFunc</span> <span class="cm-operator">=</span> <span class="cm-variable">linker</span>.<span class="cm-variable">upcallStub</span>(<span class="cm-variable">comparHandle</span>, <span class="cm-variable">comparDesc</span>, <span class="cm-variable">session</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">MemorySegment</span> <span class="cm-variable">array</span> <span class="cm-operator">=</span> <span class="cm-variable">session</span>.<span class="cm-variable">allocateArray</span>(<span class="cm-number">0</span>, <span class="cm-number">9</span>, <span class="cm-number">3</span>, <span class="cm-number">4</span>, <span class="cm-number">6</span>, <span class="cm-number">5</span>, <span class="cm-number">1</span>, <span class="cm-number">8</span>, <span class="cm-number">2</span>, <span class="cm-number">7</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">qsort</span>.<span class="cm-variable">invoke</span>(<span class="cm-variable">array</span>, <span class="cm-number">10L</span>, <span class="cm-number">4L</span>, <span class="cm-variable">comparFunc</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable-3">int</span>[] <span class="cm-variable">sorted</span> <span class="cm-operator">=</span> <span class="cm-variable">array</span>.<span class="cm-variable">toArray</span>(<span class="cm-variable">JAVA_INT</span>); <span class="cm-comment">// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 138px;"></div><div class="CodeMirror-gutters" style="display: none; height: 138px;"></div></div></div></pre><p><span>The above code creates an upcall stub — </span><code>comparFunc</code><span> — a function pointer that can be used to invoke our Java comparator function, of type </span><code>MemorySegment</code><span>. The upcall stub is associated with the provided segment scope instance; this means that the stub will be uninstalled when the arena is closed.</span></p><p><span>The snippet then creates an off-heap array from a Java array, which is then passed to the </span><code>qsort</code><span> handle, along with the comparator function we obtained from the foreign linker.  As a side effect, after the call, the contents of the off-heap array will be sorted (as instructed by our comparator function, written in Java). We can than extract a new Java array from the segment, which contains the sorted elements. This is a more advanced example, but one that shows how powerful the native interop support provided by the foreign linker abstraction is, allowing full bidirectional interop support between Java and native.</span></p><h3 id='varargs'><span>Varargs</span></h3><p><span>Some C functions are </span><em><span>variadic</span></em><span> and can take an arbitrary number of arguments. Perhaps the most common example of this is the </span><code>printf</code><span> function, defined in the C standard library:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="c"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="c"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 317.969px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable-3">int</span> <span class="cm-def">printf</span>(<span class="cm-keyword">const</span> <span class="cm-variable-3">char</span> <span class="cm-variable-3">*</span><span class="cm-variable">format</span>, ...);</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 23px;"></div><div class="CodeMirror-gutters" style="display: none; height: 23px;"></div></div></div></pre><p><span>This function takes a format string, which features zero or more </span><em><span>holes</span></em><span>, and then can take a number of additional arguments that is identical to the number of holes in the format string.</span></p><p><span>The foreign function support can support variadic calls, but with a caveat: the client must provide a specialized Java signature, and a specialized description of the C signature. For instance, let&#39;s say we wanted to model the following C call:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="C"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="c"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 352.516px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">printf</span>(<span class="cm-string">"%d plus %d equals %d"</span>, <span class="cm-number">2</span>, <span class="cm-number">2</span>, <span class="cm-number">4</span>);</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 23px;"></div><div class="CodeMirror-gutters" style="display: none; height: 23px;"></div></div></div></pre><p><span>To do this using the foreign function support provided by the FFM API we would have to build a </span><em><span>specialized</span></em><span> downcall handle for that call shape, using a linker option to specify the position of the first variadic layout, as follows:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 680.703px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre>x</pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">Linker</span> <span class="cm-variable">linker</span> <span class="cm-operator">=</span> <span class="cm-variable">Linker</span>.<span class="cm-variable">nativeLinker</span>();</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">MethodHandle</span> <span class="cm-variable">printf</span> <span class="cm-operator">=</span> <span class="cm-variable">linker</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-tab" role="presentation" cm-text="	">    </span><span class="cm-variable">linker</span>.<span class="cm-variable">defaultLookup</span>().<span class="cm-variable">lookup</span>(<span class="cm-string">"printf"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">ADDRESS</span>, <span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">JAVA_INT</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">Linker</span>.<span class="cm-variable">Option</span>.<span class="cm-variable">firstVariadicArg</span>(<span class="cm-number">1</span>) <span class="cm-comment">// first int is variadic</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">);</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 138px;"></div><div class="CodeMirror-gutters" style="display: none; height: 138px;"></div></div></div></pre><p><span>Then we can call the specialized downcall handle as usual:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 922.547px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-variable">printf</span>.<span class="cm-variable">invoke</span>(<span class="cm-variable">arena</span>.<span class="cm-variable">allocateUtf8String</span>(<span class="cm-string">"%d plus %d equals %d"</span>), <span class="cm-number">2</span>, <span class="cm-number">2</span>, <span class="cm-number">4</span>); <span class="cm-comment">//prints "2 plus 2 equals 4"</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 69px;"></div><div class="CodeMirror-gutters" style="display: none; height: 69px;"></div></div></div></pre><p><span>While this works, and provides optimal performance, it has some limitations</span><a href="#3"><sup><span>3</span></sup></a><span>:</span></p><ul><li><span>If the variadic function needs to be called with many shapes, we have to create many downcall handles</span></li><li><span>while this approach works for downcalls (since the Java code is in charge of determining which and how many arguments should be passed) it fails to scale to upcalls; in that case, the call comes from native code, so we have no way to guarantee that the shape of the upcall stub we have created will match that required by the native function.</span></li></ul><h3 id='appendix-full-source-code'><span>Appendix: full source code</span></h3><p><span>The full source code containing most of the code shown throughout this document can be seen below:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll" lang="java"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.52344px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; min-width: 1026.14px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre>x</pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">Arena</span>;</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">Linker</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">FunctionDescriptor</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">SymbolLookup</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">MemorySegment</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">VaList</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">invoke</span>.<span class="cm-variable">MethodHandle</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">invoke</span>.<span class="cm-variable">MethodHandles</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-variable">java</span>.<span class="cm-variable">util</span>.<span class="cm-variable">Arrays</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-keyword">static</span> <span class="cm-variable">java</span>.<span class="cm-variable">lang</span>.<span class="cm-variable">foreign</span>.<span class="cm-variable">ValueLayout</span>.<span class="cm-operator">*</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">public</span> <span class="cm-keyword">class</span> <span class="cm-def">Examples</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">static</span> <span class="cm-variable">Linker</span> <span class="cm-variable">LINKER</span> <span class="cm-operator">=</span> <span class="cm-variable">Linker</span>.<span class="cm-variable">nativeLinker</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">static</span> <span class="cm-variable">SymbolLookup</span> <span class="cm-variable">STDLIB</span> <span class="cm-operator">=</span> <span class="cm-variable">LINKER</span>.<span class="cm-variable">defaultLookup</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">public</span> <span class="cm-keyword">static</span> <span class="cm-variable-3">void</span> <span class="cm-variable">main</span>(<span class="cm-variable-3">String</span>[] <span class="cm-variable">args</span>) <span class="cm-keyword">throws</span> <span class="cm-variable">Throwable</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">strlen</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">strlen_virtual</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">qsort</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">printf</span>();</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">public</span> <span class="cm-keyword">static</span> <span class="cm-variable-3">void</span> <span class="cm-variable">strlen</span>() <span class="cm-keyword">throws</span> <span class="cm-variable">Throwable</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">MethodHandle</span> <span class="cm-variable">strlen</span> <span class="cm-operator">=</span> <span class="cm-variable">LINKER</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">STDLIB</span>.<span class="cm-variable">find</span>(<span class="cm-string">"strlen"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">ADDRESS</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        );</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">MemorySegment</span> <span class="cm-variable">hello</span> <span class="cm-operator">=</span> <span class="cm-variable">arena</span>.<span class="cm-variable">allocateUtf8String</span>(<span class="cm-string">"Hello"</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable-3">long</span> <span class="cm-variable">len</span> <span class="cm-operator">=</span> (<span class="cm-variable-3">long</span>) <span class="cm-variable">strlen</span>.<span class="cm-variable">invoke</span>(<span class="cm-variable">hello</span>); <span class="cm-comment">// 5</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">len</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">public</span> <span class="cm-keyword">static</span> <span class="cm-variable-3">void</span> <span class="cm-variable">strlen_virtual</span>() <span class="cm-keyword">throws</span> <span class="cm-variable">Throwable</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">MethodHandle</span> <span class="cm-variable">strlen_virtual</span> <span class="cm-operator">=</span> <span class="cm-variable">LINKER</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">ADDRESS</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        );</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">MemorySegment</span> <span class="cm-variable">hello</span> <span class="cm-operator">=</span> <span class="cm-variable">arena</span>.<span class="cm-variable">allocateUtf8String</span>(<span class="cm-string">"Hello"</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable-3">long</span> <span class="cm-variable">len</span> <span class="cm-operator">=</span> (<span class="cm-variable-3">long</span>) <span class="cm-variable">strlen_virtual</span>.<span class="cm-variable">invoke</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">STDLIB</span>.<span class="cm-variable">find</span>(<span class="cm-string">"strlen"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">hello</span>); <span class="cm-comment">// 5</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">len</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">static</span> <span class="cm-keyword">class</span> <span class="cm-def">Qsort</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-keyword">static</span> <span class="cm-variable-3">int</span> <span class="cm-variable">qsortCompare</span>(<span class="cm-variable">MemorySegment</span> <span class="cm-variable">addr1</span>, <span class="cm-variable">MemorySegment</span> <span class="cm-variable">addr2</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-keyword">return</span> <span class="cm-variable">addr1</span>.<span class="cm-variable">get</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>) <span class="cm-operator">-</span> <span class="cm-variable">addr2</span>.<span class="cm-variable">get</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">public</span> <span class="cm-keyword">static</span> <span class="cm-variable-3">void</span> <span class="cm-variable">qsort</span>() <span class="cm-keyword">throws</span> <span class="cm-variable">Throwable</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">MethodHandle</span> <span class="cm-variable">qsort</span> <span class="cm-operator">=</span> <span class="cm-variable">LINKER</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">STDLIB</span>.<span class="cm-variable">find</span>(<span class="cm-string">"qsort"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">ofVoid</span>(<span class="cm-variable">ADDRESS</span>, <span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">JAVA_LONG</span>, <span class="cm-variable">ADDRESS</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        );</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">FunctionDescriptor</span> <span class="cm-variable">comparDesc</span> <span class="cm-operator">=</span> <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">ADDRESS</span>.<span class="cm-variable">asUnbounded</span>(), <span class="cm-variable">ADDRESS</span>.<span class="cm-variable">asUnbounded</span>());</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">MethodHandle</span> <span class="cm-variable">comparHandle</span> <span class="cm-operator">=</span> <span class="cm-variable">MethodHandles</span>.<span class="cm-variable">lookup</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                                         .<span class="cm-variable">findStatic</span>(<span class="cm-variable">Qsort</span>.<span class="cm-keyword">class</span>, <span class="cm-string">"qsortCompare"</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                                                     <span class="cm-variable">comparDesc</span>.<span class="cm-variable">toMethodType</span>());</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">MemorySegment</span> <span class="cm-variable">comparFunc</span> <span class="cm-operator">=</span> <span class="cm-variable">LINKER</span>.<span class="cm-variable">upcallStub</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">comparHandle</span>, <span class="cm-variable">comparDesc</span>, <span class="cm-variable">arena</span>.<span class="cm-variable">scope</span>());</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">MemorySegment</span> <span class="cm-variable">array</span> <span class="cm-operator">=</span> <span class="cm-variable">arena</span>.<span class="cm-variable">allocateArray</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-number">0</span>, <span class="cm-number">9</span>, <span class="cm-number">3</span>, <span class="cm-number">4</span>, <span class="cm-number">6</span>, <span class="cm-number">5</span>, <span class="cm-number">1</span>, <span class="cm-number">8</span>, <span class="cm-number">2</span>, <span class="cm-number">7</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">qsort</span>.<span class="cm-variable">invoke</span>(<span class="cm-variable">array</span>, <span class="cm-number">10L</span>, <span class="cm-number">4L</span>, <span class="cm-variable">comparFunc</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable-3">int</span>[] <span class="cm-variable">sorted</span> <span class="cm-operator">=</span> <span class="cm-variable">array</span>.<span class="cm-variable">toArray</span>(<span class="cm-variable">JAVA_INT</span>); <span class="cm-comment">// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">System</span>.<span class="cm-variable">out</span>.<span class="cm-variable">println</span>(<span class="cm-variable">Arrays</span>.<span class="cm-variable">toString</span>(<span class="cm-variable">sorted</span>));</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
-</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    <span class="cm-keyword">public</span> <span class="cm-keyword">static</span> <span class="cm-variable-3">void</span> <span class="cm-variable">printf</span>() <span class="cm-keyword">throws</span> <span class="cm-variable">Throwable</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-variable">MethodHandle</span> <span class="cm-variable">printf</span> <span class="cm-operator">=</span> <span class="cm-variable">LINKER</span>.<span class="cm-variable">downcallHandle</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">STDLIB</span>.<span class="cm-variable">find</span>(<span class="cm-string">"printf"</span>).<span class="cm-variable">get</span>(),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">FunctionDescriptor</span>.<span class="cm-variable">of</span>(<span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">ADDRESS</span>, <span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">JAVA_INT</span>, <span class="cm-variable">JAVA_INT</span>),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">                <span class="cm-variable">Linker</span>.<span class="cm-variable">Option</span>.<span class="cm-variable">firstVariadicArg</span>(<span class="cm-number">1</span>) <span class="cm-comment">// first int is variadic</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        );</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        <span class="cm-keyword">try</span> (<span class="cm-variable">Arena</span> <span class="cm-variable">arena</span> <span class="cm-operator">=</span> <span class="cm-variable">Arena</span>.<span class="cm-variable">openConfined</span>()) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">MemorySegment</span> <span class="cm-variable">s</span> <span class="cm-operator">=</span> <span class="cm-variable">arena</span>.<span class="cm-variable">allocateUtf8String</span>(<span class="cm-string">"%d plus %d equals %d\n"</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">            <span class="cm-variable">printf</span>.<span class="cm-variable">invoke</span>(<span class="cm-variable">s</span>, <span class="cm-number">2</span>, <span class="cm-number">2</span>, <span class="cm-number">4</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">        }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">    }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 2097px;"></div><div class="CodeMirror-gutters" style="display: none; height: 2097px;"></div></div></div></pre><p>&nbsp;</p><ul><li><a id="1"/><span>(</span><sup><span>1</span></sup><span>):</span><small><span> For simplicity, the examples shown in this document use </span><code>MethodHandle::invoke</code><span> rather than </span><code>MethodHandle::invokeExact</code><span>; by doing so we avoid having to cast by-reference arguments back to </span><code>Addressable</code><span>. With </span><code>invokeExact</code><span> the method handle invocation should be rewritten as </span><code>strlen.invokeExact((Addressable)session.allocateUtf8String(&quot;Hello&quot;));</code></small></li><li><a id="2"/><span>(</span><sup><span>2</span></sup><span>):</span><small><span> In reality this is not entirely new; even in JNI, when you call a </span><code>native</code><span> method the VM trusts that the corresponding implementing function in C will feature compatible parameter types and return values; if not a crash might occur.</span></small></li><li><a id="3"/><span>(</span><sup><span>3</span></sup><span>):</span><small><span> Previous iterations of the FFM API provided a </span><code>VaList</code><span> class that could be used to model a C </span><code>va_list</code><span>. This class was later dropped from the FFM API as too implementation specific. It is possible that a future version of the </span><code>jextract</code><span> tool might provide higher-level bindings for variadic calls. </span></small></li></ul></div></div>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/panama_ffi.md b/doc/panama_ffi.md
index b683849964f..a14f72d9c3b 100644
--- a/doc/panama_ffi.md
+++ b/doc/panama_ffi.md
@@ -1,6 +1,6 @@
 ## State of foreign function support
 
-**March 2023**
+**December 2023**
 
 **Maurizio Cimadamore**
 
@@ -69,37 +69,35 @@ At the core of the FFM API's foreign function support we find the `Linker` abstr
 
 ```java
 interface Linker {
-    MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function);
-    MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, SegmentScope scope);
+    MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Linker.Option... options);
+    MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options);
     ... // some overloads omitted here
 
     static Linker nativeLinker() { ... }
 }
 ```
 
-Both functions take a `FunctionDescriptor` instance — essentially an aggregate of memory layouts which is used to describe the argument and return types of a foreign function in full. Supported layouts are *value layouts* (for scalars and pointers) and *group layouts* (for structs/unions). Each layout in a function descriptor is associated with a carrier Java type (see table below); together, all the carrier types associated with layouts in a function descriptor will determine a unique Java `MethodType` — that is, the Java signature that clients will be using when interacting with said downcall handles, or upcall stubs.
+The `Linker::nativeLinker` factory is used to obtain a `Linker` implementation for the ABI associated with the OS and processor where the Java runtime is currently executing. As such, the native linker can be used to call C functions. When interacting with the native linker, clients must provide a platform-dependent description of the signature of the C function they wish to link against. This description, a `FunctionDescriptor` defines the layouts associated with the parameter types and return type (if any) of the C function.
 
-The `Linker::nativeLinker` factory is used to obtain a `Linker` implementation for the ABI associated with the OS and processor where the Java runtime is currently executing. As such, the native linker can be used to call C functions. The following table shows the mapping between C types, layouts and Java carriers under the Linux/macOS native linker implementation; note that the mappings can be platform dependent: on Windows/x64, the C type `long` is 32-bit, so the `JAVA_INT` layout (and the Java carrier `int.class`) would have to be used instead:
+Scalar C types such as `bool`, `int` are modeled as value layouts of a suitable carrier. Which layout is used to model a C type can vary, depending on the data model supported by a given ABI. For instance, the C type `long` maps to the layout constant `ValueLayout::JAVA_LONG` on Linux/x64, but maps to the layout constant `ValueLayout::JAVA_INT` on Windows/x64. The `Linker` provides a method, namely `Linker::canonicalLayouts` to allow clients to discover the mapping between C types and memory layouts programmatically:
 
-| C type                                                       | Layout                                                       | Java carrier    |
-| ------------------------------------------------------------ | ------------------------------------------------------------ | --------------- |
-| `bool`                                                       | `JAVA_BOOLEAN`                                               | `byte`          |
-| `char`                                                       | `JAVA_BYTE`                                                  | `byte`          |
-| `short`                                                      | `JAVA_SHORT`                                                 | `short`, `char` |
-| `int`                                                        | `JAVA_INT`                                                   | `int`           |
-| `long`                                                       | `JAVA_LONG`                                                  | `long`          |
-| `long long`                                                  | `JAVA_LONG`                                                  | `long`          |
-| `float`                                                      | `JAVA_FLOAT`                                                 | `float`         |
-| `double`                                                     | `JAVA_DOUBLE`                                                | `double`        |
-| `char*`<br />`int**`<br /> ...                               | `ADDRESS`                                                    | `MemorySegment` |
-| `struct Point { int x; int y; };`<br />`union Choice { float a; int b; };`<br />... | `MemoryLayout.structLayout(...)`<br />`MemoryLayout.unionLayout(...)`<br /> | `MemorySegment` |
+```java
+MemoryLayout SIZE_T = Linker.nativeLinker().canonicalLayouts().get("size_t");
+```
 
-Both C structs/unions and pointers are modelled using the `MemorySegment` carrier type. However, C structs/unions are modelled in function descriptors with memory layouts of type `GroupLayout`, whereas pointers are modelled using the `ADDRESS` value layout constant (whose size is platform-specific). Moreover, the behavior of a downcall method handle returning a struct/union type is radically different from that of a downcall method handle returning a C pointer:
+Composite types are modeled as group layouts. More specifically, a C struct type maps to a `StructLayout`, whereas a C `union` type maps to a `UnionLayout`. When defining a struct or union layout, clients must pay attention to the size and alignment constraint of the corresponding composite type definition in C. For instance, padding between two struct fields must be modeled explicitly, by adding an adequately sized padding layout member to the resulting struct layout.
+
+Finally, pointer types such as `int**`, and `int(*)(size_t*, size_t*)` are modeled as address layouts. When the spatial bounds of the pointer type are known statically, the address layout can be associated with a *target layout*. For instance, a pointer that is known to point to a C `int[2]` array can be modelled as follows:
+
+```java
+ValueLayout.ADDRESS.withTargetLayout(
+        MemoryLayout.sequenceLayout(2,
+                                    Linker.nativeLinker().canonicalLayouts().get("int")));
+```
 
-* downcall method handles returning C pointers will wrap the pointer address into a fresh zero-length memory segment (unless an unbounded address layout is specified);
-* downcall method handles returning a C struct/union type will return a *new* segment, of given size (the size of the struct/union). The segment is allocated using a user-provided `SegmentAllocator`, which is provided using an additional prefix parameter inserted in the downcall method handle signature.
+For more exhaustive examples of mappings between C types and layouts, please refer to the [appendix](#c-types-mapping-in-linuxx64). In the following sections, we will assume Linux/x64 as our target platform.
 
-A tool, such as `jextract`, will generate all the required C layouts (for scalars and structs/unions) *automatically*, so that clients do not have to worry about platform-dependent details such as sizes, alignment constraints and padding.
+> Note: the [jextract](https://github.com/openjdk/jextract) tool can generate all the required C layouts (for scalars and structs/unions) *automatically*, so that clients do not have to worry about platform-dependent details such as sizes, alignment constraints and padding.
 
 ### Downcalls
 
@@ -113,10 +111,9 @@ In order to do that, we have to:
 
 * lookup the `strlen` symbol
 * describe the signature of the C function using a function descriptor
-
 * create a *downcall* native method handle with the above information, using the native linker
 
-Here's an example of how we might want to do that (a full listing of all the examples in this and subsequent sections will be provided in the [appendix](#appendix-full-source-code)):
+Here's an example of how we might want to do that (a full listing of all the examples in this and subsequent sections will be provided in the [appendix](#Full-source-code)):
 
 ```java
 Linker linker = Linker.nativeLinker();
@@ -132,7 +129,7 @@ Once we have obtained the downcall method handle, we can just use it as any othe
 
 ```java
 try (Arena arena = Arena.ofConfined()) {
-    long len = strlen.invokeExact(arena.allocateUtf8String("Hello")); // 5
+    long len = strlen.invokeExact(arena.allocateFrom("Hello")); // 5
 }
 ```
 
@@ -148,7 +145,7 @@ MethodHandle strlen_virtual = linker.downcallHandle( // address parameter missin
 try (Arena arena = Arena.ofConfined()) {
     long len = strlen_virtual.invokeExact(
         linker.defaultLookup().find("strlen").get() // address provided here!
-        arena.allocateUtf8String("Hello")
+        arena.allocateFrom("Hello")
     ); // 5
 }
 ```
@@ -208,7 +205,7 @@ To do that, we first create a function descriptor for the function pointer type.
 ```java
 try (Arena arena = Arena.ofConfined()) {
     MemorySegment comparFunc = linker.upcallStub(comparHandle, comparDesc, arena);
-    MemorySegment array = session.allocateArray(0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
+    MemorySegment array = arena.allocateFrom(0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
     qsort.invokeExact(array, 10L, 4L, comparFunc);
     int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
 }
@@ -234,7 +231,7 @@ The foreign function support can support variadic calls, but with a caveat: the
 printf("%d plus %d equals %d", 2, 2, 4);
 ```
 
-To do this using the foreign function support provided by the FFM API we would have to build a *specialized* downcall handle for that call shape, using a linker option to specify the position of the first variadic layout, as follows:
+To do this using the foreign function support provided by the FFM API we would have to build a *specialized* downcall handle for that call shape, using a linker option<a href="#2"><sup>2</sup></a> to specify the position of the first variadic layout, as follows:
 
 ```java
 Linker linker = Linker.nativeLinker();
@@ -249,16 +246,33 @@ Then we can call the specialized downcall handle as usual:
 
 ```java
 try (Arena arena = Arena.ofConfined()) {
-    int res = (int)printf.invokeExact(arena.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
+    int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
 }
 ```
 
-While this works, and provides optimal performance, it has some limitations<a href="#2"><sup>2</sup></a>:
+While this works, and provides optimal performance, it has some limitations<a href="#3"><sup>3</sup></a>:
 
 * If the variadic function needs to be called with many shapes, we have to create many downcall handles
 * while this approach works for downcalls (since the Java code is in charge of determining which and how many arguments should be passed) it fails to scale to upcalls; in that case, the call comes from native code, so we have no way to guarantee that the shape of the upcall stub we have created will match that required by the native function.
 
-### Appendix: full source code
+### Appendix
+
+##### C types mapping in Linux/x64
+
+| C type                                                       | Layout                                                       | Java carrier    |
+| ------------------------------------------------------------ | ------------------------------------------------------------ | --------------- |
+| `bool`                                                       | `JAVA_BOOLEAN`                                               | `byte`          |
+| `char`                                                       | `JAVA_BYTE`                                                  | `byte`          |
+| `short`                                                      | `JAVA_SHORT`                                                 | `short`, `char` |
+| `int`                                                        | `JAVA_INT`                                                   | `int`           |
+| `long`                                                       | `JAVA_LONG`                                                  | `long`          |
+| `long long`                                                  | `JAVA_LONG`                                                  | `long`          |
+| `float`                                                      | `JAVA_FLOAT`                                                 | `float`         |
+| `double`                                                     | `JAVA_DOUBLE`                                                | `double`        |
+| `char*`<br />`int**`<br /> ...                               | `ADDRESS`                                                    | `MemorySegment` |
+| `struct Point { int x; int y; };`<br />`union Choice { float a; int b; };`<br />... | `MemoryLayout.structLayout(...)`<br />`MemoryLayout.unionLayout(...)`<br /> | `MemorySegment` |
+
+##### Full source code
 
 The full source code containing most of the code shown throughout this document can be seen below:
 
@@ -357,7 +371,6 @@ public class Examples {
 }
 ```
 
-
-
 * <a id="1"/>(<sup>1</sup>):<small> In reality this is not entirely new; even in JNI, when you call a `native` method the VM trusts that the corresponding implementing function in C will feature compatible parameter types and return values; if not a crash might occur.</small>
-* <a id="2"/>(<sup>2</sup>):<small> Previous iterations of the FFM API provided a `VaList` class that could be used to model a C `va_list`. This class was later dropped from the FFM API as too implementation specific. It is possible that a future version of the `jextract` tool might provide higher-level bindings for variadic calls. </small>
+* <a id="2"/>(<sup>2</sup>):<small> Linker options can be used to customize the linkage request in various ways, for instance to allow clients to pass heap segments to native functions without copying, to remove Java to native thread transitions and to save the state of special runtime variables (such as `errno`). </small>
+* <a id="3"/>(<sup>3</sup>):<small> Previous iterations of the FFM API provided a `VaList` class that could be used to model a C `va_list`. This class was later dropped from the FFM API as too implementation specific. It is possible that a future version of the `jextract` tool might provide higher-level bindings for variadic calls. </small>
diff --git a/doc/panama_memaccess.md b/doc/panama_memaccess.md
index 69138b80ac7..4c19f78691a 100644
--- a/doc/panama_memaccess.md
+++ b/doc/panama_memaccess.md
@@ -1,6 +1,6 @@
 ## State of foreign memory support
 
-**March 2023**
+**December 2023**
 
 **Maurizio Cimadamore**
 
@@ -58,7 +58,7 @@ MemorySegment slice = segment.asSlice(4, 4);
 
 The above code creates a slice that starts at offset 4 and has a length of 4 bytes. Slices have the *same* temporal bounds (i.e. segment scope) as the parent segment. In the above example, the memory associated with the parent segment will not be released as long as there is at least one *reachable* slice derived from that segment.
 
-To process the contents of a memory segment in bulk, a memory segment can be turned into a stream of slices, using the `MemorySegment::stream` method:
+To process the contents of a memory segment in bulk, a memory segment can be turned into a stream of slices, using the `MemorySegment::elements` method:
 
 ```java
 SequenceLayout seq = MemoryLayout.sequenceLayout(1_000_000, JAVA_INT);
@@ -77,7 +77,7 @@ try (Arena arena = Arena.ofShared()) {
 }
 ```
 
-The `MemorySegment::elements` method takes an element layout and returns a new stream. The stream is built on top of a spliterator instance (see `MemorySegment::spliterator`) which splits the segment into chunks whose size match that of the provided layout. Here, we want to sum elements in an array which contains a million of elements; now, doing a parallel sum where each computation processes *exactly* one element would be inefficient, so instead we use a *bulk* element layout. The bulk element layout is a sequence layout containing a group of 100 elements — which should make it more amenable to parallel processing. Since we are using `Stream::parallel` to work on disjoint slices in parallel, here we use a *shared* arena, to ensure that the resulting segment can be accessed by multiple threads.
+The `MemorySegment::elements` method takes an element layout and returns a new stream. The stream is built on top of a spliterator instance (see `MemorySegment::spliterator`) which splits the segment into chunks whose size matches that of the provided layout. Here, we want to sum elements in an array which contains a million of elements; now, doing a parallel sum where each computation processes *exactly* one element would be inefficient, so instead we use a *bulk* element layout. The bulk element layout is a sequence layout containing a group of 100 elements — which should make it more amenable to parallel processing. Since we are using `Stream::parallel` to work on disjoint slices in parallel, here we use a *shared* arena, to ensure that the resulting segment can be accessed by multiple threads.
 
 ### Accessing segments
 
@@ -132,15 +132,28 @@ VarHandle xHandle = points.varHandle(PathElement.sequenceElement(), PathElement.
 VarHandle yHandle = points.varHandle(PathElement.sequenceElement(), PathElement.groupElement("y"));
 Point[] values = new Point[10];
 for (int i = 0 ; i < values.length ; i++) {
-    int x = (int)xHandle.get(segment, (long)i);
-    int y = (int)yHandle.get(segment, (long)i);
+    int x = (int)xHandle.get(segment, 0L /* base offset */, (long)i /* index */);
+    int y = (int)yHandle.get(segment, 0L /* base offset */, (long)i /* index */);
 }
 ```
 
-In the above, `xHandle` and `yHandle` are two var handle instances whose type is `int` and which takes two access coordinates:
+In the above, `xHandle` and `yHandle` are two var handle instances whose type is `int` and which takes three access coordinates:
 
 1. a `MemorySegment` instance; the segment whose memory should be dereferenced
-2. a *logical* index, which is used to select the element of the sequence we want to access (as the layout path used to construct these var handles contains one free dimension)
+2. a *base offset*, which indicates the portions of the memory segment to be accessed; this is typically left to zero (as above), but can be useful when combining memory access var handles (see below);
+3. a *logical* index, which is used to select the element of the sequence we want to access (as the layout path used to construct these var handles contains one free dimension)
+
+In other words, the offset of the access operation can be expressed as follows:
+
+```java
+offset = baseOffset + (index * JAVA_INT.byteSize());
+```
+
+Or, equivalently, using the `MemoryLayout::scale` method, as:
+
+```java
+offset = JAVA_INT.scale(baseOffset, index);
+```
 
 Note that memory access var handles (as any other var handle) are *strongly* typed; and to get maximum efficiency, it is generally necessary to introduce casts to make sure that the access coordinates match the expected types — in this case we have to cast `i` into a `long`; similarly, since the signature polymorphic method `VarHandle::get` notionally returns `Object` a cast is necessary to force the right return type the var handle operation <a href="#3"><sup>3</sup></a>.
 
@@ -151,12 +164,12 @@ In other words, manual offset computation is no longer needed — offsets and st
 We have seen in the previous sections how memory access var handles dramatically simplify user code when structured access is involved. While deriving memory access var handles from layout is the most convenient option, the FFM API also allows to create such memory access var handles in a standalone fashion, as demonstrated in the following code:
 
 ```java
-VarHandle intHandle = MethodHandles.memorySegmentViewVarHandle(JAVA_INT); // (MS, J) -> I
+VarHandle intHandle = JAVA_INT.varHandle(); // (MS, J) -> I
 ```
 
 The above code creates a memory access var handle which reads/writes `int` values at a certain byte offset in a segment. To create this var handle we have to specify a carrier type — the type we want to use e.g. to extract values from memory, as well as whether any byte swapping should be applied when contents are read from or stored to memory. Additionally, the user might want to impose additional constraints on how memory dereferences should occur; for instance, a client might want to prevent access to misaligned 32 bit values. Of course, all this information can be succinctly derived from the provided value layout (`JAVA_INT` in the above example).
 
-The attentive reader might have noted how rich the var handles obtained from memory layouts are, compared to the simple memory access var handle we have constructed here. How do we go from a simple access var handle that takes a byte offset to a var handle that can dereference a complex layout path? The answer is, by using var handle *combinators*. Developers familiar with the method handles know how simpler method handles can be combined into more complex ones using the various combinator methods in the `MethodHandles` class. These methods allow, for instance, to insert (or bind) arguments into a target method handle, filter return values, permute arguments and much more.
+The attentive reader might have noted how the var handles obtained from the sequence layout in the previous section can be in fact derived from  the simple memory access var handle we have constructed here. That is, var handles can be adapted and turned into more complex var handles, using var handle *combinators*. Developers familiar with the method handle API know how simpler method handles can be combined into more complex ones using the various combinator methods in the `MethodHandles` class. These methods allow, for instance, to insert (or bind) arguments into a target method handle, filter return values, permute arguments and much more.
 
 The FFM API adds a rich set of var handle combinators in the `MethodHandles` class; with these tools, developers can express var handle transformations such as:
 
@@ -168,7 +181,7 @@ The FFM API adds a rich set of var handle combinators in the `MethodHandles` cla
 Without diving too deep, let's consider how we might want to take a basic memory access handle and turn it into a var handle which dereference a segment at a specific offset (again using the `points` layout defined previously):
 
 ```java
-VarHandle intHandle = MemoryHandles.memorySegmentViewVarHandle(JAVA_INT); // (MS, J) -> I
+VarHandle intHandle = JAVA_INT.varHandle(); // (MS, J) -> I
 long offsetOfY = points.byteOffset(PathElement.sequenceElement(3), PathElement.groupElement("y"));
 VarHandle valueHandle = MethodHandles.insertCoordinates(intHandle, 1, offsetOfValue); // (MS) -> I
 ```
@@ -182,8 +195,8 @@ Memory allocation is often a bottleneck when clients use off-heap memory. The FF
 ```java
 FileChannel channel = ...
 try (Arena offHeap = Arena.ofConfined()) {
-    MemorySegment nativeArray   = offHeap.allocateArray(ValueLayout.JAVA_INT, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-    MemorySegment nativeString  = offHeap.allocateUtf8String("Hello!");
+    MemorySegment nativeArray   = offHeap.allocateFrom(ValueLayout.JAVA_INT, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    MemorySegment nativeString  = offHeap.allocateFrom("Hello!");
 
     MemorySegment mappedSegment = channel.map(MapMode.READ_WRITE, 0, 1000, arena);
    ...
@@ -196,7 +209,7 @@ Segment allocators can also be obtained via factories in the `SegmentAllocator`
 MemorySegment segment = ...
 SegmentAllocator allocator = SegmentAllocator.slicingAllocator(segment);
 for (int i = 0 ; i < 10 ; i++) {
-    MemorySegment s = allocator.allocateArray(JAVA_INT, new int[] { 1, 2, 3, 4, 5 });
+    MemorySegment s = allocator.allocateFrom(JAVA_INT, 1, 2, 3, 4, 5);
     ...
 }
 ```
@@ -214,7 +227,7 @@ class SlicingArena {
          slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
      }
 
-public void allocate(long byteSize, long byteAlignment) {
+     public void allocate(long byteSize, long byteAlignment) {
          return slicingAllocator.allocate(byteSize, byteAlignment);
      }
 
@@ -233,7 +246,7 @@ The earlier code which used a slicing allocator directly can now be written more
 ```java
 try (Arena slicingArena = new SlicingArena(1000)) {
      for (int i = 0 ; i < 10 ; i++) {
-         MemorySegment s = arena.allocateArray(JAVA_INT, new int[] { 1, 2, 3, 4, 5 });
+         MemorySegment s = arena.allocateFrom(JAVA_INT, 1, 2, 3, 4, 5);
          ...
      }
 } // all memory allocated is released here