CINXE.COM

A New Bytecode Format for JavaScriptCore | WebKit

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta name="robots" content="noodp"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover"> <meta name="theme-color" content="hsl(203.6, 100%, 12%)"> <title> A New Bytecode Format for JavaScriptCore | WebKit</title> <meta name="application-name" content="WebKit"> <link rel="stylesheet" type="text/css" href="https://webkit.org/wp-content/themes/webkit/style.css?2022100501" media="all"> <link rel="stylesheet" href="https://www.apple.com/wss/fonts?families=SF+Pro,v1" type="text/css"> <link rel="stylesheet" href="https://www.apple.com/wss/fonts?families=SF+Mono,v2" type="text/css"> <meta name="supported-color-schemes" content="light dark"> <noscript> <img src="https://shynet.webkit.org/ingress/561b9e53-fb8c-4297-ae4d-bde05e8daa59/pixel.gif"> </noscript> <script defer src="https://shynet.webkit.org/ingress/561b9e53-fb8c-4297-ae4d-bde05e8daa59/script.js"></script> <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="https://webkit.org/feed/"> <link rel="alternate" type="text/xml" title="RSS .92" href="https://webkit.org/feed/rss/"> <link rel="alternate" type="application/atom+xml" title="Atom 0.3" href="https://webkit.org/feed/atom/"> <link rel="pingback" href="https://webkit.org/wp/xmlrpc.php"> <link rel="shortcut icon" sizes="32x32" type="image/x-icon" href="/favicon.ico"> <meta name='robots' content='max-image-preview:large' /> <link rel='stylesheet' id='wp-block-library-css' href='https://webkit.org/wp/wp-includes/css/dist/block-library/style.min.css?ver=6.7' type='text/css' media='all' /> <style id='classic-theme-styles-inline-css' type='text/css'> /*! This file is auto-generated */ .wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none} </style> <style id='global-styles-inline-css' type='text/css'> :root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;} :where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;} :where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;} :root :where(.wp-block-pullquote){font-size: 1.5em;line-height: 1.6;} </style> <link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://webkit.org/wp/xmlrpc.php?rsd" /> <meta name="generator" content="WordPress 6.7" /> <link rel="canonical" href="https://webkit.org/blog/9329/a-new-bytecode-format-for-javascriptcore/" /> <link rel='shortlink' href='https://webkit.org/?p=9329' /> <link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://webkit.org/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fwebkit.org%2Fblog%2F9329%2Fa-new-bytecode-format-for-javascriptcore%2F" /> <link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://webkit.org/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fwebkit.org%2Fblog%2F9329%2Fa-new-bytecode-format-for-javascriptcore%2F&#038;format=xml" /> <!-- Schema.org markup --> <meta itemprop="name" content="A New Bytecode Format for JavaScriptCore"> <meta itemprop="description" content="In revision r237547 we introduced a new bytecode format for JavaScriptCore (JSC)."> <meta itemprop="image" content="https://webkit.org/wp-content/uploads/unlinked.png"> <!-- Twitter Card data --> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:image:src" content="https://webkit.org/wp-content/uploads/unlinked.png"> <meta name="twitter:site" content="@webkit"> <meta name="twitter:title" content="A New Bytecode Format for JavaScriptCore"> <meta name="twitter:description" content="In revision r237547 we introduced a new bytecode format for JavaScriptCore (JSC)."> <meta name="twitter:creator" content="@tadeuzagallo"> <!-- Open Graph data --> <meta property="og:title" content="A New Bytecode Format for JavaScriptCore"> <meta property="og:type" content="article"> <meta property="og:url" content="https://webkit.org/blog/9329/a-new-bytecode-format-for-javascriptcore/"> <meta property="og:image" content="https://webkit.org/wp-content/uploads/unlinked.png"> <meta property="og:description" content="In revision r237547 we introduced a new bytecode format for JavaScriptCore (JSC)."> <meta property="og:site_name" content="WebKit"> <meta property="article:published_time" content="2019-06-21T10:00:20-07:00"> <meta property="article:modified_time" content="2019-06-21T10:23:33-07:00"> <meta property="article:section" content="JavaScript"> <meta property="fb:admins" content="1085088865"> </head> <body class="post-template-default single single-post postid-9329 single-format-standard"> <!-- Copyright © 2020 Apple Inc. All rights reserved. --> <svg xmlns="http://www.w3.org/2000/svg"> <style> svg { display: block; width: 0; height: 0; } </style> <filter id="invertLightness" x="0" y="0" style="color-interpolation-filters: sRGB"> <feColorMatrix type="matrix" in="SourceGraphic" result="red" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1" /> <feColorMatrix type="matrix" in="SourceGraphic" result="green" values="0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1" /> <feColorMatrix type="matrix" in="SourceGraphic" result="blue" values="0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1" /> <feBlend in="red" in2="green" mode="lighten" result="maxyellow" /> <feBlend in="maxyellow" in2="blue" mode="lighten" result="max" /> <feBlend in="red" in2="green" mode="darken" result="minyellow" /> <feBlend in="minyellow" in2="blue" mode="darken" result="min" /> <feComponentTransfer result="adjustment" in="min"> <feFuncR type="linear" intercept="1" slope="-1" /> <feFuncG type="linear" intercept="1" slope="-1" /> <feFuncB type="linear" intercept="1" slope="-1" /> </feComponentTransfer> <feComposite operator="arithmetic" in="SourceGraphic" in2="adjustment" k1="0" k2="1" k3="1" k4="-1" result="channelAdjustment" /> <feComposite operator="arithmetic" in="channelAdjustment" in2="max" k1="0" k2="1" k3="-1" k4="1" result="finalColors" /> <feComposite operator="in" in="finalColors" in2="SourceAlpha" /> </filter> </svg> <header aria-label="WebKit.org Header" id="header"> <div class="page-width"> <a href="/"><div id="logo" class="site-logo">WebKit</div></a> <nav id="site-nav" aria-label="Site Menu"> <div class="menu-main-menu-container"><input type="checkbox" id="menu-main-menu-toggle" class="menu-toggle" /><label for="menu-main-menu-toggle" class="label-toggle main-menu" data-open="Main Menu" data-close="Close Menu"></label><ul id="menu-main-menu" class="menu" role="menubar"><li id="menu-item-6091" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-6091"><a href="https://webkit.org/downloads/" role="menuitem">Downloads</a></li> <li id="menu-item-4272" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-4272"><input type="checkbox" id="toggle-4272" class="menu-toggle" /><a href="#nav-sub-menu" role="menuitem" aria-haspopup="true" aria-owns="sub-menu-for-4272" aria-controls="sub-menu-for-4272" aria-expanded="true"><label for="toggle-4272" class="label-toggle">Feature Status</label></a> <ul class="sub-menu sub-menu-layer" role="menu" id="sub-menu-for-4272"> <li id="menu-item-13052" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13052"><a href="https://webkit.org/css-status/" role="menuitem">CSS Features</a></li> <li id="menu-item-14388" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-14388"><a href="https://webkit.org/standards-positions/" role="menuitem">Standards Positions</a></li> </ul> </li> <li id="menu-item-9988" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-9988"><input type="checkbox" id="toggle-9988" class="menu-toggle" /><a href="#nav-sub-menu" role="menuitem" aria-haspopup="true" aria-owns="sub-menu-for-9988" aria-controls="sub-menu-for-9988" aria-expanded="true"><label for="toggle-9988" class="label-toggle">Documentation</label></a> <ul class="sub-menu sub-menu-layer" role="menu" id="sub-menu-for-9988"> <li id="menu-item-9989" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-9989"><a href="/web-inspector" role="menuitem">Web Inspector</a></li> <li id="menu-item-10868" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-10868"><a href="https://webkit.org/tracking-prevention/" role="menuitem">Tracking Prevention</a></li> </ul> </li> <li id="menu-item-4282" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-4282"><input type="checkbox" id="toggle-4282" class="menu-toggle" /><a href="#nav-sub-menu" role="menuitem" aria-haspopup="true" aria-owns="sub-menu-for-4282" aria-controls="sub-menu-for-4282" aria-expanded="true"><label for="toggle-4282" class="label-toggle">Policies</label></a> <ul class="sub-menu sub-menu-layer" role="menu" id="sub-menu-for-4282"> <li id="menu-item-10037" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-10037"><a href="https://webkit.org/project/" role="menuitem">Project Goals</a></li> <li id="menu-item-13077" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13077"><a href="https://webkit.org/bug-prioritization/" role="menuitem">Bug Prioritization</a></li> <li id="menu-item-13076" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13076"><a href="https://webkit.org/bug-report-guidelines/" role="menuitem">Bug Report Guidelines</a></li> <li id="menu-item-13075" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13075"><a href="https://webkit.org/code-style-guidelines/" role="menuitem">Code Style Guidelines</a></li> <li id="menu-item-13074" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13074"><a href="https://webkit.org/commit-and-review-policy/" role="menuitem">Commit and Review Policy</a></li> <li id="menu-item-13073" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13073"><a href="https://webkit.org/feature-policy/" role="menuitem">Feature Policy</a></li> <li id="menu-item-13072" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13072"><a href="https://webkit.org/security-policy/" role="menuitem">Security Policy</a></li> <li id="menu-item-13071" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-13071"><a href="https://webkit.org/tracking-prevention-policy/" role="menuitem">Tracking Prevention Policy</a></li> </ul> </li> <li id="menu-item-4274" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-4274"><input type="checkbox" id="toggle-4274" class="menu-toggle" /><a href="#nav-sub-menu" role="menuitem" aria-haspopup="true" aria-owns="sub-menu-for-4274" aria-controls="sub-menu-for-4274" aria-expanded="true"><label for="toggle-4274" class="label-toggle">Contribute</label></a> <ul class="sub-menu sub-menu-layer" role="menu" id="sub-menu-for-4274"> <li id="menu-item-4277" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4277"><a href="https://webkit.org/getting-started/" role="menuitem">Getting Started</a></li> <li id="menu-item-4284" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4284"><a href="https://webkit.org/contributing-code/" role="menuitem">Contributing Code</a></li> <li id="menu-item-4281" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4281"><a href="https://webkit.org/testing-contributions/" role="menuitem">Testing Contributions</a></li> <li id="menu-item-4273" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4273"><a href="https://webkit.org/reporting-bugs/" role="menuitem">How to Report Bugs</a></li> <li id="menu-item-4278" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-4278"><a href="https://github.com/WebKit/WebKit" role="menuitem">GitHub Repository</a></li> </ul> </li> <li id="menu-item-4270" class="menu-item menu-item-type-post_type menu-item-object-page current_page_parent menu-item-has-children menu-item-4270"><input type="checkbox" id="toggle-4270" class="menu-toggle" /><a href="#nav-sub-menu" role="menuitem" aria-haspopup="true" aria-owns="sub-menu-for-4270" aria-controls="sub-menu-for-4270" aria-expanded="true"><label for="toggle-4270" class="label-toggle">Blog</label></a> <ul class="sub-menu sub-menu-layer" role="menu" id="sub-menu-for-4270"> <li id="menu-item-13057" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13057"><a href="https://webkit.org/blog/category/news/" role="menuitem">News Posts</a></li> <li id="menu-item-13058" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13058"><a href="https://webkit.org/blog/category/css/" role="menuitem">CSS Posts</a></li> <li id="menu-item-13063" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13063"><a href="https://webkit.org/blog/category/contributing/" role="menuitem">Contributing Posts</a></li> <li id="menu-item-13062" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13062"><a href="https://webkit.org/blog/category/privacy/" role="menuitem">Privacy Posts</a></li> <li id="menu-item-13060" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13060"><a href="https://webkit.org/blog/category/performance/" role="menuitem">Performance Posts</a></li> <li id="menu-item-13061" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-13061"><a href="https://webkit.org/blog/category/javascript/" role="menuitem">JavaScript Posts</a></li> <li id="menu-item-13056" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13056"><a href="https://webkit.org/blog/category/standards/" role="menuitem">Standards Posts</a></li> <li id="menu-item-13059" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13059"><a href="https://webkit.org/blog/category/web-inspector/" role="menuitem">Web Inspector Posts</a></li> <li id="menu-item-13055" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-13055"><a href="https://webkit.org/blog/category/safari-technology-preview/" role="menuitem">Safari Technology Preview Posts</a></li> </ul> </li> <li><form action="/" method="get"><input type="search" name="s" class="search-input" value=""></form></li></ul></div></nav> </div> </header> <main id="content"> <div class="page-width"> <article class="post-9329 post type-post status-publish format-standard hentry category-javascript" id="post-9329"> <h1><a href="https://webkit.org/blog/9329/a-new-bytecode-format-for-javascriptcore/" rel="bookmark" title="Permanent Link: A New Bytecode Format for JavaScriptCore">A New Bytecode Format for JavaScriptCore</a></h1> <div class="byline"> <p class="date">Jun 21, 2019</p> <p class="author">by <span>Tadeu Zagallo</span></p> <p class="twitter"><a href="https://twitter.com/tadeuzagallo" target="_blank">@tadeuzagallo</a></p> </div> <div class="bodycopy"> <p>In revision <a href="https://trac.webkit.org/r237547">r237547</a> we introduced a new bytecode format for JavaScriptCore (JSC). The goals of the new format were to improve memory usage and allow the bytecode to be cached on disk, while the previous format was optimized for interpreter throughput at the cost of memory usage.</p> <p>In this post, we will start with a quick overview of JSC’s bytecode, key aspects of the old bytecode format and the optimizations it enabled. Next, we will look into the new format and how it affects interpreter execution. Finally, we will look at the impact of the new format on memory usage and performance and how this rewrite improved type safety in JavaScriptCore.</p> <h2>Background</h2> <p>Before JSC executes any JavaScript code, it must lex, parse and generate bytecode for it. JSC has 4 tiers of execution:</p> <ul> <li><strong>Low Level Interpreter (LLInt)</strong>: the start-up interpreter</li> <li><strong>Baseline JIT</strong>: a template JIT</li> <li><strong>DFG JIT</strong>: a low-latency optimizing compiler</li> <li><strong>FTL JIT</strong>: a high-throughput optimizing compiler</li> </ul> <p>Execution starts by interpreting the bytecode, at the lowest tier, and as the code gets executed more it gets promoted to a higher tier. This is described in a lot more details in <a href="https://webkit.org/blog/3362/introducing-the-webkit-ftl-jit/">this blog post about the FTL</a>.</p> <p>The bytecode is the source of truth throughout the whole engine. The LLInt executes the bytecode. The baseline is a template JIT, which emits snippets of machine code for each bytecode instruction. Finally, the DFG and FTL parse the bytecode and emit DFG IR, which is then run through an optimizing compiler.</p> <p>Because the bytecode is the source of truth, it tends to stay alive in memory throughout the whole program execution. In JavaScript-heavy websites, such as Facebook or Reddit, the bytecode is responsible for <strong>20%</strong> of the overall memory usage.</p> <h2>The Bytecode</h2> <p>To make things more concrete, let&#8217;s look at a simple JavaScript program, learn how to inspect the bytecode generated by JSC and how to interpret the bytecode dump.</p> <pre><code class="js"><span class="comment">// double.js </span><span class="keyword type">function</span> <span class="keyword type">double</span>(<span class="identifier">a</span>) { <span class="keyword control">return</span> <span class="identifier">a</span> <span class="operator">+</span> <span class="identifier">a</span>; } <span class="keyword type">double</span>(<span class="number">2</span>); </code></pre> <p>If you run the above program with <code>jsc -d double.js</code>, JSC will dump all the bytecode it generates to <code>stderr</code>. The bytecode dump will contain the bytecode generated for <code>double</code>:</p> <pre><code>[ 0] enter [ 1] get_scope loc4 [ 3] mov loc5, loc4 [ 6] check_traps [ 7] add loc7, arg1, arg1, OperandTypes(126, 126) [ 13] ret loc7 </code></pre> <p>Each line starts with the offset of the instruction in brackets, followed by the opcode name and its operands. Here we can see the operands <code>loc</code> for local variables, <code>arg</code> for function arguments and <code>OperandTypes</code>, which is metadata about the predicted types of the arguments.</p> <h2>Old Bytecode Format</h2> <p>The old bytecode format had a few issues that we wanted to fix:</p> <ul> <li>It used too much memory.</li> <li>The instruction stream was writable, which prevented memory-mapping the bytecode stream.</li> <li>It had optimizations that we no longer benefited from, such as <a href="http://wiki.c2.com/?DirectThreadedCode">direct threading</a>.</li> </ul> <p>In order to better understand how we addressed these issues in the new format, we need a basic understanding of the old bytecode format. In the old format, instructions could be in one of two forms: <em>unlinked</em>, which is compact and optimized for storage and <em>linked</em>, which is inflated and optimized for execution, containing memory addresses of runtime objects directly in the instruction stream.</p> <h3>Unlinked Instructions</h3> <p>The instructions were encoded using <a href="https://en.wikipedia.org/wiki/Variable-width_encoding">variable-width encoding</a>. The opcode and each operand took as little space as possible, ranging from 1 to 5 bytes. Take the add instruction from the program above as an example, it would take 6 bytes: one for the opcode (add), one for each of the registers (<code>loc7</code>, <code>arg1</code> and <code>arg1</code> again) and two bytes for the operand types.</p> <figure class="widescreen mattewhite"><img fetchpriority="high" decoding="async" width="1366" height="310" src="https://webkit.org/wp-content/uploads/unlinked.png" alt="Unlinked instructions" class="wp-image-9351" srcset="https://webkit.org/wp-content/uploads/unlinked.png 1366w, https://webkit.org/wp-content/uploads/unlinked-300x68.png 300w, https://webkit.org/wp-content/uploads/unlinked-768x174.png 768w, https://webkit.org/wp-content/uploads/unlinked-1024x232.png 1024w" sizes="(max-width: 1366px) 100vw, 1366px" /></figure> <h3>Linking / Linked Instructions</h3> <p>Before executing the bytecode it needed to be linked. Linking inflated all the instructions, making the opcode and each of the operands pointer-sized. The opcode was replaced by the actual pointer to the implementation of the instruction and the profiling-related metadata replaced with the memory address of the newly allocated profiling data structures. The <code>add</code> from above took 40 bytes to represent:</p> <figure class="widescreen mattewhite"><img decoding="async" width="1674" height="313" src="https://webkit.org/wp-content/uploads/linked.png" alt="Linked instructions" class="wp-image-9342" srcset="https://webkit.org/wp-content/uploads/linked.png 1674w, https://webkit.org/wp-content/uploads/linked-300x56.png 300w, https://webkit.org/wp-content/uploads/linked-768x144.png 768w, https://webkit.org/wp-content/uploads/linked-1024x191.png 1024w" sizes="(max-width: 1674px) 100vw, 1674px" /></figure> <h3>Execution</h3> <p>The bytecode is executed by the LLInt, which is written in a portable assembly called <em>offlineasm</em>. Here are a few notes about offlineasm that may help understand the code snippets that will follow:</p> <ul> <li>Temporary registers are <code>t0-t5</code>, argument registers are <code>a0-a3</code> and return registers are <code>r0</code> and <code>r1</code>. For floating point, the equivalent registers are <code>ft0-ft5</code>, <code>fa0-fa3</code> and <code>fr</code>. <code>cfp</code> and <code>sp</code> are special registers that hold the call frame and stack pointer respectively.</li> <li>Instructions have one of the following suffixes: <code>b</code> for byte, <code>h</code> for 16-bit word, <code>i</code> for 32-bit word, <code>q</code> for 64-bit word and <code>p</code> for pointer (either 32- or 64-bit depending on the architecture).</li> <li>Macros are lambda expressions that take zero or more arguments and return code. Macros may be named or anonymous and can be passed as arguments to other macros.</li> </ul> <p>If you want to learn more about offlineasm, <a href="https://github.com/WebKit/webkit/blob/ce43591e98f2805d8eae85ee2518e3441088cbe0/Source/JavaScriptCore/llint/LowLevelInterpreter.asm">LowLevelInterpreter.asm</a> is the main offlineasm file in JSC and it contains a more in depth explanation of the language at the top.</p> <p>The old bytecode format had two big advantages related to interpreter throughput: direct threading and inline caching.</p> <p><strong>Direct Threading</strong></p> <p>The linked bytecode had the actual pointer to the offlineasm implementation of the instruction in place of the opcode, which made executing the next instruction as simple as advancing the program counter (PC) by the size of the current instruction and making an indirect jump. That is illustrated in the following offlineasm code:</p> <pre><code class="cpp"><span class="identifier">macro</span> <span class="identifier">dispatch</span>(<span class="identifier">instructionSize</span>) <span class="identifier">addp</span> <span class="identifier">instructionSize</span> * <span class="identifier">PtrSize</span>, <span class="identifier">PC</span> <span class="identifier">jmp</span> [<span class="identifier">PC</span>] <span class="identifier">end</span> </code></pre> <p>Notice that <code>dispatch</code> is a macro, this way the code is duplicated at the end of every instruction. This is very efficient, since it&#8217;s just an addition plus an indirect branch. The duplication reduces branch prediction pollution since we don&#8217;t have all instructions jumping to a common label and sharing the same indirect jump to the next instruction.</p> <p><strong>Inline Caching</strong></p> <p>Since the instruction stream is writable and all the arguments are pointer-sized, we can store metadata in the instruction stream itself. The best example of this is for the <code>get_by_id</code> instruction, which is emitted when we load from an object in JavaScript.</p> <pre><code class="js"><span class="identifier">object</span>.<span class="identifier">field</span> </code></pre> <p>This emits a <code>get_by_id</code> for loading the property <code>field</code> from <code>object</code>. Since this is one of the most common operations in JavaScript, it&#8217;s crucial that it be fast. JSC uses <a href="https://dl.acm.org/citation.cfm?id=800542">inline caching</a> as a way of speeding this up. The way this was done in the interpreter was by reserving space in the instruction stream to cache metadata about the load. More specifically, we recorded the <code>StructureID</code> of the object we are loading from and the memory offset from which we have to load the value. The LLInt implementation of <code>get_by_id</code> looked like the following:</p> <pre><code class="cpp"><span class="identifier">_llint_op_get_by_id</span>: <span class="comment">// Read operand 2 from the instruction stream as a signed integer, </span> <span class="comment">// i.e. the virtual register of `object` </span> <span class="identifier">loadisFromInstruction</span>(<span class="number">2</span>, <span class="identifier">t0</span>) <span class="comment">// Load `object` from the stack and its structureID </span> <span class="identifier">loadConstantOrVariableCell</span>(<span class="identifier">t0</span>, <span class="identifier">t3</span>, .<span class="identifier">opGetByIdSlow</span>) <span class="identifier">loadi</span> <span class="identifier">JSCell</span>::<span class="identifier">m_structureID</span>[<span class="identifier">t3</span>], <span class="identifier">t1</span> <span class="comment">// Read the cached StructureID and verify that it matches the object's </span> <span class="identifier">loadisFromInstruction</span>(<span class="number">4</span>, <span class="identifier">t2</span>) <span class="identifier">bineq</span> <span class="identifier">t2</span>, <span class="identifier">t1</span>, .<span class="identifier">opGetByIdSlow</span> <span class="comment">// Read the PropertyOffset of `field` and load the actual value from it </span> <span class="identifier">loadisFromInstruction</span>(<span class="number">5</span>, <span class="identifier">t1</span>) <span class="identifier">loadPropertyAtVariableOffset</span>(<span class="identifier">t1</span>, <span class="identifier">t3</span>, <span class="identifier">t0</span>) <span class="comment">// Read the virtual register where the result should be stored and store </span> <span class="comment">// the value to it </span> <span class="identifier">loadisFromInstruction</span>(<span class="number">1</span>, <span class="identifier">t2</span>) <span class="identifier">storeq</span> <span class="identifier">t0</span>, [<span class="identifier">cfr</span>, <span class="identifier">t2</span>, <span class="number">8</span>] <span class="identifier">dispatch</span>(<span class="identifier">constexpr</span> <span class="identifier">op_get_by_id_length</span>) .<span class="identifier">opGetByIdSlow</span> <span class="comment">// Jump to C++ slow path </span> <span class="identifier">callSlowPath</span>(<span class="identifier">_llint_slow_path_get_by_id</span>) <span class="identifier">dispatch</span>(<span class="identifier">constexpr</span> <span class="identifier">op_get_by_id_length</span>) </code></pre> <h2>New Bytecode Format</h2> <p>When designing the new bytecode, we had two major goals: it should be more compact and easily cacheable on disk. With these two goals, we expected significant improvements on memory usage and set ourselves to improve runtime performance through caching. This shaped how we encoded instructions as well as runtime metadata.</p> <p>The first and biggest change is that we no longer have a separate linked encoding for execution. This immediately means that the bytecode can no longer be direct threaded, since the address of the instruction could not be stored to disk, as it changes with every program invocation. Removing this optimization was a deliberate choice of the design.</p> <p>In order to make the single format suitable for both storage and execution, each instruction can be encoded as either <em>narrow</em> or <em>wide</em>.</p> <h3>Narrow Instructions</h3> <p>In a narrow instruction, the opcode and its operands each take 1-byte. Here&#8217;s the <code>add</code> instruction again, this time as a narrow instruction in the new format:</p> <figure class="widescreen mattewhite"><img decoding="async" src="https://webkit.org/wp-content/uploads/narrow.png" alt="Narrow" width="1372" height="326" class="alignnone size-full wp-image-9344" srcset="https://webkit.org/wp-content/uploads/narrow.png 1372w, https://webkit.org/wp-content/uploads/narrow-300x71.png 300w, https://webkit.org/wp-content/uploads/narrow-768x182.png 768w, https://webkit.org/wp-content/uploads/narrow-1024x243.png 1024w" sizes="(max-width: 1372px) 100vw, 1372px" /></figure> <p>Ideally, all instructions would be encoded as narrow, but not all operands fit into a single byte. If any of the operands (or the opcode for that matter) requires more than 1 byte, the whole instruction is promoted to wide.</p> <h3>Wide Instructions</h3> <p>A wide instruction consists of a special 1-byte opcode, <code>op_wide</code>, followed by a series of 4-byte slots for the original opcode and each of its arguments.</p> <figure class="widescreen mattewhite"><img loading="lazy" decoding="async" width="1504" height="327" src="https://webkit.org/wp-content/uploads/wide.png" alt="Wide Instructions" class="wp-image-9350" srcset="https://webkit.org/wp-content/uploads/wide.png 1504w, https://webkit.org/wp-content/uploads/wide-300x65.png 300w, https://webkit.org/wp-content/uploads/wide-768x167.png 768w, https://webkit.org/wp-content/uploads/wide-1024x223.png 1024w" sizes="auto, (max-width: 1504px) 100vw, 1504px" /></figure> <p>An important thing to notice here is that it is not possible to have a single wide operand &#8211; if one operand overflows, the whole instruction becomes wide. This is an important compromise, because even though it might seem wasteful at first, it makes the implementation much simpler: the offset of any given operand is the same regardless of the instruction being narrow or wide. The only difference is whether the instruction stream is treated as an array of 4-byte values or 1-byte values.</p> <h3>Linking / Metadata Table</h3> <p>The other fundamental part of the new bytecode is the metadata table. During linking, instead of constructing a new instruction stream, we initialize a side table with all the writable data associated with any given instruction. Conceptually, the table is 2-dimensional, its first index is the opcode for the instruction, e.g. <code>add</code>, which points to a monomorphic array of metadata entries for that specific instruction. For example, we have a struct called <code>OpAdd::Metadata</code> to hold the metadata for the <code>add</code> instruction, so accessing <code>metadataTable[op_add]</code> will result in a pointer of type <code>OpAdd::Metadata*</code>. Additionally, each instruction has a special operand, <code>metadataID</code>, which is used as the second index in the metadata table.</p> <figure class="widescreen mattewhite"><img loading="lazy" decoding="async" width="1536" height="661" src="https://webkit.org/wp-content/uploads/metadata.png" alt="Metadata" class="wp-image-9339" srcset="https://webkit.org/wp-content/uploads/metadata.png 1536w, https://webkit.org/wp-content/uploads/metadata-300x129.png 300w, https://webkit.org/wp-content/uploads/metadata-768x331.png 768w, https://webkit.org/wp-content/uploads/metadata-1024x441.png 1024w" sizes="auto, (max-width: 1536px) 100vw, 1536px" /></figure> <p>For compactness, the metadata table is laid out in memory as a single block of memory. Here&#8217;s a representation of what the table above would actually look like in memory.</p> <figure class="widescreen mattewhite"><img loading="lazy" decoding="async" width="1902" height="361" src="https://webkit.org/wp-content/uploads/metadata-memory.png" alt="Metadata Memory Table" class="wp-image-9338" srcset="https://webkit.org/wp-content/uploads/metadata-memory.png 1902w, https://webkit.org/wp-content/uploads/metadata-memory-300x57.png 300w, https://webkit.org/wp-content/uploads/metadata-memory-768x146.png 768w, https://webkit.org/wp-content/uploads/metadata-memory-1024x194.png 1024w" sizes="auto, (max-width: 1902px) 100vw, 1902px" /></figure> <p>At the start of the table is the header, an array containing an integer for each opcode representing the offset from the start of the table where the metadata for that opcode starts. The next region is the payload, which contains the actual metadata for each opcode.</p> <h3>Execution</h3> <p>The biggest changes to execution are that the interpreter is now <em>indirect threaded</em>, and for any writable or runtime metadata, we need to read from the metadata table. Another interesting aspect is how wide instructions are executed.</p> <h4>Indirect Threading</h4> <p>The process of mapping from opcode to instruction address, which used to be done as part of linking in the old format, is now part of the interpreter dispatch. This means that extra loads are required, and the dispatch macro now looks like the following:</p> <pre><code class="cpp"><span class="identifier">macro</span> <span class="identifier">dispatch</span>(<span class="identifier">instructionSize</span>) <span class="identifier">addp</span> <span class="identifier">instructionSize</span>, <span class="identifier">PC</span> <span class="identifier">loadb</span> [<span class="identifier">PC</span>], <span class="identifier">t0</span> <span class="identifier">leap</span> <span class="identifier">_g_opcodeMap</span>, <span class="identifier">t1</span> <span class="identifier">jmp</span> [<span class="identifier">t1</span>, <span class="identifier">t0</span>, <span class="identifier">PtrSize</span>] <span class="identifier">end</span> </code></pre> <h4>Metadata Table</h4> <p>The same kind of &#8220;inline caching&#8221;† still applies to <code>get_by_id</code>, but given that we need to write the metadata at runtime and the instruction stream is now read-only, this data needs to live in the metadata table.</p> <p>Loads from the metadata table are a bit costly, since the <code>CodeBlock</code> needs to be loaded from the call frame, the metadata table from the <code>CodeBlock</code>, the array for the current opcode from the table and then finally the metadata entry from the array based on the current instruction&#8217;s <code>metadataID</code>.</p> <p><em>† I write &#8220;inline caching&#8221; in quotes here since it&#8217;s not technically inline anymore.</em></p> <h4>Wide Instruction Execution</h4> <p>The execution of wide instructions is surprisingly simple: there are two functions for each instruction, one for the narrow version and another for the wide. We take advantage of <em>offlineasm</em> to generate the two functions from a single implementation. (e.g. the implementation of <code>op_add</code> will automatically generate its wide version, <code>op_add_wide</code>.)</p> <p>By default, the narrow version of the instruction is executed, until the special instruction <code>op_wide</code> is executed. All it does is read the next opcode, and dispatch to its wide version, e.g. <code>op_add_wide</code>. Once the wide opcode is done, it goes back to dispatching a narrow instruction, since every wide instruction needs the 1-byte <code>op_wide</code> prefix.</p> <h2>Memory Usage</h2> <p>The new bytecode format uses approximately <strong>50%</strong> less memory, which means a reduction of <strong>10%</strong> in overall memory usage for JavaScript-heavy websites, such as Facebook or Reddit.</p> <p>Here&#8217;s a chart comparing the <strong>bytecode size</strong> for <a href="https://reddit.com/">reddit.com</a>, <a href="https://apple.com/">apple.com</a>, <a href="https://facebook.com/">facebook.com</a> and <a href="https://gmail.com/">gmail.com</a>.</p> <figure class="widescreen mattewhite"><img loading="lazy" decoding="async" width="2474" height="3054" src="https://webkit.org/wp-content/uploads/Screen-Shot-2019-04-19-at-10.19.30.png" alt="Bytecode size charts for reddit.com, apple.com, facebook.com and gmail.com" class="wp-image-9334" style="max-height: 900px;" srcset="https://webkit.org/wp-content/uploads/Screen-Shot-2019-04-19-at-10.19.30.png 2474w, https://webkit.org/wp-content/uploads/Screen-Shot-2019-04-19-at-10.19.30-243x300.png 243w, https://webkit.org/wp-content/uploads/Screen-Shot-2019-04-19-at-10.19.30-768x948.png 768w, https://webkit.org/wp-content/uploads/Screen-Shot-2019-04-19-at-10.19.30-830x1024.png 830w" sizes="auto, (max-width: 2474px) 100vw, 2474px" /></figure> <p>Notice that in the <em>After</em> case the <em>Metadata</em> has been merged with <em>Linked</em> to represent the memory used by the metadata table and <em>Unlinked</em> represents the actual bytecode instructions. The reason is that a significant part of what lives in the new metadata used to live in the old linked bytecode. Otherwise, the comparison would look skewed, since the whole <em>Linked</em> bar would be gone and the <em>Metadata</em> would seem to have doubled in size, when in reality it was part of the data from <em>Linked</em> that moved into <em>Metadata</em>.</p> <h2>Performance</h2> <p>As discussed earlier, indirect threading increases the overhead of the interpreter dispatch. However, given the average complexity of the bytecode instructions in JSC we did not expect the dispatch overhead to play a meaningful role in the overall performance of the interpreter. This is further amortized by the multiple JIT tiers. We profiled purely switching from direct to indirect threading in CLoop, the C++ backend for LLInt, and the results were neutral even with the JITs disabled.</p> <p>Loads from the metadata table are costly, involving a large chain of loads. In order to reduce this chain, we pin a <a href="https://en.wikipedia.org/wiki/X86_calling_conventions#Callee-saved_(non-volatile)_registers">callee save register</a> in the interpreter to hold the pointer to the metadata table at all times. Even with this optimization, it takes three loads to access the metadata entry. This was a 10% interpreter slowdown, but was neutral when running with all JIT tiers enabled.</p> <h2>Bonus: Type Safety</h2> <p>Changing the bytecode format required changes across the whole engine, so we decided to take this as an opportunity to improve the bytecode-related infrastructure, increasing the type safety, readability and maintainability of the code.</p> <p>To support all this changes, first we needed to change how instructions were specified. Originally, instructions were declared in a JSON file, with their respective name and length (the number of operands plus one, for the opcode). Here is how the <code>add</code> instruction was declared:</p> <pre><code class="json">{ <span class="string">"name"</span><span class="operator">:</span> <span class="string">"op_add"</span>, <span class="string">"length"</span><span class="operator">:</span> <span class="number">5</span> } </code></pre> <p>When accessing the instruction and its operands from C++ the code would look roughly like this:</p> <pre><code class="cpp"><span class="identifier">SLOW_PATH_DECL</span>(<span class="identifier">slow_path_add</span>) { <span class="identifier">JSValue</span> <span class="identifier">lhs</span> = <span class="identifier">OP_C</span>(<span class="number">2</span>).<span class="identifier">jsValue</span>(); <span class="identifier">JSValue</span> <span class="identifier">rhs</span> = <span class="identifier">OP_C</span>(<span class="number">3</span>).<span class="identifier">jsValue</span>(); ... } </code></pre> <p>Notice that operands were accessed by their offset: <code>OP_C</code> was a macro that would access the <code>Instruction* pc</code> argument (hidden here by the <code>SLOW_PATH_DECL</code> macro) at the given offset. However, the type of the data at the specified offset is unknown, so the result would have to be cast to the desired type. This is error-prone and makes the code harder to understand. The only way to learn which operands an instruction had (and their types) was to look for usages of it and look at variable names and type casts.</p> <p>With the new infrastructure, when declaring an instruction, a name and type must be given for each of the operands, as well as declaring all the data that will be stored in the metadata table.</p> <pre><code class="cpp"><span class="identifier">op</span> :<span class="identifier">add</span>, <span class="identifier">args</span>: { <span class="identifier">dst</span>: <span class="identifier">VirtualRegister</span>, <span class="identifier">lhs</span>: <span class="identifier">VirtualRegister</span>, <span class="identifier">rhs</span>: <span class="identifier">VirtualRegister</span>, <span class="identifier">operandTypes</span>: <span class="identifier">OperandTypes</span>, }, <span class="identifier">metadata</span>: { <span class="identifier">arithProfile</span>: <span class="identifier">ArithProfile</span>, } </code></pre> <p>With this extra information, it is now possible to generate a fully typed <code>struct</code> for each instruction, which results in safer C++ code:</p> <pre><code class="cpp"><span class="identifier">SLOW_PATH_DECL</span>(<span class="identifier">slow_path_add</span>) { <span class="identifier">OpAdd</span> <span class="identifier">bytecode</span> = <span class="identifier">pc</span>-&gt;<span class="identifier">as</span>&lt;<span class="identifier">OpAdd</span>&gt;(); <span class="identifier">JSValue</span> <span class="identifier">lhs</span> = <span class="identifier">GET_C</span>(<span class="identifier">bytecode</span>.<span class="identifier">m_lhs</span>); <span class="identifier">JSValue</span> <span class="identifier">rhs</span> = <span class="identifier">GET_C</span>(<span class="identifier">bytecode</span>.<span class="identifier">m_rhs</span>); ... } </code></pre> <p>In the example above, we first need to convert the generic <code>Instruction* pc</code> to the instruction we want to access, which will perform a runtime check. If the opcode matches, it returns an instance of the generated struct, <code>OpAdd</code>, which includes the fields <code>m_lhs</code> and <code>m_rhs</code>, both of type <code>VirtualRegister</code> as specified in our instruction declaration.</p> <p>The extra information also allowed us to replace a lot of mechanical code with safer, generated code. For example, we auto generate all the type safe code for writing instructions to the instruction stream, which automatically does the narrow/wide fitting. We also generate all the code to dump the instructions for debugging.</p> <h2>Conclusion</h2> <p>JavaScriptCore has a new bytecode format that uses 50% less memory on average and is available on Safari 12.1 and <a href="https://webkit.org/downloads/">Safari Technology Preview</a>. The work on the caching API for the new bytecode is already underway in the WebKit repository, and anyone interested is welcome to follow along and contribute on <a href="http://bugs.webkit.org/">bugs.webkit.org</a>! You can also get in touch with me on <a href="https://twitter.com/tadeuzagallo">Twitter</a> with any questions or comments.</p> </div> </article> <aside class="nextrouter" aria-label="Next/Previous posts"> <div class="bodycopy"> <a class="page-numbers next-post" href="https://webkit.org/blog/9375/release-notes-for-safari-technology-preview-86/" rel="next"><div class="nextrouter-copy"><span class="label">Next</span><span class="title">Release Notes for Safari Technology Preview 86</span><span class="link">Learn more</span></div></a> </div> </aside> <aside class="nextrouter previous" aria-label="Next/Previous posts"> <div class="bodycopy"> <a class="page-numbers prev-post" href="https://webkit.org/blog/9281/release-notes-for-safari-technology-preview-85/" rel="prev"><div class="nextrouter-copy"><span class="label">Previously</span><span class="title">Release Notes for Safari Technology Preview 85</span><span class="link">Learn more</span></div></a> </div> </aside> </div><!--.page-width--> </main><!-- #content --> <footer> <div class="page-width"> <nav id="footer-nav" aria-label="Footer menu"><div class="menu-footer-menu-container"><ul id="menu-footer-menu" class="menu"><li id="menu-item-7617" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-7617"><a rel="me" href="https://front-end.social/@webkit">@webkit@front-end.social</a></li> <li id="menu-item-5365" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-5365"><a href="https://webkit.org/sitemap/">Site Map</a></li> <li id="menu-item-4185" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-4185"><a href="http://www.apple.com/legal/privacy/">Privacy Policy</a></li> <li id="menu-item-4287" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4287"><a href="https://webkit.org/licensing-webkit/">Licensing WebKit</a></li> <li id="menu-item-4187" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4187"><a href="https://webkit.org/terms-of-use/">WebKit and the WebKit logo are trademarks of Apple Inc.</a></li> </ul></div></nav> </div> </footer> <script type="text/javascript" src="https://webkit.org/wp-content/themes/webkit/scripts/global.js?ver=1.0" id="theme-global-js"></script> </body> </html> <!-- Dynamic page generated in 0.350 seconds. --> <!-- Cached page generated by WP-Super-Cache on 2024-11-27 08:13:37 --> <!-- super cache -->

Pages: 1 2 3 4 5 6 7 8 9 10