Compare commits

..

5 Commits

Author SHA1 Message Date
minggo 9eae68bdbf
Merge pull request #437 from cocos/v3.8.1
V3.8.1
2023-10-10 15:17:30 +08:00
minggo d2d1fb09aa
Revert "V3.8.1 (#435)" (#436)
This reverts commit c481216bf5.
2023-10-10 15:16:30 +08:00
minggo c481216bf5
V3.8.1 (#435)
* update spine wasm & asm, fix event data bind. (#410)

* update spine wasm & asm, fix event data bind.

* update spine wasm & asm to fix event data.

* update spine wasm & asm api.

* update spine wasm & asm to fix const string.

* update bullet wasm: [fix] cct scaling causes trigger event missing (#416)

---------

Co-authored-by: Canvas <Canvasfull@gmail.com>
Co-authored-by: Ling Zhan <lealzhan@126.com>
2023-10-10 14:02:28 +08:00
minggo 2fe0317e84
Merge pull request #414 from dumganhar/v3.8.1-hmi
v3.8.1-hmi merges v3.8.0-hmi branch
2023-09-01 10:29:02 +08:00
James Chen 43a8b88764 Merge branch 'v3.8.0-hmi' into v3.8.1-hmi 2023-09-01 10:26:08 +08:00
161 changed files with 192 additions and 53564 deletions

149
emscripten/webgpu/glslang.js Executable file → Normal file
View File

@ -1,49 +1,118 @@
var Module = (function() {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
var Module = (() => { return (
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; function(Module) {
Module = Module || {};
return ( var c;c||(c=typeof Module !== 'undefined' ? Module : {});
function(Module) { c.compileGLSLZeroCopy=function(a,b,d,e){d=!!d;switch(b){case "vertex":var g=0;break;case "fragment":g=4;break;case "compute":g=5;break;default:throw Error("shader_stage must be 'vertex', 'fragment', or 'compute'.");}switch(e||"1.0"){case "1.0":var f=65536;break;case "1.1":f=65792;break;case "1.2":f=66048;break;case "1.3":f=66304;break;case "1.4":f=66560;break;case "1.5":f=66816;break;default:throw Error("spirv_version must be '1.0' ~ '1.5'.");}e=c._malloc(4);b=c._malloc(4);var h=aa([a,g,d,f,e,b]);
Module = Module || {}; d=k(e);a=k(b);c._free(e);c._free(b);if(0===h)throw Error("GLSL compilation failed");e={};d/=4;e.data=c.HEAPU32.subarray(d,d+a);e.free=function(){c._destroy_output_buffer(h)};return e};c.compileGLSL=function(a,b,d,e){a=c.compileGLSLZeroCopy(a,b,d,e);b=a.data.slice();a.free();return b};var p={},q;for(q in c)c.hasOwnProperty(q)&&(p[q]=c[q]);var r="./this.program",t=!1,u=!1;t="object"===typeof window;u="function"===typeof importScripts;var v="",w;
if(t||u)u?v=self.location.href:document.currentScript&&(v=document.currentScript.src),_scriptDir&&(v=_scriptDir),0!==v.indexOf("blob:")?v=v.substr(0,v.lastIndexOf("/")+1):v="",u&&(w=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)});var x=c.print||console.log.bind(console),y=c.printErr||console.warn.bind(console);for(q in p)p.hasOwnProperty(q)&&(c[q]=p[q]);p=null;c.thisProgram&&(r=c.thisProgram);var A;
c.wasmBinary&&(A=c.wasmBinary);"object"!==typeof WebAssembly&&y("no native wasm support detected");function k(a){var b="i32";"*"===b.charAt(b.length-1)&&(b="i32");switch(b){case "i1":return B[a>>0];case "i8":return B[a>>0];case "i16":return ba[a>>1];case "i32":return C[a>>2];case "i64":return C[a>>2];case "float":return ca[a>>2];case "double":return da[a>>3];default:D("invalid type for getValue: "+b)}return null}var E,ea=new WebAssembly.Table({initial:859,maximum:859,element:"anyfunc"}),fa=!1;
function ha(){var a=c._convert_glsl_to_spirv;a||D("Assertion failed: Cannot call unknown function convert_glsl_to_spirv, make sure it is exported");return a}
function aa(a){var b="string number boolean number number number".split(" "),d={string:function(a){var b=0;if(null!==a&&void 0!==a&&0!==a){var d=(a.length<<2)+1;b=G(d);ia(a,H,b,d)}return b},array:function(a){var b=G(a.length);B.set(a,b);return b}},e=ha(),g=[],f=0;if(a)for(var h=0;h<a.length;h++){var n=d[b[h]];n?(0===f&&(f=ja()),g[h]=n(a[h])):g[h]=a[h]}a=e.apply(null,g);0!==f&&ka(f);return a}var la="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;
function I(a,b,d){var e=b+d;for(d=b;a[d]&&!(d>=e);)++d;if(16<d-b&&a.subarray&&la)return la.decode(a.subarray(b,d));for(e="";b<d;){var g=a[b++];if(g&128){var f=a[b++]&63;if(192==(g&224))e+=String.fromCharCode((g&31)<<6|f);else{var h=a[b++]&63;g=224==(g&240)?(g&15)<<12|f<<6|h:(g&7)<<18|f<<12|h<<6|a[b++]&63;65536>g?e+=String.fromCharCode(g):(g-=65536,e+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else e+=String.fromCharCode(g)}return e}
function ia(a,b,d,e){if(0<e){e=d+e-1;for(var g=0;g<a.length;++g){var f=a.charCodeAt(g);if(55296<=f&&57343>=f){var h=a.charCodeAt(++g);f=65536+((f&1023)<<10)|h&1023}if(127>=f){if(d>=e)break;b[d++]=f}else{if(2047>=f){if(d+1>=e)break;b[d++]=192|f>>6}else{if(65535>=f){if(d+2>=e)break;b[d++]=224|f>>12}else{if(d+3>=e)break;b[d++]=240|f>>18;b[d++]=128|f>>12&63}b[d++]=128|f>>6&63}b[d++]=128|f&63}}b[d]=0}}"undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");var J,B,H,ba,C,ca,da;
function ma(a){J=a;c.HEAP8=B=new Int8Array(a);c.HEAP16=ba=new Int16Array(a);c.HEAP32=C=new Int32Array(a);c.HEAPU8=H=new Uint8Array(a);c.HEAPU16=new Uint16Array(a);c.HEAPU32=new Uint32Array(a);c.HEAPF32=ca=new Float32Array(a);c.HEAPF64=da=new Float64Array(a)}var na=c.TOTAL_MEMORY||16777216;c.wasmMemory?E=c.wasmMemory:E=new WebAssembly.Memory({initial:na/65536});E&&(J=E.buffer);na=J.byteLength;ma(J);C[84916]=5582704;
function K(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b();else{var d=b.J;"number"===typeof d?void 0===b.H?c.dynCall_v(d):c.dynCall_vi(d,b.H):d(void 0===b.H?null:b.H)}}}var oa=[],pa=[],qa=[],ra=[];function sa(){var a=c.preRun.shift();oa.unshift(a)}var L=0,M=null,N=null;c.preloadedImages={};c.preloadedAudios={};function D(a){if(c.onAbort)c.onAbort(a);x(a);y(a);fa=!0;throw new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");}
function ta(){var a=O;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var O="glslang.wasm";if(!ta()){var ua=O;O=c.locateFile?c.locateFile(ua,v):v+ua}function wa(){try{if(A)return new Uint8Array(A);if(w)return w(O);throw"both async and sync fetching of the wasm failed";}catch(a){D(a)}}
function xa(){return A||!t&&!u||"function"!==typeof fetch?new Promise(function(a){a(wa())}):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return wa()})}pa.push({J:function(){ya()}});var za=[null,[],[]],P=0;function Aa(){P+=4;return C[P-4>>2]}var Q={},Ba={};
function Ca(){if(!R){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"===typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:r},b;for(b in Ba)a[b]=Ba[b];var d=[];for(b in a)d.push(b+"="+a[b]);R=d}return R}var R;function S(a){return 0===a%4&&(0!==a%100||0===a%400)}function T(a,b){for(var d=0,e=0;e<=b;d+=a[e++]);return d}var U=[31,29,31,30,31,30,31,31,30,31,30,31],W=[31,28,31,30,31,30,31,31,30,31,30,31];
function X(a,b){for(a=new Date(a.getTime());0<b;){var d=a.getMonth(),e=(S(a.getFullYear())?U:W)[d];if(b>e-a.getDate())b-=e-a.getDate()+1,a.setDate(1),11>d?a.setMonth(d+1):(a.setMonth(0),a.setFullYear(a.getFullYear()+1));else{a.setDate(a.getDate()+b);break}}return a}
function Da(a,b,d,e){function g(a,b,d){for(a="number"===typeof a?a.toString():a||"";a.length<b;)a=d[0]+a;return a}function f(a,b){return g(a,b,"0")}function h(a,b){function V(a){return 0>a?-1:0<a?1:0}var d;0===(d=V(a.getFullYear()-b.getFullYear()))&&0===(d=V(a.getMonth()-b.getMonth()))&&(d=V(a.getDate()-b.getDate()));return d}function n(a){switch(a.getDay()){case 0:return new Date(a.getFullYear()-1,11,29);case 1:return a;case 2:return new Date(a.getFullYear(),0,3);case 3:return new Date(a.getFullYear(),
0,2);case 4:return new Date(a.getFullYear(),0,1);case 5:return new Date(a.getFullYear()-1,11,31);case 6:return new Date(a.getFullYear()-1,11,30)}}function z(a){a=X(new Date(a.A+1900,0,1),a.G);var b=n(new Date(a.getFullYear()+1,0,4));return 0>=h(n(new Date(a.getFullYear(),0,4)),a)?0>=h(b,a)?a.getFullYear()+1:a.getFullYear():a.getFullYear()-1}var m=C[e+40>>2];e={N:C[e>>2],M:C[e+4>>2],D:C[e+8>>2],C:C[e+12>>2],B:C[e+16>>2],A:C[e+20>>2],F:C[e+24>>2],G:C[e+28>>2],X:C[e+32>>2],L:C[e+36>>2],O:m?m?I(H,m,void 0):
"":""};d=d?I(H,d,void 0):"";m={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var l in m)d=d.replace(new RegExp(l,"g"),m[l]);var F="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),
va="January February March April May June July August September October November December".split(" ");m={"%a":function(a){return F[a.F].substring(0,3)},"%A":function(a){return F[a.F]},"%b":function(a){return va[a.B].substring(0,3)},"%B":function(a){return va[a.B]},"%C":function(a){return f((a.A+1900)/100|0,2)},"%d":function(a){return f(a.C,2)},"%e":function(a){return g(a.C,2," ")},"%g":function(a){return z(a).toString().substring(2)},"%G":function(a){return z(a)},"%H":function(a){return f(a.D,2)},
"%I":function(a){a=a.D;0==a?a=12:12<a&&(a-=12);return f(a,2)},"%j":function(a){return f(a.C+T(S(a.A+1900)?U:W,a.B-1),3)},"%m":function(a){return f(a.B+1,2)},"%M":function(a){return f(a.M,2)},"%n":function(){return"\n"},"%p":function(a){return 0<=a.D&&12>a.D?"AM":"PM"},"%S":function(a){return f(a.N,2)},"%t":function(){return"\t"},"%u":function(a){return a.F||7},"%U":function(a){var b=new Date(a.A+1900,0,1),d=0===b.getDay()?b:X(b,7-b.getDay());a=new Date(a.A+1900,a.B,a.C);return 0>h(d,a)?f(Math.ceil((31-
d.getDate()+(T(S(a.getFullYear())?U:W,a.getMonth()-1)-31)+a.getDate())/7),2):0===h(d,b)?"01":"00"},"%V":function(a){var b=n(new Date(a.A+1900,0,4)),d=n(new Date(a.A+1901,0,4)),e=X(new Date(a.A+1900,0,1),a.G);return 0>h(e,b)?"53":0>=h(d,e)?"01":f(Math.ceil((b.getFullYear()<a.A+1900?a.G+32-b.getDate():a.G+1-b.getDate())/7),2)},"%w":function(a){return a.F},"%W":function(a){var b=new Date(a.A,0,1),d=1===b.getDay()?b:X(b,0===b.getDay()?1:7-b.getDay()+1);a=new Date(a.A+1900,a.B,a.C);return 0>h(d,a)?f(Math.ceil((31-
d.getDate()+(T(S(a.getFullYear())?U:W,a.getMonth()-1)-31)+a.getDate())/7),2):0===h(d,b)?"01":"00"},"%y":function(a){return(a.A+1900).toString().substring(2)},"%Y":function(a){return a.A+1900},"%z":function(a){a=a.L;var b=0<=a;a=Math.abs(a)/60;return(b?"+":"-")+String("0000"+(a/60*100+a%60)).slice(-4)},"%Z":function(a){return a.O},"%%":function(){return"%"}};for(l in m)0<=d.indexOf(l)&&(d=d.replace(new RegExp(l,"g"),m[l](e)));l=Ea(d);if(l.length>b)return 0;B.set(l,a);return l.length-1}
function Ea(a){for(var b=0,d=0;d<a.length;++d){var e=a.charCodeAt(d);55296<=e&&57343>=e&&(e=65536+((e&1023)<<10)|a.charCodeAt(++d)&1023);127>=e?++b:b=2047>=e?b+2:65535>=e?b+3:b+4}b=Array(b+1);ia(a,b,0,b.length);return b}
var Ga={f:function(){},c:function(){c.___errno_location&&(C[c.___errno_location()>>2]=63);return-1},n:function(a,b){P=b;try{var d=Aa();var e=Aa();if(-1===d||0===e)var g=-28;else{var f=Q.K[d];if(f&&e===f.U){var h=(void 0).T(f.S);Q.R(d,h,e,f.flags,f.offset);(void 0).W(h);Q.K[d]=null;f.P&&Fa(f.V)}g=0}return g}catch(n){return D(n),-n.I}},a:function(){},b:function(){D()},k:function(a,b,d){H.set(H.subarray(b,b+d),a)},l:function(a){var b=B.length;if(2147418112<a)return!1;for(var d=1;4>=d;d*=2){var e=b*(1+
.2/d);e=Math.min(e,a+100663296);e=Math.max(16777216,a,e);0<e%65536&&(e+=65536-e%65536);a:{try{E.grow(Math.min(2147418112,e)-J.byteLength+65535>>16);ma(E.buffer);var g=1;break a}catch(f){}g=void 0}if(g)return!0}return!1},d:function(a,b){var d=0;Ca().forEach(function(e,g){var f=b+d;g=C[a+4*g>>2]=f;for(f=0;f<e.length;++f)B[g++>>0]=e.charCodeAt(f);B[g>>0]=0;d+=e.length+1});return 0},e:function(a,b){var d=Ca();C[a>>2]=d.length;var e=0;d.forEach(function(a){e+=a.length+1});C[b>>2]=e;return 0},h:function(){return 0},
j:function(){return 0},g:function(a,b,d,e){try{for(var g=0,f=0;f<d;f++){for(var h=C[b+8*f>>2],n=C[b+(8*f+4)>>2],z=0;z<n;z++){var m=H[h+z],l=za[a];0===m||10===m?((1===a?x:y)(I(l,0)),l.length=0):l.push(m)}g+=n}C[e>>2]=g;return 0}catch(F){return D(F),F.I}},memory:E,o:function(){},i:function(){},m:function(a,b,d,e){return Da(a,b,d,e)},table:ea},Ha=function(){function a(a){c.asm=a.exports;L--;c.monitorRunDependencies&&c.monitorRunDependencies(L);0==L&&(null!==M&&(clearInterval(M),M=null),N&&(a=N,N=null,
a()))}function b(b){a(b.instance)}function d(a){return xa().then(function(a){return WebAssembly.instantiate(a,e)}).then(a,function(a){y("failed to asynchronously prepare wasm: "+a);D(a)})}var e={env:Ga,wasi_snapshot_preview1:Ga};L++;c.monitorRunDependencies&&c.monitorRunDependencies(L);if(c.instantiateWasm)try{return c.instantiateWasm(e,a)}catch(g){return y("Module.instantiateWasm callback failed with error: "+g),!1}(function(){if(A||"function"!==typeof WebAssembly.instantiateStreaming||ta()||"function"!==
typeof fetch)return d(b);fetch(O,{credentials:"same-origin"}).then(function(a){return WebAssembly.instantiateStreaming(a,e).then(b,function(a){y("wasm streaming compile failed: "+a);y("falling back to ArrayBuffer instantiation");d(b)})})})();return{}}();c.asm=Ha;var ya=c.___wasm_call_ctors=function(){return(ya=c.___wasm_call_ctors=c.asm.p).apply(null,arguments)};c._convert_glsl_to_spirv=function(){return(c._convert_glsl_to_spirv=c.asm.q).apply(null,arguments)};
c._destroy_output_buffer=function(){return(c._destroy_output_buffer=c.asm.r).apply(null,arguments)};c._malloc=function(){return(c._malloc=c.asm.s).apply(null,arguments)};var Fa=c._free=function(){return(Fa=c._free=c.asm.t).apply(null,arguments)},ja=c.stackSave=function(){return(ja=c.stackSave=c.asm.u).apply(null,arguments)},G=c.stackAlloc=function(){return(G=c.stackAlloc=c.asm.v).apply(null,arguments)},ka=c.stackRestore=function(){return(ka=c.stackRestore=c.asm.w).apply(null,arguments)};
c.dynCall_vi=function(){return(c.dynCall_vi=c.asm.x).apply(null,arguments)};c.dynCall_v=function(){return(c.dynCall_v=c.asm.y).apply(null,arguments)};c.asm=Ha;var Y;c.then=function(a){if(Y)a(c);else{var b=c.onRuntimeInitialized;c.onRuntimeInitialized=function(){b&&b();a(c)}}return c};N=function Ia(){Y||Z();Y||(N=Ia)};
function Z(){function a(){if(!Y&&(Y=!0,!fa)){K(pa);K(qa);if(c.onRuntimeInitialized)c.onRuntimeInitialized();if(c.postRun)for("function"==typeof c.postRun&&(c.postRun=[c.postRun]);c.postRun.length;){var a=c.postRun.shift();ra.unshift(a)}K(ra)}}if(!(0<L)){if(c.preRun)for("function"==typeof c.preRun&&(c.preRun=[c.preRun]);c.preRun.length;)sa();K(oa);0<L||(c.setStatus?(c.setStatus("Running..."),setTimeout(function(){setTimeout(function(){c.setStatus("")},1);a()},1)):a())}}c.run=Z;
if(c.preInit)for("function"==typeof c.preInit&&(c.preInit=[c.preInit]);0<c.preInit.length;)c.preInit.pop()();Z();
var c;c||(c=typeof Module !== 'undefined' ? Module : {});var r,t;c.ready=new Promise(function(b,d){r=b;t=d}); return Module
c.compileGLSLZeroCopy=function(b,d,e,f){e=!!e;switch(d){case "vertex":var h=0;break;case "fragment":h=4;break;case "compute":h=5;break;default:throw Error("shader_stage must be 'vertex', 'fragment', or 'compute'.");}switch(f||"1.0"){case "1.0":var g=65536;break;case "1.1":g=65792;break;case "1.2":g=66048;break;case "1.3":g=66304;break;case "1.4":g=66560;break;case "1.5":g=66816;break;default:throw Error("spirv_version must be '1.0' ~ '1.5'.");}f=c._malloc(4);d=c._malloc(4);var m=aa([b,h,e,g,f,d]); }
e=u(f);b=u(d);c._free(f);c._free(d);if(0===m)throw Error("GLSL compilation failed");f={};e/=4;f.data=c.HEAPU32.subarray(e,e+b);f.free=function(){c._destroy_output_buffer(m)};return f};c.compileGLSL=function(b,d,e,f){b=c.compileGLSLZeroCopy(b,d,e,f);d=b.data.slice();b.free();return d};var v=Object.assign({},c),x="./this.program",y="object"==typeof window,z="function"==typeof importScripts,B="",C; );
if(y||z)z?B=self.location.href:"undefined"!=typeof document&&document.currentScript&&(B=document.currentScript.src),_scriptDir&&(B=_scriptDir),0!==B.indexOf("blob:")?B=B.substr(0,B.replace(/[?#].*/,"").lastIndexOf("/")+1):B="",z&&(C=b=>{var d=new XMLHttpRequest;d.open("GET",b,!1);d.responseType="arraybuffer";d.send(null);return new Uint8Array(d.response)});var ba=c.print||console.log.bind(console),D=c.printErr||console.warn.bind(console);Object.assign(c,v);v=null;c.thisProgram&&(x=c.thisProgram); })();
var E;c.wasmBinary&&(E=c.wasmBinary);var noExitRuntime=c.noExitRuntime||!0;"object"!=typeof WebAssembly&&F("no native wasm support detected");var G,H=!1,I="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0; // if (typeof exports === 'object' && typeof module === 'object')
function J(b,d){for(var e=d+NaN,f=d;b[f]&&!(f>=e);)++f;if(16<f-d&&b.buffer&&I)return I.decode(b.subarray(d,f));for(e="";d<f;){var h=b[d++];if(h&128){var g=b[d++]&63;if(192==(h&224))e+=String.fromCharCode((h&31)<<6|g);else{var m=b[d++]&63;h=224==(h&240)?(h&15)<<12|g<<6|m:(h&7)<<18|g<<12|m<<6|b[d++]&63;65536>h?e+=String.fromCharCode(h):(h-=65536,e+=String.fromCharCode(55296|h>>10,56320|h&1023))}}else e+=String.fromCharCode(h)}return e} // module.exports = Module;
function K(b,d,e,f){if(0<f){f=e+f-1;for(var h=0;h<b.length;++h){var g=b.charCodeAt(h);if(55296<=g&&57343>=g){var m=b.charCodeAt(++h);g=65536+((g&1023)<<10)|m&1023}if(127>=g){if(e>=f)break;d[e++]=g}else{if(2047>=g){if(e+1>=f)break;d[e++]=192|g>>6}else{if(65535>=g){if(e+2>=f)break;d[e++]=224|g>>12}else{if(e+3>=f)break;d[e++]=240|g>>18;d[e++]=128|g>>12&63}d[e++]=128|g>>6&63}d[e++]=128|g&63}}d[e]=0}}var L,M,N,ca,O,P,da,ea; // else if (typeof define === 'function' && define['amd'])
function fa(){var b=G.buffer;L=b;c.HEAP8=M=new Int8Array(b);c.HEAP16=ca=new Int16Array(b);c.HEAP32=O=new Int32Array(b);c.HEAPU8=N=new Uint8Array(b);c.HEAPU16=new Uint16Array(b);c.HEAPU32=P=new Uint32Array(b);c.HEAPF32=da=new Float32Array(b);c.HEAPF64=ea=new Float64Array(b)}var ha=[],ia=[],ja=[];function ka(){var b=c.preRun.shift();ha.unshift(b)}var Q=0,R=null,S=null; // define([], function() { return Module; });
function F(b){if(c.onAbort)c.onAbort(b);b="Aborted("+b+")";D(b);H=!0;b=new WebAssembly.RuntimeError(b+". Build with -sASSERTIONS for more info.");t(b);throw b;}function la(){return T.startsWith("data:application/octet-stream;base64,")}var T;T="glslang.wasm";if(!la()){var ma=T;T=c.locateFile?c.locateFile(ma,B):B+ma}function na(){var b=T;try{if(b==T&&E)return new Uint8Array(E);if(C)return C(b);throw"both async and sync fetching of the wasm failed";}catch(d){F(d)}} // else if (typeof exports === 'object')
function ra(){return E||!y&&!z||"function"!=typeof fetch?Promise.resolve().then(function(){return na()}):fetch(T,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+T+"'";return b.arrayBuffer()}).catch(function(){return na()})}function U(b){for(;0<b.length;)b.shift()(c)} // exports["Module"] = Module;
function u(b){var d="i32";d.endsWith("*")&&(d="*");switch(d){case "i1":return M[b>>0];case "i8":return M[b>>0];case "i16":return ca[b>>1];case "i32":return O[b>>2];case "i64":return O[b>>2];case "float":return da[b>>2];case "double":return ea[b>>3];case "*":return P[b>>2];default:F("invalid type for getValue: "+d)}return null}var V={}; // export default (() => {
function sa(){if(!W){var b={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:x||"./this.program"},d;for(d in V)void 0===V[d]?delete b[d]:b[d]=V[d];var e=[];for(d in b)e.push(d+"="+b[d]);W=e}return W}var W,ta=[null,[],[]];function X(b){return 0===b%4&&(0!==b%100||0===b%400)}var ua=[31,29,31,30,31,30,31,31,30,31,30,31],va=[31,28,31,30,31,30,31,31,30,31,30,31]; // const initialize = () => {
function wa(b){for(var d=0,e=0;e<b.length;++e){var f=b.charCodeAt(e);127>=f?d++:2047>=f?d+=2:55296<=f&&57343>=f?(d+=4,++e):d+=3}d=Array(d+1);K(b,d,0,d.length);return d} // return new Promise(resolve => {
function xa(b,d,e,f){function h(a,k,l){for(a="number"==typeof a?a.toString():a||"";a.length<k;)a=l[0]+a;return a}function g(a,k){return h(a,k,"0")}function m(a,k){function l(oa){return 0>oa?-1:0<oa?1:0}var A;0===(A=l(a.getFullYear()-k.getFullYear()))&&0===(A=l(a.getMonth()-k.getMonth()))&&(A=l(a.getDate()-k.getDate()));return A}function w(a){switch(a.getDay()){case 0:return new Date(a.getFullYear()-1,11,29);case 1:return a;case 2:return new Date(a.getFullYear(),0,3);case 3:return new Date(a.getFullYear(), // Module({
0,2);case 4:return new Date(a.getFullYear(),0,1);case 5:return new Date(a.getFullYear()-1,11,31);case 6:return new Date(a.getFullYear()-1,11,30)}}function p(a){var k=a.v;for(a=new Date((new Date(a.A+1900,0,1)).getTime());0<k;){var l=a.getMonth(),A=(X(a.getFullYear())?ua:va)[l];if(k>A-a.getDate())k-=A-a.getDate()+1,a.setDate(1),11>l?a.setMonth(l+1):(a.setMonth(0),a.setFullYear(a.getFullYear()+1));else{a.setDate(a.getDate()+k);break}}l=new Date(a.getFullYear()+1,0,4);k=w(new Date(a.getFullYear(),0, // locateFile() {
4));l=w(l);return 0>=m(k,a)?0>=m(l,a)?a.getFullYear()+1:a.getFullYear():a.getFullYear()-1}var n=O[f+40>>2];f={H:O[f>>2],G:O[f+4>>2],B:O[f+8>>2],D:O[f+12>>2],C:O[f+16>>2],A:O[f+20>>2],u:O[f+24>>2],v:O[f+28>>2],J:O[f+32>>2],F:O[f+36>>2],I:n?n?J(N,n):"":""};e=e?J(N,e):"";n={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d", // const i = import.meta.url.lastIndexOf('/')
"%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var q in n)e=e.replace(new RegExp(q,"g"),n[q]);var pa="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),qa="January February March April May June July August September October November December".split(" ");n={"%a":function(a){return pa[a.u].substring(0,3)},"%A":function(a){return pa[a.u]},"%b":function(a){return qa[a.C].substring(0,3)},"%B":function(a){return qa[a.C]}, // return import.meta.url.substring(0, i) + '/glslang.wasm';
"%C":function(a){return g((a.A+1900)/100|0,2)},"%d":function(a){return g(a.D,2)},"%e":function(a){return h(a.D,2," ")},"%g":function(a){return p(a).toString().substring(2)},"%G":function(a){return p(a)},"%H":function(a){return g(a.B,2)},"%I":function(a){a=a.B;0==a?a=12:12<a&&(a-=12);return g(a,2)},"%j":function(a){for(var k=0,l=0;l<=a.C-1;k+=(X(a.A+1900)?ua:va)[l++]);return g(a.D+k,3)},"%m":function(a){return g(a.C+1,2)},"%M":function(a){return g(a.G,2)},"%n":function(){return"\n"},"%p":function(a){return 0<= // },
a.B&&12>a.B?"AM":"PM"},"%S":function(a){return g(a.H,2)},"%t":function(){return"\t"},"%u":function(a){return a.u||7},"%U":function(a){return g(Math.floor((a.v+7-a.u)/7),2)},"%V":function(a){var k=Math.floor((a.v+7-(a.u+6)%7)/7);2>=(a.u+371-a.v-2)%7&&k++;if(k)53==k&&(l=(a.u+371-a.v)%7,4==l||3==l&&X(a.A)||(k=1));else{k=52;var l=(a.u+7-a.v-1)%7;(4==l||5==l&&X(a.A%400-1))&&k++}return g(k,2)},"%w":function(a){return a.u},"%W":function(a){return g(Math.floor((a.v+7-(a.u+6)%7)/7),2)},"%y":function(a){return(a.A+ // onRuntimeInitialized() {
1900).toString().substring(2)},"%Y":function(a){return a.A+1900},"%z":function(a){a=a.F;var k=0<=a;a=Math.abs(a)/60;return(k?"+":"-")+String("0000"+(a/60*100+a%60)).slice(-4)},"%Z":function(a){return a.I},"%%":function(){return"%"}};e=e.replace(/%%/g,"\x00\x00");for(q in n)e.includes(q)&&(e=e.replace(new RegExp(q,"g"),n[q](f)));e=e.replace(/\0\0/g,"%");q=wa(e);if(q.length>d)return 0;M.set(q,b);return q.length-1} // resolve({
function aa(b){var d="string number boolean number number number".split(" "),e={string:p=>{var n=0;if(null!==p&&void 0!==p&&0!==p){var q=(p.length<<2)+1;n=Y(q);K(p,N,n,q)}return n},array:p=>{var n=Y(p.length);M.set(p,n);return n}},f=c._convert_glsl_to_spirv,h=[],g=0;if(b)for(var m=0;m<b.length;m++){var w=e[d[m]];w?(0===g&&(g=ya()),h[m]=w(b[m])):h[m]=b[m]}b=f.apply(null,h);return b=function(p){0!==g&&za(g);return p}(b)} // compileGLSLZeroCopy: this.compileGLSLZeroCopy,
var Aa={b:function(){F("")},i:function(b,d,e){N.copyWithin(b,d,d+e)},g:function(b){var d=N.length;b>>>=0;if(2147483648<b)return!1;for(var e=1;4>=e;e*=2){var f=d*(1+.2/e);f=Math.min(f,b+100663296);var h=Math;f=Math.max(b,f);h=h.min.call(h,2147483648,f+(65536-f%65536)%65536);a:{try{G.grow(h-L.byteLength+65535>>>16);fa();var g=1;break a}catch(m){}g=void 0}if(g)return!0}return!1},e:function(b,d){var e=0;sa().forEach(function(f,h){var g=d+e;h=P[b+4*h>>2]=g;for(g=0;g<f.length;++g)M[h++>>0]=f.charCodeAt(g); // compileGLSL: this.compileGLSL,
M[h>>0]=0;e+=f.length+1});return 0},f:function(b,d){var e=sa();P[b>>2]=e.length;var f=0;e.forEach(function(h){f+=h.length+1});P[d>>2]=f;return 0},h:function(){return 52},c:function(){return 70},a:function(b,d,e,f){for(var h=0,g=0;g<e;g++){var m=P[d>>2],w=P[d+4>>2];d+=8;for(var p=0;p<w;p++){var n=N[m+p],q=ta[b];0===n||10===n?((1===b?ba:D)(J(q,0)),q.length=0):q.push(n)}h+=w}P[f>>2]=h;return 0},d:function(b,d,e,f){return xa(b,d,e,f)}}; // });
(function(){function b(h){c.asm=h.exports;G=c.asm.j;fa();ia.unshift(c.asm.k);Q--;c.monitorRunDependencies&&c.monitorRunDependencies(Q);0==Q&&(null!==R&&(clearInterval(R),R=null),S&&(h=S,S=null,h()))}function d(h){b(h.instance)}function e(h){return ra().then(function(g){return WebAssembly.instantiate(g,f)}).then(function(g){return g}).then(h,function(g){D("failed to asynchronously prepare wasm: "+g);F(g)})}var f={a:Aa};Q++;c.monitorRunDependencies&&c.monitorRunDependencies(Q);if(c.instantiateWasm)try{return c.instantiateWasm(f, // },
b)}catch(h){return D("Module.instantiateWasm callback failed with error: "+h),!1}(function(){return E||"function"!=typeof WebAssembly.instantiateStreaming||la()||"function"!=typeof fetch?e(d):fetch(T,{credentials:"same-origin"}).then(function(h){return WebAssembly.instantiateStreaming(h,f).then(d,function(g){D("wasm streaming compile failed: "+g);D("falling back to ArrayBuffer instantiation");return e(d)})})})().catch(t);return{}})(); // });
c.___wasm_call_ctors=function(){return(c.___wasm_call_ctors=c.asm.k).apply(null,arguments)};c._convert_glsl_to_spirv=function(){return(c._convert_glsl_to_spirv=c.asm.l).apply(null,arguments)};c._destroy_output_buffer=function(){return(c._destroy_output_buffer=c.asm.m).apply(null,arguments)};c._malloc=function(){return(c._malloc=c.asm.o).apply(null,arguments)};c._free=function(){return(c._free=c.asm.p).apply(null,arguments)}; // });
var ya=c.stackSave=function(){return(ya=c.stackSave=c.asm.q).apply(null,arguments)},za=c.stackRestore=function(){return(za=c.stackRestore=c.asm.r).apply(null,arguments)},Y=c.stackAlloc=function(){return(Y=c.stackAlloc=c.asm.s).apply(null,arguments)},Z;S=function Ba(){Z||Ca();Z||(S=Ba)}; // };
function Ca(){function b(){if(!Z&&(Z=!0,c.calledRun=!0,!H)){U(ia);r(c);if(c.onRuntimeInitialized)c.onRuntimeInitialized();if(c.postRun)for("function"==typeof c.postRun&&(c.postRun=[c.postRun]);c.postRun.length;){var d=c.postRun.shift();ja.unshift(d)}U(ja)}}if(!(0<Q)){if(c.preRun)for("function"==typeof c.preRun&&(c.preRun=[c.preRun]);c.preRun.length;)ka();U(ha);0<Q||(c.setStatus?(c.setStatus("Running..."),setTimeout(function(){setTimeout(function(){c.setStatus("")},1);b()},1)):b())}}
if(c.preInit)for("function"==typeof c.preInit&&(c.preInit=[c.preInit]);0<c.preInit.length;)c.preInit.pop()();Ca(); // let instance;
// return () => {
// if (!instance) {
// instance = initialize();
// }
// return instance;
// };
// })();
// (function tryToExport(root, factory) {
// if (typeof exports === 'object' && typeof module === 'object')
// module.exports = factory();
// else if (typeof define === 'function' && define.amd)
// define("glslang", [], factory);
// else if (typeof exports === 'object')
// exports["glslang"] = factory();
// else
// root["glslang"] = factory();
// })(typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this, () => {
// const initialize = (wasmPath) => {
// wasmPath = 'http://localhost:7456/glslang.wasm'
// return new Promise(resolve => {
// Module({
// locateFile() {
// return wasmPath;
// },
// onRuntimeInitialized() {
// resolve({
// compileGLSLZeroCopy: this.compileGLSLZeroCopy,
// compileGLSL: this.compileGLSL,
// });
// },
// });
// });
// };
// let instance;
// return (wasmPath) => {
// if (!instance) {
// instance = initialize(wasmPath);
// }
// return instance;
// };
// });
return Module.ready const initialize = (wasmPath) => {
}
);
})();
const initialize = (wasmPath) => {
return new Promise(resolve => { return new Promise(resolve => {
Module({ Module({
locateFile() { locateFile() {

BIN
emscripten/webgpu/glslang.wasm Executable file → Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -7,8 +7,3 @@ declare module 'external:emscripten/webgpu/glslang.js' {
function factory (wasmUrl: string): Promise<any>; function factory (wasmUrl: string): Promise<any>;
export default factory; export default factory;
} }
declare module 'external:emscripten/webgpu/twgsl.js' {
function factory (gfx: any): Promise<any>;
export default factory;
}

File diff suppressed because one or more lines are too long

BIN
emscripten/webgpu/webgpu_wasm.wasm Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -22,10 +22,3 @@
#define %module_macro(m) %feature("module_macro","m") #define %module_macro(m) %feature("module_macro","m")
#define %release_returned_cpp_object_in_gc(method) %feature("release_returned_cpp_object_in_gc", "1") method #define %release_returned_cpp_object_in_gc(method) %feature("release_returned_cpp_object_in_gc", "1") method
%define %virtual_inherit(klass)
%feature("virtual_inherit", "1") klass;
%typemap(in) klass *self
%{ $1 = SE_THIS_OBJECT_VIRTUAL<$*ltype, cc::VirtualInheritBase>(s);
if (nullptr == $1) return true;%}
%enddef

View File

@ -22,7 +22,8 @@ static bool $jswrapper(se::State& s) // NOLINT(readability-identifier-naming)
$js_check_arg_count $js_check_arg_count
$jslocals $jslocals
$jscode $jscode
$js_set_private_object auto *ptr = JSB_MAKE_PRIVATE_OBJECT_WITH_INSTANCE(result);
s.thisObject()->setPrivateObject(ptr);
return true; return true;
} }
SE_BIND_CTOR($jswrapper, __jsb_$jsmangledname_class, js_delete_$jsdtor)%} SE_BIND_CTOR($jswrapper, __jsb_$jsmangledname_class, js_delete_$jsdtor)%}
@ -61,7 +62,8 @@ static bool $jswrapper(se::State& s) // NOLINT(readability-identifier-naming)
CC_UNUSED bool ok = true; CC_UNUSED bool ok = true;
$jslocals $jslocals
$jscode $jscode
$js_set_private_object auto *ptr = JSB_MAKE_PRIVATE_OBJECT_WITH_INSTANCE(result);
s.thisObject()->setPrivateObject(ptr);
return true; return true;
} }
%} %}
@ -84,20 +86,19 @@ static bool $jswrapper(se::State& s) // NOLINT(readability-identifier-naming)
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* js_dtor: template for a destructor wrapper * js_dtor: template for a destructor wrapper
* - $classname_mangled: mangled class name * - $jsmangledname: mangled class name
* - $jstype: class type * - $jstype: class type
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
%fragment ("js_dtor", "templates") %fragment ("js_dtor", "templates")
%{ %{
static bool $jswrapper(se::State& s) { static bool $jswrapper(se::State& s) {
cc::invokeOnGarbageCollectMethod<$jsclass_type>(s);
return true; return true;
} }
SE_BIND_FINALIZE_FUNC($jswrapper) %} SE_BIND_FINALIZE_FUNC($jswrapper) %}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* js_dtor: template for a destructor wrapper * js_dtor: template for a destructor wrapper
* - $classname_mangled: mangled class name * - $jsmangledname: mangled class name
* - $jstype: class type * - $jstype: class type
* - ${destructor_action}: The custom destructor action to invoke. * - ${destructor_action}: The custom destructor action to invoke.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
@ -105,7 +106,6 @@ SE_BIND_FINALIZE_FUNC($jswrapper) %}
%{ %{
static bool $jswrapper(se::State& s) static bool $jswrapper(se::State& s)
{ {
cc::invokeOnGarbageCollectMethod<$jsclass_type>(s);
return true; return true;
} }
SE_BIND_FINALIZE_FUNC($jswrapper) %} SE_BIND_FINALIZE_FUNC($jswrapper) %}

Binary file not shown.

View File

@ -22,10 +22,3 @@
#define %module_macro(m) %feature("module_macro","m") #define %module_macro(m) %feature("module_macro","m")
#define %release_returned_cpp_object_in_gc(method) %feature("release_returned_cpp_object_in_gc", "1") method #define %release_returned_cpp_object_in_gc(method) %feature("release_returned_cpp_object_in_gc", "1") method
%define %virtual_inherit(klass)
%feature("virtual_inherit", "1") klass;
%typemap(in) klass *self
%{ $1 = SE_THIS_OBJECT_VIRTUAL<$*ltype, cc::VirtualInheritBase>(s);
if (nullptr == $1) return true;%}
%enddef

View File

@ -22,7 +22,8 @@ static bool $jswrapper(se::State& s) // NOLINT(readability-identifier-naming)
$js_check_arg_count $js_check_arg_count
$jslocals $jslocals
$jscode $jscode
$js_set_private_object auto *ptr = JSB_MAKE_PRIVATE_OBJECT_WITH_INSTANCE(result);
s.thisObject()->setPrivateObject(ptr);
return true; return true;
} }
SE_BIND_CTOR($jswrapper, __jsb_$jsmangledname_class, js_delete_$jsdtor)%} SE_BIND_CTOR($jswrapper, __jsb_$jsmangledname_class, js_delete_$jsdtor)%}
@ -61,7 +62,8 @@ static bool $jswrapper(se::State& s) // NOLINT(readability-identifier-naming)
CC_UNUSED bool ok = true; CC_UNUSED bool ok = true;
$jslocals $jslocals
$jscode $jscode
$js_set_private_object auto *ptr = JSB_MAKE_PRIVATE_OBJECT_WITH_INSTANCE(result);
s.thisObject()->setPrivateObject(ptr);
return true; return true;
} }
%} %}
@ -84,20 +86,19 @@ static bool $jswrapper(se::State& s) // NOLINT(readability-identifier-naming)
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* js_dtor: template for a destructor wrapper * js_dtor: template for a destructor wrapper
* - $classname_mangled: mangled class name * - $jsmangledname: mangled class name
* - $jstype: class type * - $jstype: class type
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
%fragment ("js_dtor", "templates") %fragment ("js_dtor", "templates")
%{ %{
static bool $jswrapper(se::State& s) { static bool $jswrapper(se::State& s) {
cc::invokeOnGarbageCollectMethod<$jsclass_type>(s);
return true; return true;
} }
SE_BIND_FINALIZE_FUNC($jswrapper) %} SE_BIND_FINALIZE_FUNC($jswrapper) %}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* js_dtor: template for a destructor wrapper * js_dtor: template for a destructor wrapper
* - $classname_mangled: mangled class name * - $jsmangledname: mangled class name
* - $jstype: class type * - $jstype: class type
* - ${destructor_action}: The custom destructor action to invoke. * - ${destructor_action}: The custom destructor action to invoke.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
@ -105,7 +106,6 @@ SE_BIND_FINALIZE_FUNC($jswrapper) %}
%{ %{
static bool $jswrapper(se::State& s) static bool $jswrapper(se::State& s)
{ {
cc::invokeOnGarbageCollectMethod<$jsclass_type>(s);
return true; return true;
} }
SE_BIND_FINALIZE_FUNC($jswrapper) %} SE_BIND_FINALIZE_FUNC($jswrapper) %}

View File

@ -85,17 +85,30 @@ if(USE_SE_V8)
add_library(v8_monolith STATIC IMPORTED GLOBAL) add_library(v8_monolith STATIC IMPORTED GLOBAL)
set_target_properties(v8_monolith PROPERTIES set_target_properties(v8_monolith PROPERTIES
IMPORTED_LOCATION ${ohos_lib_dir}/libv8_monolith.a IMPORTED_LOCATION ${ohos_lib_dir}/libv8_monolith.a
INTERFACE_INCLUDE_DIRECTORIES ${platform_spec_path}/include/v8
) )
set(OHOS_ARM64_MACROS set(OHOS_ARM64_MACROS
V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64
ENABLE_MINOR_MC
V8_INTL_SUPPORT
V8_CONCURRENT_MARKING
V8_ENABLE_LAZY_SOURCE_POSITIONS
V8_EMBEDDED_BUILTINS
V8_WIN64_UNWINDING_INFO
V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH
V8_SNAPSHOT_COMPRESSION
V8_31BIT_SMIS_ON_64BIT_ARCH V8_31BIT_SMIS_ON_64BIT_ARCH
V8_DEPRECATION_WARNINGS V8_DEPRECATION_WARNINGS
V8_IMMINENT_DEPRECATION_WARNINGS V8_IMMINENT_DEPRECATION_WARNINGS
V8_TARGET_ARCH_ARM64 V8_TARGET_ARCH_ARM64
V8_HAVE_TARGET_OS V8_HAVE_TARGET_OS
V8_TARGET_OS_LINUX V8_TARGET_OS_LINUX
DISABLE_UNTRUSTED_CODE_MITIGATIONS
V8_COMPRESS_POINTERS V8_COMPRESS_POINTERS
U_USING_ICU_NAMESPACE=0
U_ENABLE_DYLOAD=0
USE_CHROMIUM_ICU=1
U_STATIC_IMPLEMENTATION
) )
if(OHOS_ARCH STREQUAL "arm64-v8a") if(OHOS_ARCH STREQUAL "arm64-v8a")
@ -104,7 +117,13 @@ if(USE_SE_V8)
) )
endif() endif()
set(se_libs_name v8_monolith) add_library(v8_inspector STATIC IMPORTED GLOBAL)
set_target_properties(v8_inspector PROPERTIES
IMPORTED_LOCATION ${ohos_lib_dir}/libinspector.a
INTERFACE_INCLUDE_DIRECTORIES ${platform_spec_path}/include/v8
)
set(se_libs_name v8_monolith v8_inspector)
endif() endif()
if(USE_SOCKET) if(USE_SOCKET)
@ -113,6 +132,11 @@ if(USE_SOCKET)
) )
endif() endif()
if(USE_SE_V8 AND USE_V8_DEBUGGER)
list(APPEND CC_EXTERNAL_LIBS
v8_inspector
)
endif()
add_library(glslang STATIC IMPORTED GLOBAL) add_library(glslang STATIC IMPORTED GLOBAL)
set_target_properties(glslang PROPERTIES set_target_properties(glslang PROPERTIES
@ -195,10 +219,6 @@ list(APPEND CC_EXTERNAL_LIBS
${glslang_libs_name} ${glslang_libs_name}
) )
if(NOT USE_MODULES)
list(APPEND CC_EXTERNAL_LIBS ${se_libs_name})
endif()
list(APPEND CC_EXTERNAL_INCLUDES list(APPEND CC_EXTERNAL_INCLUDES
${platform_spec_path}/include ${platform_spec_path}/include
${platform_spec_path}/include/sqlite ${platform_spec_path}/include/sqlite

View File

@ -1,72 +0,0 @@
# The V8 public C++ API
# Overview
The V8 public C++ API aims to support four use cases:
1. Enable applications that embed V8 (called the embedder) to configure and run
one or more instances of V8.
2. Expose ECMAScript-like capabilities to the embedder.
3. Enable the embedder to interact with ECMAScript by exposing API objects.
4. Provide access to the V8 debugger (inspector).
# Configuring and running an instance of V8
V8 requires access to certain OS-level primitives such as the ability to
schedule work on threads, or allocate memory.
The embedder can define how to access those primitives via the v8::Platform
interface. While V8 bundles a basic implementation, embedders are highly
encouraged to implement v8::Platform themselves.
Currently, the v8::ArrayBuffer::Allocator is passed to the v8::Isolate factory
method, however, conceptually it should also be part of the v8::Platform since
all instances of V8 should share one allocator.
Once the v8::Platform is configured, an v8::Isolate can be created. All
further interactions with V8 should explicitly reference the v8::Isolate they
refer to. All API methods should eventually take an v8::Isolate parameter.
When a given instance of V8 is no longer needed, it can be destroyed by
disposing the respective v8::Isolate. If the embedder wishes to free all memory
associated with the v8::Isolate, it has to first clear all global handles
associated with that v8::Isolate.
# ECMAScript-like capabilities
In general, the C++ API shouldn't enable capabilities that aren't available to
scripts running in V8. Experience has shown that it's not possible to maintain
such API methods in the long term. However, capabilities also available to
scripts, i.e., ones that are defined in the ECMAScript standard are there to
stay, and we can safely expose them to embedders.
The C++ API should also be pleasant to use, and not require learning new
paradigms. Similarly to how the API exposed to scripts aims to provide good
ergonomics, we should aim to provide a reasonable developer experience for this
API surface.
ECMAScript makes heavy use of exceptions, however, V8's C++ code doesn't use
C++ exceptions. Therefore, all API methods that can throw exceptions should
indicate so by returning a v8::Maybe&lt;&gt; or v8::MaybeLocal&lt;&gt; result,
and by taking a v8::Local&lt;v8::Context&gt; parameter that indicates in which
context a possible exception should be thrown.
# API objects
V8 allows embedders to define special objects that expose additional
capabilities and APIs to scripts. The most prominent example is exposing the
HTML DOM in Blink. Other examples are e.g. node.js. It is less clear what kind
of capabilities we want to expose via this API surface. As a rule of thumb, we
want to expose operations as defined in the WebIDL and HTML spec: we
assume that those requirements are somewhat stable, and that they are a
superset of the requirements of other embedders including node.js.
Ideally, the API surfaces defined in those specs hook into the ECMAScript spec
which in turn guarantees long-term stability of the API.
# The V8 inspector
All debugging capabilities of V8 should be exposed via the inspector protocol.
The exception to this are profiling features exposed via v8-profiler.h.
Changes to the inspector protocol need to ensure backwards compatibility and
commitment to maintain.

View File

@ -1,10 +0,0 @@
include_rules = [
# v8-inspector-protocol.h depends on generated files under include/inspector.
"+inspector",
"+cppgc/common.h",
# Used by v8-cppgc.h to bridge to cppgc.
"+cppgc/custom-space.h",
"+cppgc/heap-statistics.h",
"+cppgc/internal/write-barrier.h",
"+cppgc/visitor.h",
]

View File

@ -1,11 +0,0 @@
# Metadata information for this directory.
#
# For more information on DIR_METADATA files, see:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
#
# For the schema of this file, see Metadata message:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
monorail {
component: "Blink>JavaScript>API"
}

View File

@ -1,18 +0,0 @@
adamk@chromium.org
cbruni@chromium.org
leszeks@chromium.org
mlippautz@chromium.org
ulan@chromium.org
verwaest@chromium.org
yangguo@chromium.org
per-file *DEPS=file:../COMMON_OWNERS
per-file v8-internal.h=file:../COMMON_OWNERS
per-file v8-inspector.h=file:../src/inspector/OWNERS
per-file v8-inspector-protocol.h=file:../src/inspector/OWNERS
per-file js_protocol.pdl=file:../src/inspector/OWNERS
# For branch updates:
per-file v8-version.h=file:../INFRA_OWNERS
per-file v8-version.h=hablich@chromium.org
per-file v8-version.h=vahl@chromium.org

View File

@ -1,8 +0,0 @@
include_rules = [
"-include",
"+v8config.h",
"+v8-platform.h",
"+cppgc",
"-src",
"+libplatform/libplatform.h",
]

View File

@ -1,2 +0,0 @@
bikineev@chromium.org
omerkatz@chromium.org

View File

@ -1,5 +0,0 @@
# C++ Garbage Collection
This directory provides an open-source garbage collection library for C++.
The library is under construction, meaning that *all APIs in this directory are incomplete and considered unstable and should not be used*.

View File

@ -1,232 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_ALLOCATION_H_
#define INCLUDE_CPPGC_ALLOCATION_H_
#include <stdint.h>
#include <atomic>
#include "cppgc/custom-space.h"
#include "cppgc/garbage-collected.h"
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/gc-info.h"
namespace cppgc {
template <typename T>
class MakeGarbageCollectedTraitBase;
namespace internal {
class ObjectAllocator;
} // namespace internal
/**
* AllocationHandle is used to allocate garbage-collected objects.
*/
class AllocationHandle;
namespace internal {
class V8_EXPORT MakeGarbageCollectedTraitInternal {
protected:
static inline void MarkObjectAsFullyConstructed(const void* payload) {
// See api_constants for an explanation of the constants.
std::atomic<uint16_t>* atomic_mutable_bitfield =
reinterpret_cast<std::atomic<uint16_t>*>(
const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
reinterpret_cast<const uint8_t*>(payload) -
api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
atomic_mutable_bitfield->fetch_or(api_constants::kFullyConstructedBitMask,
std::memory_order_release);
}
template <typename U, typename CustomSpace>
struct SpacePolicy {
static void* Allocate(AllocationHandle& handle, size_t size) {
// Custom space.
static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
"Custom space must inherit from CustomSpaceBase.");
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, internal::GCInfoTrait<U>::Index(),
CustomSpace::kSpaceIndex);
}
};
template <typename U>
struct SpacePolicy<U, void> {
static void* Allocate(AllocationHandle& handle, size_t size) {
// Default space.
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, internal::GCInfoTrait<U>::Index());
}
};
private:
static void* Allocate(cppgc::AllocationHandle& handle, size_t size,
GCInfoIndex index);
static void* Allocate(cppgc::AllocationHandle& handle, size_t size,
GCInfoIndex index, CustomSpaceIndex space_index);
friend class HeapObjectHeader;
};
} // namespace internal
/**
* Base trait that provides utilities for advancers users that have custom
* allocation needs (e.g., overriding size). It's expected that users override
* MakeGarbageCollectedTrait (see below) and inherit from
* MakeGarbageCollectedTraitBase and make use of the low-level primitives
* offered to allocate and construct an object.
*/
template <typename T>
class MakeGarbageCollectedTraitBase
: private internal::MakeGarbageCollectedTraitInternal {
private:
static_assert(internal::IsGarbageCollectedType<T>::value,
"T needs to be a garbage collected object");
static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
sizeof(T) <=
internal::api_constants::kLargeObjectSizeThreshold,
"GarbageCollectedMixin may not be a large object");
protected:
/**
* Allocates memory for an object of type T.
*
* \param handle AllocationHandle identifying the heap to allocate the object
* on.
* \param size The size that should be reserved for the object.
* \returns the memory to construct an object of type T on.
*/
V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
return SpacePolicy<
typename internal::GCInfoFolding<
T, typename T::ParentMostGarbageCollectedType>::ResultType,
typename SpaceTrait<T>::Space>::Allocate(handle, size);
}
/**
* Marks an object as fully constructed, resulting in precise handling by the
* garbage collector.
*
* \param payload The base pointer the object is allocated at.
*/
V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
payload);
}
};
/**
* Passed to MakeGarbageCollected to specify how many bytes should be appended
* to the allocated object.
*
* Example:
* \code
* class InlinedArray final : public GarbageCollected<InlinedArray> {
* public:
* explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
* void Trace(Visitor*) const {}
* size_t size;
* char* byte_array;
* };
*
* auto* inlined_array = MakeGarbageCollected<InlinedArray(
* GetAllocationHandle(), AdditionalBytes(4), 4);
* for (size_t i = 0; i < 4; i++) {
* Process(inlined_array->byte_array[i]);
* }
* \endcode
*/
struct AdditionalBytes {
constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
const size_t value;
};
/**
* Default trait class that specifies how to construct an object of type T.
* Advanced users may override how an object is constructed using the utilities
* that are provided through MakeGarbageCollectedTraitBase.
*
* Any trait overriding construction must
* - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
* - mark the object as fully constructed using
* `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
*/
template <typename T>
class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> {
public:
template <typename... Args>
static T* Call(AllocationHandle& handle, Args&&... args) {
void* memory =
MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
T* object = ::new (memory) T(std::forward<Args>(args)...);
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
return object;
}
template <typename... Args>
static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
Args&&... args) {
void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
handle, sizeof(T) + additional_bytes.value);
T* object = ::new (memory) T(std::forward<Args>(args)...);
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
return object;
}
};
/**
* Allows users to specify a post-construction callback for specific types. The
* callback is invoked on the instance of type T right after it has been
* constructed. This can be useful when the callback requires a
* fully-constructed object to be able to dispatch to virtual methods.
*/
template <typename T, typename = void>
struct PostConstructionCallbackTrait {
static void Call(T*) {}
};
/**
* Constructs a managed object of type T where T transitively inherits from
* GarbageCollected.
*
* \param args List of arguments with which an instance of T will be
* constructed.
* \returns an instance of type T.
*/
template <typename T, typename... Args>
T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
T* object =
MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
PostConstructionCallbackTrait<T>::Call(object);
return object;
}
/**
* Constructs a managed object of type T where T transitively inherits from
* GarbageCollected. Created objects will have additional bytes appended to
* it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
*
* \param additional_bytes Denotes how many bytes to append to T.
* \param args List of arguments with which an instance of T will be
* constructed.
* \returns an instance of type T.
*/
template <typename T, typename... Args>
T* MakeGarbageCollected(AllocationHandle& handle,
AdditionalBytes additional_bytes, Args&&... args) {
T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
std::forward<Args>(args)...);
PostConstructionCallbackTrait<T>::Call(object);
return object;
}
} // namespace cppgc
#endif // INCLUDE_CPPGC_ALLOCATION_H_

View File

@ -1,29 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_COMMON_H_
#define INCLUDE_CPPGC_COMMON_H_
// TODO(chromium:1056170): Remove dependency on v8.
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* Indicator for the stack state of the embedder.
*/
enum class EmbedderStackState {
/**
* Stack may contain interesting heap pointers.
*/
kMayContainHeapPointers,
/**
* Stack does not contain any interesting heap pointers.
*/
kNoHeapPointers,
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_COMMON_H_

View File

@ -1,384 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
#include <atomic>
#include "cppgc/internal/persistent-node.h"
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/persistent.h"
#include "cppgc/visitor.h"
namespace cppgc {
namespace internal {
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
class BasicCrossThreadPersistent final : public PersistentBase,
public LocationPolicy,
private WeaknessPolicy,
private CheckingPolicy {
public:
using typename WeaknessPolicy::IsStrongPersistent;
using PointeeType = T;
~BasicCrossThreadPersistent() { Clear(); }
BasicCrossThreadPersistent( // NOLINT
const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicCrossThreadPersistent( // NOLINT
std::nullptr_t, const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicCrossThreadPersistent( // NOLINT
SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(s), LocationPolicy(loc) {}
BasicCrossThreadPersistent( // NOLINT
T* raw, const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(raw), LocationPolicy(loc) {
if (!IsValid(raw)) return;
PersistentRegionLock guard;
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
SetNode(region.AllocateNode(this, &Trace));
this->CheckPointer(raw);
}
class UnsafeCtorTag {
private:
UnsafeCtorTag() = default;
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy>
friend class BasicCrossThreadPersistent;
};
BasicCrossThreadPersistent( // NOLINT
UnsafeCtorTag, T* raw,
const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(raw), LocationPolicy(loc) {
if (!IsValid(raw)) return;
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
SetNode(region.AllocateNode(this, &Trace));
this->CheckPointer(raw);
}
BasicCrossThreadPersistent( // NOLINT
T& raw, const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(&raw, loc) {}
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent( // NOLINT
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy>
member,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(member.Get(), loc) {}
BasicCrossThreadPersistent(
const BasicCrossThreadPersistent& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(loc) {
// Invoke operator=.
*this = other;
}
// Heterogeneous ctor.
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent( // NOLINT
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
OtherLocationPolicy,
OtherCheckingPolicy>& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(loc) {
*this = other;
}
BasicCrossThreadPersistent(
BasicCrossThreadPersistent&& other,
const SourceLocation& loc = SourceLocation::Current()) noexcept {
// Invoke operator=.
*this = std::move(other);
}
BasicCrossThreadPersistent& operator=(
const BasicCrossThreadPersistent& other) {
PersistentRegionLock guard;
AssignUnsafe(other.Get());
return *this;
}
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent& operator=(
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
OtherLocationPolicy,
OtherCheckingPolicy>& other) {
PersistentRegionLock guard;
AssignUnsafe(other.Get());
return *this;
}
BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
if (this == &other) return *this;
Clear();
PersistentRegionLock guard;
PersistentBase::operator=(std::move(other));
LocationPolicy::operator=(std::move(other));
if (!IsValid(GetValue())) return *this;
GetNode()->UpdateOwner(this);
other.SetValue(nullptr);
other.SetNode(nullptr);
this->CheckPointer(GetValue());
return *this;
}
BasicCrossThreadPersistent& operator=(T* other) {
Assign(other);
return *this;
}
// Assignment from member.
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent& operator=(
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy>
member) {
return operator=(member.Get());
}
BasicCrossThreadPersistent& operator=(std::nullptr_t) {
Clear();
return *this;
}
BasicCrossThreadPersistent& operator=(SentinelPointer s) {
Assign(s);
return *this;
}
/**
* Returns a pointer to the stored object.
*
* Note: **Not thread-safe.**
*
* \returns a pointer to the stored object.
*/
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
return static_cast<T*>(const_cast<void*>(GetValue()));
}
/**
* Clears the stored object.
*/
void Clear() {
// Simplified version of `Assign()` to allow calling without a complete type
// `T`.
const void* old_value = GetValue();
if (IsValid(old_value)) {
PersistentRegionLock guard;
old_value = GetValue();
// The fast path check (IsValid()) does not acquire the lock. Reload
// the value to ensure the reference has not been cleared.
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
region.FreeNode(GetNode());
SetNode(nullptr);
} else {
CPPGC_DCHECK(!GetNode());
}
}
SetValue(nullptr);
}
/**
* Returns a pointer to the stored object and releases it.
*
* Note: **Not thread-safe.**
*
* \returns a pointer to the stored object.
*/
T* Release() {
T* result = Get();
Clear();
return result;
}
/**
* Conversio to boolean.
*
* Note: **Not thread-safe.**
*
* \returns true if an actual object has been stored and false otherwise.
*/
explicit operator bool() const { return Get(); }
/**
* Conversion to object of type T.
*
* Note: **Not thread-safe.**
*
* \returns the object.
*/
operator T*() const { return Get(); } // NOLINT
/**
* Dereferences the stored object.
*
* Note: **Not thread-safe.**
*/
T* operator->() const { return Get(); }
T& operator*() const { return *Get(); }
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
typename OtherLocationPolicy = LocationPolicy,
typename OtherCheckingPolicy = CheckingPolicy>
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>
To() const {
using OtherBasicCrossThreadPersistent =
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>;
PersistentRegionLock guard;
return OtherBasicCrossThreadPersistent(
typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
static_cast<U*>(Get()));
}
template <typename U = T,
typename = typename std::enable_if<!BasicCrossThreadPersistent<
U, WeaknessPolicy>::IsStrongPersistent::value>::type>
BasicCrossThreadPersistent<U, internal::StrongCrossThreadPersistentPolicy>
Lock() const {
return BasicCrossThreadPersistent<
U, internal::StrongCrossThreadPersistentPolicy>(*this);
}
private:
static bool IsValid(const void* ptr) {
return ptr && ptr != kSentinelPointer;
}
static void Trace(Visitor* v, const void* ptr) {
const auto* handle = static_cast<const BasicCrossThreadPersistent*>(ptr);
v->TraceRoot(*handle, handle->Location());
}
void Assign(T* ptr) {
const void* old_value = GetValue();
if (IsValid(old_value)) {
PersistentRegionLock guard;
old_value = GetValue();
// The fast path check (IsValid()) does not acquire the lock. Reload
// the value to ensure the reference has not been cleared.
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
if (IsValid(ptr) && (&region == &this->GetPersistentRegion(ptr))) {
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
region.FreeNode(GetNode());
SetNode(nullptr);
} else {
CPPGC_DCHECK(!GetNode());
}
}
SetValue(ptr);
if (!IsValid(ptr)) return;
PersistentRegionLock guard;
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace));
this->CheckPointer(ptr);
}
void AssignUnsafe(T* ptr) {
PersistentRegionLock::AssertLocked();
const void* old_value = GetValue();
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
if (IsValid(ptr) && (&region == &this->GetPersistentRegion(ptr))) {
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
region.FreeNode(GetNode());
SetNode(nullptr);
}
SetValue(ptr);
if (!IsValid(ptr)) return;
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace));
this->CheckPointer(ptr);
}
void ClearFromGC() const {
if (IsValid(GetValue())) {
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
PersistentBase::ClearFromGC();
}
}
friend class cppgc::Visitor;
};
template <typename T, typename LocationPolicy, typename CheckingPolicy>
struct IsWeak<
BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy,
LocationPolicy, CheckingPolicy>>
: std::true_type {};
} // namespace internal
namespace subtle {
/**
* **DO NOT USE: Has known caveats, see below.**
*
* CrossThreadPersistent allows retaining objects from threads other than the
* thread the owning heap is operating on.
*
* Known caveats:
* - Does not protect the heap owning an object from terminating.
* - Reaching transitively through the graph is unsupported as objects may be
* moved concurrently on the thread owning the object.
*/
template <typename T>
using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
T, internal::StrongCrossThreadPersistentPolicy>;
/**
* **DO NOT USE: Has known caveats, see below.**
*
* CrossThreadPersistent allows weakly retaining objects from threads other than
* the thread the owning heap is operating on.
*
* Known caveats:
* - Does not protect the heap owning an object from terminating.
* - Reaching transitively through the graph is unsupported as objects may be
* moved concurrently on the thread owning the object.
*/
template <typename T>
using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
T, internal::WeakCrossThreadPersistentPolicy>;
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_

View File

@ -1,97 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_
#define INCLUDE_CPPGC_CUSTOM_SPACE_H_
#include <stddef.h>
namespace cppgc {
/**
* Index identifying a custom space.
*/
struct CustomSpaceIndex {
constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT
size_t value;
};
/**
* Top-level base class for custom spaces. Users must inherit from CustomSpace
* below.
*/
class CustomSpaceBase {
public:
virtual ~CustomSpaceBase() = default;
virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0;
virtual bool IsCompactable() const = 0;
};
/**
* Base class custom spaces should directly inherit from. The class inheriting
* from `CustomSpace` must define `kSpaceIndex` as unique space index. These
* indices need for form a sequence starting at 0.
*
* Example:
* \code
* class CustomSpace1 : public CustomSpace<CustomSpace1> {
* public:
* static constexpr CustomSpaceIndex kSpaceIndex = 0;
* };
* class CustomSpace2 : public CustomSpace<CustomSpace2> {
* public:
* static constexpr CustomSpaceIndex kSpaceIndex = 1;
* };
* \endcode
*/
template <typename ConcreteCustomSpace>
class CustomSpace : public CustomSpaceBase {
public:
/**
* Compaction is only supported on spaces that manually manage slots
* recording.
*/
static constexpr bool kSupportsCompaction = false;
CustomSpaceIndex GetCustomSpaceIndex() const final {
return ConcreteCustomSpace::kSpaceIndex;
}
bool IsCompactable() const final {
return ConcreteCustomSpace::kSupportsCompaction;
}
};
/**
* User-overridable trait that allows pinning types to custom spaces.
*/
template <typename T, typename = void>
struct SpaceTrait {
using Space = void;
};
namespace internal {
template <typename CustomSpace>
struct IsAllocatedOnCompactableSpaceImpl {
static constexpr bool value = CustomSpace::kSupportsCompaction;
};
template <>
struct IsAllocatedOnCompactableSpaceImpl<void> {
// Non-custom spaces are by default not compactable.
static constexpr bool value = false;
};
template <typename T>
struct IsAllocatedOnCompactableSpace {
public:
static constexpr bool value =
IsAllocatedOnCompactableSpaceImpl<typename SpaceTrait<T>::Space>::value;
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_

View File

@ -1,75 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
#include <memory>
#include <vector>
#include "cppgc/platform.h"
#include "libplatform/libplatform.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* Platform provided by cppgc. Uses V8's DefaultPlatform provided by
* libplatform internally. Exception: `GetForegroundTaskRunner()`, see below.
*/
class V8_EXPORT DefaultPlatform : public Platform {
public:
/**
* Use this method instead of 'cppgc::InitializeProcess' when using
* 'cppgc::DefaultPlatform'. 'cppgc::DefaultPlatform::InitializeProcess'
* will initialize cppgc and v8 if needed (for non-standalone builds).
*
* \param platform DefaultPlatform instance used to initialize cppgc/v8.
*/
static void InitializeProcess(DefaultPlatform* platform);
using IdleTaskSupport = v8::platform::IdleTaskSupport;
explicit DefaultPlatform(
int thread_pool_size = 0,
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
std::unique_ptr<TracingController> tracing_controller = {})
: v8_platform_(v8::platform::NewDefaultPlatform(
thread_pool_size, idle_task_support,
v8::platform::InProcessStackDumping::kDisabled,
std::move(tracing_controller))) {}
cppgc::PageAllocator* GetPageAllocator() override {
return v8_platform_->GetPageAllocator();
}
double MonotonicallyIncreasingTime() override {
return v8_platform_->MonotonicallyIncreasingTime();
}
std::shared_ptr<cppgc::TaskRunner> GetForegroundTaskRunner() override {
// V8's default platform creates a new task runner when passed the
// `v8::Isolate` pointer the first time. For non-default platforms this will
// require getting the appropriate task runner.
return v8_platform_->GetForegroundTaskRunner(kNoIsolate);
}
std::unique_ptr<cppgc::JobHandle> PostJob(
cppgc::TaskPriority priority,
std::unique_ptr<cppgc::JobTask> job_task) override {
return v8_platform_->PostJob(priority, std::move(job_task));
}
TracingController* GetTracingController() override {
return v8_platform_->GetTracingController();
}
protected:
static constexpr v8::Isolate* kNoIsolate = nullptr;
std::unique_ptr<v8::Platform> v8_platform_;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_

View File

@ -1,30 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_
#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_
#include "cppgc/liveness-broker.h"
#include "cppgc/member.h"
namespace cppgc {
/**
* An ephemeron pair is used to conditionally retain an object.
* The `value` will be kept alive only if the `key` is alive.
*/
template <typename K, typename V>
struct EphemeronPair {
EphemeronPair(K* k, V* v) : key(k), value(v) {}
WeakMember<K> key;
Member<V> value;
void ClearValueIfKeyIsDead(const LivenessBroker& broker) {
if (!broker.IsHeapObjectAlive(key)) value = nullptr;
}
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_

View File

@ -1,73 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#include <cstddef>
#include "cppgc/allocation.h"
#include "cppgc/internal/logging.h"
#include "cppgc/type-traits.h"
namespace cppgc {
namespace internal {
V8_EXPORT void FreeUnreferencedObject(void*);
V8_EXPORT bool Resize(void*, size_t);
} // namespace internal
namespace subtle {
/**
* Informs the garbage collector that `object` can be immediately reclaimed. The
* destructor may not be invoked immediately but only on next garbage
* collection.
*
* It is up to the embedder to guarantee that no other object holds a reference
* to `object` after calling `FreeUnreferencedObject()`. In case such a
* reference exists, it's use results in a use-after-free.
*
* \param object Reference to an object that is of type `GarbageCollected` and
* should be immediately reclaimed.
*/
template <typename T>
void FreeUnreferencedObject(T* object) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
if (!object) return;
internal::FreeUnreferencedObject(object);
}
/**
* Tries to resize `object` of type `T` with additional bytes on top of
* sizeof(T). Resizing is only useful with trailing inlined storage, see e.g.
* `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`.
*
* `Resize()` performs growing or shrinking as needed and may skip the operation
* for internal reasons, see return value.
*
* It is up to the embedder to guarantee that in case of shrinking a larger
* object down, the reclaimed area is not used anymore. Any subsequent use
* results in a use-after-free.
*
* \param object Reference to an object that is of type `GarbageCollected` and
* should be resized.
* \param additional_bytes Bytes in addition to sizeof(T) that the object should
* provide.
* \returns true when the operation was successful and the result can be relied
* on, and false otherwise.
*/
template <typename T>
bool Resize(T& object, AdditionalBytes additional_bytes) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
return internal::Resize(&object, sizeof(T) + additional_bytes.value);
}
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_

View File

@ -1,117 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
#include <type_traits>
#include "cppgc/internal/api-constants.h"
#include "cppgc/platform.h"
#include "cppgc/trace-trait.h"
#include "cppgc/type-traits.h"
namespace cppgc {
class Visitor;
namespace internal {
class GarbageCollectedBase {
public:
// Must use MakeGarbageCollected.
void* operator new(size_t) = delete;
void* operator new[](size_t) = delete;
// The garbage collector is taking care of reclaiming the object. Also,
// virtual destructor requires an unambiguous, accessible 'operator delete'.
void operator delete(void*) {
#ifdef V8_ENABLE_CHECKS
internal::Abort();
#endif // V8_ENABLE_CHECKS
}
void operator delete[](void*) = delete;
protected:
GarbageCollectedBase() = default;
};
} // namespace internal
/**
* Base class for managed objects. Only descendent types of `GarbageCollected`
* can be constructed using `MakeGarbageCollected()`. Must be inherited from as
* left-most base class.
*
* Types inheriting from GarbageCollected must provide a method of
* signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
* pointers to the visitor and delegates to garbage-collected base classes.
* The method must be virtual if the type is not directly a child of
* GarbageCollected and marked as final.
*
* \code
* // Example using final class.
* class FinalType final : public GarbageCollected<FinalType> {
* public:
* void Trace(cppgc::Visitor* visitor) const {
* // Dispatch using visitor->Trace(...);
* }
* };
*
* // Example using non-final base class.
* class NonFinalBase : public GarbageCollected<NonFinalBase> {
* public:
* virtual void Trace(cppgc::Visitor*) const {}
* };
*
* class FinalChild final : public NonFinalBase {
* public:
* void Trace(cppgc::Visitor* visitor) const final {
* // Dispatch using visitor->Trace(...);
* NonFinalBase::Trace(visitor);
* }
* };
* \endcode
*/
template <typename T>
class GarbageCollected : public internal::GarbageCollectedBase {
public:
using IsGarbageCollectedTypeMarker = void;
using ParentMostGarbageCollectedType = T;
protected:
GarbageCollected() = default;
};
/**
* Base class for managed mixin objects. Such objects cannot be constructed
* directly but must be mixed into the inheritance hierarchy of a
* GarbageCollected object.
*
* Types inheriting from GarbageCollectedMixin must override a virtual method
* of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
* pointers to the visitor and delegates to base classes.
*
* \code
* class Mixin : public GarbageCollectedMixin {
* public:
* void Trace(cppgc::Visitor* visitor) const override {
* // Dispatch using visitor->Trace(...);
* }
* };
* \endcode
*/
class GarbageCollectedMixin : public internal::GarbageCollectedBase {
public:
using IsGarbageCollectedMixinTypeMarker = void;
/**
* This Trace method must be overriden by objects inheriting from
* GarbageCollectedMixin.
*/
virtual void Trace(cppgc::Visitor*) const {}
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_

View File

@ -1,236 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_
#include <cstddef>
#include "cppgc/internal/write-barrier.h"
#include "cppgc/macros.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class HeapHandle;
namespace subtle {
/**
* **DO NOT USE: Use the appropriate managed types.**
*
* Consistency helpers that aid in maintaining a consistent internal state of
* the garbage collector.
*/
class HeapConsistency final {
public:
using WriteBarrierParams = internal::WriteBarrier::Params;
using WriteBarrierType = internal::WriteBarrier::Type;
/**
* Gets the required write barrier type for a specific write.
*
* \param slot Slot containing the pointer to the object. The slot itself
* must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
* \param value The pointer to the object. May be an interior pointer to an
* interface of the actual object.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
static V8_INLINE WriteBarrierType GetWriteBarrierType(
const void* slot, const void* value, WriteBarrierParams& params) {
return internal::WriteBarrier::GetWriteBarrierType(slot, value, params);
}
/**
* Gets the required write barrier type for a specific write.
*
* \param slot Slot to some part of an object. The object must not necessarily
have been allocated using `MakeGarbageCollected()` but can also live
off-heap or on stack.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \param callback Callback returning the corresponding heap handle. The
* callback is only invoked if the heap cannot otherwise be figured out. The
* callback must not allocate.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrierType
GetWriteBarrierType(const void* slot, WriteBarrierParams& params,
HeapHandleCallback callback) {
return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback);
}
/**
* Conservative Dijkstra-style write barrier that processes an object if it
* has not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param object The pointer to the object. May be an interior pointer to a
* an interface of the actual object.
*/
static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params,
const void* object) {
internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
}
/**
* Conservative Dijkstra-style write barrier that processes a range of
* elements if they have not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param first_element Pointer to the first element that should be processed.
* The slot itself must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
* \param element_size Size of the element in bytes.
* \param number_of_elements Number of elements that should be processed,
* starting with `first_element`.
* \param trace_callback The trace callback that should be invoked for each
* element if necessary.
*/
static V8_INLINE void DijkstraWriteBarrierRange(
const WriteBarrierParams& params, const void* first_element,
size_t element_size, size_t number_of_elements,
TraceCallback trace_callback) {
internal::WriteBarrier::DijkstraMarkingBarrierRange(
params, first_element, element_size, number_of_elements,
trace_callback);
}
/**
* Steele-style write barrier that re-processes an object if it has already
* been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param object The pointer to the object which must point to an object that
* has been allocated using `MakeGarbageCollected()`. Interior pointers are
* not supported.
*/
static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params,
const void* object) {
internal::WriteBarrier::SteeleMarkingBarrier(params, object);
}
/**
* Generational barrier for maintaining consistency when running with multiple
* generations.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param slot Slot containing the pointer to the object. The slot itself
* must reside in an object that has been allocated using
* `MakeGarbageCollected()`.
*/
static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
const void* slot) {
internal::WriteBarrier::GenerationalBarrier(params, slot);
}
private:
HeapConsistency() = delete;
};
/**
* Disallows garbage collection finalizations. Any garbage collection triggers
* result in a crash when in this scope.
*
* Note that the garbage collector already covers paths that can lead to garbage
* collections, so user code does not require checking
* `IsGarbageCollectionAllowed()` before allocations.
*/
class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final {
CPPGC_STACK_ALLOCATED();
public:
/**
* \returns whether garbage collections are currently allowed.
*/
static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle);
/**
* Enters a disallow garbage collection scope. Must be paired with `Leave()`.
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Enter(HeapHandle& heap_handle);
/**
* Leaves a disallow garbage collection scope. Must be paired with `Enter()`.
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Leave(HeapHandle& heap_handle);
/**
* Constructs a scoped object that automatically enters and leaves a disallow
* garbage collection scope based on its lifetime.
*
* \param heap_handle The corresponding heap.
*/
explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle);
~DisallowGarbageCollectionScope();
DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) =
delete;
DisallowGarbageCollectionScope& operator=(
const DisallowGarbageCollectionScope&) = delete;
private:
HeapHandle& heap_handle_;
};
/**
* Avoids invoking garbage collection finalizations. Already running garbage
* collection phase are unaffected by this scope.
*
* Should only be used temporarily as the scope has an impact on memory usage
* and follow up garbage collections.
*/
class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final {
CPPGC_STACK_ALLOCATED();
public:
/**
* Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer
* a scope instance of `NoGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Enter(HeapHandle& heap_handle);
/**
* Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer
* a scope instance of `NoGarbageCollectionScope`.
*
* \param heap_handle The corresponding heap.
*/
static void Leave(HeapHandle& heap_handle);
/**
* Constructs a scoped object that automatically enters and leaves a no
* garbage collection scope based on its lifetime.
*
* \param heap_handle The corresponding heap.
*/
explicit NoGarbageCollectionScope(HeapHandle& heap_handle);
~NoGarbageCollectionScope();
NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete;
NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete;
private:
HeapHandle& heap_handle_;
};
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_

View File

@ -1,70 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_HEAP_STATE_H_
#define INCLUDE_CPPGC_HEAP_STATE_H_
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class HeapHandle;
namespace subtle {
/**
* Helpers to peek into heap-internal state.
*/
class V8_EXPORT HeapState final {
public:
/**
* Returns whether the garbage collector is marking. This API is experimental
* and is expected to be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently marking, and false
* otherwise.
*/
static bool IsMarking(const HeapHandle& heap_handle);
/*
* Returns whether the garbage collector is sweeping. This API is experimental
* and is expected to be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently sweeping, and false
* otherwise.
*/
static bool IsSweeping(const HeapHandle& heap_handle);
/**
* Returns whether the garbage collector is in the atomic pause, i.e., the
* mutator is stopped from running. This API is experimental and is expected
* to be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the garbage collector is currently in the atomic pause,
* and false otherwise.
*/
static bool IsInAtomicPause(const HeapHandle& heap_handle);
/**
* Returns whether the last garbage collection was finalized conservatively
* (i.e., with a non-empty stack). This API is experimental and is expected to
* be removed in future.
*
* \param heap_handle The corresponding heap.
* \returns true if the last garbage collection was finalized conservatively,
* and false otherwise.
*/
static bool PreviousGCWasConservative(const HeapHandle& heap_handle);
private:
HeapState() = delete;
};
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_STATE_H_

View File

@ -1,110 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_HEAP_STATISTICS_H_
#define INCLUDE_CPPGC_HEAP_STATISTICS_H_
#include <memory>
#include <string>
#include <vector>
namespace cppgc {
/**
* `HeapStatistics` contains memory consumption and utilization statistics for a
* cppgc heap.
*/
struct HeapStatistics final {
/**
* Specifies the detail level of the heap statistics. Brief statistics contain
* only the top-level allocated and used memory statistics for the entire
* heap. Detailed statistics also contain a break down per space and page, as
* well as freelist statistics and object type histograms. Note that used
* memory reported by brief statistics and detailed statistics might differ
* slightly.
*/
enum DetailLevel : uint8_t {
kBrief,
kDetailed,
};
/**
* Statistics of object types. For each type the statistics record its name,
* how many objects of that type were allocated, and the overall size used by
* these objects.
*/
struct ObjectStatistics {
/** Number of distinct types in the heap. */
size_t num_types = 0;
/** Name of each type in the heap. */
std::vector<std::string> type_name;
/** Number of allocated objects per each type. */
std::vector<size_t> type_count;
/** Overall size of allocated objects per each type. */
std::vector<size_t> type_bytes;
};
/**
* Page granularity statistics. For each page the statistics record the
* allocated memory size and overall used memory size for the page.
*/
struct PageStatistics {
/** Overall amount of memory allocated for the page. */
size_t physical_size_bytes = 0;
/** Amount of memory actually used on the page. */
size_t used_size_bytes = 0;
};
/**
* Stastistics of the freelist (used only in non-large object spaces). For
* each bucket in the freelist the statistics record the bucket size, the
* number of freelist entries in the bucket, and the overall allocated memory
* consumed by these freelist entries.
*/
struct FreeListStatistics {
/** bucket sizes in the freelist. */
std::vector<size_t> bucket_size;
/** number of freelist entries per bucket. */
std::vector<size_t> free_count;
/** memory size concumed by freelist entries per size. */
std::vector<size_t> free_size;
};
/**
* Space granularity statistics. For each space the statistics record the
* space name, the amount of allocated memory and overall used memory for the
* space. The statistics also contain statistics for each of the space's
* pages, its freelist and the objects allocated on the space.
*/
struct SpaceStatistics {
/** The space name */
std::string name;
/** Overall amount of memory allocated for the space. */
size_t physical_size_bytes = 0;
/** Amount of memory actually used on the space. */
size_t used_size_bytes = 0;
/** Statistics for each of the pages in the space. */
std::vector<PageStatistics> page_stats;
/** Statistics for the freelist of the space. */
FreeListStatistics free_list_stats;
/** Statistics for object allocated on the space. Filled only when
* NameProvider::HideInternalNames() is false. */
ObjectStatistics object_stats;
};
/** Overall amount of memory allocated for the heap. */
size_t physical_size_bytes = 0;
/** Amount of memory actually used on the heap. */
size_t used_size_bytes = 0;
/** Detail level of this HeapStatistics. */
DetailLevel detail_level;
/** Statistics for each of the spaces in the heap. Filled only when
* detail_level is kDetailed. */
std::vector<SpaceStatistics> space_stats;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_

View File

@ -1,199 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_HEAP_H_
#define INCLUDE_CPPGC_HEAP_H_
#include <memory>
#include <vector>
#include "cppgc/common.h"
#include "cppgc/custom-space.h"
#include "cppgc/platform.h"
#include "v8config.h" // NOLINT(build/include_directory)
/**
* cppgc - A C++ garbage collection library.
*/
namespace cppgc {
class AllocationHandle;
/**
* Implementation details of cppgc. Those details are considered internal and
* may change at any point in time without notice. Users should never rely on
* the contents of this namespace.
*/
namespace internal {
class Heap;
} // namespace internal
/**
* Used for additional heap APIs.
*/
class HeapHandle;
class V8_EXPORT Heap {
public:
/**
* Specifies the stack state the embedder is in.
*/
using StackState = EmbedderStackState;
/**
* Specifies whether conservative stack scanning is supported.
*/
enum class StackSupport : uint8_t {
/**
* Conservative stack scan is supported.
*/
kSupportsConservativeStackScan,
/**
* Conservative stack scan is not supported. Embedders may use this option
* when using custom infrastructure that is unsupported by the library.
*/
kNoConservativeStackScan,
};
/**
* Specifies supported marking types
*/
enum class MarkingType : uint8_t {
/**
* Atomic stop-the-world marking. This option does not require any write
* barriers but is the most intrusive in terms of jank.
*/
kAtomic,
/**
* Incremental marking, i.e. interleave marking is the rest of the
* application on the same thread.
*/
kIncremental,
/**
* Incremental and concurrent marking.
*/
kIncrementalAndConcurrent
};
/**
* Specifies supported sweeping types
*/
enum class SweepingType : uint8_t {
/**
* Atomic stop-the-world sweeping. All of sweeping is performed at once.
*/
kAtomic,
/**
* Incremental and concurrent sweeping. Sweeping is split and interleaved
* with the rest of the application.
*/
kIncrementalAndConcurrent
};
/**
* Constraints for a Heap setup.
*/
struct ResourceConstraints {
/**
* Allows the heap to grow to some initial size in bytes before triggering
* garbage collections. This is useful when it is known that applications
* need a certain minimum heap to run to avoid repeatedly invoking the
* garbage collector when growing the heap.
*/
size_t initial_heap_size_bytes = 0;
};
/**
* Options specifying Heap properties (e.g. custom spaces) when initializing a
* heap through `Heap::Create()`.
*/
struct HeapOptions {
/**
* Creates reasonable defaults for instantiating a Heap.
*
* \returns the HeapOptions that can be passed to `Heap::Create()`.
*/
static HeapOptions Default() { return {}; }
/**
* Custom spaces added to heap are required to have indices forming a
* numbered sequence starting at 0, i.e., their `kSpaceIndex` must
* correspond to the index they reside in the vector.
*/
std::vector<std::unique_ptr<CustomSpaceBase>> custom_spaces;
/**
* Specifies whether conservative stack scan is supported. When conservative
* stack scan is not supported, the collector may try to invoke
* garbage collections using non-nestable task, which are guaranteed to have
* no interesting stack, through the provided Platform. If such tasks are
* not supported by the Platform, the embedder must take care of invoking
* the GC through `ForceGarbageCollectionSlow()`.
*/
StackSupport stack_support = StackSupport::kSupportsConservativeStackScan;
/**
* Specifies which types of marking are supported by the heap.
*/
MarkingType marking_support = MarkingType::kIncrementalAndConcurrent;
/**
* Specifies which types of sweeping are supported by the heap.
*/
SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent;
/**
* Resource constraints specifying various properties that the internal
* GC scheduler follows.
*/
ResourceConstraints resource_constraints;
};
/**
* Creates a new heap that can be used for object allocation.
*
* \param platform implemented and provided by the embedder.
* \param options HeapOptions specifying various properties for the Heap.
* \returns a new Heap instance.
*/
static std::unique_ptr<Heap> Create(
std::shared_ptr<Platform> platform,
HeapOptions options = HeapOptions::Default());
virtual ~Heap() = default;
/**
* Forces garbage collection.
*
* \param source String specifying the source (or caller) triggering a
* forced garbage collection.
* \param reason String specifying the reason for the forced garbage
* collection.
* \param stack_state The embedder stack state, see StackState.
*/
void ForceGarbageCollectionSlow(
const char* source, const char* reason,
StackState stack_state = StackState::kMayContainHeapPointers);
/**
* \returns the opaque handle for allocating objects using
* `MakeGarbageCollected()`.
*/
AllocationHandle& GetAllocationHandle();
/**
* \returns the opaque heap handle which may be used to refer to this heap in
* other APIs. Valid as long as the underlying `Heap` is alive.
*/
HeapHandle& GetHeapHandle();
private:
Heap() = default;
friend class internal::Heap;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_HEAP_H_

View File

@ -1,47 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_
#include <stddef.h>
#include <stdint.h>
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
// Embedders should not rely on this code!
// Internal constants to avoid exposing internal types on the API surface.
namespace api_constants {
constexpr size_t kKB = 1024;
constexpr size_t kMB = kKB * 1024;
constexpr size_t kGB = kMB * 1024;
// Offset of the uint16_t bitfield from the payload contaning the
// in-construction bit. This is subtracted from the payload pointer to get
// to the right bitfield.
static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload =
2 * sizeof(uint16_t);
// Mask for in-construction bit.
static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1};
static constexpr size_t kPageSize = size_t{1} << 17;
static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2;
#if defined(CPPGC_CAGED_HEAP)
constexpr size_t kCagedHeapReservationSize = static_cast<size_t>(4) * kGB;
constexpr size_t kCagedHeapReservationAlignment = kCagedHeapReservationSize;
#endif
} // namespace api_constants
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_

View File

@ -1,48 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_
#include <atomic>
namespace cppgc {
namespace internal {
// A flag which provides a fast check whether a scope may be entered on the
// current thread, without needing to access thread-local storage or mutex. Can
// have false positives (i.e., spuriously report that it might be entered), so
// it is expected that this will be used in tandem with a precise check that the
// scope is in fact entered on that thread.
//
// Example:
// g_frobnicating_flag.MightBeEntered() &&
// ThreadLocalFrobnicator().IsFrobnicating()
//
// Relaxed atomic operations are sufficient, since:
// - all accesses remain atomic
// - each thread must observe its own operations in order
// - no thread ever exits the flag more times than it enters (if used correctly)
// And so if a thread observes zero, it must be because it has observed an equal
// number of exits as entries.
class AtomicEntryFlag final {
public:
void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); }
void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); }
// Returns false only if the current thread is not between a call to Enter
// and a call to Exit. Returns true if this thread or another thread may
// currently be in the scope guarded by this flag.
bool MightBeEntered() const {
return entries_.load(std::memory_order_relaxed) != 0;
}
private:
std::atomic_int entries_{0};
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_

View File

@ -1,68 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
#include <array>
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/logging.h"
#include "cppgc/platform.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class HeapBase;
#if defined(CPPGC_YOUNG_GENERATION)
// AgeTable contains entries that correspond to 4KB memory regions. Each entry
// can be in one of three states: kOld, kYoung or kUnknown.
class AgeTable final {
static constexpr size_t kGranularityBits = 12; // 4KiB per byte.
public:
enum class Age : uint8_t { kOld, kYoung, kUnknown };
static constexpr size_t kEntrySizeInBytes = 1 << kGranularityBits;
Age& operator[](uintptr_t offset) { return table_[entry(offset)]; }
Age operator[](uintptr_t offset) const { return table_[entry(offset)]; }
void Reset(PageAllocator* allocator);
private:
static constexpr size_t kAgeTableSize =
api_constants::kCagedHeapReservationSize >> kGranularityBits;
size_t entry(uintptr_t offset) const {
const size_t entry = offset >> kGranularityBits;
CPPGC_DCHECK(table_.size() > entry);
return entry;
}
std::array<Age, kAgeTableSize> table_;
};
static_assert(sizeof(AgeTable) == 1 * api_constants::kMB,
"Size of AgeTable is 1MB");
#endif // CPPGC_YOUNG_GENERATION
struct CagedHeapLocalData final {
explicit CagedHeapLocalData(HeapBase* heap_base) : heap_base(heap_base) {}
bool is_incremental_marking_in_progress = false;
HeapBase* heap_base = nullptr;
#if defined(CPPGC_YOUNG_GENERATION)
AgeTable age_table;
#endif
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_

View File

@ -1,38 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_
namespace cppgc {
#if defined(__has_attribute)
#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE)
#else
#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0
#endif
#if defined(__has_cpp_attribute)
#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE)
#else
#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0
#endif
// [[no_unique_address]] comes in C++20 but supported in clang with -std >=
// c++11.
#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address) // NOLINTNEXTLINE
#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define CPPGC_NO_UNIQUE_ADDRESS
#endif
#if CPPGC_HAS_ATTRIBUTE(unused) // NOLINTNEXTLINE
#define CPPGC_UNUSED __attribute__((unused))
#else
#define CPPGC_UNUSED
#endif
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_

View File

@ -1,90 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_
#include <type_traits>
#include "cppgc/type-traits.h"
namespace cppgc {
namespace internal {
using FinalizationCallback = void (*)(void*);
template <typename T, typename = void>
struct HasFinalizeGarbageCollectedObject : std::false_type {};
template <typename T>
struct HasFinalizeGarbageCollectedObject<
T, void_t<decltype(std::declval<T>().FinalizeGarbageCollectedObject())>>
: std::true_type {};
// The FinalizerTraitImpl specifies how to finalize objects.
template <typename T, bool isFinalized>
struct FinalizerTraitImpl;
template <typename T>
struct FinalizerTraitImpl<T, true> {
private:
// Dispatch to custom FinalizeGarbageCollectedObject().
struct Custom {
static void Call(void* obj) {
static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
}
};
// Dispatch to regular destructor.
struct Destructor {
static void Call(void* obj) { static_cast<T*>(obj)->~T(); }
};
using FinalizeImpl =
std::conditional_t<HasFinalizeGarbageCollectedObject<T>::value, Custom,
Destructor>;
public:
static void Finalize(void* obj) {
static_assert(sizeof(T), "T must be fully defined");
FinalizeImpl::Call(obj);
}
};
template <typename T>
struct FinalizerTraitImpl<T, false> {
static void Finalize(void* obj) {
static_assert(sizeof(T), "T must be fully defined");
}
};
// The FinalizerTrait is used to determine if a type requires finalization and
// what finalization means.
template <typename T>
struct FinalizerTrait {
private:
// Object has a finalizer if it has
// - a custom FinalizeGarbageCollectedObject method, or
// - a destructor.
static constexpr bool kNonTrivialFinalizer =
internal::HasFinalizeGarbageCollectedObject<T>::value ||
!std::is_trivially_destructible<typename std::remove_cv<T>::type>::value;
static void Finalize(void* obj) {
internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
}
public:
// The callback used to finalize an object of type T.
static constexpr FinalizationCallback kCallback =
kNonTrivialFinalizer ? Finalize : nullptr;
};
template <typename T>
constexpr FinalizationCallback FinalizerTrait<T>::kCallback;
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_

View File

@ -1,75 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
#include <atomic>
#include <cstdint>
#include "cppgc/internal/finalizer-trait.h"
#include "cppgc/internal/name-trait.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
using GCInfoIndex = uint16_t;
// Acquires a new GC info object and returns the index. In addition, also
// updates `registered_index` atomically.
V8_EXPORT GCInfoIndex
EnsureGCInfoIndex(std::atomic<GCInfoIndex>& registered_index,
FinalizationCallback, TraceCallback, NameCallback, bool);
// Fold types based on finalizer behavior. Note that finalizer characteristics
// align with trace behavior, i.e., destructors are virtual when trace methods
// are and vice versa.
template <typename T, typename ParentMostGarbageCollectedType>
struct GCInfoFolding {
static constexpr bool kHasVirtualDestructorAtBase =
std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
static constexpr bool kBothTypesAreTriviallyDestructible =
std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
std::is_trivially_destructible<T>::value;
static constexpr bool kHasCustomFinalizerDispatchAtBase =
internal::HasFinalizeGarbageCollectedObject<
ParentMostGarbageCollectedType>::value;
#ifdef CPPGC_SUPPORTS_OBJECT_NAMES
static constexpr bool kWantsDetailedObjectNames = true;
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
static constexpr bool kWantsDetailedObjectNames = false;
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
// Folding would regresses name resolution when deriving names from C++
// class names as it would just folds a name to the base class name.
using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase ||
kBothTypesAreTriviallyDestructible ||
kHasCustomFinalizerDispatchAtBase) &&
!kWantsDetailedObjectNames,
ParentMostGarbageCollectedType, T>;
};
// Trait determines how the garbage collector treats objects wrt. to traversing,
// finalization, and naming.
template <typename T>
struct GCInfoTrait final {
static GCInfoIndex Index() {
static_assert(sizeof(T), "T must be fully defined");
static std::atomic<GCInfoIndex>
registered_index; // Uses zero initialization.
const GCInfoIndex index = registered_index.load(std::memory_order_acquire);
return index ? index
: EnsureGCInfoIndex(
registered_index, FinalizerTrait<T>::kCallback,
TraceTrait<T>::Trace, NameTrait<T>::GetName,
std::is_polymorphic<T>::value);
}
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_

View File

@ -1,50 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_
#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_
#include "cppgc/source-location.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
void V8_EXPORT DCheckImpl(const char*,
const SourceLocation& = SourceLocation::Current());
[[noreturn]] void V8_EXPORT
FatalImpl(const char*, const SourceLocation& = SourceLocation::Current());
// Used to ignore -Wunused-variable.
template <typename>
struct EatParams {};
#if DEBUG
#define CPPGC_DCHECK_MSG(condition, message) \
do { \
if (V8_UNLIKELY(!(condition))) { \
::cppgc::internal::DCheckImpl(message); \
} \
} while (false)
#else
#define CPPGC_DCHECK_MSG(condition, message) \
(static_cast<void>(::cppgc::internal::EatParams<decltype( \
static_cast<void>(condition), message)>{}))
#endif
#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition)
#define CPPGC_CHECK_MSG(condition, message) \
do { \
if (V8_UNLIKELY(!(condition))) { \
::cppgc::internal::FatalImpl(message); \
} \
} while (false)
#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition)
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_

View File

@ -1,111 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
#define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_
#include <cstddef>
#include "cppgc/name-provider.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
#if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__)
#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1
// Provides constexpr c-string storage for a name of fixed |Size| characters.
// Automatically appends terminating 0 byte.
template <size_t Size>
struct NameBuffer {
char name[Size + 1]{};
static constexpr NameBuffer FromCString(const char* str) {
NameBuffer result;
for (size_t i = 0; i < Size; ++i) result.name[i] = str[i];
result.name[Size] = 0;
return result;
}
};
template <typename T>
const char* GetTypename() {
static constexpr char kSelfPrefix[] =
"const char *cppgc::internal::GetTypename() [T =";
static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix,
sizeof(kSelfPrefix) - 1) == 0,
"The prefix must match");
static constexpr const char* kTypenameStart =
__PRETTY_FUNCTION__ + sizeof(kSelfPrefix);
static constexpr size_t kTypenameSize =
__builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1;
// NameBuffer is an indirection that is needed to make sure that only a
// substring of __PRETTY_FUNCTION__ gets materialized in the binary.
static constexpr auto buffer =
NameBuffer<kTypenameSize>::FromCString(kTypenameStart);
return buffer.name;
}
#else
#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0
#endif
struct HeapObjectName {
const char* value;
bool name_was_hidden;
};
class V8_EXPORT NameTraitBase {
protected:
static HeapObjectName GetNameFromTypeSignature(const char*);
};
// Trait that specifies how the garbage collector retrieves the name for a
// given object.
template <typename T>
class NameTrait final : public NameTraitBase {
public:
static HeapObjectName GetName(const void* obj) {
return GetNameFor(static_cast<const T*>(obj));
}
private:
static HeapObjectName GetNameFor(const NameProvider* name_provider) {
return {name_provider->GetName(), false};
}
static HeapObjectName GetNameFor(...) {
#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
return {GetTypename<T>(), false};
#elif CPPGC_SUPPORTS_OBJECT_NAMES
#if defined(V8_CC_GNU)
#define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__
#elif defined(V8_CC_MSVC)
#define PRETTY_FUNCTION_VALUE __FUNCSIG__
#else
#define PRETTY_FUNCTION_VALUE nullptr
#endif
static const HeapObjectName leaky_name =
GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE);
return leaky_name;
#undef PRETTY_FUNCTION_VALUE
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
return {NameProvider::kHiddenName, true};
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
}
};
using NameCallback = HeapObjectName (*)(const void*);
} // namespace internal
} // namespace cppgc
#undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME
#endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_

View File

@ -1,172 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
#include <array>
#include <memory>
#include <vector>
#include "cppgc/internal/logging.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class Visitor;
namespace internal {
class CrossThreadPersistentRegion;
// PersistentNode represents a variant of two states:
// 1) traceable node with a back pointer to the Persistent object;
// 2) freelist entry.
class PersistentNode final {
public:
PersistentNode() = default;
PersistentNode(const PersistentNode&) = delete;
PersistentNode& operator=(const PersistentNode&) = delete;
void InitializeAsUsedNode(void* owner, TraceCallback trace) {
CPPGC_DCHECK(trace);
owner_ = owner;
trace_ = trace;
}
void InitializeAsFreeNode(PersistentNode* next) {
next_ = next;
trace_ = nullptr;
}
void UpdateOwner(void* owner) {
CPPGC_DCHECK(IsUsed());
owner_ = owner;
}
PersistentNode* FreeListNext() const {
CPPGC_DCHECK(!IsUsed());
return next_;
}
void Trace(Visitor* visitor) const {
CPPGC_DCHECK(IsUsed());
trace_(visitor, owner_);
}
bool IsUsed() const { return trace_; }
void* owner() const {
CPPGC_DCHECK(IsUsed());
return owner_;
}
private:
// PersistentNode acts as a designated union:
// If trace_ != nullptr, owner_ points to the corresponding Persistent handle.
// Otherwise, next_ points to the next freed PersistentNode.
union {
void* owner_ = nullptr;
PersistentNode* next_;
};
TraceCallback trace_ = nullptr;
};
class V8_EXPORT PersistentRegion final {
using PersistentNodeSlots = std::array<PersistentNode, 256u>;
public:
PersistentRegion() = default;
// Clears Persistent fields to avoid stale pointers after heap teardown.
~PersistentRegion();
PersistentRegion(const PersistentRegion&) = delete;
PersistentRegion& operator=(const PersistentRegion&) = delete;
PersistentNode* AllocateNode(void* owner, TraceCallback trace) {
if (!free_list_head_) {
EnsureNodeSlots();
}
PersistentNode* node = free_list_head_;
free_list_head_ = free_list_head_->FreeListNext();
CPPGC_DCHECK(!node->IsUsed());
node->InitializeAsUsedNode(owner, trace);
nodes_in_use_++;
return node;
}
void FreeNode(PersistentNode* node) {
CPPGC_DCHECK(node);
CPPGC_DCHECK(node->IsUsed());
node->InitializeAsFreeNode(free_list_head_);
free_list_head_ = node;
CPPGC_DCHECK(nodes_in_use_ > 0);
nodes_in_use_--;
}
void Trace(Visitor*);
size_t NodesInUse() const;
void ClearAllUsedNodes();
private:
void EnsureNodeSlots();
std::vector<std::unique_ptr<PersistentNodeSlots>> nodes_;
PersistentNode* free_list_head_ = nullptr;
size_t nodes_in_use_ = 0;
friend class CrossThreadPersistentRegion;
};
// CrossThreadPersistent uses PersistentRegion but protects it using this lock
// when needed.
class V8_EXPORT PersistentRegionLock final {
public:
PersistentRegionLock();
~PersistentRegionLock();
static void AssertLocked();
};
// Variant of PersistentRegion that checks whether the PersistentRegionLock is
// locked.
class V8_EXPORT CrossThreadPersistentRegion final {
public:
CrossThreadPersistentRegion() = default;
// Clears Persistent fields to avoid stale pointers after heap teardown.
~CrossThreadPersistentRegion();
CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete;
CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) =
delete;
V8_INLINE PersistentNode* AllocateNode(void* owner, TraceCallback trace) {
PersistentRegionLock::AssertLocked();
return persistent_region_.AllocateNode(owner, trace);
}
V8_INLINE void FreeNode(PersistentNode* node) {
PersistentRegionLock::AssertLocked();
persistent_region_.FreeNode(node);
}
void Trace(Visitor*);
size_t NodesInUse() const;
void ClearAllUsedNodes();
private:
PersistentRegion persistent_region_;
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_

View File

@ -1,146 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
#include <cstdint>
#include <type_traits>
#include "cppgc/internal/write-barrier.h"
#include "cppgc/source-location.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class PersistentRegion;
class CrossThreadPersistentRegion;
// Tags to distinguish between strong and weak member types.
class StrongMemberTag;
class WeakMemberTag;
class UntracedMemberTag;
struct DijkstraWriteBarrierPolicy {
static void InitializingBarrier(const void*, const void*) {
// Since in initializing writes the source object is always white, having no
// barrier doesn't break the tri-color invariant.
}
static void AssigningBarrier(const void* slot, const void* value) {
WriteBarrier::Params params;
switch (WriteBarrier::GetWriteBarrierType(slot, value, params)) {
case WriteBarrier::Type::kGenerational:
WriteBarrier::GenerationalBarrier(params, slot);
break;
case WriteBarrier::Type::kMarking:
WriteBarrier::DijkstraMarkingBarrier(params, value);
break;
case WriteBarrier::Type::kNone:
break;
}
}
};
struct NoWriteBarrierPolicy {
static void InitializingBarrier(const void*, const void*) {}
static void AssigningBarrier(const void*, const void*) {}
};
class V8_EXPORT EnabledCheckingPolicy {
protected:
EnabledCheckingPolicy();
void CheckPointer(const void* ptr);
private:
void* impl_;
};
class DisabledCheckingPolicy {
protected:
void CheckPointer(const void* raw) {}
};
#if V8_ENABLE_CHECKS
using DefaultCheckingPolicy = EnabledCheckingPolicy;
#else
using DefaultCheckingPolicy = DisabledCheckingPolicy;
#endif
class KeepLocationPolicy {
public:
constexpr const SourceLocation& Location() const { return location_; }
protected:
constexpr KeepLocationPolicy() = default;
constexpr explicit KeepLocationPolicy(const SourceLocation& location)
: location_(location) {}
// KeepLocationPolicy must not copy underlying source locations.
KeepLocationPolicy(const KeepLocationPolicy&) = delete;
KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete;
// Location of the original moved from object should be preserved.
KeepLocationPolicy(KeepLocationPolicy&&) = default;
KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default;
private:
SourceLocation location_;
};
class IgnoreLocationPolicy {
public:
constexpr SourceLocation Location() const { return {}; }
protected:
constexpr IgnoreLocationPolicy() = default;
constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {}
};
#if CPPGC_SUPPORTS_OBJECT_NAMES
using DefaultLocationPolicy = KeepLocationPolicy;
#else
using DefaultLocationPolicy = IgnoreLocationPolicy;
#endif
struct StrongPersistentPolicy {
using IsStrongPersistent = std::true_type;
static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
};
struct WeakPersistentPolicy {
using IsStrongPersistent = std::false_type;
static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
};
struct StrongCrossThreadPersistentPolicy {
using IsStrongPersistent = std::true_type;
static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
const void* object);
};
struct WeakCrossThreadPersistentPolicy {
using IsStrongPersistent = std::false_type;
static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
const void* object);
};
// Forward declarations setting up the default policies.
template <typename T, typename WeaknessPolicy,
typename LocationPolicy = DefaultLocationPolicy,
typename CheckingPolicy = DisabledCheckingPolicy>
class BasicCrossThreadPersistent;
template <typename T, typename WeaknessPolicy,
typename LocationPolicy = DefaultLocationPolicy,
typename CheckingPolicy = DefaultCheckingPolicy>
class BasicPersistent;
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy = DefaultCheckingPolicy>
class BasicMember;
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_

View File

@ -1,30 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_
#define INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_
#include "cppgc/heap.h"
#include "cppgc/liveness-broker.h"
namespace cppgc {
namespace internal {
class V8_EXPORT PreFinalizerRegistrationDispatcher final {
public:
using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*);
struct PreFinalizer {
void* object;
PreFinalizerCallback callback;
bool operator==(const PreFinalizer& other) const;
};
static void RegisterPrefinalizer(PreFinalizer pre_finalizer);
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_

View File

@ -1,390 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
#include "cppgc/heap-state.h"
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/atomic-entry-flag.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
#if defined(CPPGC_CAGED_HEAP)
#include "cppgc/internal/caged-heap-local-data.h"
#endif
namespace cppgc {
class HeapHandle;
namespace internal {
class WriteBarrierTypeForCagedHeapPolicy;
class WriteBarrierTypeForNonCagedHeapPolicy;
class V8_EXPORT WriteBarrier final {
public:
enum class Type : uint8_t {
kNone,
kMarking,
kGenerational,
};
struct Params {
HeapHandle* heap = nullptr;
#if V8_ENABLE_CHECKS
Type type = Type::kNone;
#endif // !V8_ENABLE_CHECKS
#if defined(CPPGC_CAGED_HEAP)
uintptr_t start = 0;
CagedHeapLocalData& caged_heap() const {
return *reinterpret_cast<CagedHeapLocalData*>(start);
}
uintptr_t slot_offset = 0;
uintptr_t value_offset = 0;
#endif // CPPGC_CAGED_HEAP
};
enum class ValueMode {
kValuePresent,
kNoValuePresent,
};
// Returns the required write barrier for a given `slot` and `value`.
static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value,
Params& params);
// Returns the required write barrier for a given `slot`.
template <typename HeapHandleCallback>
static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params,
HeapHandleCallback callback);
template <typename HeapHandleCallback>
static V8_INLINE Type GetWriteBarrierTypeForExternallyReferencedObject(
const void* value, Params& params, HeapHandleCallback callback);
static V8_INLINE void DijkstraMarkingBarrier(const Params& params,
const void* object);
static V8_INLINE void DijkstraMarkingBarrierRange(
const Params& params, const void* first_element, size_t element_size,
size_t number_of_elements, TraceCallback trace_callback);
static V8_INLINE void SteeleMarkingBarrier(const Params& params,
const void* object);
#if defined(CPPGC_YOUNG_GENERATION)
static V8_INLINE void GenerationalBarrier(const Params& params,
const void* slot);
#else // !CPPGC_YOUNG_GENERATION
static V8_INLINE void GenerationalBarrier(const Params& params,
const void* slot) {}
#endif // CPPGC_YOUNG_GENERATION
#if V8_ENABLE_CHECKS
static void CheckParams(Type expected_type, const Params& params);
#else // !V8_ENABLE_CHECKS
static void CheckParams(Type expected_type, const Params& params) {}
#endif // !V8_ENABLE_CHECKS
// The IncrementalOrConcurrentUpdater class allows cppgc internal to update
// |incremental_or_concurrent_marking_flag_|.
class IncrementalOrConcurrentMarkingFlagUpdater;
static bool IsAnyIncrementalOrConcurrentMarking() {
return incremental_or_concurrent_marking_flag_.MightBeEntered();
}
private:
WriteBarrier() = delete;
#if defined(CPPGC_CAGED_HEAP)
using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy;
#else // !CPPGC_CAGED_HEAP
using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy;
#endif // !CPPGC_CAGED_HEAP
static void DijkstraMarkingBarrierSlow(const void* value);
static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value);
static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle,
const void* first_element,
size_t element_size,
size_t number_of_elements,
TraceCallback trace_callback);
static void SteeleMarkingBarrierSlow(const void* value);
static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value);
#if defined(CPPGC_YOUNG_GENERATION)
static CagedHeapLocalData& GetLocalData(HeapHandle&);
static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data,
const AgeTable& ageTable,
const void* slot, uintptr_t value_offset);
#endif // CPPGC_YOUNG_GENERATION
static AtomicEntryFlag incremental_or_concurrent_marking_flag_;
};
template <WriteBarrier::Type type>
V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) {
if (type == WriteBarrier::Type::kNone) return WriteBarrier::Type::kNone;
#if V8_ENABLE_CHECKS
params.type = type;
#endif // !V8_ENABLE_CHECKS
return type;
}
#if defined(CPPGC_CAGED_HEAP)
class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final {
public:
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
}
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type GetForExternallyReferenced(
const void* value, WriteBarrier::Params& params, HeapHandleCallback) {
if (!TryGetCagedHeap(value, value, params)) {
return WriteBarrier::Type::kNone;
}
if (V8_UNLIKELY(params.caged_heap().is_incremental_marking_in_progress)) {
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
private:
WriteBarrierTypeForCagedHeapPolicy() = delete;
template <WriteBarrier::ValueMode value_mode>
struct ValueModeDispatch;
static V8_INLINE bool TryGetCagedHeap(const void* slot, const void* value,
WriteBarrier::Params& params) {
params.start = reinterpret_cast<uintptr_t>(value) &
~(api_constants::kCagedHeapReservationAlignment - 1);
const uintptr_t slot_offset =
reinterpret_cast<uintptr_t>(slot) - params.start;
if (slot_offset > api_constants::kCagedHeapReservationSize) {
// Check if slot is on stack or value is sentinel or nullptr. This relies
// on the fact that kSentinelPointer is encoded as 0x1.
return false;
}
return true;
}
// Returns whether marking is in progress. If marking is not in progress
// sets the start of the cage accordingly.
//
// TODO(chromium:1056170): Create fast path on API.
static bool IsMarking(const HeapHandle&, WriteBarrier::Params&);
};
template <>
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
WriteBarrier::Params& params,
HeapHandleCallback) {
bool within_cage = TryGetCagedHeap(slot, value, params);
if (!within_cage) {
return WriteBarrier::Type::kNone;
}
if (V8_LIKELY(!params.caged_heap().is_incremental_marking_in_progress)) {
#if defined(CPPGC_YOUNG_GENERATION)
params.heap = reinterpret_cast<HeapHandle*>(params.start);
params.slot_offset = reinterpret_cast<uintptr_t>(slot) - params.start;
params.value_offset = reinterpret_cast<uintptr_t>(value) - params.start;
return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
#else // !CPPGC_YOUNG_GENERATION
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
#endif // !CPPGC_YOUNG_GENERATION
}
params.heap = reinterpret_cast<HeapHandle*>(params.start);
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
};
template <>
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kNoValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
#if defined(CPPGC_YOUNG_GENERATION)
HeapHandle& handle = callback();
if (V8_LIKELY(!IsMarking(handle, params))) {
// params.start is populated by IsMarking().
params.heap = &handle;
params.slot_offset = reinterpret_cast<uintptr_t>(slot) - params.start;
// params.value_offset stays 0.
if (params.slot_offset > api_constants::kCagedHeapReservationSize) {
// Check if slot is on stack.
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
}
#else // !CPPGC_YOUNG_GENERATION
if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) {
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
HeapHandle& handle = callback();
if (V8_UNLIKELY(!subtle::HeapState::IsMarking(handle))) {
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
#endif // !CPPGC_YOUNG_GENERATION
params.heap = &handle;
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
};
#endif // CPPGC_CAGED_HEAP
class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final {
public:
template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
}
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type GetForExternallyReferenced(
const void* value, WriteBarrier::Params& params,
HeapHandleCallback callback) {
// The slot will never be used in `Get()` below.
return Get<WriteBarrier::ValueMode::kValuePresent>(nullptr, value, params,
callback);
}
private:
template <WriteBarrier::ValueMode value_mode>
struct ValueModeDispatch;
// TODO(chromium:1056170): Create fast path on API.
static bool IsMarking(const void*, HeapHandle**);
// TODO(chromium:1056170): Create fast path on API.
static bool IsMarking(HeapHandle&);
WriteBarrierTypeForNonCagedHeapPolicy() = delete;
};
template <>
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void*, const void* object,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
// The following check covers nullptr as well as sentinel pointer.
if (object <= static_cast<void*>(kSentinelPointer)) {
return WriteBarrier::Type::kNone;
}
if (IsMarking(object, &params.heap)) {
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
return SetAndReturnType<WriteBarrier::Type::kNone>(params);
}
};
template <>
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
WriteBarrier::ValueMode::kNoValuePresent> {
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrier::Type Get(const void*, const void*,
WriteBarrier::Params& params,
HeapHandleCallback callback) {
if (V8_UNLIKELY(WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) {
HeapHandle& handle = callback();
if (IsMarking(handle)) {
params.heap = &handle;
return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
}
}
return WriteBarrier::Type::kNone;
}
};
// static
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
const void* slot, const void* value, WriteBarrier::Params& params) {
return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
params, []() {});
}
// static
template <typename HeapHandleCallback>
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
const void* slot, WriteBarrier::Params& params,
HeapHandleCallback callback) {
return WriteBarrierTypePolicy::Get<ValueMode::kNoValuePresent>(
slot, nullptr, params, callback);
}
// static
template <typename HeapHandleCallback>
WriteBarrier::Type
WriteBarrier::GetWriteBarrierTypeForExternallyReferencedObject(
const void* value, Params& params, HeapHandleCallback callback) {
return WriteBarrierTypePolicy::GetForExternallyReferenced(value, params,
callback);
}
// static
void WriteBarrier::DijkstraMarkingBarrier(const Params& params,
const void* object) {
CheckParams(Type::kMarking, params);
#if defined(CPPGC_CAGED_HEAP)
// Caged heap already filters out sentinels.
DijkstraMarkingBarrierSlow(object);
#else // !CPPGC_CAGED_HEAP
DijkstraMarkingBarrierSlowWithSentinelCheck(object);
#endif // !CPPGC_CAGED_HEAP
}
// static
void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params,
const void* first_element,
size_t element_size,
size_t number_of_elements,
TraceCallback trace_callback) {
CheckParams(Type::kMarking, params);
DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size,
number_of_elements, trace_callback);
}
// static
void WriteBarrier::SteeleMarkingBarrier(const Params& params,
const void* object) {
CheckParams(Type::kMarking, params);
#if defined(CPPGC_CAGED_HEAP)
// Caged heap already filters out sentinels.
SteeleMarkingBarrierSlow(object);
#else // !CPPGC_CAGED_HEAP
SteeleMarkingBarrierSlowWithSentinelCheck(object);
#endif // !CPPGC_CAGED_HEAP
}
#if defined(CPPGC_YOUNG_GENERATION)
// static
void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) {
CheckParams(Type::kGenerational, params);
const CagedHeapLocalData& local_data = params.caged_heap();
const AgeTable& age_table = local_data.age_table;
// Bail out if the slot is in young generation.
if (V8_LIKELY(age_table[params.slot_offset] == AgeTable::Age::kYoung)) return;
GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset);
}
#endif // !CPPGC_YOUNG_GENERATION
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_

View File

@ -1,74 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_
#define INCLUDE_CPPGC_LIVENESS_BROKER_H_
#include "cppgc/heap.h"
#include "cppgc/member.h"
#include "cppgc/trace-trait.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class LivenessBrokerFactory;
} // namespace internal
/**
* The broker is passed to weak callbacks to allow (temporarily) querying
* the liveness state of an object. References to non-live objects must be
* cleared when `IsHeapObjectAlive()` returns false.
*
* \code
* class GCedWithCustomWeakCallback final
* : public GarbageCollected<GCedWithCustomWeakCallback> {
* public:
* UntracedMember<Bar> bar;
*
* void CustomWeakCallbackMethod(const LivenessBroker& broker) {
* if (!broker.IsHeapObjectAlive(bar))
* bar = nullptr;
* }
*
* void Trace(cppgc::Visitor* visitor) const {
* visitor->RegisterWeakCallbackMethod<
* GCedWithCustomWeakCallback,
* &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this);
* }
* };
* \endcode
*/
class V8_EXPORT LivenessBroker final {
public:
template <typename T>
bool IsHeapObjectAlive(const T* object) const {
return object &&
IsHeapObjectAliveImpl(
TraceTrait<T>::GetTraceDescriptor(object).base_object_payload);
}
template <typename T>
bool IsHeapObjectAlive(const WeakMember<T>& weak_member) const {
return (weak_member != kSentinelPointer) &&
IsHeapObjectAlive<T>(weak_member.Get());
}
template <typename T>
bool IsHeapObjectAlive(const UntracedMember<T>& untraced_member) const {
return (untraced_member != kSentinelPointer) &&
IsHeapObjectAlive<T>(untraced_member.Get());
}
private:
LivenessBroker() = default;
bool IsHeapObjectAliveImpl(const void*) const;
friend class internal::LivenessBrokerFactory;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_

View File

@ -1,26 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_MACROS_H_
#define INCLUDE_CPPGC_MACROS_H_
#include <stddef.h>
#include "cppgc/internal/compiler-specific.h"
namespace cppgc {
// Use if the object is only stack allocated.
#define CPPGC_STACK_ALLOCATED() \
public: \
using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \
\
private: \
void* operator new(size_t) = delete; \
void* operator new(size_t, void*) = delete; \
static_assert(true, "Force semicolon.")
} // namespace cppgc
#endif // INCLUDE_CPPGC_MACROS_H_

View File

@ -1,271 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_MEMBER_H_
#define INCLUDE_CPPGC_MEMBER_H_
#include <atomic>
#include <cstddef>
#include <type_traits>
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/type-traits.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class Visitor;
namespace internal {
// MemberBase always refers to the object as const object and defers to
// BasicMember on casting to the right type as needed.
class MemberBase {
protected:
MemberBase() = default;
explicit MemberBase(const void* value) : raw_(value) {}
const void** GetRawSlot() const { return &raw_; }
const void* GetRaw() const { return raw_; }
void SetRaw(void* value) { raw_ = value; }
const void* GetRawAtomic() const {
return reinterpret_cast<const std::atomic<const void*>*>(&raw_)->load(
std::memory_order_relaxed);
}
void SetRawAtomic(const void* value) {
reinterpret_cast<std::atomic<const void*>*>(&raw_)->store(
value, std::memory_order_relaxed);
}
void ClearFromGC() const { raw_ = nullptr; }
private:
mutable const void* raw_ = nullptr;
};
// The basic class from which all Member classes are 'generated'.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy>
class BasicMember final : private MemberBase, private CheckingPolicy {
public:
using PointeeType = T;
constexpr BasicMember() = default;
constexpr BasicMember(std::nullptr_t) {} // NOLINT
BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT
BasicMember(T* raw) : MemberBase(raw) { // NOLINT
InitializingWriteBarrier();
this->CheckPointer(Get());
}
BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT
// Copy ctor.
BasicMember(const BasicMember& other) : BasicMember(other.Get()) {}
// Allow heterogeneous construction.
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember( // NOLINT
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other)
: BasicMember(other.Get()) {}
// Move ctor.
BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) {
other.Clear();
}
// Allow heterogeneous move construction.
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember( // NOLINT
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>&& other) noexcept
: BasicMember(other.Get()) {
other.Clear();
}
// Construction from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember( // NOLINT
const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy, PersistentCheckingPolicy>&
p)
: BasicMember(p.Get()) {}
// Copy assignment.
BasicMember& operator=(const BasicMember& other) {
return operator=(other.Get());
}
// Allow heterogeneous copy assignment.
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other) {
return operator=(other.Get());
}
// Move assignment.
BasicMember& operator=(BasicMember&& other) noexcept {
operator=(other.Get());
other.Clear();
return *this;
}
// Heterogeneous move assignment.
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>&& other) noexcept {
operator=(other.Get());
other.Clear();
return *this;
}
// Assignment from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(
const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy, PersistentCheckingPolicy>&
other) {
return operator=(other.Get());
}
BasicMember& operator=(T* other) {
SetRawAtomic(other);
AssigningWriteBarrier();
this->CheckPointer(Get());
return *this;
}
BasicMember& operator=(std::nullptr_t) {
Clear();
return *this;
}
BasicMember& operator=(SentinelPointer s) {
SetRawAtomic(s);
return *this;
}
template <typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy>
void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other) {
T* tmp = Get();
*this = other;
other = tmp;
}
explicit operator bool() const { return Get(); }
operator T*() const { return Get(); } // NOLINT
T* operator->() const { return Get(); }
T& operator*() const { return *Get(); }
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
// Executed by the mutator, hence non atomic load.
//
// The const_cast below removes the constness from MemberBase storage. The
// following static_cast re-adds any constness if specified through the
// user-visible template parameter T.
return static_cast<T*>(const_cast<void*>(MemberBase::GetRaw()));
}
void Clear() { SetRawAtomic(nullptr); }
T* Release() {
T* result = Get();
Clear();
return result;
}
const T** GetSlotForTesting() const {
return reinterpret_cast<const T**>(GetRawSlot());
}
private:
const T* GetRawAtomic() const {
return static_cast<const T*>(MemberBase::GetRawAtomic());
}
void InitializingWriteBarrier() const {
WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw());
}
void AssigningWriteBarrier() const {
WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw());
}
void ClearFromGC() const { MemberBase::ClearFromGC(); }
friend class cppgc::Visitor;
template <typename U>
friend struct cppgc::TraceTrait;
};
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2>
bool operator==(
BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1,
BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>
member2) {
return member1.Get() == member2.Get();
}
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2>
bool operator!=(
BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1,
BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>
member2) {
return !(member1 == member2);
}
template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy>
struct IsWeak<
internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy, CheckingPolicy>>
: std::true_type {};
} // namespace internal
/**
* Members are used in classes to contain strong pointers to other garbage
* collected objects. All Member fields of a class must be traced in the class'
* trace method.
*/
template <typename T>
using Member = internal::BasicMember<T, internal::StrongMemberTag,
internal::DijkstraWriteBarrierPolicy>;
/**
* WeakMember is similar to Member in that it is used to point to other garbage
* collected objects. However instead of creating a strong pointer to the
* object, the WeakMember creates a weak pointer, which does not keep the
* pointee alive. Hence if all pointers to to a heap allocated object are weak
* the object will be garbage collected. At the time of GC the weak pointers
* will automatically be set to null.
*/
template <typename T>
using WeakMember = internal::BasicMember<T, internal::WeakMemberTag,
internal::DijkstraWriteBarrierPolicy>;
/**
* UntracedMember is a pointer to an on-heap object that is not traced for some
* reason. Do not use this unless you know what you are doing. Keeping raw
* pointers to on-heap objects is prohibited unless used from stack. Pointee
* must be kept alive through other means.
*/
template <typename T>
using UntracedMember = internal::BasicMember<T, internal::UntracedMemberTag,
internal::NoWriteBarrierPolicy>;
} // namespace cppgc
#endif // INCLUDE_CPPGC_MEMBER_H_

View File

@ -1,65 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_NAME_PROVIDER_H_
#define INCLUDE_CPPGC_NAME_PROVIDER_H_
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* NameProvider allows for providing a human-readable name for garbage-collected
* objects.
*
* There's two cases of names to distinguish:
* a. Explicitly specified names via using NameProvider. Such names are always
* preserved in the system.
* b. Internal names that Oilpan infers from a C++ type on the class hierarchy
* of the object. This is not necessarily the type of the actually
* instantiated object.
*
* Depending on the build configuration, Oilpan may hide names, i.e., represent
* them with kHiddenName, of case b. to avoid exposing internal details.
*/
class V8_EXPORT NameProvider {
public:
/**
* Name that is used when hiding internals.
*/
static constexpr const char kHiddenName[] = "InternalNode";
/**
* Name that is used in case compiler support is missing for composing a name
* from C++ types.
*/
static constexpr const char kNoNameDeducible[] = "<No name>";
/**
* Indicating whether internal names are hidden or not.
*
* @returns true if C++ names should be hidden and represented by kHiddenName.
*/
static constexpr bool HideInternalNames() {
#if CPPGC_SUPPORTS_OBJECT_NAMES
return false;
#else // !CPPGC_SUPPORTS_OBJECT_NAMES
return true;
#endif // !CPPGC_SUPPORTS_OBJECT_NAMES
}
virtual ~NameProvider() = default;
/**
* Specifies a name for the garbage-collected object. Such names will never
* be hidden, as they are explicitly specified by the user of this API.
*
* @returns a human readable name for the object.
*/
virtual const char* GetName() const = 0;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_

View File

@ -1,58 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
#define INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_
#include <cstddef>
#include "cppgc/type-traits.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
struct V8_EXPORT BaseObjectSizeTrait {
protected:
static size_t GetObjectSizeForGarbageCollected(const void*);
static size_t GetObjectSizeForGarbageCollectedMixin(const void*);
};
} // namespace internal
namespace subtle {
/**
* Trait specifying how to get the size of an object that was allocated using
* `MakeGarbageCollected()`. Also supports querying the size with an inner
* pointer to a mixin.
*/
template <typename T, bool = IsGarbageCollectedMixinTypeV<T>>
struct ObjectSizeTrait;
template <typename T>
struct ObjectSizeTrait<T, false> : cppgc::internal::BaseObjectSizeTrait {
static_assert(sizeof(T), "T must be fully defined");
static_assert(IsGarbageCollectedTypeV<T>,
"T must be of type GarbageCollected or GarbageCollectedMixin");
static size_t GetSize(const T& object) {
return GetObjectSizeForGarbageCollected(&object);
}
};
template <typename T>
struct ObjectSizeTrait<T, true> : cppgc::internal::BaseObjectSizeTrait {
static_assert(sizeof(T), "T must be fully defined");
static size_t GetSize(const T& object) {
return GetObjectSizeForGarbageCollectedMixin(&object);
}
};
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_

View File

@ -1,365 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_PERSISTENT_H_
#define INCLUDE_CPPGC_PERSISTENT_H_
#include <type_traits>
#include "cppgc/internal/persistent-node.h"
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/sentinel-pointer.h"
#include "cppgc/source-location.h"
#include "cppgc/type-traits.h"
#include "cppgc/visitor.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class Visitor;
namespace internal {
// PersistentBase always refers to the object as const object and defers to
// BasicPersistent on casting to the right type as needed.
class PersistentBase {
protected:
PersistentBase() = default;
explicit PersistentBase(const void* raw) : raw_(raw) {}
const void* GetValue() const { return raw_; }
void SetValue(const void* value) { raw_ = value; }
PersistentNode* GetNode() const { return node_; }
void SetNode(PersistentNode* node) { node_ = node; }
// Performs a shallow clear which assumes that internal persistent nodes are
// destroyed elsewhere.
void ClearFromGC() const {
raw_ = nullptr;
node_ = nullptr;
}
private:
mutable const void* raw_ = nullptr;
mutable PersistentNode* node_ = nullptr;
friend class PersistentRegion;
};
// The basic class from which all Persistent classes are generated.
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
class BasicPersistent final : public PersistentBase,
public LocationPolicy,
private WeaknessPolicy,
private CheckingPolicy {
public:
using typename WeaknessPolicy::IsStrongPersistent;
using PointeeType = T;
// Null-state/sentinel constructors.
BasicPersistent( // NOLINT
const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicPersistent(std::nullptr_t, // NOLINT
const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicPersistent( // NOLINT
SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(s), LocationPolicy(loc) {}
// Raw value constructors.
BasicPersistent(T* raw, // NOLINT
const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(raw), LocationPolicy(loc) {
if (!IsValid()) return;
SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
.AllocateNode(this, &BasicPersistent::Trace));
this->CheckPointer(Get());
}
BasicPersistent(T& raw, // NOLINT
const SourceLocation& loc = SourceLocation::Current())
: BasicPersistent(&raw, loc) {}
// Copy ctor.
BasicPersistent(const BasicPersistent& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicPersistent(other.Get(), loc) {}
// Heterogeneous ctor.
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicPersistent( // NOLINT
const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicPersistent(other.Get(), loc) {}
// Move ctor. The heterogeneous move ctor is not supported since e.g.
// persistent can't reuse persistent node from weak persistent.
BasicPersistent(
BasicPersistent&& other,
const SourceLocation& loc = SourceLocation::Current()) noexcept
: PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
if (!IsValid()) return;
GetNode()->UpdateOwner(this);
other.SetValue(nullptr);
other.SetNode(nullptr);
this->CheckPointer(Get());
}
// Constructor from member.
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicPersistent(internal::BasicMember<U, MemberBarrierPolicy, // NOLINT
MemberWeaknessTag, MemberCheckingPolicy>
member,
const SourceLocation& loc = SourceLocation::Current())
: BasicPersistent(member.Get(), loc) {}
~BasicPersistent() { Clear(); }
// Copy assignment.
BasicPersistent& operator=(const BasicPersistent& other) {
return operator=(other.Get());
}
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicPersistent& operator=(
const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>& other) {
return operator=(other.Get());
}
// Move assignment.
BasicPersistent& operator=(BasicPersistent&& other) {
if (this == &other) return *this;
Clear();
PersistentBase::operator=(std::move(other));
LocationPolicy::operator=(std::move(other));
if (!IsValid()) return *this;
GetNode()->UpdateOwner(this);
other.SetValue(nullptr);
other.SetNode(nullptr);
this->CheckPointer(Get());
return *this;
}
// Assignment from member.
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicPersistent& operator=(
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy>
member) {
return operator=(member.Get());
}
BasicPersistent& operator=(T* other) {
Assign(other);
return *this;
}
BasicPersistent& operator=(std::nullptr_t) {
Clear();
return *this;
}
BasicPersistent& operator=(SentinelPointer s) {
Assign(s);
return *this;
}
explicit operator bool() const { return Get(); }
operator T*() const { return Get(); } // NOLINT
T* operator->() const { return Get(); }
T& operator*() const { return *Get(); }
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
// The const_cast below removes the constness from PersistentBase storage.
// The following static_cast re-adds any constness if specified through the
// user-visible template parameter T.
return static_cast<T*>(const_cast<void*>(GetValue()));
}
void Clear() {
// Simplified version of `Assign()` to allow calling without a complete type
// `T`.
if (IsValid()) {
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
SetNode(nullptr);
}
SetValue(nullptr);
}
T* Release() {
T* result = Get();
Clear();
return result;
}
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
typename OtherLocationPolicy = LocationPolicy,
typename OtherCheckingPolicy = CheckingPolicy>
BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>
To() const {
return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>(static_cast<U*>(Get()));
}
private:
static void Trace(Visitor* v, const void* ptr) {
const auto* persistent = static_cast<const BasicPersistent*>(ptr);
v->TraceRoot(*persistent, persistent->Location());
}
bool IsValid() const {
// Ideally, handling kSentinelPointer would be done by the embedder. On the
// other hand, having Persistent aware of it is beneficial since no node
// gets wasted.
return GetValue() != nullptr && GetValue() != kSentinelPointer;
}
void Assign(T* ptr) {
if (IsValid()) {
if (ptr && ptr != kSentinelPointer) {
// Simply assign the pointer reusing the existing node.
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
SetNode(nullptr);
}
SetValue(ptr);
if (!IsValid()) return;
SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
.AllocateNode(this, &BasicPersistent::Trace));
this->CheckPointer(Get());
}
void ClearFromGC() const {
if (IsValid()) {
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
PersistentBase::ClearFromGC();
}
}
friend class cppgc::Visitor;
};
template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
typename LocationPolicy2, typename CheckingPolicy2>
bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
CheckingPolicy1>& p1,
const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
CheckingPolicy2>& p2) {
return p1.Get() == p2.Get();
}
template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
typename LocationPolicy2, typename CheckingPolicy2>
bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
CheckingPolicy1>& p1,
const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
CheckingPolicy2>& p2) {
return !(p1 == p2);
}
template <typename T1, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
typename T2, typename MemberWriteBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy>
bool operator==(const BasicPersistent<T1, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p,
BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
MemberCheckingPolicy>
m) {
return p.Get() == m.Get();
}
template <typename T1, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
typename T2, typename MemberWriteBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy>
bool operator!=(const BasicPersistent<T1, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p,
BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
MemberCheckingPolicy>
m) {
return !(p == m);
}
template <typename T1, typename MemberWriteBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename T2, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
bool operator==(BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
MemberCheckingPolicy>
m,
const BasicPersistent<T1, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p) {
return m.Get() == p.Get();
}
template <typename T1, typename MemberWriteBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename T2, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
bool operator!=(BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
MemberCheckingPolicy>
m,
const BasicPersistent<T1, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p) {
return !(m == p);
}
template <typename T, typename LocationPolicy, typename CheckingPolicy>
struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy,
CheckingPolicy>> : std::true_type {};
} // namespace internal
/**
* Persistent is a way to create a strong pointer from an off-heap object to
* another on-heap object. As long as the Persistent handle is alive the GC will
* keep the object pointed to alive. The Persistent handle is always a GC root
* from the point of view of the GC. Persistent must be constructed and
* destructed in the same thread.
*/
template <typename T>
using Persistent =
internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
/**
* WeakPersistent is a way to create a weak pointer from an off-heap object to
* an on-heap object. The pointer is automatically cleared when the pointee gets
* collected. WeakPersistent must be constructed and destructed in the same
* thread.
*/
template <typename T>
using WeakPersistent =
internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
} // namespace cppgc
#endif // INCLUDE_CPPGC_PERSISTENT_H_

View File

@ -1,151 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_PLATFORM_H_
#define INCLUDE_CPPGC_PLATFORM_H_
#include "v8-platform.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
// TODO(v8:10346): Create separate includes for concepts that are not
// V8-specific.
using IdleTask = v8::IdleTask;
using JobHandle = v8::JobHandle;
using JobDelegate = v8::JobDelegate;
using JobTask = v8::JobTask;
using PageAllocator = v8::PageAllocator;
using Task = v8::Task;
using TaskPriority = v8::TaskPriority;
using TaskRunner = v8::TaskRunner;
using TracingController = v8::TracingController;
/**
* Platform interface used by Heap. Contains allocators and executors.
*/
class V8_EXPORT Platform {
public:
virtual ~Platform() = default;
/**
* Returns the allocator used by cppgc to allocate its heap and various
* support structures.
*/
virtual PageAllocator* GetPageAllocator() = 0;
/**
* Monotonically increasing time in seconds from an arbitrary fixed point in
* the past. This function is expected to return at least
* millisecond-precision values. For this reason,
* it is recommended that the fixed point be no further in the past than
* the epoch.
**/
virtual double MonotonicallyIncreasingTime() = 0;
/**
* Foreground task runner that should be used by a Heap.
*/
virtual std::shared_ptr<TaskRunner> GetForegroundTaskRunner() {
return nullptr;
}
/**
* Posts `job_task` to run in parallel. Returns a `JobHandle` associated with
* the `Job`, which can be joined or canceled.
* This avoids degenerate cases:
* - Calling `CallOnWorkerThread()` for each work item, causing significant
* overhead.
* - Fixed number of `CallOnWorkerThread()` calls that split the work and
* might run for a long time. This is problematic when many components post
* "num cores" tasks and all expect to use all the cores. In these cases,
* the scheduler lacks context to be fair to multiple same-priority requests
* and/or ability to request lower priority work to yield when high priority
* work comes in.
* A canonical implementation of `job_task` looks like:
* \code
* class MyJobTask : public JobTask {
* public:
* MyJobTask(...) : worker_queue_(...) {}
* // JobTask implementation.
* void Run(JobDelegate* delegate) override {
* while (!delegate->ShouldYield()) {
* // Smallest unit of work.
* auto work_item = worker_queue_.TakeWorkItem(); // Thread safe.
* if (!work_item) return;
* ProcessWork(work_item);
* }
* }
*
* size_t GetMaxConcurrency() const override {
* return worker_queue_.GetSize(); // Thread safe.
* }
* };
*
* // ...
* auto handle = PostJob(TaskPriority::kUserVisible,
* std::make_unique<MyJobTask>(...));
* handle->Join();
* \endcode
*
* `PostJob()` and methods of the returned JobHandle/JobDelegate, must never
* be called while holding a lock that could be acquired by `JobTask::Run()`
* or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This
* is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding
* internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock
* (B) if that lock is *never* held while calling back into `JobHandle` from
* any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or
* `JobTask::GetMaxConcurrency()` may be invoked synchronously from
* `JobHandle` (B=>JobHandle::foo=>B deadlock).
*
* A sufficient `PostJob()` implementation that uses the default Job provided
* in libplatform looks like:
* \code
* std::unique_ptr<JobHandle> PostJob(
* TaskPriority priority, std::unique_ptr<JobTask> job_task) override {
* return std::make_unique<DefaultJobHandle>(
* std::make_shared<DefaultJobState>(
* this, std::move(job_task), kNumThreads));
* }
* \endcode
*/
virtual std::unique_ptr<JobHandle> PostJob(
TaskPriority priority, std::unique_ptr<JobTask> job_task) {
return nullptr;
}
/**
* Returns an instance of a `TracingController`. This must be non-nullptr. The
* default implementation returns an empty `TracingController` that consumes
* trace data without effect.
*/
virtual TracingController* GetTracingController();
};
/**
* Process-global initialization of the garbage collector. Must be called before
* creating a Heap.
*
* Can be called multiple times when paired with `ShutdownProcess()`.
*
* \param page_allocator The allocator used for maintaining meta data. Must not
* change between multiple calls to InitializeProcess.
*/
V8_EXPORT void InitializeProcess(PageAllocator* page_allocator);
/**
* Must be called after destroying the last used heap. Some process-global
* metadata may not be returned and reused upon a subsequent
* `InitializeProcess()` call.
*/
V8_EXPORT void ShutdownProcess();
namespace internal {
V8_EXPORT void Abort();
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_PLATFORM_H_

View File

@ -1,52 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_PREFINALIZER_H_
#define INCLUDE_CPPGC_PREFINALIZER_H_
#include "cppgc/internal/compiler-specific.h"
#include "cppgc/internal/prefinalizer-handler.h"
#include "cppgc/liveness-broker.h"
namespace cppgc {
namespace internal {
template <typename T>
class PrefinalizerRegistration final {
public:
explicit PrefinalizerRegistration(T* self) {
static_assert(sizeof(&T::InvokePreFinalizer) > 0,
"USING_PRE_FINALIZER(T) must be defined.");
cppgc::internal::PreFinalizerRegistrationDispatcher::RegisterPrefinalizer(
{self, T::InvokePreFinalizer});
}
void* operator new(size_t, void* location) = delete;
void* operator new(size_t) = delete;
};
} // namespace internal
#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \
public: \
static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \
void* object) { \
static_assert(cppgc::IsGarbageCollectedOrMixinTypeV<Class>, \
"Only garbage collected objects can have prefinalizers"); \
Class* self = static_cast<Class*>(object); \
if (liveness_broker.IsHeapObjectAlive(self)) return false; \
self->Class::PreFinalizer(); \
return true; \
} \
\
private: \
CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration<Class> \
prefinalizer_dummy_{this}; \
static_assert(true, "Force semicolon.")
} // namespace cppgc
#endif // INCLUDE_CPPGC_PREFINALIZER_H_

View File

@ -1,36 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
#define INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_
#include <atomic>
#include <cstddef>
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
namespace internal {
class ProcessHeapStatisticsUpdater;
} // namespace internal
class V8_EXPORT ProcessHeapStatistics final {
public:
static size_t TotalAllocatedObjectSize() {
return total_allocated_object_size_.load(std::memory_order_relaxed);
}
static size_t TotalAllocatedSpace() {
return total_allocated_space_.load(std::memory_order_relaxed);
}
private:
static std::atomic_size_t total_allocated_space_;
static std::atomic_size_t total_allocated_object_size_;
friend class internal::ProcessHeapStatisticsUpdater;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_

View File

@ -1,32 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_SENTINEL_POINTER_H_
#define INCLUDE_CPPGC_SENTINEL_POINTER_H_
#include <cstdint>
namespace cppgc {
namespace internal {
// Special tag type used to denote some sentinel member. The semantics of the
// sentinel is defined by the embedder.
struct SentinelPointer {
template <typename T>
operator T*() const { // NOLINT
static constexpr intptr_t kSentinelValue = 1;
return reinterpret_cast<T*>(kSentinelValue);
}
// Hidden friends.
friend bool operator==(SentinelPointer, SentinelPointer) { return true; }
friend bool operator!=(SentinelPointer, SentinelPointer) { return false; }
};
} // namespace internal
constexpr internal::SentinelPointer kSentinelPointer;
} // namespace cppgc
#endif // INCLUDE_CPPGC_SENTINEL_POINTER_H_

View File

@ -1,91 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_SOURCE_LOCATION_H_
#define INCLUDE_CPPGC_SOURCE_LOCATION_H_
#include <string>
#include "v8config.h" // NOLINT(build/include_directory)
#if defined(__has_builtin)
#define CPPGC_SUPPORTS_SOURCE_LOCATION \
(__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \
__has_builtin(__builtin_LINE)) // NOLINT
#elif defined(V8_CC_GNU) && __GNUC__ >= 7
#define CPPGC_SUPPORTS_SOURCE_LOCATION 1
#elif defined(V8_CC_INTEL) && __ICC >= 1800
#define CPPGC_SUPPORTS_SOURCE_LOCATION 1
#else
#define CPPGC_SUPPORTS_SOURCE_LOCATION 0
#endif
namespace cppgc {
/**
* Encapsulates source location information. Mimics C++20's
* `std::source_location`.
*/
class V8_EXPORT SourceLocation final {
public:
/**
* Construct source location information corresponding to the location of the
* call site.
*/
#if CPPGC_SUPPORTS_SOURCE_LOCATION
static constexpr SourceLocation Current(
const char* function = __builtin_FUNCTION(),
const char* file = __builtin_FILE(), size_t line = __builtin_LINE()) {
return SourceLocation(function, file, line);
}
#else
static constexpr SourceLocation Current() { return SourceLocation(); }
#endif // CPPGC_SUPPORTS_SOURCE_LOCATION
/**
* Constructs unspecified source location information.
*/
constexpr SourceLocation() = default;
/**
* Returns the name of the function associated with the position represented
* by this object, if any.
*
* \returns the function name as cstring.
*/
constexpr const char* Function() const { return function_; }
/**
* Returns the name of the current source file represented by this object.
*
* \returns the file name as cstring.
*/
constexpr const char* FileName() const { return file_; }
/**
* Returns the line number represented by this object.
*
* \returns the line number.
*/
constexpr size_t Line() const { return line_; }
/**
* Returns a human-readable string representing this object.
*
* \returns a human-readable string representing source location information.
*/
std::string ToString() const;
private:
constexpr SourceLocation(const char* function, const char* file, size_t line)
: function_(function), file_(file), line_(line) {}
const char* function_ = nullptr;
const char* file_ = nullptr;
size_t line_ = 0u;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_SOURCE_LOCATION_H_

View File

@ -1,99 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_TESTING_H_
#define INCLUDE_CPPGC_TESTING_H_
#include "cppgc/common.h"
#include "cppgc/macros.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class HeapHandle;
/**
* Namespace contains testing helpers.
*/
namespace testing {
/**
* Overrides the state of the stack with the provided value. Takes precedence
* over other parameters that set the stack state. Must no be nested.
*/
class V8_EXPORT V8_NODISCARD OverrideEmbedderStackStateScope final {
CPPGC_STACK_ALLOCATED();
public:
/**
* Constructs a scoped object that automatically enters and leaves the scope.
*
* \param heap_handle The corresponding heap.
*/
explicit OverrideEmbedderStackStateScope(HeapHandle& heap_handle,
EmbedderStackState state);
~OverrideEmbedderStackStateScope();
OverrideEmbedderStackStateScope(const OverrideEmbedderStackStateScope&) =
delete;
OverrideEmbedderStackStateScope& operator=(
const OverrideEmbedderStackStateScope&) = delete;
private:
HeapHandle& heap_handle_;
};
/**
* Testing interface for managed heaps that allows for controlling garbage
* collection timings. Embedders should use this class when testing the
* interaction of their code with incremental/concurrent garbage collection.
*/
class V8_EXPORT StandaloneTestingHeap final {
public:
explicit StandaloneTestingHeap(HeapHandle&);
/**
* Start an incremental garbage collection.
*/
void StartGarbageCollection();
/**
* Perform an incremental step. This will also schedule concurrent steps if
* needed.
*
* \param stack_state The state of the stack during the step.
*/
bool PerformMarkingStep(EmbedderStackState stack_state);
/**
* Finalize the current garbage collection cycle atomically.
* Assumes that garbage collection is in progress.
*
* \param stack_state The state of the stack for finalizing the garbage
* collection cycle.
*/
void FinalizeGarbageCollection(EmbedderStackState stack_state);
/**
* Toggle main thread marking on/off. Allows to stress concurrent marking
* (e.g. to better detect data races).
*
* \param should_mark Denotes whether the main thread should contribute to
* marking. Defaults to true.
*/
void ToggleMainThreadMarking(bool should_mark);
/**
* Force enable compaction for the next garbage collection cycle.
*/
void ForceCompactionForNextGarbageCollection();
private:
HeapHandle& heap_handle_;
};
} // namespace testing
} // namespace cppgc
#endif // INCLUDE_CPPGC_TESTING_H_

View File

@ -1,116 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_TRACE_TRAIT_H_
#define INCLUDE_CPPGC_TRACE_TRAIT_H_
#include <type_traits>
#include "cppgc/type-traits.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
class Visitor;
namespace internal {
// Implementation of the default TraceTrait handling GarbageCollected and
// GarbageCollectedMixin.
template <typename T,
bool =
IsGarbageCollectedMixinTypeV<typename std::remove_const<T>::type>>
struct TraceTraitImpl;
} // namespace internal
/**
* Callback for invoking tracing on a given object.
*
* \param visitor The visitor to dispatch to.
* \param object The object to invoke tracing on.
*/
using TraceCallback = void (*)(Visitor* visitor, const void* object);
/**
* Describes how to trace an object, i.e., how to visit all Oilpan-relevant
* fields of an object.
*/
struct TraceDescriptor {
/**
* Adjusted base pointer, i.e., the pointer to the class inheriting directly
* from GarbageCollected, of the object that is being traced.
*/
const void* base_object_payload;
/**
* Callback for tracing the object.
*/
TraceCallback callback;
};
namespace internal {
struct V8_EXPORT TraceTraitFromInnerAddressImpl {
static TraceDescriptor GetTraceDescriptor(const void* address);
};
/**
* Trait specifying how the garbage collector processes an object of type T.
*
* Advanced users may override handling by creating a specialization for their
* type.
*/
template <typename T>
struct TraceTraitBase {
static_assert(internal::IsTraceableV<T>, "T must have a Trace() method");
/**
* Accessor for retrieving a TraceDescriptor to process an object of type T.
*
* \param self The object to be processed.
* \returns a TraceDescriptor to process the object.
*/
static TraceDescriptor GetTraceDescriptor(const void* self) {
return internal::TraceTraitImpl<T>::GetTraceDescriptor(
static_cast<const T*>(self));
}
/**
* Function invoking the tracing for an object of type T.
*
* \param visitor The visitor to dispatch to.
* \param self The object to invoke tracing on.
*/
static void Trace(Visitor* visitor, const void* self) {
static_cast<const T*>(self)->Trace(visitor);
}
};
} // namespace internal
template <typename T>
struct TraceTrait : public internal::TraceTraitBase<T> {};
namespace internal {
template <typename T>
struct TraceTraitImpl<T, false> {
static_assert(IsGarbageCollectedTypeV<T>,
"T must be of type GarbageCollected or GarbageCollectedMixin");
static TraceDescriptor GetTraceDescriptor(const void* self) {
return {self, TraceTrait<T>::Trace};
}
};
template <typename T>
struct TraceTraitImpl<T, true> {
static TraceDescriptor GetTraceDescriptor(const void* self) {
return internal::TraceTraitFromInnerAddressImpl::GetTraceDescriptor(self);
}
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_TRACE_TRAIT_H_

View File

@ -1,228 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_TYPE_TRAITS_H_
#define INCLUDE_CPPGC_TYPE_TRAITS_H_
// This file should stay with minimal dependencies to allow embedder to check
// against Oilpan types without including any other parts.
#include <type_traits>
namespace cppgc {
class Visitor;
namespace internal {
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy>
class BasicMember;
struct DijkstraWriteBarrierPolicy;
struct NoWriteBarrierPolicy;
class StrongMemberTag;
class UntracedMemberTag;
class WeakMemberTag;
// Pre-C++17 custom implementation of std::void_t.
template <typename... Ts>
struct make_void {
typedef void type;
};
template <typename... Ts>
using void_t = typename make_void<Ts...>::type;
// Not supposed to be specialized by the user.
template <typename T>
struct IsWeak : std::false_type {};
// IsTraceMethodConst is used to verify that all Trace methods are marked as
// const. It is equivalent to IsTraceable but for a non-const object.
template <typename T, typename = void>
struct IsTraceMethodConst : std::false_type {};
template <typename T>
struct IsTraceMethodConst<T, void_t<decltype(std::declval<const T>().Trace(
std::declval<Visitor*>()))>> : std::true_type {
};
template <typename T, typename = void>
struct IsTraceable : std::false_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct IsTraceable<
T, void_t<decltype(std::declval<T>().Trace(std::declval<Visitor*>()))>>
: std::true_type {
// All Trace methods should be marked as const. If an object of type
// 'T' is traceable then any object of type 'const T' should also
// be traceable.
static_assert(IsTraceMethodConst<T>(),
"Trace methods should be marked as const.");
};
template <typename T>
constexpr bool IsTraceableV = IsTraceable<T>::value;
template <typename T, typename = void>
struct HasGarbageCollectedMixinTypeMarker : std::false_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct HasGarbageCollectedMixinTypeMarker<
T,
void_t<typename std::remove_const_t<T>::IsGarbageCollectedMixinTypeMarker>>
: std::true_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T, typename = void>
struct HasGarbageCollectedTypeMarker : std::false_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct HasGarbageCollectedTypeMarker<
T, void_t<typename std::remove_const_t<T>::IsGarbageCollectedTypeMarker>>
: std::true_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T, bool = HasGarbageCollectedTypeMarker<T>::value,
bool = HasGarbageCollectedMixinTypeMarker<T>::value>
struct IsGarbageCollectedMixinType : std::false_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct IsGarbageCollectedMixinType<T, false, true> : std::true_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T, bool = HasGarbageCollectedTypeMarker<T>::value>
struct IsGarbageCollectedType : std::false_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct IsGarbageCollectedType<T, true> : std::true_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct IsGarbageCollectedOrMixinType
: std::integral_constant<bool, IsGarbageCollectedType<T>::value ||
IsGarbageCollectedMixinType<T>::value> {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T, bool = (HasGarbageCollectedTypeMarker<T>::value &&
HasGarbageCollectedMixinTypeMarker<T>::value)>
struct IsGarbageCollectedWithMixinType : std::false_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename T>
struct IsGarbageCollectedWithMixinType<T, true> : std::true_type {
static_assert(sizeof(T), "T must be fully defined");
};
template <typename BasicMemberCandidate, typename WeaknessTag,
typename WriteBarrierPolicy>
struct IsSubclassOfBasicMemberTemplate {
private:
template <typename T, typename CheckingPolicy>
static std::true_type SubclassCheck(
BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy>*);
static std::false_type SubclassCheck(...);
public:
static constexpr bool value =
decltype(SubclassCheck(std::declval<BasicMemberCandidate*>()))::value;
};
template <typename T,
bool = IsSubclassOfBasicMemberTemplate<
T, StrongMemberTag, DijkstraWriteBarrierPolicy>::value>
struct IsMemberType : std::false_type {};
template <typename T>
struct IsMemberType<T, true> : std::true_type {};
template <typename T, bool = IsSubclassOfBasicMemberTemplate<
T, WeakMemberTag, DijkstraWriteBarrierPolicy>::value>
struct IsWeakMemberType : std::false_type {};
template <typename T>
struct IsWeakMemberType<T, true> : std::true_type {};
template <typename T, bool = IsSubclassOfBasicMemberTemplate<
T, UntracedMemberTag, NoWriteBarrierPolicy>::value>
struct IsUntracedMemberType : std::false_type {};
template <typename T>
struct IsUntracedMemberType<T, true> : std::true_type {};
} // namespace internal
/**
* Value is true for types that inherit from `GarbageCollectedMixin` but not
* `GarbageCollected<T>` (i.e., they are free mixins), and false otherwise.
*/
template <typename T>
constexpr bool IsGarbageCollectedMixinTypeV =
internal::IsGarbageCollectedMixinType<T>::value;
/**
* Value is true for types that inherit from `GarbageCollected<T>`, and false
* otherwise.
*/
template <typename T>
constexpr bool IsGarbageCollectedTypeV =
internal::IsGarbageCollectedType<T>::value;
/**
* Value is true for types that inherit from either `GarbageCollected<T>` or
* `GarbageCollectedMixin`, and false otherwise.
*/
template <typename T>
constexpr bool IsGarbageCollectedOrMixinTypeV =
internal::IsGarbageCollectedOrMixinType<T>::value;
/**
* Value is true for types that inherit from `GarbageCollected<T>` and
* `GarbageCollectedMixin`, and false otherwise.
*/
template <typename T>
constexpr bool IsGarbageCollectedWithMixinTypeV =
internal::IsGarbageCollectedWithMixinType<T>::value;
/**
* Value is true for types of type `Member<T>`, and false otherwise.
*/
template <typename T>
constexpr bool IsMemberTypeV = internal::IsMemberType<T>::value;
/**
* Value is true for types of type `UntracedMember<T>`, and false otherwise.
*/
template <typename T>
constexpr bool IsUntracedMemberTypeV = internal::IsUntracedMemberType<T>::value;
/**
* Value is true for types of type `WeakMember<T>`, and false otherwise.
*/
template <typename T>
constexpr bool IsWeakMemberTypeV = internal::IsWeakMemberType<T>::value;
/**
* Value is true for types that are considered weak references, and false
* otherwise.
*/
template <typename T>
constexpr bool IsWeakV = internal::IsWeak<T>::value;
} // namespace cppgc
#endif // INCLUDE_CPPGC_TYPE_TRAITS_H_

View File

@ -1,377 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_VISITOR_H_
#define INCLUDE_CPPGC_VISITOR_H_
#include "cppgc/custom-space.h"
#include "cppgc/ephemeron-pair.h"
#include "cppgc/garbage-collected.h"
#include "cppgc/internal/logging.h"
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/liveness-broker.h"
#include "cppgc/member.h"
#include "cppgc/source-location.h"
#include "cppgc/trace-trait.h"
#include "cppgc/type-traits.h"
namespace cppgc {
namespace internal {
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
class BasicCrossThreadPersistent;
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
class BasicPersistent;
class ConservativeTracingVisitor;
class VisitorBase;
class VisitorFactory;
} // namespace internal
using WeakCallback = void (*)(const LivenessBroker&, const void*);
/**
* Visitor passed to trace methods. All managed pointers must have called the
* Visitor's trace method on them.
*
* \code
* class Foo final : public GarbageCollected<Foo> {
* public:
* void Trace(Visitor* visitor) const {
* visitor->Trace(foo_);
* visitor->Trace(weak_foo_);
* }
* private:
* Member<Foo> foo_;
* WeakMember<Foo> weak_foo_;
* };
* \endcode
*/
class V8_EXPORT Visitor {
public:
class Key {
private:
Key() = default;
friend class internal::VisitorFactory;
};
explicit Visitor(Key) {}
virtual ~Visitor() = default;
/**
* Trace method for raw pointers. Prefer the versions for managed pointers.
*
* \param member Reference retaining an object.
*/
template <typename T>
void Trace(const T* t) {
static_assert(sizeof(T), "Pointee type must be fully defined.");
static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
"T must be GarbageCollected or GarbageCollectedMixin type");
if (!t) {
return;
}
Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
}
/**
* Trace method for Member.
*
* \param member Member reference retaining an object.
*/
template <typename T>
void Trace(const Member<T>& member) {
const T* value = member.GetRawAtomic();
CPPGC_DCHECK(value != kSentinelPointer);
Trace(value);
}
/**
* Trace method for WeakMember.
*
* \param weak_member WeakMember reference weakly retaining an object.
*/
template <typename T>
void Trace(const WeakMember<T>& weak_member) {
static_assert(sizeof(T), "Pointee type must be fully defined.");
static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
"T must be GarbageCollected or GarbageCollectedMixin type");
static_assert(!internal::IsAllocatedOnCompactableSpace<T>::value,
"Weak references to compactable objects are not allowed");
const T* value = weak_member.GetRawAtomic();
// Bailout assumes that WeakMember emits write barrier.
if (!value) {
return;
}
CPPGC_DCHECK(value != kSentinelPointer);
VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
&HandleWeak<WeakMember<T>>, &weak_member);
}
/**
* Trace method for inlined objects that are not allocated themselves but
* otherwise follow managed heap layout and have a Trace() method.
*
* \param object reference of the inlined object.
*/
template <typename T>
void Trace(const T& object) {
#if V8_ENABLE_CHECKS
// This object is embedded in potentially multiple nested objects. The
// outermost object must not be in construction as such objects are (a) not
// processed immediately, and (b) only processed conservatively if not
// otherwise possible.
CheckObjectNotInConstruction(&object);
#endif // V8_ENABLE_CHECKS
TraceTrait<T>::Trace(this, &object);
}
/**
* Registers a weak callback method on the object of type T. See
* LivenessBroker for an usage example.
*
* \param object of type T specifying a weak callback method.
*/
template <typename T, void (T::*method)(const LivenessBroker&)>
void RegisterWeakCallbackMethod(const T* object) {
RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
}
/**
* Trace method for EphemeronPair.
*
* \param ephemeron_pair EphemeronPair reference weakly retaining a key object
* and strongly retaining a value object in case the key object is alive.
*/
template <typename K, typename V>
void Trace(const EphemeronPair<K, V>& ephemeron_pair) {
TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value);
RegisterWeakCallbackMethod<EphemeronPair<K, V>,
&EphemeronPair<K, V>::ClearValueIfKeyIsDead>(
&ephemeron_pair);
}
/**
* Trace method for a single ephemeron. Used for tracing a raw ephemeron in
* which the `key` and `value` are kept separately.
*
* \param weak_member_key WeakMember reference weakly retaining a key object.
* \param member_value Member reference with ephemeron semantics.
*/
template <typename KeyType, typename ValueType>
void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
const Member<ValueType>* member_value) {
const KeyType* key = weak_member_key.GetRawAtomic();
if (!key) return;
// `value` must always be non-null.
CPPGC_DCHECK(member_value);
const ValueType* value = member_value->GetRawAtomic();
if (!value) return;
// KeyType and ValueType may refer to GarbageCollectedMixin.
TraceDescriptor value_desc =
TraceTrait<ValueType>::GetTraceDescriptor(value);
CPPGC_DCHECK(value_desc.base_object_payload);
const void* key_base_object_payload =
TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
CPPGC_DCHECK(key_base_object_payload);
VisitEphemeron(key_base_object_payload, value, value_desc);
}
/**
* Trace method for a single ephemeron. Used for tracing a raw ephemeron in
* which the `key` and `value` are kept separately. Note that this overload
* is for non-GarbageCollected `value`s that can be traced though.
*
* \param key `WeakMember` reference weakly retaining a key object.
* \param value Reference weakly retaining a value object. Note that
* `ValueType` here should not be `Member`. It is expected that
* `TraceTrait<ValueType>::GetTraceDescriptor(value)` returns a
* `TraceDescriptor` with a null base pointer but a valid trace method.
*/
template <typename KeyType, typename ValueType>
void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
const ValueType* value) {
static_assert(!IsGarbageCollectedOrMixinTypeV<ValueType>,
"garbage-collected types must use WeakMember and Member");
const KeyType* key = weak_member_key.GetRawAtomic();
if (!key) return;
// `value` must always be non-null.
CPPGC_DCHECK(value);
TraceDescriptor value_desc =
TraceTrait<ValueType>::GetTraceDescriptor(value);
// `value_desc.base_object_payload` must be null as this override is only
// taken for non-garbage-collected values.
CPPGC_DCHECK(!value_desc.base_object_payload);
// KeyType might be a GarbageCollectedMixin.
const void* key_base_object_payload =
TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
CPPGC_DCHECK(key_base_object_payload);
VisitEphemeron(key_base_object_payload, value, value_desc);
}
/**
* Trace method that strongifies a WeakMember.
*
* \param weak_member WeakMember reference retaining an object.
*/
template <typename T>
void TraceStrongly(const WeakMember<T>& weak_member) {
const T* value = weak_member.GetRawAtomic();
CPPGC_DCHECK(value != kSentinelPointer);
Trace(value);
}
/**
* Trace method for weak containers.
*
* \param object reference of the weak container.
* \param callback to be invoked.
* \param data custom data that is passed to the callback.
*/
template <typename T>
void TraceWeakContainer(const T* object, WeakCallback callback,
const void* data) {
if (!object) return;
VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object),
TraceTrait<T>::GetWeakTraceDescriptor(object), callback,
data);
}
/**
* Registers a slot containing a reference to an object allocated on a
* compactable space. Such references maybe be arbitrarily moved by the GC.
*
* \param slot location of reference to object that might be moved by the GC.
*/
template <typename T>
void RegisterMovableReference(const T** slot) {
static_assert(internal::IsAllocatedOnCompactableSpace<T>::value,
"Only references to objects allocated on compactable spaces "
"should be registered as movable slots.");
static_assert(!IsGarbageCollectedMixinTypeV<T>,
"Mixin types do not support compaction.");
HandleMovableReference(reinterpret_cast<const void**>(slot));
}
/**
* Registers a weak callback that is invoked during garbage collection.
*
* \param callback to be invoked.
* \param data custom data that is passed to the callback.
*/
virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
/**
* Defers tracing an object from a concurrent thread to the mutator thread.
* Should be called by Trace methods of types that are not safe to trace
* concurrently.
*
* \param parameter tells the trace callback which object was deferred.
* \param callback to be invoked for tracing on the mutator thread.
* \param deferred_size size of deferred object.
*
* \returns false if the object does not need to be deferred (i.e. currently
* traced on the mutator thread) and true otherwise (i.e. currently traced on
* a concurrent thread).
*/
virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent(
const void* parameter, TraceCallback callback, size_t deferred_size) {
// By default tracing is not deferred.
return false;
}
protected:
virtual void Visit(const void* self, TraceDescriptor) {}
virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
const void* weak_member) {}
virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {}
virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
const void* weak_root, const SourceLocation&) {}
virtual void VisitEphemeron(const void* key, const void* value,
TraceDescriptor value_desc) {}
virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc,
TraceDescriptor weak_desc,
WeakCallback callback, const void* data) {}
virtual void HandleMovableReference(const void**) {}
private:
template <typename T, void (T::*method)(const LivenessBroker&)>
static void WeakCallbackMethodDelegate(const LivenessBroker& info,
const void* self) {
// Callback is registered through a potential const Trace method but needs
// to be able to modify fields. See HandleWeak.
(const_cast<T*>(static_cast<const T*>(self))->*method)(info);
}
template <typename PointerType>
static void HandleWeak(const LivenessBroker& info, const void* object) {
const PointerType* weak = static_cast<const PointerType*>(object);
// Sentinel values are preserved for weak pointers.
if (*weak == kSentinelPointer) return;
const auto* raw = weak->Get();
if (!info.IsHeapObjectAlive(raw)) {
weak->ClearFromGC();
}
}
template <typename Persistent,
std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr>
void TraceRoot(const Persistent& p, const SourceLocation& loc) {
using PointeeType = typename Persistent::PointeeType;
static_assert(sizeof(PointeeType),
"Persistent's pointee type must be fully defined");
static_assert(internal::IsGarbageCollectedOrMixinType<PointeeType>::value,
"Persistent's pointee type must be GarbageCollected or "
"GarbageCollectedMixin");
if (!p.Get()) {
return;
}
VisitRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()),
loc);
}
template <
typename WeakPersistent,
std::enable_if_t<!WeakPersistent::IsStrongPersistent::value>* = nullptr>
void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) {
using PointeeType = typename WeakPersistent::PointeeType;
static_assert(sizeof(PointeeType),
"Persistent's pointee type must be fully defined");
static_assert(internal::IsGarbageCollectedOrMixinType<PointeeType>::value,
"Persistent's pointee type must be GarbageCollected or "
"GarbageCollectedMixin");
static_assert(!internal::IsAllocatedOnCompactableSpace<PointeeType>::value,
"Weak references to compactable objects are not allowed");
VisitWeakRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()),
&HandleWeak<WeakPersistent>, &p, loc);
}
#if V8_ENABLE_CHECKS
void CheckObjectNotInConstruction(const void* address);
#endif // V8_ENABLE_CHECKS
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
friend class internal::BasicCrossThreadPersistent;
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
friend class internal::BasicPersistent;
friend class internal::ConservativeTracingVisitor;
friend class internal::VisitorBase;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_VISITOR_H_

View File

@ -1,997 +0,0 @@
{
"version": { "major": "1", "minor": "2" },
"domains": [
{
"domain": "Schema",
"description": "Provides information about the protocol schema.",
"types": [
{
"id": "Domain",
"type": "object",
"description": "Description of the protocol domain.",
"exported": true,
"properties": [
{ "name": "name", "type": "string", "description": "Domain name." },
{ "name": "version", "type": "string", "description": "Domain version." }
]
}
],
"commands": [
{
"name": "getDomains",
"description": "Returns supported domains.",
"handlers": ["browser", "renderer"],
"returns": [
{ "name": "domains", "type": "array", "items": { "$ref": "Domain" }, "description": "List of supported domains." }
]
}
]
},
{
"domain": "Runtime",
"description": "Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. Evaluation results are returned as mirror object that expose object type, string representation and unique identifier that can be used for further object reference. Original objects are maintained in memory unless they are either explicitly released or are released along with the other objects in their object group.",
"types": [
{
"id": "ScriptId",
"type": "string",
"description": "Unique script identifier."
},
{
"id": "RemoteObjectId",
"type": "string",
"description": "Unique object identifier."
},
{
"id": "UnserializableValue",
"type": "string",
"enum": ["Infinity", "NaN", "-Infinity", "-0"],
"description": "Primitive value which cannot be JSON-stringified."
},
{
"id": "RemoteObject",
"type": "object",
"description": "Mirror object referencing original JavaScript object.",
"exported": true,
"properties": [
{ "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." },
{ "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
{ "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for <code>object</code> type values only." },
{ "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." },
{ "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified does not have <code>value</code>, but gets this property." },
{ "name": "description", "type": "string", "optional": true, "description": "String representation of the object." },
{ "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." },
{ "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for <code>object</code> type values only.", "experimental": true },
{ "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true}
]
},
{
"id": "CustomPreview",
"type": "object",
"experimental": true,
"properties": [
{ "name": "header", "type": "string"},
{ "name": "hasBody", "type": "boolean"},
{ "name": "formatterObjectId", "$ref": "RemoteObjectId"},
{ "name": "bindRemoteObjectFunctionId", "$ref": "RemoteObjectId" },
{ "name": "configObjectId", "$ref": "RemoteObjectId", "optional": true }
]
},
{
"id": "ObjectPreview",
"type": "object",
"experimental": true,
"description": "Object containing abbreviated remote object value.",
"properties": [
{ "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." },
{ "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
{ "name": "description", "type": "string", "optional": true, "description": "String representation of the object." },
{ "name": "overflow", "type": "boolean", "description": "True iff some of the properties or entries of the original object did not fit." },
{ "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "description": "List of the properties." },
{ "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for <code>map</code> and <code>set</code> subtype values only." }
]
},
{
"id": "PropertyPreview",
"type": "object",
"experimental": true,
"properties": [
{ "name": "name", "type": "string", "description": "Property name." },
{ "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." },
{ "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." },
{ "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." },
{ "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }
]
},
{
"id": "EntryPreview",
"type": "object",
"experimental": true,
"properties": [
{ "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." },
{ "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." }
]
},
{
"id": "PropertyDescriptor",
"type": "object",
"description": "Object property descriptor.",
"properties": [
{ "name": "name", "type": "string", "description": "Property name or symbol description." },
{ "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." },
{ "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." },
{ "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or <code>undefined</code> if there is no getter (accessor descriptors only)." },
{ "name": "set", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a setter for the property, or <code>undefined</code> if there is no setter (accessor descriptors only)." },
{ "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." },
{ "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." },
{ "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." },
{ "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." },
{ "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the <code>symbol</code> type." }
]
},
{
"id": "InternalPropertyDescriptor",
"type": "object",
"description": "Object internal property descriptor. This property isn't normally visible in JavaScript code.",
"properties": [
{ "name": "name", "type": "string", "description": "Conventional property name." },
{ "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." }
]
},
{
"id": "CallArgument",
"type": "object",
"description": "Represents function call argument. Either remote object id <code>objectId</code>, primitive <code>value</code>, unserializable primitive value or neither of (for undefined) them should be specified.",
"properties": [
{ "name": "value", "type": "any", "optional": true, "description": "Primitive value." },
{ "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified." },
{ "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." }
]
},
{
"id": "ExecutionContextId",
"type": "integer",
"description": "Id of an execution context."
},
{
"id": "ExecutionContextDescription",
"type": "object",
"description": "Description of an isolated world.",
"properties": [
{ "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." },
{ "name": "origin", "type": "string", "description": "Execution context origin." },
{ "name": "name", "type": "string", "description": "Human readable name describing given context." },
{ "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }
]
},
{
"id": "ExceptionDetails",
"type": "object",
"description": "Detailed information about exception (or error) that was thrown during script compilation or execution.",
"properties": [
{ "name": "exceptionId", "type": "integer", "description": "Exception id." },
{ "name": "text", "type": "string", "description": "Exception text, which should be used together with exception object when available." },
{ "name": "lineNumber", "type": "integer", "description": "Line number of the exception location (0-based)." },
{ "name": "columnNumber", "type": "integer", "description": "Column number of the exception location (0-based)." },
{ "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Script ID of the exception location." },
{ "name": "url", "type": "string", "optional": true, "description": "URL of the exception location, to be used when the script was not reported." },
{ "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace if available." },
{ "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object if available." },
{ "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." }
]
},
{
"id": "Timestamp",
"type": "number",
"description": "Number of milliseconds since epoch."
},
{
"id": "CallFrame",
"type": "object",
"description": "Stack entry for runtime errors and assertions.",
"properties": [
{ "name": "functionName", "type": "string", "description": "JavaScript function name." },
{ "name": "scriptId", "$ref": "ScriptId", "description": "JavaScript script id." },
{ "name": "url", "type": "string", "description": "JavaScript script name or url." },
{ "name": "lineNumber", "type": "integer", "description": "JavaScript script line number (0-based)." },
{ "name": "columnNumber", "type": "integer", "description": "JavaScript script column number (0-based)." }
]
},
{
"id": "StackTrace",
"type": "object",
"description": "Call frames for assertions or error messages.",
"exported": true,
"properties": [
{ "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." },
{ "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." },
{ "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." }
]
}
],
"commands": [
{
"name": "evaluate",
"async": true,
"parameters": [
{ "name": "expression", "type": "string", "description": "Expression to evaluate." },
{ "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." },
{ "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." },
{ "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides <code>setPauseOnException</code> state." },
{ "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." },
{ "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." },
{ "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." },
{ "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." },
{ "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." }
],
"returns": [
{ "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."}
],
"description": "Evaluates expression on global object."
},
{
"name": "awaitPromise",
"async": true,
"parameters": [
{ "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." },
{ "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." },
{ "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }
],
"returns": [
{ "name": "result", "$ref": "RemoteObject", "description": "Promise result. Will contain rejected value if promise was rejected." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details if stack strace is available."}
],
"description": "Add handler to promise with given promise object id."
},
{
"name": "callFunctionOn",
"async": true,
"parameters": [
{ "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to call function on." },
{ "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." },
{ "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." },
{ "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides <code>setPauseOnException</code> state." },
{ "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." },
{ "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." },
{ "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." },
{ "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." }
],
"returns": [
{ "name": "result", "$ref": "RemoteObject", "description": "Call result." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."}
],
"description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object."
},
{
"name": "getProperties",
"parameters": [
{ "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." },
{ "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." },
{ "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true },
{ "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." }
],
"returns": [
{ "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." },
{ "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself)." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."}
],
"description": "Returns properties of a given object. Object group of the result is inherited from the target object."
},
{
"name": "releaseObject",
"parameters": [
{ "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to release." }
],
"description": "Releases remote object with given id."
},
{
"name": "releaseObjectGroup",
"parameters": [
{ "name": "objectGroup", "type": "string", "description": "Symbolic object group name." }
],
"description": "Releases all remote objects that belong to a given group."
},
{
"name": "runIfWaitingForDebugger",
"description": "Tells inspected instance to run if it was waiting for debugger to attach."
},
{
"name": "enable",
"description": "Enables reporting of execution contexts creation by means of <code>executionContextCreated</code> event. When the reporting gets enabled the event will be sent immediately for each existing execution context."
},
{
"name": "disable",
"description": "Disables reporting of execution contexts creation."
},
{
"name": "discardConsoleEntries",
"description": "Discards collected exceptions and console API calls."
},
{
"name": "setCustomObjectFormatterEnabled",
"parameters": [
{
"name": "enabled",
"type": "boolean"
}
],
"experimental": true
},
{
"name": "compileScript",
"parameters": [
{ "name": "expression", "type": "string", "description": "Expression to compile." },
{ "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." },
{ "name": "persistScript", "type": "boolean", "description": "Specifies whether the compiled script should be persisted." },
{ "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }
],
"returns": [
{ "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Id of the script." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."}
],
"description": "Compiles expression."
},
{
"name": "runScript",
"async": true,
"parameters": [
{ "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." },
{ "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." },
{ "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." },
{ "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides <code>setPauseOnException</code> state." },
{ "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." },
{ "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." },
{ "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." },
{ "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." }
],
"returns": [
{ "name": "result", "$ref": "RemoteObject", "description": "Run result." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."}
],
"description": "Runs script with given id in a given context."
}
],
"events": [
{
"name": "executionContextCreated",
"parameters": [
{ "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution contex." }
],
"description": "Issued when new execution context is created."
},
{
"name": "executionContextDestroyed",
"parameters": [
{ "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Id of the destroyed context" }
],
"description": "Issued when execution context is destroyed."
},
{
"name": "executionContextsCleared",
"description": "Issued when all executionContexts were cleared in browser"
},
{
"name": "exceptionThrown",
"description": "Issued when exception was thrown and unhandled.",
"parameters": [
{ "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp of the exception." },
{ "name": "exceptionDetails", "$ref": "ExceptionDetails" }
]
},
{
"name": "exceptionRevoked",
"description": "Issued when unhandled exception was revoked.",
"parameters": [
{ "name": "reason", "type": "string", "description": "Reason describing why exception was revoked." },
{ "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in <code>exceptionUnhandled</code>." }
]
},
{
"name": "consoleAPICalled",
"description": "Issued when console API was called.",
"parameters": [
{ "name": "type", "type": "string", "enum": ["log", "debug", "info", "error", "warning", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "profile", "profileEnd"], "description": "Type of the call." },
{ "name": "args", "type": "array", "items": { "$ref": "RemoteObject" }, "description": "Call arguments." },
{ "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Identifier of the context where the call was made." },
{ "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." },
{ "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." }
]
},
{
"name": "inspectRequested",
"description": "Issued when object should be inspected (for example, as a result of inspect() command line API call).",
"parameters": [
{ "name": "object", "$ref": "RemoteObject" },
{ "name": "hints", "type": "object" }
]
}
]
},
{
"domain": "Debugger",
"description": "Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing breakpoints, stepping through execution, exploring stack traces, etc.",
"dependencies": ["Runtime"],
"types": [
{
"id": "BreakpointId",
"type": "string",
"description": "Breakpoint identifier."
},
{
"id": "CallFrameId",
"type": "string",
"description": "Call frame identifier."
},
{
"id": "Location",
"type": "object",
"properties": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the <code>Debugger.scriptParsed</code>." },
{ "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." },
{ "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." }
],
"description": "Location in the source code."
},
{
"id": "ScriptPosition",
"experimental": true,
"type": "object",
"properties": [
{ "name": "lineNumber", "type": "integer" },
{ "name": "columnNumber", "type": "integer" }
],
"description": "Location in the source code."
},
{
"id": "CallFrame",
"type": "object",
"properties": [
{ "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." },
{ "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." },
{ "name": "functionLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code." },
{ "name": "location", "$ref": "Location", "description": "Location in the source code." },
{ "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." },
{ "name": "this", "$ref": "Runtime.RemoteObject", "description": "<code>this</code> object for this call frame." },
{ "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "description": "The value being returned, if the function is at return point." }
],
"description": "JavaScript call frame. Array of call frames form the call stack."
},
{
"id": "Scope",
"type": "object",
"properties": [
{ "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script"], "description": "Scope type." },
{ "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For <code>global</code> and <code>with</code> scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." },
{ "name": "name", "type": "string", "optional": true },
{ "name": "startLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope starts" },
{ "name": "endLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope ends" }
],
"description": "Scope description."
},
{
"id": "SearchMatch",
"type": "object",
"description": "Search match for resource.",
"exported": true,
"properties": [
{ "name": "lineNumber", "type": "number", "description": "Line number in resource content." },
{ "name": "lineContent", "type": "string", "description": "Line with match content." }
],
"experimental": true
}
],
"commands": [
{
"name": "enable",
"description": "Enables debugger for the given page. Clients should not assume that the debugging has been enabled until the result for this command is received."
},
{
"name": "disable",
"description": "Disables debugger for given page."
},
{
"name": "setBreakpointsActive",
"parameters": [
{ "name": "active", "type": "boolean", "description": "New value for breakpoints active state." }
],
"description": "Activates / deactivates all breakpoints on the page."
},
{
"name": "setSkipAllPauses",
"parameters": [
{ "name": "skip", "type": "boolean", "description": "New value for skip pauses state." }
],
"description": "Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc)."
},
{
"name": "setBreakpointByUrl",
"parameters": [
{ "name": "lineNumber", "type": "integer", "description": "Line number to set breakpoint at." },
{ "name": "url", "type": "string", "optional": true, "description": "URL of the resources to set breakpoint on." },
{ "name": "urlRegex", "type": "string", "optional": true, "description": "Regex pattern for the URLs of the resources to set breakpoints on. Either <code>url</code> or <code>urlRegex</code> must be specified." },
{ "name": "columnNumber", "type": "integer", "optional": true, "description": "Offset in the line to set breakpoint at." },
{ "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." }
],
"returns": [
{ "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." },
{ "name": "locations", "type": "array", "items": { "$ref": "Location" }, "description": "List of the locations this breakpoint resolved into upon addition." }
],
"description": "Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this command is issued, all existing parsed scripts will have breakpoints resolved and returned in <code>locations</code> property. Further matching script parsing will result in subsequent <code>breakpointResolved</code> events issued. This logical breakpoint will survive page reloads."
},
{
"name": "setBreakpoint",
"parameters": [
{ "name": "location", "$ref": "Location", "description": "Location to set breakpoint in." },
{ "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." }
],
"returns": [
{ "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." },
{ "name": "actualLocation", "$ref": "Location", "description": "Location this breakpoint resolved into." }
],
"description": "Sets JavaScript breakpoint at a given location."
},
{
"name": "removeBreakpoint",
"parameters": [
{ "name": "breakpointId", "$ref": "BreakpointId" }
],
"description": "Removes JavaScript breakpoint."
},
{
"name": "continueToLocation",
"parameters": [
{ "name": "location", "$ref": "Location", "description": "Location to continue to." }
],
"description": "Continues execution until specific location is reached."
},
{
"name": "stepOver",
"description": "Steps over the statement."
},
{
"name": "stepInto",
"description": "Steps into the function call."
},
{
"name": "stepOut",
"description": "Steps out of the function call."
},
{
"name": "pause",
"description": "Stops on the next JavaScript statement."
},
{
"name": "resume",
"description": "Resumes JavaScript execution."
},
{
"name": "searchInContent",
"parameters": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to search in." },
{ "name": "query", "type": "string", "description": "String to search for." },
{ "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." },
{ "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." }
],
"returns": [
{ "name": "result", "type": "array", "items": { "$ref": "SearchMatch" }, "description": "List of search matches." }
],
"experimental": true,
"description": "Searches for given string in script content."
},
{
"name": "setScriptSource",
"parameters": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." },
{ "name": "scriptSource", "type": "string", "description": "New content of the script." },
{ "name": "dryRun", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Dry run may be used to get result description without actually modifying the code." }
],
"returns": [
{ "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." },
{ "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes." },
{ "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." },
{ "name": "exceptionDetails", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Exception details if any." }
],
"description": "Edits JavaScript source live."
},
{
"name": "restartFrame",
"parameters": [
{ "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }
],
"returns": [
{ "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." },
{ "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }
],
"description": "Restarts particular call frame from the beginning."
},
{
"name": "getScriptSource",
"parameters": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to get source for." }
],
"returns": [
{ "name": "scriptSource", "type": "string", "description": "Script source." }
],
"description": "Returns source for the script with given id."
},
{
"name": "setPauseOnExceptions",
"parameters": [
{ "name": "state", "type": "string", "enum": ["none", "uncaught", "all"], "description": "Pause on exceptions mode." }
],
"description": "Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions or no exceptions. Initial pause on exceptions state is <code>none</code>."
},
{
"name": "evaluateOnCallFrame",
"parameters": [
{ "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." },
{ "name": "expression", "type": "string", "description": "Expression to evaluate." },
{ "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using <code>releaseObjectGroup</code>)." },
{ "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." },
{ "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides <code>setPauseOnException</code> state." },
{ "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." },
{ "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }
],
"returns": [
{ "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." },
{ "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "description": "Exception details."}
],
"description": "Evaluates expression on a given call frame."
},
{
"name": "setVariableValue",
"parameters": [
{ "name": "scopeNumber", "type": "integer", "description": "0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually." },
{ "name": "variableName", "type": "string", "description": "Variable name." },
{ "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." },
{ "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." }
],
"description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually."
},
{
"name": "setAsyncCallStackDepth",
"parameters": [
{ "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to <code>0</code> will effectively disable collecting async call stacks (default)." }
],
"description": "Enables or disables async call stacks tracking."
},
{
"name": "setBlackboxPatterns",
"parameters": [
{ "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." }
],
"experimental": true,
"description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful."
},
{
"name": "setBlackboxedRanges",
"parameters": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." },
{ "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } }
],
"experimental": true,
"description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted."
}
],
"events": [
{
"name": "scriptParsed",
"parameters": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." },
{ "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." },
{ "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." },
{ "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." },
{ "name": "endLine", "type": "integer", "description": "Last line of the script." },
{ "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." },
{ "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." },
{ "name": "hash", "type": "string", "description": "Content hash of the script."},
{ "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." },
{ "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true },
{ "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." },
{ "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true }
],
"description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger."
},
{
"name": "scriptFailedToParse",
"parameters": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." },
{ "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." },
{ "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." },
{ "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." },
{ "name": "endLine", "type": "integer", "description": "Last line of the script." },
{ "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." },
{ "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." },
{ "name": "hash", "type": "string", "description": "Content hash of the script."},
{ "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." },
{ "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." },
{ "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true }
],
"description": "Fired when virtual machine fails to parse the script."
},
{
"name": "breakpointResolved",
"parameters": [
{ "name": "breakpointId", "$ref": "BreakpointId", "description": "Breakpoint unique identifier." },
{ "name": "location", "$ref": "Location", "description": "Actual breakpoint location." }
],
"description": "Fired when breakpoint is resolved to an actual script and location."
},
{
"name": "paused",
"parameters": [
{ "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." },
{ "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason.", "exported": true },
{ "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." },
{ "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs" },
{ "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }
],
"description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria."
},
{
"name": "resumed",
"description": "Fired when the virtual machine resumed execution."
}
]
},
{
"domain": "Console",
"description": "This domain is deprecated - use Runtime or Log instead.",
"dependencies": ["Runtime"],
"deprecated": true,
"types": [
{
"id": "ConsoleMessage",
"type": "object",
"description": "Console message.",
"properties": [
{ "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "security", "other", "deprecation", "worker"], "description": "Message source." },
{ "name": "level", "type": "string", "enum": ["log", "warning", "error", "debug", "info"], "description": "Message severity." },
{ "name": "text", "type": "string", "description": "Message text." },
{ "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." },
{ "name": "line", "type": "integer", "optional": true, "description": "Line number in the resource that generated this message (1-based)." },
{ "name": "column", "type": "integer", "optional": true, "description": "Column number in the resource that generated this message (1-based)." }
]
}
],
"commands": [
{
"name": "enable",
"description": "Enables console domain, sends the messages collected so far to the client by means of the <code>messageAdded</code> notification."
},
{
"name": "disable",
"description": "Disables console domain, prevents further console messages from being reported to the client."
},
{
"name": "clearMessages",
"description": "Does nothing."
}
],
"events": [
{
"name": "messageAdded",
"parameters": [
{ "name": "message", "$ref": "ConsoleMessage", "description": "Console message that has been added." }
],
"description": "Issued when new console message is added."
}
]
},
{
"domain": "Profiler",
"dependencies": ["Runtime", "Debugger"],
"types": [
{
"id": "ProfileNode",
"type": "object",
"description": "Profile node. Holds callsite information, execution statistics and child nodes.",
"properties": [
{ "name": "id", "type": "integer", "description": "Unique id of the node." },
{ "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." },
{ "name": "hitCount", "type": "integer", "optional": true, "experimental": true, "description": "Number of samples where this node was on top of the call stack." },
{ "name": "children", "type": "array", "items": { "type": "integer" }, "optional": true, "description": "Child node ids." },
{ "name": "deoptReason", "type": "string", "optional": true, "description": "The reason of being not optimized. The function may be deoptimized or marked as don't optimize."},
{ "name": "positionTicks", "type": "array", "items": { "$ref": "PositionTickInfo" }, "optional": true, "experimental": true, "description": "An array of source position ticks." }
]
},
{
"id": "Profile",
"type": "object",
"description": "Profile.",
"properties": [
{ "name": "nodes", "type": "array", "items": { "$ref": "ProfileNode" }, "description": "The list of profile nodes. First item is the root node." },
{ "name": "startTime", "type": "number", "description": "Profiling start timestamp in microseconds." },
{ "name": "endTime", "type": "number", "description": "Profiling end timestamp in microseconds." },
{ "name": "samples", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Ids of samples top nodes." },
{ "name": "timeDeltas", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Time intervals between adjacent samples in microseconds. The first delta is relative to the profile startTime." }
]
},
{
"id": "PositionTickInfo",
"type": "object",
"experimental": true,
"description": "Specifies a number of samples attributed to a certain source position.",
"properties": [
{ "name": "line", "type": "integer", "description": "Source line number (1-based)." },
{ "name": "ticks", "type": "integer", "description": "Number of samples attributed to the source line." }
]
}
],
"commands": [
{
"name": "enable"
},
{
"name": "disable"
},
{
"name": "setSamplingInterval",
"parameters": [
{ "name": "interval", "type": "integer", "description": "New sampling interval in microseconds." }
],
"description": "Changes CPU profiler sampling interval. Must be called before CPU profiles recording started."
},
{
"name": "start"
},
{
"name": "stop",
"returns": [
{ "name": "profile", "$ref": "Profile", "description": "Recorded profile." }
]
}
],
"events": [
{
"name": "consoleProfileStarted",
"parameters": [
{ "name": "id", "type": "string" },
{ "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profile()." },
{ "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." }
],
"description": "Sent when new profile recodring is started using console.profile() call."
},
{
"name": "consoleProfileFinished",
"parameters": [
{ "name": "id", "type": "string" },
{ "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profileEnd()." },
{ "name": "profile", "$ref": "Profile" },
{ "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." }
]
}
]
},
{
"domain": "HeapProfiler",
"dependencies": ["Runtime"],
"experimental": true,
"types": [
{
"id": "HeapSnapshotObjectId",
"type": "string",
"description": "Heap snapshot object id."
},
{
"id": "SamplingHeapProfileNode",
"type": "object",
"description": "Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes.",
"properties": [
{ "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." },
{ "name": "selfSize", "type": "number", "description": "Allocations size in bytes for the node excluding children." },
{ "name": "children", "type": "array", "items": { "$ref": "SamplingHeapProfileNode" }, "description": "Child nodes." }
]
},
{
"id": "SamplingHeapProfile",
"type": "object",
"description": "Profile.",
"properties": [
{ "name": "head", "$ref": "SamplingHeapProfileNode" }
]
}
],
"commands": [
{
"name": "enable"
},
{
"name": "disable"
},
{
"name": "startTrackingHeapObjects",
"parameters": [
{ "name": "trackAllocations", "type": "boolean", "optional": true }
]
},
{
"name": "stopTrackingHeapObjects",
"parameters": [
{ "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken when the tracking is stopped." }
]
},
{
"name": "takeHeapSnapshot",
"parameters": [
{ "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken." }
]
},
{
"name": "collectGarbage"
},
{
"name": "getObjectByHeapObjectId",
"parameters": [
{ "name": "objectId", "$ref": "HeapSnapshotObjectId" },
{ "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }
],
"returns": [
{ "name": "result", "$ref": "Runtime.RemoteObject", "description": "Evaluation result." }
]
},
{
"name": "addInspectedHeapObject",
"parameters": [
{ "name": "heapObjectId", "$ref": "HeapSnapshotObjectId", "description": "Heap snapshot object id to be accessible by means of $x command line API." }
],
"description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions)."
},
{
"name": "getHeapObjectId",
"parameters": [
{ "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Identifier of the object to get heap object id for." }
],
"returns": [
{ "name": "heapSnapshotObjectId", "$ref": "HeapSnapshotObjectId", "description": "Id of the heap snapshot object corresponding to the passed remote object id." }
]
},
{
"name": "startSampling",
"parameters": [
{ "name": "samplingInterval", "type": "number", "optional": true, "description": "Average sample interval in bytes. Poisson distribution is used for the intervals. The default value is 32768 bytes." }
]
},
{
"name": "stopSampling",
"returns": [
{ "name": "profile", "$ref": "SamplingHeapProfile", "description": "Recorded sampling heap profile." }
]
}
],
"events": [
{
"name": "addHeapSnapshotChunk",
"parameters": [
{ "name": "chunk", "type": "string" }
]
},
{
"name": "resetProfiles"
},
{
"name": "reportHeapSnapshotProgress",
"parameters": [
{ "name": "done", "type": "integer" },
{ "name": "total", "type": "integer" },
{ "name": "finished", "type": "boolean", "optional": true }
]
},
{
"name": "lastSeenObjectId",
"description": "If heap objects tracking has been started then backend regulary sends a current value for last seen object id and corresponding timestamp. If the were changes in the heap since last event then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event.",
"parameters": [
{ "name": "lastSeenObjectId", "type": "integer" },
{ "name": "timestamp", "type": "number" }
]
},
{
"name": "heapStatsUpdate",
"description": "If heap objects tracking has been started then backend may send update for one or more fragments",
"parameters": [
{ "name": "statsUpdate", "type": "array", "items": { "type": "integer" }, "description": "An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment."}
]
}
]
}]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
include_rules = [
"+libplatform/libplatform-export.h",
]
specific_include_rules = {
"libplatform\.h": [
"+libplatform/v8-tracing.h",
],
}

View File

@ -1,29 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_
#define V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_
#if defined(_WIN32)
#ifdef BUILDING_V8_PLATFORM_SHARED
#define V8_PLATFORM_EXPORT __declspec(dllexport)
#elif USING_V8_PLATFORM_SHARED
#define V8_PLATFORM_EXPORT __declspec(dllimport)
#else
#define V8_PLATFORM_EXPORT
#endif // BUILDING_V8_PLATFORM_SHARED
#else // defined(_WIN32)
// Setup for Linux shared library export.
#ifdef BUILDING_V8_PLATFORM_SHARED
#define V8_PLATFORM_EXPORT __attribute__((visibility("default")))
#else
#define V8_PLATFORM_EXPORT
#endif
#endif // defined(_WIN32)
#endif // V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_

View File

@ -1,117 +0,0 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_LIBPLATFORM_LIBPLATFORM_H_
#define V8_LIBPLATFORM_LIBPLATFORM_H_
#include <memory>
#include "libplatform/libplatform-export.h"
#include "libplatform/v8-tracing.h"
#include "v8-platform.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
namespace platform {
enum class IdleTaskSupport { kDisabled, kEnabled };
enum class InProcessStackDumping { kDisabled, kEnabled };
enum class MessageLoopBehavior : bool {
kDoNotWait = false,
kWaitForWork = true
};
/**
* Returns a new instance of the default v8::Platform implementation.
*
* The caller will take ownership of the returned pointer. |thread_pool_size|
* is the number of worker threads to allocate for background jobs. If a value
* of zero is passed, a suitable default based on the current number of
* processors online will be chosen.
* If |idle_task_support| is enabled then the platform will accept idle
* tasks (IdleTasksEnabled will return true) and will rely on the embedder
* calling v8::platform::RunIdleTasks to process the idle tasks.
* If |tracing_controller| is nullptr, the default platform will create a
* v8::platform::TracingController instance and use it.
*/
V8_PLATFORM_EXPORT std::unique_ptr<v8::Platform> NewDefaultPlatform(
int thread_pool_size = 0,
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
InProcessStackDumping in_process_stack_dumping =
InProcessStackDumping::kDisabled,
std::unique_ptr<v8::TracingController> tracing_controller = {});
/**
* The same as NewDefaultPlatform but disables the worker thread pool.
* It must be used with the --single-threaded V8 flag.
*/
V8_PLATFORM_EXPORT std::unique_ptr<v8::Platform>
NewSingleThreadedDefaultPlatform(
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
InProcessStackDumping in_process_stack_dumping =
InProcessStackDumping::kDisabled,
std::unique_ptr<v8::TracingController> tracing_controller = {});
/**
* Returns a new instance of the default v8::JobHandle implementation.
*
* The job will be executed by spawning up to |num_worker_threads| many worker
* threads on the provided |platform| with the given |priority|.
*/
V8_PLATFORM_EXPORT std::unique_ptr<v8::JobHandle> NewDefaultJobHandle(
v8::Platform* platform, v8::TaskPriority priority,
std::unique_ptr<v8::JobTask> job_task, size_t num_worker_threads);
/**
* Pumps the message loop for the given isolate.
*
* The caller has to make sure that this is called from the right thread.
* Returns true if a task was executed, and false otherwise. If the call to
* PumpMessageLoop is nested within another call to PumpMessageLoop, only
* nestable tasks may run. Otherwise, any task may run. Unless requested through
* the |behavior| parameter, this call does not block if no task is pending. The
* |platform| has to be created using |NewDefaultPlatform|.
*/
V8_PLATFORM_EXPORT bool PumpMessageLoop(
v8::Platform* platform, v8::Isolate* isolate,
MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait);
/**
* Runs pending idle tasks for at most |idle_time_in_seconds| seconds.
*
* The caller has to make sure that this is called from the right thread.
* This call does not block if no task is pending. The |platform| has to be
* created using |NewDefaultPlatform|.
*/
V8_PLATFORM_EXPORT void RunIdleTasks(v8::Platform* platform,
v8::Isolate* isolate,
double idle_time_in_seconds);
/**
* Attempts to set the tracing controller for the given platform.
*
* The |platform| has to be created using |NewDefaultPlatform|.
*
*/
V8_DEPRECATE_SOON("Access the DefaultPlatform directly")
V8_PLATFORM_EXPORT void SetTracingController(
v8::Platform* platform,
v8::platform::tracing::TracingController* tracing_controller);
/**
* Notifies the given platform about the Isolate getting deleted soon. Has to be
* called for all Isolates which are deleted - unless we're shutting down the
* platform.
*
* The |platform| has to be created using |NewDefaultPlatform|.
*
*/
V8_PLATFORM_EXPORT void NotifyIsolateShutdown(v8::Platform* platform,
Isolate* isolate);
} // namespace platform
} // namespace v8
#endif // V8_LIBPLATFORM_LIBPLATFORM_H_

View File

@ -1,334 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_LIBPLATFORM_V8_TRACING_H_
#define V8_LIBPLATFORM_V8_TRACING_H_
#include <atomic>
#include <fstream>
#include <memory>
#include <unordered_set>
#include <vector>
#include "libplatform/libplatform-export.h"
#include "v8-platform.h" // NOLINT(build/include_directory)
namespace perfetto {
namespace trace_processor {
class TraceProcessorStorage;
}
class TracingSession;
}
namespace v8 {
namespace base {
class Mutex;
} // namespace base
namespace platform {
namespace tracing {
class TraceEventListener;
const int kTraceMaxNumArgs = 2;
class V8_PLATFORM_EXPORT TraceObject {
public:
union ArgValue {
V8_DEPRECATED("use as_uint ? true : false") bool as_bool;
uint64_t as_uint;
int64_t as_int;
double as_double;
const void* as_pointer;
const char* as_string;
};
TraceObject() = default;
~TraceObject();
void Initialize(
char phase, const uint8_t* category_enabled_flag, const char* name,
const char* scope, uint64_t id, uint64_t bind_id, int num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values,
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
unsigned int flags, int64_t timestamp, int64_t cpu_timestamp);
void UpdateDuration(int64_t timestamp, int64_t cpu_timestamp);
void InitializeForTesting(
char phase, const uint8_t* category_enabled_flag, const char* name,
const char* scope, uint64_t id, uint64_t bind_id, int num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values,
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
unsigned int flags, int pid, int tid, int64_t ts, int64_t tts,
uint64_t duration, uint64_t cpu_duration);
int pid() const { return pid_; }
int tid() const { return tid_; }
char phase() const { return phase_; }
const uint8_t* category_enabled_flag() const {
return category_enabled_flag_;
}
const char* name() const { return name_; }
const char* scope() const { return scope_; }
uint64_t id() const { return id_; }
uint64_t bind_id() const { return bind_id_; }
int num_args() const { return num_args_; }
const char** arg_names() { return arg_names_; }
uint8_t* arg_types() { return arg_types_; }
ArgValue* arg_values() { return arg_values_; }
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables() {
return arg_convertables_;
}
unsigned int flags() const { return flags_; }
int64_t ts() { return ts_; }
int64_t tts() { return tts_; }
uint64_t duration() { return duration_; }
uint64_t cpu_duration() { return cpu_duration_; }
private:
int pid_;
int tid_;
char phase_;
const char* name_;
const char* scope_;
const uint8_t* category_enabled_flag_;
uint64_t id_;
uint64_t bind_id_;
int num_args_ = 0;
const char* arg_names_[kTraceMaxNumArgs];
uint8_t arg_types_[kTraceMaxNumArgs];
ArgValue arg_values_[kTraceMaxNumArgs];
std::unique_ptr<v8::ConvertableToTraceFormat>
arg_convertables_[kTraceMaxNumArgs];
char* parameter_copy_storage_ = nullptr;
unsigned int flags_;
int64_t ts_;
int64_t tts_;
uint64_t duration_;
uint64_t cpu_duration_;
// Disallow copy and assign
TraceObject(const TraceObject&) = delete;
void operator=(const TraceObject&) = delete;
};
class V8_PLATFORM_EXPORT TraceWriter {
public:
TraceWriter() = default;
virtual ~TraceWriter() = default;
virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
virtual void Flush() = 0;
static TraceWriter* CreateJSONTraceWriter(std::ostream& stream);
static TraceWriter* CreateJSONTraceWriter(std::ostream& stream,
const std::string& tag);
static TraceWriter* CreateSystemInstrumentationTraceWriter();
private:
// Disallow copy and assign
TraceWriter(const TraceWriter&) = delete;
void operator=(const TraceWriter&) = delete;
};
class V8_PLATFORM_EXPORT TraceBufferChunk {
public:
explicit TraceBufferChunk(uint32_t seq);
void Reset(uint32_t new_seq);
bool IsFull() const { return next_free_ == kChunkSize; }
TraceObject* AddTraceEvent(size_t* event_index);
TraceObject* GetEventAt(size_t index) { return &chunk_[index]; }
uint32_t seq() const { return seq_; }
size_t size() const { return next_free_; }
static const size_t kChunkSize = 64;
private:
size_t next_free_ = 0;
TraceObject chunk_[kChunkSize];
uint32_t seq_;
// Disallow copy and assign
TraceBufferChunk(const TraceBufferChunk&) = delete;
void operator=(const TraceBufferChunk&) = delete;
};
class V8_PLATFORM_EXPORT TraceBuffer {
public:
TraceBuffer() = default;
virtual ~TraceBuffer() = default;
virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0;
virtual TraceObject* GetEventByHandle(uint64_t handle) = 0;
virtual bool Flush() = 0;
static const size_t kRingBufferChunks = 1024;
static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks,
TraceWriter* trace_writer);
private:
// Disallow copy and assign
TraceBuffer(const TraceBuffer&) = delete;
void operator=(const TraceBuffer&) = delete;
};
// Options determines how the trace buffer stores data.
enum TraceRecordMode {
// Record until the trace buffer is full.
RECORD_UNTIL_FULL,
// Record until the user ends the trace. The trace buffer is a fixed size
// and we use it as a ring buffer during recording.
RECORD_CONTINUOUSLY,
// Record until the trace buffer is full, but with a huge buffer size.
RECORD_AS_MUCH_AS_POSSIBLE,
// Echo to console. Events are discarded.
ECHO_TO_CONSOLE,
};
class V8_PLATFORM_EXPORT TraceConfig {
public:
typedef std::vector<std::string> StringList;
static TraceConfig* CreateDefaultTraceConfig();
TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {}
TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
const StringList& GetEnabledCategories() const {
return included_categories_;
}
bool IsSystraceEnabled() const { return enable_systrace_; }
bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
void EnableSystrace() { enable_systrace_ = true; }
void EnableArgumentFilter() { enable_argument_filter_ = true; }
void AddIncludedCategory(const char* included_category);
bool IsCategoryGroupEnabled(const char* category_group) const;
private:
TraceRecordMode record_mode_;
bool enable_systrace_ : 1;
bool enable_argument_filter_ : 1;
StringList included_categories_;
// Disallow copy and assign
TraceConfig(const TraceConfig&) = delete;
void operator=(const TraceConfig&) = delete;
};
#if defined(_MSC_VER)
#define V8_PLATFORM_NON_EXPORTED_BASE(code) \
__pragma(warning(suppress : 4275)) code
#else
#define V8_PLATFORM_NON_EXPORTED_BASE(code) code
#endif // defined(_MSC_VER)
class V8_PLATFORM_EXPORT TracingController
: public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) {
public:
TracingController();
~TracingController() override;
#if defined(V8_USE_PERFETTO)
// Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides
// the output stream for the JSON trace data.
void InitializeForPerfetto(std::ostream* output_stream);
// Provide an optional listener for testing that will receive trace events.
// Must be called before StartTracing().
void SetTraceEventListenerForTesting(TraceEventListener* listener);
#else // defined(V8_USE_PERFETTO)
// The pointer returned from GetCategoryGroupEnabled() points to a value with
// zero or more of the following bits. Used in this class only. The
// TRACE_EVENT macros should only use the value as a bool. These values must
// be in sync with macro values in TraceEvent.h in Blink.
enum CategoryGroupEnabledFlags {
// Category group enabled for the recording mode.
ENABLED_FOR_RECORDING = 1 << 0,
// Category group enabled by SetEventCallbackEnabled().
ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
// Category group enabled to export events to ETW.
ENABLED_FOR_ETW_EXPORT = 1 << 3
};
// Takes ownership of |trace_buffer|.
void Initialize(TraceBuffer* trace_buffer);
// v8::TracingController implementation.
const uint8_t* GetCategoryGroupEnabled(const char* category_group) override;
uint64_t AddTraceEvent(
char phase, const uint8_t* category_enabled_flag, const char* name,
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values,
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
unsigned int flags) override;
uint64_t AddTraceEventWithTimestamp(
char phase, const uint8_t* category_enabled_flag, const char* name,
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values,
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
unsigned int flags, int64_t timestamp) override;
void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
const char* name, uint64_t handle) override;
static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag);
#endif // !defined(V8_USE_PERFETTO)
void AddTraceStateObserver(
v8::TracingController::TraceStateObserver* observer) override;
void RemoveTraceStateObserver(
v8::TracingController::TraceStateObserver* observer) override;
void StartTracing(TraceConfig* trace_config);
void StopTracing();
protected:
#if !defined(V8_USE_PERFETTO)
virtual int64_t CurrentTimestampMicroseconds();
virtual int64_t CurrentCpuTimestampMicroseconds();
#endif // !defined(V8_USE_PERFETTO)
private:
#if !defined(V8_USE_PERFETTO)
void UpdateCategoryGroupEnabledFlag(size_t category_index);
void UpdateCategoryGroupEnabledFlags();
#endif // !defined(V8_USE_PERFETTO)
std::unique_ptr<base::Mutex> mutex_;
std::unique_ptr<TraceConfig> trace_config_;
std::atomic_bool recording_{false};
std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
#if defined(V8_USE_PERFETTO)
std::ostream* output_stream_ = nullptr;
std::unique_ptr<perfetto::trace_processor::TraceProcessorStorage>
trace_processor_;
TraceEventListener* listener_for_testing_ = nullptr;
std::unique_ptr<perfetto::TracingSession> tracing_session_;
#else // !defined(V8_USE_PERFETTO)
std::unique_ptr<TraceBuffer> trace_buffer_;
#endif // !defined(V8_USE_PERFETTO)
// Disallow copy and assign
TracingController(const TracingController&) = delete;
void operator=(const TracingController&) = delete;
};
#undef V8_PLATFORM_NON_EXPORTED_BASE
} // namespace tracing
} // namespace platform
} // namespace v8
#endif // V8_LIBPLATFORM_V8_TRACING_H_

View File

@ -1,293 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_V8_CPPGC_H_
#define INCLUDE_V8_CPPGC_H_
#include <cstdint>
#include <memory>
#include <vector>
#include "cppgc/common.h"
#include "cppgc/custom-space.h"
#include "cppgc/heap-statistics.h"
#include "cppgc/internal/write-barrier.h"
#include "cppgc/visitor.h"
#include "v8-internal.h" // NOLINT(build/include_directory)
#include "v8.h" // NOLINT(build/include_directory)
namespace cppgc {
class AllocationHandle;
class HeapHandle;
} // namespace cppgc
namespace v8 {
namespace internal {
class CppHeap;
} // namespace internal
/**
* Describes how V8 wrapper objects maintain references to garbage-collected C++
* objects.
*/
struct WrapperDescriptor final {
/**
* The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and
* related APIs to add additional data to an object which is used to identify
* JS->C++ references.
*/
using InternalFieldIndex = int;
/**
* Unknown embedder id. The value is reserved for internal usages and must not
* be used with `CppHeap`.
*/
static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX;
constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index,
InternalFieldIndex wrappable_instance_index,
uint16_t embedder_id_for_garbage_collected)
: wrappable_type_index(wrappable_type_index),
wrappable_instance_index(wrappable_instance_index),
embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {}
/**
* Index of the wrappable type.
*/
InternalFieldIndex wrappable_type_index;
/**
* Index of the wrappable instance.
*/
InternalFieldIndex wrappable_instance_index;
/**
* Embedder id identifying instances of garbage-collected objects. It is
* expected that the first field of the wrappable type is a uint16_t holding
* the id. Only references to instances of wrappables types with an id of
* `embedder_id_for_garbage_collected` will be considered by CppHeap.
*/
uint16_t embedder_id_for_garbage_collected;
};
struct V8_EXPORT CppHeapCreateParams {
CppHeapCreateParams(const CppHeapCreateParams&) = delete;
CppHeapCreateParams& operator=(const CppHeapCreateParams&) = delete;
std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> custom_spaces;
WrapperDescriptor wrapper_descriptor;
};
/**
* A heap for allocating managed C++ objects.
*/
class V8_EXPORT CppHeap {
public:
static std::unique_ptr<CppHeap> Create(v8::Platform* platform,
const CppHeapCreateParams& params);
virtual ~CppHeap() = default;
/**
* \returns the opaque handle for allocating objects using
* `MakeGarbageCollected()`.
*/
cppgc::AllocationHandle& GetAllocationHandle();
/**
* \returns the opaque heap handle which may be used to refer to this heap in
* other APIs. Valid as long as the underlying `CppHeap` is alive.
*/
cppgc::HeapHandle& GetHeapHandle();
/**
* Terminate clears all roots and performs multiple garbage collections to
* reclaim potentially newly created objects in destructors.
*
* After this call, object allocation is prohibited.
*/
void Terminate();
/**
* \param detail_level specifies whether should return detailed
* statistics or only brief summary statistics.
* \returns current CppHeap statistics regarding memory consumption
* and utilization.
*/
cppgc::HeapStatistics CollectStatistics(
cppgc::HeapStatistics::DetailLevel detail_level);
/**
* Enables a detached mode that allows testing garbage collection using
* `cppgc::testing` APIs. Once used, the heap cannot be attached to an
* `Isolate` anymore.
*/
void EnableDetachedGarbageCollectionsForTesting();
/**
* Performs a stop-the-world garbage collection for testing purposes.
*
* \param stack_state The stack state to assume for the garbage collection.
*/
void CollectGarbageForTesting(cppgc::EmbedderStackState stack_state);
private:
CppHeap() = default;
friend class internal::CppHeap;
};
class JSVisitor : public cppgc::Visitor {
public:
explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
void Trace(const TracedReferenceBase& ref) {
if (ref.IsEmptyThreadSafe()) return;
Visit(ref);
}
protected:
using cppgc::Visitor::Visit;
virtual void Visit(const TracedReferenceBase& ref) {}
};
/**
* **DO NOT USE: Use the appropriate managed types.**
*
* Consistency helpers that aid in maintaining a consistent internal state of
* the garbage collector.
*/
class V8_EXPORT JSHeapConsistency final {
public:
using WriteBarrierParams = cppgc::internal::WriteBarrier::Params;
using WriteBarrierType = cppgc::internal::WriteBarrier::Type;
/**
* Gets the required write barrier type for a specific write.
*
* Note: Handling for C++ to JS references.
*
* \param ref The reference being written to.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \param callback Callback returning the corresponding heap handle. The
* callback is only invoked if the heap cannot otherwise be figured out. The
* callback must not allocate.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrierType
GetWriteBarrierType(const TracedReferenceBase& ref,
WriteBarrierParams& params, HeapHandleCallback callback) {
if (ref.IsEmpty()) return WriteBarrierType::kNone;
if (V8_LIKELY(!cppgc::internal::WriteBarrier::
IsAnyIncrementalOrConcurrentMarking())) {
return cppgc::internal::WriteBarrier::Type::kNone;
}
cppgc::HeapHandle& handle = callback();
if (!cppgc::subtle::HeapState::IsMarking(handle)) {
return cppgc::internal::WriteBarrier::Type::kNone;
}
params.heap = &handle;
#if V8_ENABLE_CHECKS
params.type = cppgc::internal::WriteBarrier::Type::kMarking;
#endif // !V8_ENABLE_CHECKS
return cppgc::internal::WriteBarrier::Type::kMarking;
}
/**
* Gets the required write barrier type for a specific write.
*
* Note: Handling for JS to C++ references.
*
* \param wrapper The wrapper that has been written into.
* \param wrapper_index The wrapper index in `wrapper` that has been written
* into.
* \param wrappable The value that was written.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \param callback Callback returning the corresponding heap handle. The
* callback is only invoked if the heap cannot otherwise be figured out. The
* callback must not allocate.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrierType GetWriteBarrierType(
v8::Local<v8::Object>& wrapper, int wrapper_index, const void* wrappable,
WriteBarrierParams& params, HeapHandleCallback callback) {
#if V8_ENABLE_CHECKS
CheckWrapper(wrapper, wrapper_index, wrappable);
#endif // V8_ENABLE_CHECKS
return cppgc::internal::WriteBarrier::
GetWriteBarrierTypeForExternallyReferencedObject(wrappable, params,
callback);
}
/**
* Conservative Dijkstra-style write barrier that processes an object if it
* has not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param ref The reference being written to.
*/
static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params,
cppgc::HeapHandle& heap_handle,
const TracedReferenceBase& ref) {
cppgc::internal::WriteBarrier::CheckParams(WriteBarrierType::kMarking,
params);
DijkstraMarkingBarrierSlow(heap_handle, ref);
}
/**
* Conservative Dijkstra-style write barrier that processes an object if it
* has not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param object The pointer to the object. May be an interior pointer to a
* an interface of the actual object.
*/
static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params,
cppgc::HeapHandle& heap_handle,
const void* object) {
cppgc::internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
}
/**
* Generational barrier for maintaining consistency when running with multiple
* generations.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param ref The reference being written to.
*/
static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
const TracedReferenceBase& ref) {}
private:
JSHeapConsistency() = delete;
static void CheckWrapper(v8::Local<v8::Object>&, int, const void*);
static void DijkstraMarkingBarrierSlow(cppgc::HeapHandle&,
const TracedReferenceBase& ref);
};
} // namespace v8
namespace cppgc {
template <typename T>
struct TraceTrait<v8::TracedReference<T>> {
static void Trace(Visitor* visitor, const v8::TracedReference<T>* self) {
static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
}
};
} // namespace cppgc
#endif // INCLUDE_V8_CPPGC_H_

View File

@ -1,529 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* This file provides additional API on top of the default one for making
* API calls, which come from embedder C++ functions. The functions are being
* called directly from optimized code, doing all the necessary typechecks
* in the compiler itself, instead of on the embedder side. Hence the "fast"
* in the name. Example usage might look like:
*
* \code
* void FastMethod(int param, bool another_param);
*
* v8::FunctionTemplate::New(isolate, SlowCallback, data,
* signature, length, constructor_behavior
* side_effect_type,
* &v8::CFunction::Make(FastMethod));
* \endcode
*
* By design, fast calls are limited by the following requirements, which
* the embedder should enforce themselves:
* - they should not allocate on the JS heap;
* - they should not trigger JS execution.
* To enforce them, the embedder could use the existing
* v8::Isolate::DisallowJavascriptExecutionScope and a utility similar to
* Blink's NoAllocationScope:
* https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/heap/thread_state_scopes.h;l=16
*
* Due to these limitations, it's not directly possible to report errors by
* throwing a JS exception or to otherwise do an allocation. There is an
* alternative way of creating fast calls that supports falling back to the
* slow call and then performing the necessary allocation. When one creates
* the fast method by using CFunction::MakeWithFallbackSupport instead of
* CFunction::Make, the fast callback gets as last parameter an output variable,
* through which it can request falling back to the slow call. So one might
* declare their method like:
*
* \code
* void FastMethodWithFallback(int param, FastApiCallbackOptions& options);
* \endcode
*
* If the callback wants to signal an error condition or to perform an
* allocation, it must set options.fallback to true and do an early return from
* the fast method. Then V8 checks the value of options.fallback and if it's
* true, falls back to executing the SlowCallback, which is capable of reporting
* the error (either by throwing a JS exception or logging to the console) or
* doing the allocation. It's the embedder's responsibility to ensure that the
* fast callback is idempotent up to the point where error and fallback
* conditions are checked, because otherwise executing the slow callback might
* produce visible side-effects twice.
*
* An example for custom embedder type support might employ a way to wrap/
* unwrap various C++ types in JSObject instances, e.g:
*
* \code
*
* // Helper method with a check for field count.
* template <typename T, int offset>
* inline T* GetInternalField(v8::Local<v8::Object> wrapper) {
* assert(offset < wrapper->InternalFieldCount());
* return reinterpret_cast<T*>(
* wrapper->GetAlignedPointerFromInternalField(offset));
* }
*
* class CustomEmbedderType {
* public:
* // Returns the raw C object from a wrapper JS object.
* static CustomEmbedderType* Unwrap(v8::Local<v8::Object> wrapper) {
* return GetInternalField<CustomEmbedderType,
* kV8EmbedderWrapperObjectIndex>(wrapper);
* }
* static void FastMethod(v8::ApiObject receiver_obj, int param) {
* v8::Object* v8_object = reinterpret_cast<v8::Object*>(&api_object);
* CustomEmbedderType* receiver = static_cast<CustomEmbedderType*>(
* receiver_obj->GetAlignedPointerFromInternalField(
* kV8EmbedderWrapperObjectIndex));
*
* // Type checks are already done by the optimized code.
* // Then call some performance-critical method like:
* // receiver->Method(param);
* }
*
* static void SlowMethod(
* const v8::FunctionCallbackInfo<v8::Value>& info) {
* v8::Local<v8::Object> instance =
* v8::Local<v8::Object>::Cast(info.Holder());
* CustomEmbedderType* receiver = Unwrap(instance);
* // TODO: Do type checks and extract {param}.
* receiver->Method(param);
* }
* };
*
* // TODO(mslekova): Clean-up these constants
* // The constants kV8EmbedderWrapperTypeIndex and
* // kV8EmbedderWrapperObjectIndex describe the offsets for the type info
* // struct and the native object, when expressed as internal field indices
* // within a JSObject. The existance of this helper function assumes that
* // all embedder objects have their JSObject-side type info at the same
* // offset, but this is not a limitation of the API itself. For a detailed
* // use case, see the third example.
* static constexpr int kV8EmbedderWrapperTypeIndex = 0;
* static constexpr int kV8EmbedderWrapperObjectIndex = 1;
*
* // The following setup function can be templatized based on
* // the {embedder_object} argument.
* void SetupCustomEmbedderObject(v8::Isolate* isolate,
* v8::Local<v8::Context> context,
* CustomEmbedderType* embedder_object) {
* isolate->set_embedder_wrapper_type_index(
* kV8EmbedderWrapperTypeIndex);
* isolate->set_embedder_wrapper_object_index(
* kV8EmbedderWrapperObjectIndex);
*
* v8::CFunction c_func =
* MakeV8CFunction(CustomEmbedderType::FastMethod);
*
* Local<v8::FunctionTemplate> method_template =
* v8::FunctionTemplate::New(
* isolate, CustomEmbedderType::SlowMethod, v8::Local<v8::Value>(),
* v8::Local<v8::Signature>(), 1, v8::ConstructorBehavior::kAllow,
* v8::SideEffectType::kHasSideEffect, &c_func);
*
* v8::Local<v8::ObjectTemplate> object_template =
* v8::ObjectTemplate::New(isolate);
* object_template->SetInternalFieldCount(
* kV8EmbedderWrapperObjectIndex + 1);
* object_template->Set(isolate, "method", method_template);
*
* // Instantiate the wrapper JS object.
* v8::Local<v8::Object> object =
* object_template->NewInstance(context).ToLocalChecked();
* object->SetAlignedPointerInInternalField(
* kV8EmbedderWrapperObjectIndex,
* reinterpret_cast<void*>(embedder_object));
*
* // TODO: Expose {object} where it's necessary.
* }
* \endcode
*
* For instance if {object} is exposed via a global "obj" variable,
* one could write in JS:
* function hot_func() {
* obj.method(42);
* }
* and once {hot_func} gets optimized, CustomEmbedderType::FastMethod
* will be called instead of the slow version, with the following arguments:
* receiver := the {embedder_object} from above
* param := 42
*
* Currently supported return types:
* - void
* - bool
* - int32_t
* - uint32_t
* - float32_t
* - float64_t
* Currently supported argument types:
* - pointer to an embedder type
* - bool
* - int32_t
* - uint32_t
* - int64_t
* - uint64_t
* - float32_t
* - float64_t
*
* The 64-bit integer types currently have the IDL (unsigned) long long
* semantics: https://heycam.github.io/webidl/#abstract-opdef-converttoint
* In the future we'll extend the API to also provide conversions from/to
* BigInt to preserve full precision.
* The floating point types currently have the IDL (unrestricted) semantics,
* which is the only one used by WebGL. We plan to add support also for
* restricted floats/doubles, similarly to the BigInt conversion policies.
* We also differ from the specific NaN bit pattern that WebIDL prescribes
* (https://heycam.github.io/webidl/#es-unrestricted-float) in that Blink
* passes NaN values as-is, i.e. doesn't normalize them.
*
* To be supported types:
* - arrays of C types
* - arrays of embedder types
*/
#ifndef INCLUDE_V8_FAST_API_CALLS_H_
#define INCLUDE_V8_FAST_API_CALLS_H_
#include <stddef.h>
#include <stdint.h>
#include <tuple>
#include <type_traits>
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
class CTypeInfo {
public:
enum class Type : uint8_t {
kVoid,
kBool,
kInt32,
kUint32,
kInt64,
kUint64,
kFloat32,
kFloat64,
kV8Value,
};
// kCallbackOptionsType is not part of the Type enum
// because it is only used internally. Use value 255 that is larger
// than any valid Type enum.
static constexpr Type kCallbackOptionsType = Type(255);
enum class Flags : uint8_t {
kNone = 0,
};
explicit constexpr CTypeInfo(Type type, Flags flags = Flags::kNone)
: type_(type), flags_(flags) {}
constexpr Type GetType() const { return type_; }
constexpr Flags GetFlags() const { return flags_; }
private:
Type type_;
Flags flags_;
};
class V8_EXPORT CFunctionInfo {
public:
// Construct a struct to hold a CFunction's type information.
// |return_info| describes the function's return type.
// |arg_info| is an array of |arg_count| CTypeInfos describing the
// arguments. Only the last argument may be of the special type
// CTypeInfo::kCallbackOptionsType.
CFunctionInfo(const CTypeInfo& return_info, unsigned int arg_count,
const CTypeInfo* arg_info);
const CTypeInfo& ReturnInfo() const { return return_info_; }
// The argument count, not including the v8::FastApiCallbackOptions
// if present.
unsigned int ArgumentCount() const {
return HasOptions() ? arg_count_ - 1 : arg_count_;
}
// |index| must be less than ArgumentCount().
// Note: if the last argument passed on construction of CFunctionInfo
// has type CTypeInfo::kCallbackOptionsType, it is not included in
// ArgumentCount().
const CTypeInfo& ArgumentInfo(unsigned int index) const;
bool HasOptions() const {
// The options arg is always the last one.
return arg_count_ > 0 && arg_info_[arg_count_ - 1].GetType() ==
CTypeInfo::kCallbackOptionsType;
}
private:
const CTypeInfo return_info_;
const unsigned int arg_count_;
const CTypeInfo* arg_info_;
};
class V8_EXPORT CFunction {
public:
constexpr CFunction() : address_(nullptr), type_info_(nullptr) {}
const CTypeInfo& ReturnInfo() const { return type_info_->ReturnInfo(); }
const CTypeInfo& ArgumentInfo(unsigned int index) const {
return type_info_->ArgumentInfo(index);
}
unsigned int ArgumentCount() const { return type_info_->ArgumentCount(); }
const void* GetAddress() const { return address_; }
const CFunctionInfo* GetTypeInfo() const { return type_info_; }
template <typename F>
static CFunction Make(F* func) {
return ArgUnwrap<F*>::Make(func);
}
template <typename F>
V8_DEPRECATED("Use CFunctionBuilder instead.")
static CFunction MakeWithFallbackSupport(F* func) {
return ArgUnwrap<F*>::Make(func);
}
CFunction(const void* address, const CFunctionInfo* type_info);
private:
const void* address_;
const CFunctionInfo* type_info_;
template <typename F>
class ArgUnwrap {
static_assert(sizeof(F) != sizeof(F),
"CFunction must be created from a function pointer.");
};
template <typename R, typename... Args>
class ArgUnwrap<R (*)(Args...)> {
public:
static CFunction Make(R (*func)(Args...));
};
};
struct ApiObject {
uintptr_t address;
};
/**
* A struct which may be passed to a fast call callback, like so:
* \code
* void FastMethodWithOptions(int param, FastApiCallbackOptions& options);
* \endcode
*/
struct FastApiCallbackOptions {
/**
* If the callback wants to signal an error condition or to perform an
* allocation, it must set options.fallback to true and do an early return
* from the fast method. Then V8 checks the value of options.fallback and if
* it's true, falls back to executing the SlowCallback, which is capable of
* reporting the error (either by throwing a JS exception or logging to the
* console) or doing the allocation. It's the embedder's responsibility to
* ensure that the fast callback is idempotent up to the point where error and
* fallback conditions are checked, because otherwise executing the slow
* callback might produce visible side-effects twice.
*/
bool fallback;
/**
* The `data` passed to the FunctionTemplate constructor, or `undefined`.
*/
const ApiObject data;
};
namespace internal {
// Helper to count the number of occurances of `T` in `List`
template <typename T, typename... List>
struct count : std::integral_constant<int, 0> {};
template <typename T, typename... Args>
struct count<T, T, Args...>
: std::integral_constant<std::size_t, 1 + count<T, Args...>::value> {};
template <typename T, typename U, typename... Args>
struct count<T, U, Args...> : count<T, Args...> {};
template <typename RetBuilder, typename... ArgBuilders>
class CFunctionInfoImpl : public CFunctionInfo {
static constexpr int kOptionsArgCount =
count<FastApiCallbackOptions&, ArgBuilders...>();
static constexpr int kReceiverCount = 1;
static_assert(kOptionsArgCount == 0 || kOptionsArgCount == 1,
"Only one options parameter is supported.");
static_assert(sizeof...(ArgBuilders) >= kOptionsArgCount + kReceiverCount,
"The receiver or the options argument is missing.");
public:
constexpr CFunctionInfoImpl()
: CFunctionInfo(RetBuilder::Build(), sizeof...(ArgBuilders),
arg_info_storage_),
arg_info_storage_{ArgBuilders::Build()...} {
constexpr CTypeInfo::Type kReturnType = RetBuilder::Build().GetType();
static_assert(kReturnType == CTypeInfo::Type::kVoid ||
kReturnType == CTypeInfo::Type::kBool ||
kReturnType == CTypeInfo::Type::kInt32 ||
kReturnType == CTypeInfo::Type::kUint32 ||
kReturnType == CTypeInfo::Type::kFloat32 ||
kReturnType == CTypeInfo::Type::kFloat64,
"64-bit int and api object values are not currently "
"supported return types.");
}
private:
const CTypeInfo arg_info_storage_[sizeof...(ArgBuilders)];
};
template <typename T>
struct TypeInfoHelper {
static_assert(sizeof(T) != sizeof(T), "This type is not supported");
};
#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR(T, Enum) \
template <> \
struct TypeInfoHelper<T> { \
static constexpr CTypeInfo::Flags Flags() { \
return CTypeInfo::Flags::kNone; \
} \
\
static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \
};
#define BASIC_C_TYPES(V) \
V(void, kVoid) \
V(bool, kBool) \
V(int32_t, kInt32) \
V(uint32_t, kUint32) \
V(int64_t, kInt64) \
V(uint64_t, kUint64) \
V(float, kFloat32) \
V(double, kFloat64) \
V(ApiObject, kV8Value)
BASIC_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR)
#undef BASIC_C_TYPES
template <>
struct TypeInfoHelper<FastApiCallbackOptions&> {
static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; }
static constexpr CTypeInfo::Type Type() {
return CTypeInfo::kCallbackOptionsType;
}
};
template <typename T, CTypeInfo::Flags... Flags>
class CTypeInfoBuilder {
public:
using BaseType = T;
static constexpr CTypeInfo Build() {
// Get the flags and merge in any additional flags.
uint8_t flags = uint8_t(TypeInfoHelper<T>::Flags());
int unused[] = {0, (flags |= uint8_t(Flags), 0)...};
// With C++17, we could use a "..." fold expression over a parameter pack.
// Since we're still using C++14, we have to evaluate an OR expresion while
// constructing an unused list of 0's. This applies the binary operator
// for each value in Flags.
(void)unused;
// Return the same type with the merged flags.
return CTypeInfo(TypeInfoHelper<T>::Type(), CTypeInfo::Flags(flags));
}
};
template <typename RetBuilder, typename... ArgBuilders>
class CFunctionBuilderWithFunction {
public:
explicit constexpr CFunctionBuilderWithFunction(const void* fn) : fn_(fn) {}
template <CTypeInfo::Flags... Flags>
constexpr auto Ret() {
return CFunctionBuilderWithFunction<
CTypeInfoBuilder<typename RetBuilder::BaseType, Flags...>,
ArgBuilders...>(fn_);
}
template <unsigned int N, CTypeInfo::Flags... Flags>
constexpr auto Arg() {
// Return a copy of the builder with the Nth arg builder merged with
// template parameter pack Flags.
return ArgImpl<N, Flags...>(
std::make_index_sequence<sizeof...(ArgBuilders)>());
}
auto Build() {
static CFunctionInfoImpl<RetBuilder, ArgBuilders...> instance;
return CFunction(fn_, &instance);
}
private:
template <bool Merge, unsigned int N, CTypeInfo::Flags... Flags>
struct GetArgBuilder;
// Returns the same ArgBuilder as the one at index N, including its flags.
// Flags in the template parameter pack are ignored.
template <unsigned int N, CTypeInfo::Flags... Flags>
struct GetArgBuilder<false, N, Flags...> {
using type =
typename std::tuple_element<N, std::tuple<ArgBuilders...>>::type;
};
// Returns an ArgBuilder with the same base type as the one at index N,
// but merges the flags with the flags in the template parameter pack.
template <unsigned int N, CTypeInfo::Flags... Flags>
struct GetArgBuilder<true, N, Flags...> {
using type = CTypeInfoBuilder<
typename std::tuple_element<N,
std::tuple<ArgBuilders...>>::type::BaseType,
std::tuple_element<N, std::tuple<ArgBuilders...>>::type::Build()
.GetFlags(),
Flags...>;
};
// Return a copy of the CFunctionBuilder, but merges the Flags on ArgBuilder
// index N with the new Flags passed in the template parameter pack.
template <unsigned int N, CTypeInfo::Flags... Flags, size_t... I>
constexpr auto ArgImpl(std::index_sequence<I...>) {
return CFunctionBuilderWithFunction<
RetBuilder, typename GetArgBuilder<N == I, I, Flags...>::type...>(fn_);
}
const void* fn_;
};
class CFunctionBuilder {
public:
constexpr CFunctionBuilder() {}
template <typename R, typename... Args>
constexpr auto Fn(R (*fn)(Args...)) {
return CFunctionBuilderWithFunction<CTypeInfoBuilder<R>,
CTypeInfoBuilder<Args>...>(
reinterpret_cast<const void*>(fn));
}
};
} // namespace internal
// static
template <typename R, typename... Args>
CFunction CFunction::ArgUnwrap<R (*)(Args...)>::Make(R (*func)(Args...)) {
return internal::CFunctionBuilder().Fn(func).Build();
}
using CFunctionBuilder = internal::CFunctionBuilder;
} // namespace v8
#endif // INCLUDE_V8_FAST_API_CALLS_H_

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_V8_INSPECTOR_PROTOCOL_H_
#define V8_V8_INSPECTOR_PROTOCOL_H_
#include "inspector/Debugger.h" // NOLINT(build/include_directory)
#include "inspector/Runtime.h" // NOLINT(build/include_directory)
#include "inspector/Schema.h" // NOLINT(build/include_directory)
#include "v8-inspector.h" // NOLINT(build/include_directory)
#endif // V8_V8_INSPECTOR_PROTOCOL_H_

View File

@ -1,336 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_V8_INSPECTOR_H_
#define V8_V8_INSPECTOR_H_
#include <stdint.h>
#include <cctype>
#include <memory>
#include <unordered_map>
#include "v8.h" // NOLINT(build/include_directory)
namespace v8_inspector {
namespace protocol {
namespace Debugger {
namespace API {
class SearchMatch;
}
}
namespace Runtime {
namespace API {
class RemoteObject;
class StackTrace;
class StackTraceId;
}
}
namespace Schema {
namespace API {
class Domain;
}
}
} // namespace protocol
class V8_EXPORT StringView {
public:
StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {}
StringView(const uint8_t* characters, size_t length)
: m_is8Bit(true), m_length(length), m_characters8(characters) {}
StringView(const uint16_t* characters, size_t length)
: m_is8Bit(false), m_length(length), m_characters16(characters) {}
bool is8Bit() const { return m_is8Bit; }
size_t length() const { return m_length; }
// TODO(dgozman): add DCHECK(m_is8Bit) to accessors once platform can be used
// here.
const uint8_t* characters8() const { return m_characters8; }
const uint16_t* characters16() const { return m_characters16; }
private:
bool m_is8Bit;
size_t m_length;
union {
const uint8_t* m_characters8;
const uint16_t* m_characters16;
};
};
class V8_EXPORT StringBuffer {
public:
virtual ~StringBuffer() = default;
virtual StringView string() const = 0;
// This method copies contents.
static std::unique_ptr<StringBuffer> create(StringView);
};
class V8_EXPORT V8ContextInfo {
public:
V8ContextInfo(v8::Local<v8::Context> context, int contextGroupId,
StringView humanReadableName)
: context(context),
contextGroupId(contextGroupId),
humanReadableName(humanReadableName),
hasMemoryOnConsole(false) {}
v8::Local<v8::Context> context;
// Each v8::Context is a part of a group. The group id must be non-zero.
int contextGroupId;
StringView humanReadableName;
StringView origin;
StringView auxData;
bool hasMemoryOnConsole;
static int executionContextId(v8::Local<v8::Context> context);
// Disallow copying and allocating this one.
enum NotNullTagEnum { NotNullLiteral };
void* operator new(size_t) = delete;
void* operator new(size_t, NotNullTagEnum, void*) = delete;
void* operator new(size_t, void*) = delete;
V8ContextInfo(const V8ContextInfo&) = delete;
V8ContextInfo& operator=(const V8ContextInfo&) = delete;
};
class V8_EXPORT V8StackTrace {
public:
virtual StringView firstNonEmptySourceURL() const = 0;
virtual bool isEmpty() const = 0;
virtual StringView topSourceURL() const = 0;
virtual int topLineNumber() const = 0;
virtual int topColumnNumber() const = 0;
virtual StringView topScriptId() const = 0;
virtual int topScriptIdAsInteger() const = 0;
virtual StringView topFunctionName() const = 0;
virtual ~V8StackTrace() = default;
virtual std::unique_ptr<protocol::Runtime::API::StackTrace>
buildInspectorObject() const = 0;
virtual std::unique_ptr<protocol::Runtime::API::StackTrace>
buildInspectorObject(int maxAsyncDepth) const = 0;
virtual std::unique_ptr<StringBuffer> toString() const = 0;
// Safe to pass between threads, drops async chain.
virtual std::unique_ptr<V8StackTrace> clone() = 0;
};
class V8_EXPORT V8InspectorSession {
public:
virtual ~V8InspectorSession() = default;
// Cross-context inspectable values (DOM nodes in different worlds, etc.).
class V8_EXPORT Inspectable {
public:
virtual v8::Local<v8::Value> get(v8::Local<v8::Context>) = 0;
virtual ~Inspectable() = default;
};
virtual void addInspectedObject(std::unique_ptr<Inspectable>) = 0;
// Dispatching protocol messages.
static bool canDispatchMethod(StringView method);
virtual void dispatchProtocolMessage(StringView message) = 0;
virtual std::vector<uint8_t> state() = 0;
virtual std::vector<std::unique_ptr<protocol::Schema::API::Domain>>
supportedDomains() = 0;
// Debugger actions.
virtual void schedulePauseOnNextStatement(StringView breakReason,
StringView breakDetails) = 0;
virtual void cancelPauseOnNextStatement() = 0;
virtual void breakProgram(StringView breakReason,
StringView breakDetails) = 0;
virtual void setSkipAllPauses(bool) = 0;
virtual void resume(bool setTerminateOnResume = false) = 0;
virtual void stepOver() = 0;
virtual std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>>
searchInTextByLines(StringView text, StringView query, bool caseSensitive,
bool isRegex) = 0;
// Remote objects.
virtual std::unique_ptr<protocol::Runtime::API::RemoteObject> wrapObject(
v8::Local<v8::Context>, v8::Local<v8::Value>, StringView groupName,
bool generatePreview) = 0;
virtual bool unwrapObject(std::unique_ptr<StringBuffer>* error,
StringView objectId, v8::Local<v8::Value>*,
v8::Local<v8::Context>*,
std::unique_ptr<StringBuffer>* objectGroup) = 0;
virtual void releaseObjectGroup(StringView) = 0;
virtual void triggerPreciseCoverageDeltaUpdate(StringView occassion) = 0;
};
class V8_EXPORT V8InspectorClient {
public:
virtual ~V8InspectorClient() = default;
virtual void runMessageLoopOnPause(int contextGroupId) {}
virtual void quitMessageLoopOnPause() {}
virtual void runIfWaitingForDebugger(int contextGroupId) {}
virtual void muteMetrics(int contextGroupId) {}
virtual void unmuteMetrics(int contextGroupId) {}
virtual void beginUserGesture() {}
virtual void endUserGesture() {}
virtual std::unique_ptr<StringBuffer> valueSubtype(v8::Local<v8::Value>) {
return nullptr;
}
virtual std::unique_ptr<StringBuffer> descriptionForValueSubtype(
v8::Local<v8::Context>, v8::Local<v8::Value>) {
return nullptr;
}
virtual bool formatAccessorsAsProperties(v8::Local<v8::Value>) {
return false;
}
virtual bool isInspectableHeapObject(v8::Local<v8::Object>) { return true; }
virtual v8::Local<v8::Context> ensureDefaultContextInGroup(
int contextGroupId) {
return v8::Local<v8::Context>();
}
virtual void beginEnsureAllContextsInGroup(int contextGroupId) {}
virtual void endEnsureAllContextsInGroup(int contextGroupId) {}
virtual void installAdditionalCommandLineAPI(v8::Local<v8::Context>,
v8::Local<v8::Object>) {}
virtual void consoleAPIMessage(int contextGroupId,
v8::Isolate::MessageErrorLevel level,
const StringView& message,
const StringView& url, unsigned lineNumber,
unsigned columnNumber, V8StackTrace*) {}
virtual v8::MaybeLocal<v8::Value> memoryInfo(v8::Isolate*,
v8::Local<v8::Context>) {
return v8::MaybeLocal<v8::Value>();
}
virtual void consoleTime(const StringView& title) {}
virtual void consoleTimeEnd(const StringView& title) {}
virtual void consoleTimeStamp(const StringView& title) {}
virtual void consoleClear(int contextGroupId) {}
virtual double currentTimeMS() { return 0; }
typedef void (*TimerCallback)(void*);
virtual void startRepeatingTimer(double, TimerCallback, void* data) {}
virtual void cancelTimer(void* data) {}
// TODO(dgozman): this was added to support service worker shadow page. We
// should not connect at all.
virtual bool canExecuteScripts(int contextGroupId) { return true; }
virtual void maxAsyncCallStackDepthChanged(int depth) {}
virtual std::unique_ptr<StringBuffer> resourceNameToUrl(
const StringView& resourceName) {
return nullptr;
}
// The caller would defer to generating a random 64 bit integer if
// this method returns 0.
virtual int64_t generateUniqueId() { return 0; }
};
// These stack trace ids are intended to be passed between debuggers and be
// resolved later. This allows to track cross-debugger calls and step between
// them if a single client connects to multiple debuggers.
struct V8_EXPORT V8StackTraceId {
uintptr_t id;
std::pair<int64_t, int64_t> debugger_id;
bool should_pause = false;
V8StackTraceId();
V8StackTraceId(const V8StackTraceId&) = default;
V8StackTraceId(uintptr_t id, const std::pair<int64_t, int64_t> debugger_id);
V8StackTraceId(uintptr_t id, const std::pair<int64_t, int64_t> debugger_id,
bool should_pause);
explicit V8StackTraceId(StringView);
V8StackTraceId& operator=(const V8StackTraceId&) = default;
V8StackTraceId& operator=(V8StackTraceId&&) noexcept = default;
~V8StackTraceId() = default;
bool IsInvalid() const;
std::unique_ptr<StringBuffer> ToString();
};
class V8_EXPORT V8Inspector {
public:
static std::unique_ptr<V8Inspector> create(v8::Isolate*, V8InspectorClient*);
virtual ~V8Inspector() = default;
// Contexts instrumentation.
virtual void contextCreated(const V8ContextInfo&) = 0;
virtual void contextDestroyed(v8::Local<v8::Context>) = 0;
virtual void resetContextGroup(int contextGroupId) = 0;
virtual v8::MaybeLocal<v8::Context> contextById(int contextId) = 0;
// Various instrumentation.
virtual void idleStarted() = 0;
virtual void idleFinished() = 0;
// Async stack traces instrumentation.
virtual void asyncTaskScheduled(StringView taskName, void* task,
bool recurring) = 0;
virtual void asyncTaskCanceled(void* task) = 0;
virtual void asyncTaskStarted(void* task) = 0;
virtual void asyncTaskFinished(void* task) = 0;
virtual void allAsyncTasksCanceled() = 0;
virtual V8StackTraceId storeCurrentStackTrace(StringView description) = 0;
virtual void externalAsyncTaskStarted(const V8StackTraceId& parent) = 0;
virtual void externalAsyncTaskFinished(const V8StackTraceId& parent) = 0;
// Exceptions instrumentation.
virtual unsigned exceptionThrown(v8::Local<v8::Context>, StringView message,
v8::Local<v8::Value> exception,
StringView detailedMessage, StringView url,
unsigned lineNumber, unsigned columnNumber,
std::unique_ptr<V8StackTrace>,
int scriptId) = 0;
virtual void exceptionRevoked(v8::Local<v8::Context>, unsigned exceptionId,
StringView message) = 0;
// Connection.
class V8_EXPORT Channel {
public:
virtual ~Channel() = default;
virtual void sendResponse(int callId,
std::unique_ptr<StringBuffer> message) = 0;
virtual void sendNotification(std::unique_ptr<StringBuffer> message) = 0;
virtual void flushProtocolNotifications() = 0;
};
virtual std::unique_ptr<V8InspectorSession> connect(int contextGroupId,
Channel*,
StringView state) = 0;
// API methods.
virtual std::unique_ptr<V8StackTrace> createStackTrace(
v8::Local<v8::StackTrace>) = 0;
virtual std::unique_ptr<V8StackTrace> captureStackTrace(bool fullStack) = 0;
// Performance counters.
class V8_EXPORT Counters : public std::enable_shared_from_this<Counters> {
public:
explicit Counters(v8::Isolate* isolate);
~Counters();
const std::unordered_map<std::string, int>& getCountersMap() const {
return m_countersMap;
}
private:
static int* getCounterPtr(const char* name);
v8::Isolate* m_isolate;
std::unordered_map<std::string, int> m_countersMap;
};
virtual std::shared_ptr<Counters> enableCounters() = 0;
};
} // namespace v8_inspector
#endif // V8_V8_INSPECTOR_H_

View File

@ -1,464 +0,0 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_V8_INTERNAL_H_
#define INCLUDE_V8_INTERNAL_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <type_traits>
#include "v8-version.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
class Context;
class Data;
class Isolate;
namespace internal {
class Isolate;
typedef uintptr_t Address;
static const Address kNullAddress = 0;
/**
* Configuration of tagging scheme.
*/
const int kApiSystemPointerSize = sizeof(void*);
const int kApiDoubleSize = sizeof(double);
const int kApiInt32Size = sizeof(int32_t);
const int kApiInt64Size = sizeof(int64_t);
// Tag information for HeapObject.
const int kHeapObjectTag = 1;
const int kWeakHeapObjectTag = 3;
const int kHeapObjectTagSize = 2;
const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1;
// Tag information for Smi.
const int kSmiTag = 0;
const int kSmiTagSize = 1;
const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
template <size_t tagged_ptr_size>
struct SmiTagging;
constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1};
constexpr uintptr_t kUintptrAllBitsSet =
static_cast<uintptr_t>(kIntptrAllBitsSet);
// Smi constants for systems where tagged pointer is a 32-bit value.
template <>
struct SmiTagging<4> {
enum { kSmiShiftSize = 0, kSmiValueSize = 31 };
static constexpr intptr_t kSmiMinValue =
static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
V8_INLINE static int SmiToInt(const internal::Address value) {
int shift_bits = kSmiTagSize + kSmiShiftSize;
// Truncate and shift down (requires >> to be sign extending).
return static_cast<int32_t>(static_cast<uint32_t>(value)) >> shift_bits;
}
V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
// Is value in range [kSmiMinValue, kSmiMaxValue].
// Use unsigned operations in order to avoid undefined behaviour in case of
// signed integer overflow.
return (static_cast<uintptr_t>(value) -
static_cast<uintptr_t>(kSmiMinValue)) <=
(static_cast<uintptr_t>(kSmiMaxValue) -
static_cast<uintptr_t>(kSmiMinValue));
}
};
// Smi constants for systems where tagged pointer is a 64-bit value.
template <>
struct SmiTagging<8> {
enum { kSmiShiftSize = 31, kSmiValueSize = 32 };
static constexpr intptr_t kSmiMinValue =
static_cast<intptr_t>(kUintptrAllBitsSet << (kSmiValueSize - 1));
static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1);
V8_INLINE static int SmiToInt(const internal::Address value) {
int shift_bits = kSmiTagSize + kSmiShiftSize;
// Shift down and throw away top 32 bits.
return static_cast<int>(static_cast<intptr_t>(value) >> shift_bits);
}
V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
// To be representable as a long smi, the value must be a 32-bit integer.
return (value == static_cast<int32_t>(value));
}
};
#ifdef V8_COMPRESS_POINTERS
static_assert(
kApiSystemPointerSize == kApiInt64Size,
"Pointer compression can be enabled only for 64-bit architectures");
const int kApiTaggedSize = kApiInt32Size;
#else
const int kApiTaggedSize = kApiSystemPointerSize;
#endif
constexpr bool PointerCompressionIsEnabled() {
return kApiTaggedSize != kApiSystemPointerSize;
}
constexpr bool HeapSandboxIsEnabled() {
#ifdef V8_HEAP_SANDBOX
return true;
#else
return false;
#endif
}
using ExternalPointer_t = Address;
// If the heap sandbox is enabled, these tag values will be XORed with the
// external pointers in the external pointer table to prevent use of pointers of
// the wrong type.
enum ExternalPointerTag : Address {
kExternalPointerNullTag = static_cast<Address>(0ULL),
kArrayBufferBackingStoreTag = static_cast<Address>(1ULL << 48),
kTypedArrayExternalPointerTag = static_cast<Address>(2ULL << 48),
kDataViewDataPointerTag = static_cast<Address>(3ULL << 48),
kExternalStringResourceTag = static_cast<Address>(4ULL << 48),
kExternalStringResourceDataTag = static_cast<Address>(5ULL << 48),
kForeignForeignAddressTag = static_cast<Address>(6ULL << 48),
kNativeContextMicrotaskQueueTag = static_cast<Address>(7ULL << 48),
// TODO(v8:10391, saelo): Currently has to be zero so that raw zero values are
// also nullptr
kEmbedderDataSlotPayloadTag = static_cast<Address>(0ULL << 48),
};
#ifdef V8_31BIT_SMIS_ON_64BIT_ARCH
using PlatformSmiTagging = SmiTagging<kApiInt32Size>;
#else
using PlatformSmiTagging = SmiTagging<kApiTaggedSize>;
#endif
// TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize
// since it's used much more often than the inividual constants.
const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
const int kSmiMinValue = static_cast<int>(PlatformSmiTagging::kSmiMinValue);
const int kSmiMaxValue = static_cast<int>(PlatformSmiTagging::kSmiMaxValue);
constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
V8_INLINE static constexpr internal::Address IntToSmi(int value) {
return (static_cast<Address>(value) << (kSmiTagSize + kSmiShiftSize)) |
kSmiTag;
}
// Converts encoded external pointer to address.
V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate,
ExternalPointer_t pointer,
ExternalPointerTag tag);
// {obj} must be the raw tagged pointer representation of a HeapObject
// that's guaranteed to never be in ReadOnlySpace.
V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
// Returns if we need to throw when an error occurs. This infers the language
// mode based on the current context and the closure. This returns true if the
// language mode is strict.
V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate);
/**
* This class exports constants and functionality from within v8 that
* is necessary to implement inline functions in the v8 api. Don't
* depend on functions and constants defined here.
*/
class Internals {
public:
// These values match non-compiler-dependent values defined within
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size;
static const int kStringResourceOffset =
1 * kApiTaggedSize + 2 * kApiInt32Size;
static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize;
static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
#ifdef V8_HEAP_SANDBOX
static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize;
#endif
static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize;
static const int kFullStringRepresentationMask = 0x0f;
static const int kStringEncodingMask = 0x8;
static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kExternalOneByteRepresentationTag = 0x0a;
static const uint32_t kNumIsolateDataSlots = 4;
// IsolateData layout guarantees.
static const int kIsolateEmbedderDataOffset = 0;
static const int kIsolateFastCCallCallerFpOffset =
kNumIsolateDataSlots * kApiSystemPointerSize;
static const int kIsolateFastCCallCallerPcOffset =
kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
static const int kIsolateFastApiCallTargetOffset =
kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
static const int kIsolateStackGuardOffset =
kIsolateFastApiCallTargetOffset + kApiSystemPointerSize;
static const int kIsolateRootsOffset =
kIsolateStackGuardOffset + 7 * kApiSystemPointerSize;
static const int kExternalPointerTableBufferOffset = 0;
static const int kExternalPointerTableLengthOffset =
kExternalPointerTableBufferOffset + kApiSystemPointerSize;
static const int kExternalPointerTableCapacityOffset =
kExternalPointerTableLengthOffset + kApiInt32Size;
static const int kUndefinedValueRootIndex = 4;
static const int kTheHoleValueRootIndex = 5;
static const int kNullValueRootIndex = 6;
static const int kTrueValueRootIndex = 7;
static const int kFalseValueRootIndex = 8;
static const int kEmptyStringRootIndex = 9;
static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize;
static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3;
static const int kNodeStateMask = 0x7;
static const int kNodeStateIsWeakValue = 2;
static const int kNodeStateIsPendingValue = 3;
static const int kFirstNonstringType = 0x40;
static const int kOddballType = 0x43;
static const int kForeignType = 0x46;
static const int kJSSpecialApiObjectType = 0x410;
static const int kJSApiObjectType = 0x420;
static const int kJSObjectType = 0x421;
static const int kUndefinedOddballKind = 5;
static const int kNullOddballKind = 3;
// Constants used by PropertyCallbackInfo to check if we should throw when an
// error occurs.
static const int kThrowOnError = 0;
static const int kDontThrow = 1;
static const int kInferShouldThrowMode = 2;
// Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an
// incremental GC once the external memory reaches this limit.
static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024;
V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate);
V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
#ifdef V8_ENABLE_CHECKS
CheckInitializedImpl(isolate);
#endif
}
V8_INLINE static bool HasHeapObjectTag(const internal::Address value) {
return (value & kHeapObjectTagMask) == static_cast<Address>(kHeapObjectTag);
}
V8_INLINE static int SmiValue(const internal::Address value) {
return PlatformSmiTagging::SmiToInt(value);
}
V8_INLINE static constexpr internal::Address IntToSmi(int value) {
return internal::IntToSmi(value);
}
V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
return PlatformSmiTagging::IsValidSmi(value);
}
V8_INLINE static int GetInstanceType(const internal::Address obj) {
typedef internal::Address A;
A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset);
return ReadRawField<uint16_t>(map, kMapInstanceTypeOffset);
}
V8_INLINE static int GetOddballKind(const internal::Address obj) {
return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset));
}
V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
int representation = (instance_type & kFullStringRepresentationMask);
return representation == kExternalTwoByteRepresentationTag;
}
V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
return *addr & static_cast<uint8_t>(1U << shift);
}
V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value,
int shift) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
uint8_t mask = static_cast<uint8_t>(1U << shift);
*addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
}
V8_INLINE static uint8_t GetNodeState(internal::Address* obj) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
return *addr & kNodeStateMask;
}
V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
*addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
}
V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot,
void* data) {
internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
kIsolateEmbedderDataOffset +
slot * kApiSystemPointerSize;
*reinterpret_cast<void**>(addr) = data;
}
V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate,
uint32_t slot) {
internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
kIsolateEmbedderDataOffset +
slot * kApiSystemPointerSize;
return *reinterpret_cast<void* const*>(addr);
}
V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) {
internal::Address addr = reinterpret_cast<internal::Address>(isolate) +
kIsolateRootsOffset +
index * kApiSystemPointerSize;
return reinterpret_cast<internal::Address*>(addr);
}
template <typename T>
V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
int offset) {
internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
#ifdef V8_COMPRESS_POINTERS
if (sizeof(T) > kApiTaggedSize) {
// TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
// fields (external pointers, doubles and BigInt data) are only
// kTaggedSize aligned so we have to use unaligned pointer friendly way of
// accessing them in order to avoid undefined behavior in C++ code.
T r;
memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
return r;
}
#endif
return *reinterpret_cast<const T*>(addr);
}
V8_INLINE static internal::Address ReadTaggedPointerField(
internal::Address heap_object_ptr, int offset) {
#ifdef V8_COMPRESS_POINTERS
uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset);
internal::Address base =
GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr);
return base + static_cast<internal::Address>(static_cast<uintptr_t>(value));
#else
return ReadRawField<internal::Address>(heap_object_ptr, offset);
#endif
}
V8_INLINE static internal::Address ReadTaggedSignedField(
internal::Address heap_object_ptr, int offset) {
#ifdef V8_COMPRESS_POINTERS
uint32_t value = ReadRawField<uint32_t>(heap_object_ptr, offset);
return static_cast<internal::Address>(static_cast<uintptr_t>(value));
#else
return ReadRawField<internal::Address>(heap_object_ptr, offset);
#endif
}
V8_INLINE static internal::Isolate* GetIsolateForHeapSandbox(
internal::Address obj) {
#ifdef V8_HEAP_SANDBOX
return internal::IsolateFromNeverReadOnlySpaceObject(obj);
#else
// Not used in non-sandbox mode.
return nullptr;
#endif
}
V8_INLINE static Address DecodeExternalPointer(
const Isolate* isolate, ExternalPointer_t encoded_pointer,
ExternalPointerTag tag) {
#ifdef V8_HEAP_SANDBOX
return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag);
#else
return encoded_pointer;
#endif
}
V8_INLINE static internal::Address ReadExternalPointerField(
internal::Isolate* isolate, internal::Address heap_object_ptr, int offset,
ExternalPointerTag tag) {
#ifdef V8_HEAP_SANDBOX
internal::ExternalPointer_t encoded_value =
ReadRawField<uint32_t>(heap_object_ptr, offset);
// We currently have to treat zero as nullptr in embedder slots.
return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag)
: 0;
#else
return ReadRawField<Address>(heap_object_ptr, offset);
#endif
}
#ifdef V8_COMPRESS_POINTERS
// See v8:7703 or src/ptr-compr.* for details about pointer compression.
static constexpr size_t kPtrComprCageReservationSize = size_t{1} << 32;
static constexpr size_t kPtrComprCageBaseAlignment = size_t{1} << 32;
V8_INLINE static internal::Address GetPtrComprCageBaseFromOnHeapAddress(
internal::Address addr) {
return addr & -static_cast<intptr_t>(kPtrComprCageBaseAlignment);
}
V8_INLINE static internal::Address DecompressTaggedAnyField(
internal::Address heap_object_ptr, uint32_t value) {
internal::Address base =
GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr);
return base + static_cast<internal::Address>(static_cast<uintptr_t>(value));
}
#endif // V8_COMPRESS_POINTERS
};
// Only perform cast check for types derived from v8::Data since
// other types do not implement the Cast method.
template <bool PerformCheck>
struct CastCheck {
template <class T>
static void Perform(T* data);
};
template <>
template <class T>
void CastCheck<true>::Perform(T* data) {
T::Cast(data);
}
template <>
template <class T>
void CastCheck<false>::Perform(T* data) {}
template <class T>
V8_INLINE void PerformCastCheck(T* data) {
CastCheck<std::is_base_of<Data, T>::value &&
!std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
}
// A base class for backing stores, which is needed due to vagaries of
// how static casts work with std::shared_ptr.
class BackingStoreBase {};
} // namespace internal
} // namespace v8
#endif // INCLUDE_V8_INTERNAL_H_

View File

@ -1,189 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_METRICS_H_
#define V8_METRICS_H_
#include "v8.h" // NOLINT(build/include_directory)
namespace v8 {
namespace metrics {
struct GarbageCollectionPhases {
int64_t compact_wall_clock_duration_in_us = -1;
int64_t mark_wall_clock_duration_in_us = -1;
int64_t sweep_wall_clock_duration_in_us = -1;
int64_t weak_wall_clock_duration_in_us = -1;
};
struct GarbageCollectionSizes {
int64_t bytes_before = -1;
int64_t bytes_after = -1;
int64_t bytes_freed = -1;
};
struct GarbageCollectionFullCycle {
GarbageCollectionPhases total;
GarbageCollectionPhases total_cpp;
GarbageCollectionPhases main_thread;
GarbageCollectionPhases main_thread_cpp;
GarbageCollectionPhases main_thread_atomic;
GarbageCollectionPhases main_thread_atomic_cpp;
GarbageCollectionPhases main_thread_incremental;
GarbageCollectionPhases main_thread_incremental_cpp;
GarbageCollectionSizes objects;
GarbageCollectionSizes objects_cpp;
GarbageCollectionSizes memory;
GarbageCollectionSizes memory_cpp;
double collection_rate_in_percent;
double collection_rate_cpp_in_percent;
double efficiency_in_bytes_per_us;
double efficiency_cpp_in_bytes_per_us;
double main_thread_efficiency_in_bytes_per_us;
double main_thread_efficiency_cpp_in_bytes_per_us;
};
struct GarbageCollectionFullMainThreadIncrementalMark {
int64_t wall_clock_duration_in_us = -1;
int64_t cpp_wall_clock_duration_in_us = -1;
};
struct GarbageCollectionFullMainThreadIncrementalSweep {
int64_t wall_clock_duration_in_us = -1;
int64_t cpp_wall_clock_duration_in_us = -1;
};
struct GarbageCollectionYoungCycle {
int64_t total_wall_clock_duration_in_us = -1;
int64_t main_thread_wall_clock_duration_in_us = -1;
double collection_rate_in_percent;
double efficiency_in_bytes_per_us;
double main_thread_efficiency_in_bytes_per_us;
};
struct WasmModuleDecoded {
bool async = false;
bool streamed = false;
bool success = false;
size_t module_size_in_bytes = 0;
size_t function_count = 0;
int64_t wall_clock_duration_in_us = -1;
};
struct WasmModuleCompiled {
bool async = false;
bool streamed = false;
bool cached = false;
bool deserialized = false;
bool lazy = false;
bool success = false;
size_t code_size_in_bytes = 0;
size_t liftoff_bailout_count = 0;
int64_t wall_clock_duration_in_us = -1;
};
struct WasmModuleInstantiated {
bool async = false;
bool success = false;
size_t imported_function_count = 0;
int64_t wall_clock_duration_in_us = -1;
};
struct WasmModuleTieredUp {
bool lazy = false;
size_t code_size_in_bytes = 0;
int64_t wall_clock_duration_in_us = -1;
};
struct WasmModulesPerIsolate {
size_t count = 0;
};
#define V8_MAIN_THREAD_METRICS_EVENTS(V) \
V(GarbageCollectionFullCycle) \
V(GarbageCollectionFullMainThreadIncrementalMark) \
V(GarbageCollectionFullMainThreadIncrementalSweep) \
V(GarbageCollectionYoungCycle) \
V(WasmModuleDecoded) \
V(WasmModuleCompiled) \
V(WasmModuleInstantiated) \
V(WasmModuleTieredUp)
#define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate)
/**
* This class serves as a base class for recording event-based metrics in V8.
* There a two kinds of metrics, those which are expected to be thread-safe and
* whose implementation is required to fulfill this requirement and those whose
* implementation does not have that requirement and only needs to be
* executable on the main thread. If such an event is triggered from a
* background thread, it will be delayed and executed by the foreground task
* runner.
*
* The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS
* macro above while the main thread event are listed in
* V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method
* AddMainThreadEvent(const E& event, v8::Context::Token token) will be
* generated and for the latter AddThreadSafeEvent(const E& event).
*
* Thread-safe events are not allowed to access the context and therefore do
* not carry a context ID with them. These IDs can be generated using
* Recorder::GetContextId() and the ID will be valid throughout the lifetime
* of the isolate. It is not guaranteed that the ID will still resolve to
* a valid context using Recorder::GetContext() at the time the metric is
* recorded. In this case, an empty handle will be returned.
*
* The embedder is expected to call v8::Isolate::SetMetricsRecorder()
* providing its implementation and have the virtual methods overwritten
* for the events it cares about.
*/
class V8_EXPORT Recorder {
public:
// A unique identifier for a context in this Isolate.
// It is guaranteed to not be reused throughout the lifetime of the Isolate.
class ContextId {
public:
ContextId() : id_(kEmptyId) {}
bool IsEmpty() const { return id_ == kEmptyId; }
static const ContextId Empty() { return ContextId{kEmptyId}; }
bool operator==(const ContextId& other) const { return id_ == other.id_; }
bool operator!=(const ContextId& other) const { return id_ != other.id_; }
private:
friend class ::v8::Context;
friend class ::v8::internal::Isolate;
explicit ContextId(uintptr_t id) : id_(id) {}
static constexpr uintptr_t kEmptyId = 0;
uintptr_t id_;
};
virtual ~Recorder() = default;
#define ADD_MAIN_THREAD_EVENT(E) \
virtual void AddMainThreadEvent(const E& event, ContextId context_id) {}
V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT)
#undef ADD_MAIN_THREAD_EVENT
#define ADD_THREAD_SAFE_EVENT(E) \
virtual void AddThreadSafeEvent(const E& event) {}
V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT)
#undef ADD_THREAD_SAFE_EVENT
virtual void NotifyIsolateDisposal() {}
// Return the context with the given id or an empty handle if the context
// was already garbage collected.
static MaybeLocal<Context> GetContext(Isolate* isolate, ContextId id);
// Return the unique id corresponding to the given context.
static ContextId GetContextId(Local<Context> context);
};
} // namespace metrics
} // namespace v8
#endif // V8_METRICS_H_

View File

@ -1,695 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_V8_PLATFORM_H_
#define V8_V8_PLATFORM_H_
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h> // For abort.
#include <memory>
#include <string>
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
class Isolate;
// Valid priorities supported by the task scheduling infrastructure.
enum class TaskPriority : uint8_t {
/**
* Best effort tasks are not critical for performance of the application. The
* platform implementation should preempt such tasks if higher priority tasks
* arrive.
*/
kBestEffort,
/**
* User visible tasks are long running background tasks that will
* improve performance and memory usage of the application upon completion.
* Example: background compilation and garbage collection.
*/
kUserVisible,
/**
* User blocking tasks are highest priority tasks that block the execution
* thread (e.g. major garbage collection). They must be finished as soon as
* possible.
*/
kUserBlocking,
};
/**
* A Task represents a unit of work.
*/
class Task {
public:
virtual ~Task() = default;
virtual void Run() = 0;
};
/**
* An IdleTask represents a unit of work to be performed in idle time.
* The Run method is invoked with an argument that specifies the deadline in
* seconds returned by MonotonicallyIncreasingTime().
* The idle task is expected to complete by this deadline.
*/
class IdleTask {
public:
virtual ~IdleTask() = default;
virtual void Run(double deadline_in_seconds) = 0;
};
/**
* A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to
* post tasks after the isolate gets destructed, but these tasks may not get
* executed anymore. All tasks posted to a given TaskRunner will be invoked in
* sequence. Tasks can be posted from any thread.
*/
class TaskRunner {
public:
/**
* Schedules a task to be invoked by this TaskRunner. The TaskRunner
* implementation takes ownership of |task|.
*/
virtual void PostTask(std::unique_ptr<Task> task) = 0;
/**
* Schedules a task to be invoked by this TaskRunner. The TaskRunner
* implementation takes ownership of |task|. The |task| cannot be nested
* within other task executions.
*
* Tasks which shouldn't be interleaved with JS execution must be posted with
* |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the
* embedder may process tasks in a callback which is called during JS
* execution.
*
* In particular, tasks which execute JS must be non-nestable, since JS
* execution is not allowed to nest.
*
* Requires that |TaskRunner::NonNestableTasksEnabled()| is true.
*/
virtual void PostNonNestableTask(std::unique_ptr<Task> task) {}
/**
* Schedules a task to be invoked by this TaskRunner. The task is scheduled
* after the given number of seconds |delay_in_seconds|. The TaskRunner
* implementation takes ownership of |task|.
*/
virtual void PostDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) = 0;
/**
* Schedules a task to be invoked by this TaskRunner. The task is scheduled
* after the given number of seconds |delay_in_seconds|. The TaskRunner
* implementation takes ownership of |task|. The |task| cannot be nested
* within other task executions.
*
* Tasks which shouldn't be interleaved with JS execution must be posted with
* |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the
* embedder may process tasks in a callback which is called during JS
* execution.
*
* In particular, tasks which execute JS must be non-nestable, since JS
* execution is not allowed to nest.
*
* Requires that |TaskRunner::NonNestableDelayedTasksEnabled()| is true.
*/
virtual void PostNonNestableDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) {}
/**
* Schedules an idle task to be invoked by this TaskRunner. The task is
* scheduled when the embedder is idle. Requires that
* |TaskRunner::IdleTasksEnabled()| is true. Idle tasks may be reordered
* relative to other task types and may be starved for an arbitrarily long
* time if no idle time is available. The TaskRunner implementation takes
* ownership of |task|.
*/
virtual void PostIdleTask(std::unique_ptr<IdleTask> task) = 0;
/**
* Returns true if idle tasks are enabled for this TaskRunner.
*/
virtual bool IdleTasksEnabled() = 0;
/**
* Returns true if non-nestable tasks are enabled for this TaskRunner.
*/
virtual bool NonNestableTasksEnabled() const { return false; }
/**
* Returns true if non-nestable delayed tasks are enabled for this TaskRunner.
*/
virtual bool NonNestableDelayedTasksEnabled() const { return false; }
TaskRunner() = default;
virtual ~TaskRunner() = default;
TaskRunner(const TaskRunner&) = delete;
TaskRunner& operator=(const TaskRunner&) = delete;
};
/**
* Delegate that's passed to Job's worker task, providing an entry point to
* communicate with the scheduler.
*/
class JobDelegate {
public:
/**
* Returns true if this thread should return from the worker task on the
* current thread ASAP. Workers should periodically invoke ShouldYield (or
* YieldIfNeeded()) as often as is reasonable.
*/
virtual bool ShouldYield() = 0;
/**
* Notifies the scheduler that max concurrency was increased, and the number
* of worker should be adjusted accordingly. See Platform::PostJob() for more
* details.
*/
virtual void NotifyConcurrencyIncrease() = 0;
/**
* Returns a task_id unique among threads currently running this job, such
* that GetTaskId() < worker count. To achieve this, the same task_id may be
* reused by a different thread after a worker_task returns.
*/
virtual uint8_t GetTaskId() = 0;
/**
* Returns true if the current task is called from the thread currently
* running JobHandle::Join().
*/
virtual bool IsJoiningThread() const = 0;
};
/**
* Handle returned when posting a Job. Provides methods to control execution of
* the posted Job.
*/
class JobHandle {
public:
virtual ~JobHandle() = default;
/**
* Notifies the scheduler that max concurrency was increased, and the number
* of worker should be adjusted accordingly. See Platform::PostJob() for more
* details.
*/
virtual void NotifyConcurrencyIncrease() = 0;
/**
* Contributes to the job on this thread. Doesn't return until all tasks have
* completed and max concurrency becomes 0. When Join() is called and max
* concurrency reaches 0, it should not increase again. This also promotes
* this Job's priority to be at least as high as the calling thread's
* priority.
*/
virtual void Join() = 0;
/**
* Forces all existing workers to yield ASAP. Waits until they have all
* returned from the Job's callback before returning.
*/
virtual void Cancel() = 0;
/*
* Forces all existing workers to yield ASAP but doesnt wait for them.
* Warning, this is dangerous if the Job's callback is bound to or has access
* to state which may be deleted after this call.
*/
virtual void CancelAndDetach() = 0;
/**
* Returns true if there's any work pending or any worker running.
*/
virtual bool IsActive() = 0;
/**
* Returns true if associated with a Job and other methods may be called.
* Returns false after Join() or Cancel() was called. This may return true
* even if no workers are running and IsCompleted() returns true
*/
virtual bool IsValid() = 0;
/**
* Returns true if job priority can be changed.
*/
virtual bool UpdatePriorityEnabled() const { return false; }
/**
* Update this Job's priority.
*/
virtual void UpdatePriority(TaskPriority new_priority) {}
};
/**
* A JobTask represents work to run in parallel from Platform::PostJob().
*/
class JobTask {
public:
virtual ~JobTask() = default;
virtual void Run(JobDelegate* delegate) = 0;
/**
* Controls the maximum number of threads calling Run() concurrently, given
* the number of threads currently assigned to this job and executing Run().
* Run() is only invoked if the number of threads previously running Run() was
* less than the value returned. Since GetMaxConcurrency() is a leaf function,
* it must not call back any JobHandle methods.
*/
virtual size_t GetMaxConcurrency(size_t worker_count) const = 0;
};
/**
* The interface represents complex arguments to trace events.
*/
class ConvertableToTraceFormat {
public:
virtual ~ConvertableToTraceFormat() = default;
/**
* Append the class info to the provided |out| string. The appended
* data must be a valid JSON object. Strings must be properly quoted, and
* escaped. There is no processing applied to the content after it is
* appended.
*/
virtual void AppendAsTraceFormat(std::string* out) const = 0;
};
/**
* V8 Tracing controller.
*
* Can be implemented by an embedder to record trace events from V8.
*/
class TracingController {
public:
virtual ~TracingController() = default;
// In Perfetto mode, trace events are written using Perfetto's Track Event
// API directly without going through the embedder. However, it is still
// possible to observe tracing being enabled and disabled.
#if !defined(V8_USE_PERFETTO)
/**
* Called by TRACE_EVENT* macros, don't call this directly.
* The name parameter is a category group for example:
* TRACE_EVENT0("v8,parse", "V8.Parse")
* The pointer returned points to a value with zero or more of the bits
* defined in CategoryGroupEnabledFlags.
**/
virtual const uint8_t* GetCategoryGroupEnabled(const char* name) {
static uint8_t no = 0;
return &no;
}
/**
* Adds a trace event to the platform tracing system. These function calls are
* usually the result of a TRACE_* macro from trace_event_common.h when
* tracing and the category of the particular trace are enabled. It is not
* advisable to call these functions on their own; they are really only meant
* to be used by the trace macros. The returned handle can be used by
* UpdateTraceEventDuration to update the duration of COMPLETE events.
*/
virtual uint64_t AddTraceEvent(
char phase, const uint8_t* category_enabled_flag, const char* name,
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values,
std::unique_ptr<ConvertableToTraceFormat>* arg_convertables,
unsigned int flags) {
return 0;
}
virtual uint64_t AddTraceEventWithTimestamp(
char phase, const uint8_t* category_enabled_flag, const char* name,
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values,
std::unique_ptr<ConvertableToTraceFormat>* arg_convertables,
unsigned int flags, int64_t timestamp) {
return 0;
}
/**
* Sets the duration field of a COMPLETE trace event. It must be called with
* the handle returned from AddTraceEvent().
**/
virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
const char* name, uint64_t handle) {}
#endif // !defined(V8_USE_PERFETTO)
class TraceStateObserver {
public:
virtual ~TraceStateObserver() = default;
virtual void OnTraceEnabled() = 0;
virtual void OnTraceDisabled() = 0;
};
/** Adds tracing state change observer. */
virtual void AddTraceStateObserver(TraceStateObserver*) {}
/** Removes tracing state change observer. */
virtual void RemoveTraceStateObserver(TraceStateObserver*) {}
};
/**
* A V8 memory page allocator.
*
* Can be implemented by an embedder to manage large host OS allocations.
*/
class PageAllocator {
public:
virtual ~PageAllocator() = default;
/**
* Gets the page granularity for AllocatePages and FreePages. Addresses and
* lengths for those calls should be multiples of AllocatePageSize().
*/
virtual size_t AllocatePageSize() = 0;
/**
* Gets the page granularity for SetPermissions and ReleasePages. Addresses
* and lengths for those calls should be multiples of CommitPageSize().
*/
virtual size_t CommitPageSize() = 0;
/**
* Sets the random seed so that GetRandomMmapAddr() will generate repeatable
* sequences of random mmap addresses.
*/
virtual void SetRandomMmapSeed(int64_t seed) = 0;
/**
* Returns a randomized address, suitable for memory allocation under ASLR.
* The address will be aligned to AllocatePageSize.
*/
virtual void* GetRandomMmapAddr() = 0;
/**
* Memory permissions.
*/
enum Permission {
kNoAccess,
kRead,
kReadWrite,
kReadWriteExecute,
kReadExecute,
// Set this when reserving memory that will later require kReadWriteExecute
// permissions. The resulting behavior is platform-specific, currently
// this is used to set the MAP_JIT flag on Apple Silicon.
// TODO(jkummerow): Remove this when Wasm has a platform-independent
// w^x implementation.
kNoAccessWillJitLater
};
/**
* Allocates memory in range with the given alignment and permission.
*/
virtual void* AllocatePages(void* address, size_t length, size_t alignment,
Permission permissions) = 0;
/**
* Frees memory in a range that was allocated by a call to AllocatePages.
*/
virtual bool FreePages(void* address, size_t length) = 0;
/**
* Releases memory in a range that was allocated by a call to AllocatePages.
*/
virtual bool ReleasePages(void* address, size_t length,
size_t new_length) = 0;
/**
* Sets permissions on pages in an allocated range.
*/
virtual bool SetPermissions(void* address, size_t length,
Permission permissions) = 0;
/**
* Frees memory in the given [address, address + size) range. address and size
* should be operating system page-aligned. The next write to this
* memory area brings the memory transparently back.
*/
virtual bool DiscardSystemPages(void* address, size_t size) { return true; }
/**
* INTERNAL ONLY: This interface has not been stabilised and may change
* without notice from one release to another without being deprecated first.
*/
class SharedMemoryMapping {
public:
// Implementations are expected to free the shared memory mapping in the
// destructor.
virtual ~SharedMemoryMapping() = default;
virtual void* GetMemory() const = 0;
};
/**
* INTERNAL ONLY: This interface has not been stabilised and may change
* without notice from one release to another without being deprecated first.
*/
class SharedMemory {
public:
// Implementations are expected to free the shared memory in the destructor.
virtual ~SharedMemory() = default;
virtual std::unique_ptr<SharedMemoryMapping> RemapTo(
void* new_address) const = 0;
virtual void* GetMemory() const = 0;
virtual size_t GetSize() const = 0;
};
/**
* INTERNAL ONLY: This interface has not been stabilised and may change
* without notice from one release to another without being deprecated first.
*
* Reserve pages at a fixed address returning whether the reservation is
* possible. The reserved memory is detached from the PageAllocator and so
* should not be freed by it. It's intended for use with
* SharedMemory::RemapTo, where ~SharedMemoryMapping would free the memory.
*/
virtual bool ReserveForSharedMemoryMapping(void* address, size_t size) {
return false;
}
/**
* INTERNAL ONLY: This interface has not been stabilised and may change
* without notice from one release to another without being deprecated first.
*
* Allocates shared memory pages. Not all PageAllocators need support this and
* so this method need not be overridden.
* Allocates a new read-only shared memory region of size |length| and copies
* the memory at |original_address| into it.
*/
virtual std::unique_ptr<SharedMemory> AllocateSharedPages(
size_t length, const void* original_address) {
return {};
}
/**
* INTERNAL ONLY: This interface has not been stabilised and may change
* without notice from one release to another without being deprecated first.
*
* If not overridden and changed to return true, V8 will not attempt to call
* AllocateSharedPages or RemapSharedPages. If overridden, AllocateSharedPages
* and RemapSharedPages must also be overridden.
*/
virtual bool CanAllocateSharedPages() { return false; }
};
/**
* V8 Platform abstraction layer.
*
* The embedder has to provide an implementation of this interface before
* initializing the rest of V8.
*/
class Platform {
public:
virtual ~Platform() = default;
/**
* Allows the embedder to manage memory page allocations.
*/
virtual PageAllocator* GetPageAllocator() {
// TODO(bbudge) Make this abstract after all embedders implement this.
return nullptr;
}
/**
* Enables the embedder to respond in cases where V8 can't allocate large
* blocks of memory. V8 retries the failed allocation once after calling this
* method. On success, execution continues; otherwise V8 exits with a fatal
* error.
* Embedder overrides of this function must NOT call back into V8.
*/
virtual void OnCriticalMemoryPressure() {
// TODO(bbudge) Remove this when embedders override the following method.
// See crbug.com/634547.
}
/**
* Enables the embedder to respond in cases where V8 can't allocate large
* memory regions. The |length| parameter is the amount of memory needed.
* Returns true if memory is now available. Returns false if no memory could
* be made available. V8 will retry allocations until this method returns
* false.
*
* Embedder overrides of this function must NOT call back into V8.
*/
virtual bool OnCriticalMemoryPressure(size_t length) { return false; }
/**
* Gets the number of worker threads used by
* Call(BlockingTask)OnWorkerThread(). This can be used to estimate the number
* of tasks a work package should be split into. A return value of 0 means
* that there are no worker threads available. Note that a value of 0 won't
* prohibit V8 from posting tasks using |CallOnWorkerThread|.
*/
virtual int NumberOfWorkerThreads() = 0;
/**
* Returns a TaskRunner which can be used to post a task on the foreground.
* The TaskRunner's NonNestableTasksEnabled() must be true. This function
* should only be called from a foreground thread.
*/
virtual std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
Isolate* isolate) = 0;
/**
* Schedules a task to be invoked on a worker thread.
*/
virtual void CallOnWorkerThread(std::unique_ptr<Task> task) = 0;
/**
* Schedules a task that blocks the main thread to be invoked with
* high-priority on a worker thread.
*/
virtual void CallBlockingTaskOnWorkerThread(std::unique_ptr<Task> task) {
// Embedders may optionally override this to process these tasks in a high
// priority pool.
CallOnWorkerThread(std::move(task));
}
/**
* Schedules a task to be invoked with low-priority on a worker thread.
*/
virtual void CallLowPriorityTaskOnWorkerThread(std::unique_ptr<Task> task) {
// Embedders may optionally override this to process these tasks in a low
// priority pool.
CallOnWorkerThread(std::move(task));
}
/**
* Schedules a task to be invoked on a worker thread after |delay_in_seconds|
* expires.
*/
virtual void CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
double delay_in_seconds) = 0;
/**
* Returns true if idle tasks are enabled for the given |isolate|.
*/
virtual bool IdleTasksEnabled(Isolate* isolate) { return false; }
/**
* Posts |job_task| to run in parallel. Returns a JobHandle associated with
* the Job, which can be joined or canceled.
* This avoids degenerate cases:
* - Calling CallOnWorkerThread() for each work item, causing significant
* overhead.
* - Fixed number of CallOnWorkerThread() calls that split the work and might
* run for a long time. This is problematic when many components post
* "num cores" tasks and all expect to use all the cores. In these cases,
* the scheduler lacks context to be fair to multiple same-priority requests
* and/or ability to request lower priority work to yield when high priority
* work comes in.
* A canonical implementation of |job_task| looks like:
* class MyJobTask : public JobTask {
* public:
* MyJobTask(...) : worker_queue_(...) {}
* // JobTask:
* void Run(JobDelegate* delegate) override {
* while (!delegate->ShouldYield()) {
* // Smallest unit of work.
* auto work_item = worker_queue_.TakeWorkItem(); // Thread safe.
* if (!work_item) return;
* ProcessWork(work_item);
* }
* }
*
* size_t GetMaxConcurrency() const override {
* return worker_queue_.GetSize(); // Thread safe.
* }
* };
* auto handle = PostJob(TaskPriority::kUserVisible,
* std::make_unique<MyJobTask>(...));
* handle->Join();
*
* PostJob() and methods of the returned JobHandle/JobDelegate, must never be
* called while holding a lock that could be acquired by JobTask::Run or
* JobTask::GetMaxConcurrency -- that could result in a deadlock. This is
* because [1] JobTask::GetMaxConcurrency may be invoked while holding
* internal lock (A), hence JobTask::GetMaxConcurrency can only use a lock (B)
* if that lock is *never* held while calling back into JobHandle from any
* thread (A=>B/B=>A deadlock) and [2] JobTask::Run or
* JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle
* (B=>JobHandle::foo=>B deadlock).
*
* A sufficient PostJob() implementation that uses the default Job provided in
* libplatform looks like:
* std::unique_ptr<JobHandle> PostJob(
* TaskPriority priority, std::unique_ptr<JobTask> job_task) override {
* return v8::platform::NewDefaultJobHandle(
* this, priority, std::move(job_task), NumberOfWorkerThreads());
* }
*/
virtual std::unique_ptr<JobHandle> PostJob(
TaskPriority priority, std::unique_ptr<JobTask> job_task) = 0;
/**
* Monotonically increasing time in seconds from an arbitrary fixed point in
* the past. This function is expected to return at least
* millisecond-precision values. For this reason,
* it is recommended that the fixed point be no further in the past than
* the epoch.
**/
virtual double MonotonicallyIncreasingTime() = 0;
/**
* Current wall-clock time in milliseconds since epoch.
* This function is expected to return at least millisecond-precision values.
*/
virtual double CurrentClockTimeMillis() = 0;
typedef void (*StackTracePrinter)();
/**
* Returns a function pointer that print a stack trace of the current stack
* on invocation. Disables printing of the stack trace if nullptr.
*/
virtual StackTracePrinter GetStackTracePrinter() { return nullptr; }
/**
* Returns an instance of a v8::TracingController. This must be non-nullptr.
*/
virtual TracingController* GetTracingController() = 0;
/**
* Tells the embedder to generate and upload a crashdump during an unexpected
* but non-critical scenario.
*/
virtual void DumpWithoutCrashing() {}
protected:
/**
* Default implementation of current wall-clock time in milliseconds
* since epoch. Useful for implementing |CurrentClockTimeMillis| if
* nothing special needed.
*/
V8_EXPORT static double SystemClockTimeMillis();
};
} // namespace v8
#endif // V8_V8_PLATFORM_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_V8_UNWINDER_STATE_H_
#define INCLUDE_V8_UNWINDER_STATE_H_
namespace v8 {
#ifdef V8_TARGET_ARCH_ARM
struct CalleeSavedRegisters {
void* arm_r4;
void* arm_r5;
void* arm_r6;
void* arm_r7;
void* arm_r8;
void* arm_r9;
void* arm_r10;
};
#elif V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 || \
V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC || \
V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_S390
struct CalleeSavedRegisters {};
#else
#error Target architecture was not detected as supported by v8
#endif
} // namespace v8
#endif // INCLUDE_V8_UNWINDER _STATE_H_

View File

@ -1,652 +0,0 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UTIL_H_
#define V8_UTIL_H_
#include "v8.h" // NOLINT(build/include_directory)
#include <assert.h>
#include <map>
#include <vector>
/**
* Support for Persistent containers.
*
* C++11 embedders can use STL containers with Global values,
* but pre-C++11 does not support the required move semantic and hence
* may want these container classes.
*/
namespace v8 {
typedef uintptr_t PersistentContainerValue;
static const uintptr_t kPersistentContainerNotFound = 0;
enum PersistentContainerCallbackType {
kNotWeak,
// These correspond to v8::WeakCallbackType
kWeakWithParameter,
kWeakWithInternalFields
};
/**
* A default trait implementation for PersistentValueMap which uses std::map
* as a backing map.
*
* Users will have to implement their own weak callbacks & dispose traits.
*/
template<typename K, typename V>
class StdMapTraits {
public:
// STL map & related:
typedef std::map<K, PersistentContainerValue> Impl;
typedef typename Impl::iterator Iterator;
static bool Empty(Impl* impl) { return impl->empty(); }
static size_t Size(Impl* impl) { return impl->size(); }
static void Swap(Impl& a, Impl& b) { std::swap(a, b); } // NOLINT
static Iterator Begin(Impl* impl) { return impl->begin(); }
static Iterator End(Impl* impl) { return impl->end(); }
static K Key(Iterator it) { return it->first; }
static PersistentContainerValue Value(Iterator it) { return it->second; }
static PersistentContainerValue Set(Impl* impl, K key,
PersistentContainerValue value) {
std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
PersistentContainerValue old_value = kPersistentContainerNotFound;
if (!res.second) {
old_value = res.first->second;
res.first->second = value;
}
return old_value;
}
static PersistentContainerValue Get(Impl* impl, K key) {
Iterator it = impl->find(key);
if (it == impl->end()) return kPersistentContainerNotFound;
return it->second;
}
static PersistentContainerValue Remove(Impl* impl, K key) {
Iterator it = impl->find(key);
if (it == impl->end()) return kPersistentContainerNotFound;
PersistentContainerValue value = it->second;
impl->erase(it);
return value;
}
};
/**
* A default trait implementation for PersistentValueMap, which inherits
* a std:map backing map from StdMapTraits and holds non-weak persistent
* objects and has no special Dispose handling.
*
* You should not derive from this class, since MapType depends on the
* surrounding class, and hence a subclass cannot simply inherit the methods.
*/
template<typename K, typename V>
class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
public:
// Weak callback & friends:
static const PersistentContainerCallbackType kCallbackType = kNotWeak;
typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
MapType;
typedef void WeakCallbackDataType;
static WeakCallbackDataType* WeakCallbackParameter(
MapType* map, const K& key, Local<V> value) {
return nullptr;
}
static MapType* MapFromWeakCallbackInfo(
const WeakCallbackInfo<WeakCallbackDataType>& data) {
return nullptr;
}
static K KeyFromWeakCallbackInfo(
const WeakCallbackInfo<WeakCallbackDataType>& data) {
return K();
}
static void DisposeCallbackData(WeakCallbackDataType* data) { }
static void Dispose(Isolate* isolate, Global<V> value, K key) {}
};
template <typename K, typename V>
class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
private:
template <typename T>
struct RemovePointer;
public:
// Weak callback & friends:
static const PersistentContainerCallbackType kCallbackType = kNotWeak;
typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
typedef void WeakCallbackDataType;
static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
Local<V> value) {
return nullptr;
}
static MapType* MapFromWeakCallbackInfo(
const WeakCallbackInfo<WeakCallbackDataType>& data) {
return nullptr;
}
static K KeyFromWeakCallbackInfo(
const WeakCallbackInfo<WeakCallbackDataType>& data) {
return K();
}
static void DisposeCallbackData(WeakCallbackDataType* data) {}
static void OnWeakCallback(
const WeakCallbackInfo<WeakCallbackDataType>& data) {}
static void Dispose(Isolate* isolate, Global<V> value, K key) {}
// This is a second pass callback, so SetSecondPassCallback cannot be called.
static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
private:
template <typename T>
struct RemovePointer<T*> {
typedef T Type;
};
};
/**
* A map wrapper that allows using Global as a mapped value.
* C++11 embedders don't need this class, as they can use Global
* directly in std containers.
*
* The map relies on a backing map, whose type and accessors are described
* by the Traits class. The backing map will handle values of type
* PersistentContainerValue, with all conversion into and out of V8
* handles being transparently handled by this class.
*/
template <typename K, typename V, typename Traits>
class PersistentValueMapBase {
public:
Isolate* GetIsolate() { return isolate_; }
/**
* Return size of the map.
*/
size_t Size() { return Traits::Size(&impl_); }
/**
* Return whether the map holds weak persistents.
*/
bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
/**
* Get value stored in map.
*/
Local<V> Get(const K& key) {
return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
}
/**
* Check whether a value is contained in the map.
*/
bool Contains(const K& key) {
return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
}
/**
* Get value stored in map and set it in returnValue.
* Return true if a value was found.
*/
bool SetReturnValue(const K& key,
ReturnValue<Value> returnValue) {
return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
}
/**
* Return value for key and remove it from the map.
*/
Global<V> Remove(const K& key) {
return Release(Traits::Remove(&impl_, key)).Pass();
}
/**
* Traverses the map repeatedly,
* in case side effects of disposal cause insertions.
**/
void Clear() {
typedef typename Traits::Iterator It;
HandleScope handle_scope(isolate_);
// TODO(dcarney): figure out if this swap and loop is necessary.
while (!Traits::Empty(&impl_)) {
typename Traits::Impl impl;
Traits::Swap(impl_, impl);
for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
Traits::Key(i));
}
}
}
/**
* Helper class for GetReference/SetWithReference. Do not use outside
* that context.
*/
class PersistentValueReference {
public:
PersistentValueReference() : value_(kPersistentContainerNotFound) { }
PersistentValueReference(const PersistentValueReference& other)
: value_(other.value_) { }
Local<V> NewLocal(Isolate* isolate) const {
return Local<V>::New(isolate, FromVal(value_));
}
bool IsEmpty() const {
return value_ == kPersistentContainerNotFound;
}
template<typename T>
bool SetReturnValue(ReturnValue<T> returnValue) {
return SetReturnValueFromVal(&returnValue, value_);
}
void Reset() {
value_ = kPersistentContainerNotFound;
}
void operator=(const PersistentValueReference& other) {
value_ = other.value_;
}
private:
friend class PersistentValueMapBase;
friend class PersistentValueMap<K, V, Traits>;
friend class GlobalValueMap<K, V, Traits>;
explicit PersistentValueReference(PersistentContainerValue value)
: value_(value) { }
void operator=(PersistentContainerValue value) {
value_ = value;
}
PersistentContainerValue value_;
};
/**
* Get a reference to a map value. This enables fast, repeated access
* to a value stored in the map while the map remains unchanged.
*
* Careful: This is potentially unsafe, so please use with care.
* The value will become invalid if the value for this key changes
* in the underlying map, as a result of Set or Remove for the same
* key; as a result of the weak callback for the same key; or as a
* result of calling Clear() or destruction of the map.
*/
PersistentValueReference GetReference(const K& key) {
return PersistentValueReference(Traits::Get(&impl_, key));
}
protected:
explicit PersistentValueMapBase(Isolate* isolate)
: isolate_(isolate), label_(nullptr) {}
PersistentValueMapBase(Isolate* isolate, const char* label)
: isolate_(isolate), label_(label) {}
~PersistentValueMapBase() { Clear(); }
Isolate* isolate() { return isolate_; }
typename Traits::Impl* impl() { return &impl_; }
static V* FromVal(PersistentContainerValue v) {
return reinterpret_cast<V*>(v);
}
static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
V* v = persistent->val_;
persistent->val_ = nullptr;
return reinterpret_cast<PersistentContainerValue>(v);
}
static PersistentContainerValue Leak(Global<V>* persistent) {
return reinterpret_cast<PersistentContainerValue>(persistent->val_);
}
/**
* Return a container value as Global and make sure the weak
* callback is properly disposed of. All remove functionality should go
* through this.
*/
static Global<V> Release(PersistentContainerValue v) {
Global<V> p;
p.val_ = FromVal(v);
if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
Traits::DisposeCallbackData(
p.template ClearWeak<typename Traits::WeakCallbackDataType>());
}
return p.Pass();
}
void RemoveWeak(const K& key) {
Global<V> p;
p.val_ = FromVal(Traits::Remove(&impl_, key));
p.Reset();
}
void AnnotateStrongRetainer(Global<V>* persistent) {
persistent->AnnotateStrongRetainer(label_);
}
private:
PersistentValueMapBase(PersistentValueMapBase&);
void operator=(PersistentValueMapBase&);
static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
PersistentContainerValue value) {
bool hasValue = value != kPersistentContainerNotFound;
if (hasValue) {
returnValue->SetInternal(
*reinterpret_cast<internal::Address*>(FromVal(value)));
}
return hasValue;
}
Isolate* isolate_;
typename Traits::Impl impl_;
const char* label_;
};
template <typename K, typename V, typename Traits>
class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
public:
explicit PersistentValueMap(Isolate* isolate)
: PersistentValueMapBase<K, V, Traits>(isolate) {}
PersistentValueMap(Isolate* isolate, const char* label)
: PersistentValueMapBase<K, V, Traits>(isolate, label) {}
typedef
typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
PersistentValueReference;
/**
* Put value into map. Depending on Traits::kIsWeak, the value will be held
* by the map strongly or weakly.
* Returns old value as Global.
*/
Global<V> Set(const K& key, Local<V> value) {
Global<V> persistent(this->isolate(), value);
return SetUnique(key, &persistent);
}
/**
* Put value into map, like Set(const K&, Local<V>).
*/
Global<V> Set(const K& key, Global<V> value) {
return SetUnique(key, &value);
}
/**
* Put the value into the map, and set the 'weak' callback when demanded
* by the Traits class.
*/
Global<V> SetUnique(const K& key, Global<V>* persistent) {
if (Traits::kCallbackType == kNotWeak) {
this->AnnotateStrongRetainer(persistent);
} else {
WeakCallbackType callback_type =
Traits::kCallbackType == kWeakWithInternalFields
? WeakCallbackType::kInternalFields
: WeakCallbackType::kParameter;
Local<V> value(Local<V>::New(this->isolate(), *persistent));
persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
Traits::WeakCallbackParameter(this, key, value), WeakCallback,
callback_type);
}
PersistentContainerValue old_value =
Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
return this->Release(old_value).Pass();
}
/**
* Put a value into the map and update the reference.
* Restrictions of GetReference apply here as well.
*/
Global<V> Set(const K& key, Global<V> value,
PersistentValueReference* reference) {
*reference = this->Leak(&value);
return SetUnique(key, &value);
}
private:
static void WeakCallback(
const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
if (Traits::kCallbackType != kNotWeak) {
PersistentValueMap<K, V, Traits>* persistentValueMap =
Traits::MapFromWeakCallbackInfo(data);
K key = Traits::KeyFromWeakCallbackInfo(data);
Traits::Dispose(data.GetIsolate(),
persistentValueMap->Remove(key).Pass(), key);
Traits::DisposeCallbackData(data.GetParameter());
}
}
};
template <typename K, typename V, typename Traits>
class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
public:
explicit GlobalValueMap(Isolate* isolate)
: PersistentValueMapBase<K, V, Traits>(isolate) {}
GlobalValueMap(Isolate* isolate, const char* label)
: PersistentValueMapBase<K, V, Traits>(isolate, label) {}
typedef
typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
PersistentValueReference;
/**
* Put value into map. Depending on Traits::kIsWeak, the value will be held
* by the map strongly or weakly.
* Returns old value as Global.
*/
Global<V> Set(const K& key, Local<V> value) {
Global<V> persistent(this->isolate(), value);
return SetUnique(key, &persistent);
}
/**
* Put value into map, like Set(const K&, Local<V>).
*/
Global<V> Set(const K& key, Global<V> value) {
return SetUnique(key, &value);
}
/**
* Put the value into the map, and set the 'weak' callback when demanded
* by the Traits class.
*/
Global<V> SetUnique(const K& key, Global<V>* persistent) {
if (Traits::kCallbackType == kNotWeak) {
this->AnnotateStrongRetainer(persistent);
} else {
WeakCallbackType callback_type =
Traits::kCallbackType == kWeakWithInternalFields
? WeakCallbackType::kInternalFields
: WeakCallbackType::kParameter;
Local<V> value(Local<V>::New(this->isolate(), *persistent));
persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
callback_type);
}
PersistentContainerValue old_value =
Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
return this->Release(old_value).Pass();
}
/**
* Put a value into the map and update the reference.
* Restrictions of GetReference apply here as well.
*/
Global<V> Set(const K& key, Global<V> value,
PersistentValueReference* reference) {
*reference = this->Leak(&value);
return SetUnique(key, &value);
}
private:
static void OnWeakCallback(
const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
if (Traits::kCallbackType != kNotWeak) {
auto map = Traits::MapFromWeakCallbackInfo(data);
K key = Traits::KeyFromWeakCallbackInfo(data);
map->RemoveWeak(key);
Traits::OnWeakCallback(data);
data.SetSecondPassCallback(SecondWeakCallback);
}
}
static void SecondWeakCallback(
const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
Traits::DisposeWeak(data);
}
};
/**
* A map that uses Global as value and std::map as the backing
* implementation. Persistents are held non-weak.
*
* C++11 embedders don't need this class, as they can use
* Global directly in std containers.
*/
template<typename K, typename V,
typename Traits = DefaultPersistentValueMapTraits<K, V> >
class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
public:
explicit StdPersistentValueMap(Isolate* isolate)
: PersistentValueMap<K, V, Traits>(isolate) {}
};
/**
* A map that uses Global as value and std::map as the backing
* implementation. Globals are held non-weak.
*
* C++11 embedders don't need this class, as they can use
* Global directly in std containers.
*/
template <typename K, typename V,
typename Traits = DefaultGlobalMapTraits<K, V> >
class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
public:
explicit StdGlobalValueMap(Isolate* isolate)
: GlobalValueMap<K, V, Traits>(isolate) {}
};
class DefaultPersistentValueVectorTraits {
public:
typedef std::vector<PersistentContainerValue> Impl;
static void Append(Impl* impl, PersistentContainerValue value) {
impl->push_back(value);
}
static bool IsEmpty(const Impl* impl) {
return impl->empty();
}
static size_t Size(const Impl* impl) {
return impl->size();
}
static PersistentContainerValue Get(const Impl* impl, size_t i) {
return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
}
static void ReserveCapacity(Impl* impl, size_t capacity) {
impl->reserve(capacity);
}
static void Clear(Impl* impl) {
impl->clear();
}
};
/**
* A vector wrapper that safely stores Global values.
* C++11 embedders don't need this class, as they can use Global
* directly in std containers.
*
* This class relies on a backing vector implementation, whose type and methods
* are described by the Traits class. The backing map will handle values of type
* PersistentContainerValue, with all conversion into and out of V8
* handles being transparently handled by this class.
*/
template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
class PersistentValueVector {
public:
explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
~PersistentValueVector() {
Clear();
}
/**
* Append a value to the vector.
*/
void Append(Local<V> value) {
Global<V> persistent(isolate_, value);
Traits::Append(&impl_, ClearAndLeak(&persistent));
}
/**
* Append a persistent's value to the vector.
*/
void Append(Global<V> persistent) {
Traits::Append(&impl_, ClearAndLeak(&persistent));
}
/**
* Are there any values in the vector?
*/
bool IsEmpty() const {
return Traits::IsEmpty(&impl_);
}
/**
* How many elements are in the vector?
*/
size_t Size() const {
return Traits::Size(&impl_);
}
/**
* Retrieve the i-th value in the vector.
*/
Local<V> Get(size_t index) const {
return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
}
/**
* Remove all elements from the vector.
*/
void Clear() {
size_t length = Traits::Size(&impl_);
for (size_t i = 0; i < length; i++) {
Global<V> p;
p.val_ = FromVal(Traits::Get(&impl_, i));
}
Traits::Clear(&impl_);
}
/**
* Reserve capacity in the vector.
* (Efficiency gains depend on the backing implementation.)
*/
void ReserveCapacity(size_t capacity) {
Traits::ReserveCapacity(&impl_, capacity);
}
private:
static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
V* v = persistent->val_;
persistent->val_ = nullptr;
return reinterpret_cast<PersistentContainerValue>(v);
}
static V* FromVal(PersistentContainerValue v) {
return reinterpret_cast<V*>(v);
}
Isolate* isolate_;
typename Traits::Impl impl_;
};
} // namespace v8
#endif // V8_UTIL_H

View File

@ -1,24 +0,0 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Compile-time constants.
*
* This header provides access to information about the value serializer at
* compile time, without declaring or defining any symbols that require linking
* to V8.
*/
#ifndef INCLUDE_V8_VALUE_SERIALIZER_VERSION_H_
#define INCLUDE_V8_VALUE_SERIALIZER_VERSION_H_
#include <stdint.h>
namespace v8 {
constexpr uint32_t CurrentValueSerializerFormatVersion() { return 13; }
} // namespace v8
#endif // INCLUDE_V8_VALUE_SERIALIZER_VERSION_H_

View File

@ -1,38 +0,0 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_VERSION_STRING_H_
#define V8_VERSION_STRING_H_
#include "v8-version.h" // NOLINT(build/include_directory)
// This is here rather than v8-version.h to keep that file simple and
// machine-processable.
#if V8_IS_CANDIDATE_VERSION
#define V8_CANDIDATE_STRING " (candidate)"
#else
#define V8_CANDIDATE_STRING ""
#endif
#ifndef V8_EMBEDDER_STRING
#define V8_EMBEDDER_STRING ""
#endif
#define V8_SX(x) #x
#define V8_S(x) V8_SX(x)
#if V8_PATCH_LEVEL > 0
#define V8_VERSION_STRING \
V8_S(V8_MAJOR_VERSION) \
"." V8_S(V8_MINOR_VERSION) "." V8_S(V8_BUILD_NUMBER) "." V8_S( \
V8_PATCH_LEVEL) V8_EMBEDDER_STRING V8_CANDIDATE_STRING
#else
#define V8_VERSION_STRING \
V8_S(V8_MAJOR_VERSION) \
"." V8_S(V8_MINOR_VERSION) "." V8_S(V8_BUILD_NUMBER) \
V8_EMBEDDER_STRING V8_CANDIDATE_STRING
#endif
#endif // V8_VERSION_STRING_H_

View File

@ -1,20 +0,0 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INCLUDE_VERSION_H_ // V8_VERSION_H_ conflicts with src/version.h
#define V8_INCLUDE_VERSION_H_
// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define V8_MAJOR_VERSION 9
#define V8_MINOR_VERSION 1
#define V8_BUILD_NUMBER 269
#define V8_PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define V8_IS_CANDIDATE_VERSION 0
#endif // V8_INCLUDE_VERSION_H_

View File

@ -1,31 +0,0 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_WASM_TRAP_HANDLER_POSIX_H_
#define V8_WASM_TRAP_HANDLER_POSIX_H_
#include <signal.h>
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
/**
* This function determines whether a memory access violation has been an
* out-of-bounds memory access in WebAssembly. If so, it will modify the context
* parameter and add a return address where the execution can continue after the
* signal handling, and return true. Otherwise, false will be returned.
*
* The parameters to this function correspond to those passed to a Posix signal
* handler. Use this function only on Linux and Mac.
*
* \param sig_code The signal code, e.g. SIGSEGV.
* \param info A pointer to the siginfo_t struct provided to the signal handler.
* \param context A pointer to a ucontext_t struct provided to the signal
* handler.
*/
V8_EXPORT bool TryHandleWebAssemblyTrapPosix(int sig_code, siginfo_t* info,
void* context);
} // namespace v8
#endif // V8_WASM_TRAP_HANDLER_POSIX_H_

View File

@ -1,28 +0,0 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_WASM_TRAP_HANDLER_WIN_H_
#define V8_WASM_TRAP_HANDLER_WIN_H_
#include <windows.h>
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
/**
* This function determines whether a memory access violation has been an
* out-of-bounds memory access in WebAssembly. If so, it will modify the
* exception parameter and add a return address where the execution can continue
* after the exception handling, and return true. Otherwise the return value
* will be false.
*
* The parameter to this function corresponds to the one passed to a Windows
* vectored exception handler. Use this function only on Windows.
*
* \param exception An EXCEPTION_POINTERS* as provided to the exception handler.
*/
V8_EXPORT bool TryHandleWebAssemblyTrapWindows(EXCEPTION_POINTERS* exception);
} // namespace v8
#endif // V8_WASM_TRAP_HANDLER_WIN_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,521 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8CONFIG_H_
#define V8CONFIG_H_
#ifdef V8_GN_HEADER
#if __cplusplus >= 201703L && !__has_include("v8-gn.h")
#error Missing v8-gn.h. The configuration for v8 is missing from the include \
path. Add it with -I<path> to the command line
#endif
#include "v8-gn.h" // NOLINT(build/include_directory)
#endif
// clang-format off
// Platform headers for feature detection below.
#if defined(__ANDROID__)
# include <sys/cdefs.h>
#elif defined(__APPLE__)
# include <TargetConditionals.h>
#elif defined(__linux__)
# include <features.h>
#endif
// This macro allows to test for the version of the GNU C library (or
// a compatible C library that masquerades as glibc). It evaluates to
// 0 if libc is not GNU libc or compatible.
// Use like:
// #if V8_GLIBC_PREREQ(2, 3)
// ...
// #endif
#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
# define V8_GLIBC_PREREQ(major, minor) \
((__GLIBC__ * 100 + __GLIBC_MINOR__) >= ((major) * 100 + (minor)))
#else
# define V8_GLIBC_PREREQ(major, minor) 0
#endif
// This macro allows to test for the version of the GNU C++ compiler.
// Note that this also applies to compilers that masquerade as GCC,
// for example clang and the Intel C++ compiler for Linux.
// Use like:
// #if V8_GNUC_PREREQ(4, 3, 1)
// ...
// #endif
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
# define V8_GNUC_PREREQ(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \
((major) * 10000 + (minor) * 100 + (patchlevel)))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
# define V8_GNUC_PREREQ(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= \
((major) * 10000 + (minor) * 100 + (patchlevel)))
#else
# define V8_GNUC_PREREQ(major, minor, patchlevel) 0
#endif
// -----------------------------------------------------------------------------
// Operating system detection (host)
//
// V8_OS_ANDROID - Android
// V8_OS_BSD - BSDish (Mac OS X, Net/Free/Open/DragonFlyBSD)
// V8_OS_CYGWIN - Cygwin
// V8_OS_DRAGONFLYBSD - DragonFlyBSD
// V8_OS_FREEBSD - FreeBSD
// V8_OS_FUCHSIA - Fuchsia
// V8_OS_LINUX - Linux
// V8_OS_MACOSX - Mac OS X
// V8_OS_IOS - iOS
// V8_OS_NETBSD - NetBSD
// V8_OS_OPENBSD - OpenBSD
// V8_OS_POSIX - POSIX compatible (mostly everything except Windows)
// V8_OS_QNX - QNX Neutrino
// V8_OS_SOLARIS - Sun Solaris and OpenSolaris
// V8_OS_STARBOARD - Starboard (platform abstraction for Cobalt)
// V8_OS_AIX - AIX
// V8_OS_WIN - Microsoft Windows
#if defined(__ANDROID__)
# define V8_OS_ANDROID 1
# define V8_OS_LINUX 1
# define V8_OS_POSIX 1
#elif defined(__APPLE__)
# define V8_OS_BSD 1
# define V8_OS_MACOSX 1
# define V8_OS_POSIX 1
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
# define V8_OS_IOS 1
# endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#elif defined(__CYGWIN__)
# define V8_OS_CYGWIN 1
# define V8_OS_POSIX 1
#elif defined(__linux__)
# define V8_OS_LINUX 1
# define V8_OS_POSIX 1
#elif defined(__sun)
# define V8_OS_POSIX 1
# define V8_OS_SOLARIS 1
#elif defined(STARBOARD)
# define V8_OS_STARBOARD 1
#elif defined(_AIX)
#define V8_OS_POSIX 1
#define V8_OS_AIX 1
#elif defined(__FreeBSD__)
# define V8_OS_BSD 1
# define V8_OS_FREEBSD 1
# define V8_OS_POSIX 1
#elif defined(__Fuchsia__)
# define V8_OS_FUCHSIA 1
# define V8_OS_POSIX 1
#elif defined(__DragonFly__)
# define V8_OS_BSD 1
# define V8_OS_DRAGONFLYBSD 1
# define V8_OS_POSIX 1
#elif defined(__NetBSD__)
# define V8_OS_BSD 1
# define V8_OS_NETBSD 1
# define V8_OS_POSIX 1
#elif defined(__OpenBSD__)
# define V8_OS_BSD 1
# define V8_OS_OPENBSD 1
# define V8_OS_POSIX 1
#elif defined(__QNXNTO__)
# define V8_OS_POSIX 1
# define V8_OS_QNX 1
#elif defined(_WIN32)
# define V8_OS_WIN 1
#endif
// -----------------------------------------------------------------------------
// Operating system detection (target)
//
// V8_TARGET_OS_ANDROID
// V8_TARGET_OS_FUCHSIA
// V8_TARGET_OS_IOS
// V8_TARGET_OS_LINUX
// V8_TARGET_OS_MACOSX
// V8_TARGET_OS_WIN
//
// If not set explicitly, these fall back to corresponding V8_OS_ values.
#ifdef V8_HAVE_TARGET_OS
// The target OS is provided, just check that at least one known value is set.
# if !defined(V8_TARGET_OS_ANDROID) \
&& !defined(V8_TARGET_OS_FUCHSIA) \
&& !defined(V8_TARGET_OS_IOS) \
&& !defined(V8_TARGET_OS_LINUX) \
&& !defined(V8_TARGET_OS_MACOSX) \
&& !defined(V8_TARGET_OS_WIN)
# error No known target OS defined.
# endif
#else // V8_HAVE_TARGET_OS
# if defined(V8_TARGET_OS_ANDROID) \
|| defined(V8_TARGET_OS_FUCHSIA) \
|| defined(V8_TARGET_OS_IOS) \
|| defined(V8_TARGET_OS_LINUX) \
|| defined(V8_TARGET_OS_MACOSX) \
|| defined(V8_TARGET_OS_WIN)
# error A target OS is defined but V8_HAVE_TARGET_OS is unset.
# endif
// Fall back to the detected host OS.
#ifdef V8_OS_ANDROID
# define V8_TARGET_OS_ANDROID
#endif
#ifdef V8_OS_FUCHSIA
# define V8_TARGET_OS_FUCHSIA
#endif
#ifdef V8_OS_IOS
# define V8_TARGET_OS_IOS
#endif
#ifdef V8_OS_LINUX
# define V8_TARGET_OS_LINUX
#endif
#ifdef V8_OS_MACOSX
# define V8_TARGET_OS_MACOSX
#endif
#ifdef V8_OS_WIN
# define V8_TARGET_OS_WIN
#endif
#endif // V8_HAVE_TARGET_OS
// -----------------------------------------------------------------------------
// C library detection
//
// V8_LIBC_MSVCRT - MSVC libc
// V8_LIBC_BIONIC - Bionic libc
// V8_LIBC_BSD - BSD libc derivate
// V8_LIBC_GLIBC - GNU C library
// V8_LIBC_UCLIBC - uClibc
//
// Note that testing for libc must be done using #if not #ifdef. For example,
// to test for the GNU C library, use:
// #if V8_LIBC_GLIBC
// ...
// #endif
#if defined (_MSC_VER)
# define V8_LIBC_MSVCRT 1
#elif defined(__BIONIC__)
# define V8_LIBC_BIONIC 1
# define V8_LIBC_BSD 1
#elif defined(__UCLIBC__)
// Must test for UCLIBC before GLIBC, as UCLIBC pretends to be GLIBC.
# define V8_LIBC_UCLIBC 1
#elif defined(__GLIBC__) || defined(__GNU_LIBRARY__)
# define V8_LIBC_GLIBC 1
#else
# define V8_LIBC_BSD V8_OS_BSD
#endif
// -----------------------------------------------------------------------------
// Compiler detection
//
// V8_CC_GNU - GCC, or clang in gcc mode
// V8_CC_INTEL - Intel C++
// V8_CC_MINGW - Minimalist GNU for Windows
// V8_CC_MINGW32 - Minimalist GNU for Windows (mingw32)
// V8_CC_MINGW64 - Minimalist GNU for Windows (mingw-w64)
// V8_CC_MSVC - Microsoft Visual C/C++, or clang in cl.exe mode
//
// C++11 feature detection
//
// Compiler-specific feature detection
//
// V8_HAS_ATTRIBUTE_ALWAYS_INLINE - __attribute__((always_inline))
// supported
// V8_HAS_ATTRIBUTE_NONNULL - __attribute__((nonnull)) supported
// V8_HAS_ATTRIBUTE_NOINLINE - __attribute__((noinline)) supported
// V8_HAS_ATTRIBUTE_UNUSED - __attribute__((unused)) supported
// V8_HAS_ATTRIBUTE_VISIBILITY - __attribute__((visibility)) supported
// V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT - __attribute__((warn_unused_result))
// supported
// V8_HAS_CPP_ATTRIBUTE_NODISCARD - [[nodiscard]] supported
// V8_HAS_BUILTIN_BSWAP16 - __builtin_bswap16() supported
// V8_HAS_BUILTIN_BSWAP32 - __builtin_bswap32() supported
// V8_HAS_BUILTIN_BSWAP64 - __builtin_bswap64() supported
// V8_HAS_BUILTIN_CLZ - __builtin_clz() supported
// V8_HAS_BUILTIN_CTZ - __builtin_ctz() supported
// V8_HAS_BUILTIN_EXPECT - __builtin_expect() supported
// V8_HAS_BUILTIN_FRAME_ADDRESS - __builtin_frame_address() supported
// V8_HAS_BUILTIN_POPCOUNT - __builtin_popcount() supported
// V8_HAS_BUILTIN_SADD_OVERFLOW - __builtin_sadd_overflow() supported
// V8_HAS_BUILTIN_SSUB_OVERFLOW - __builtin_ssub_overflow() supported
// V8_HAS_BUILTIN_UADD_OVERFLOW - __builtin_uadd_overflow() supported
// V8_HAS_COMPUTED_GOTO - computed goto/labels as values
// supported
// V8_HAS_DECLSPEC_NOINLINE - __declspec(noinline) supported
// V8_HAS_DECLSPEC_SELECTANY - __declspec(selectany) supported
// V8_HAS___FORCEINLINE - __forceinline supported
//
// Note that testing for compilers and/or features must be done using #if
// not #ifdef. For example, to test for Intel C++ Compiler, use:
// #if V8_CC_INTEL
// ...
// #endif
#if defined(__has_cpp_attribute)
#define V8_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE)
#else
#define V8_HAS_CPP_ATTRIBUTE(FEATURE) 0
#endif
#if defined(__clang__)
#if defined(__GNUC__) // Clang in gcc mode.
# define V8_CC_GNU 1
#endif
# define V8_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(always_inline))
# define V8_HAS_ATTRIBUTE_NONNULL (__has_attribute(nonnull))
# define V8_HAS_ATTRIBUTE_NOINLINE (__has_attribute(noinline))
# define V8_HAS_ATTRIBUTE_UNUSED (__has_attribute(unused))
# define V8_HAS_ATTRIBUTE_VISIBILITY (__has_attribute(visibility))
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
(__has_attribute(warn_unused_result))
# define V8_HAS_CPP_ATTRIBUTE_NODISCARD (V8_HAS_CPP_ATTRIBUTE(nodiscard))
# define V8_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned))
# define V8_HAS_BUILTIN_BSWAP16 (__has_builtin(__builtin_bswap16))
# define V8_HAS_BUILTIN_BSWAP32 (__has_builtin(__builtin_bswap32))
# define V8_HAS_BUILTIN_BSWAP64 (__has_builtin(__builtin_bswap64))
# define V8_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz))
# define V8_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz))
# define V8_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
# define V8_HAS_BUILTIN_FRAME_ADDRESS (__has_builtin(__builtin_frame_address))
# define V8_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount))
# define V8_HAS_BUILTIN_SADD_OVERFLOW (__has_builtin(__builtin_sadd_overflow))
# define V8_HAS_BUILTIN_SSUB_OVERFLOW (__has_builtin(__builtin_ssub_overflow))
# define V8_HAS_BUILTIN_UADD_OVERFLOW (__has_builtin(__builtin_uadd_overflow))
// Clang has no __has_feature for computed gotos.
// GCC doc: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
# define V8_HAS_COMPUTED_GOTO 1
// Whether constexpr has full C++14 semantics, in particular that non-constexpr
// code is allowed as long as it's not executed for any constexpr instantiation.
# define V8_HAS_CXX14_CONSTEXPR 1
#elif defined(__GNUC__)
# define V8_CC_GNU 1
# if defined(__INTEL_COMPILER) // Intel C++ also masquerades as GCC 3.2.0
# define V8_CC_INTEL 1
# endif
# if defined(__MINGW32__)
# define V8_CC_MINGW32 1
# endif
# if defined(__MINGW64__)
# define V8_CC_MINGW64 1
# endif
# define V8_CC_MINGW (V8_CC_MINGW32 || V8_CC_MINGW64)
// always_inline is available in gcc 4.0 but not very reliable until 4.4.
// Works around "sorry, unimplemented: inlining failed" build errors with
// older compilers.
# define V8_HAS_ATTRIBUTE_ALWAYS_INLINE 1
# define V8_HAS_ATTRIBUTE_NOINLINE 1
# define V8_HAS_ATTRIBUTE_UNUSED 1
# define V8_HAS_ATTRIBUTE_VISIBILITY 1
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT (!V8_CC_INTEL)
# define V8_HAS_CPP_ATTRIBUTE_NODISCARD (V8_HAS_CPP_ATTRIBUTE(nodiscard))
# define V8_HAS_BUILTIN_ASSUME_ALIGNED 1
# define V8_HAS_BUILTIN_CLZ 1
# define V8_HAS_BUILTIN_CTZ 1
# define V8_HAS_BUILTIN_EXPECT 1
# define V8_HAS_BUILTIN_FRAME_ADDRESS 1
# define V8_HAS_BUILTIN_POPCOUNT 1
// GCC doc: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
#define V8_HAS_COMPUTED_GOTO 1
// Whether constexpr has full C++14 semantics, in particular that non-constexpr
// code is allowed as long as it's not executed for any constexpr instantiation.
// GCC only supports this since version 6.
# define V8_HAS_CXX14_CONSTEXPR (V8_GNUC_PREREQ(6, 0, 0))
#endif
#if defined(_MSC_VER)
# define V8_CC_MSVC 1
# define V8_HAS_DECLSPEC_NOINLINE 1
# define V8_HAS_DECLSPEC_SELECTANY 1
# define V8_HAS___FORCEINLINE 1
#endif
// -----------------------------------------------------------------------------
// Helper macros
// A macro used to make better inlining. Don't bother for debug builds.
// Use like:
// V8_INLINE int GetZero() { return 0; }
#if !defined(DEBUG) && V8_HAS_ATTRIBUTE_ALWAYS_INLINE
# define V8_INLINE inline __attribute__((always_inline))
#elif !defined(DEBUG) && V8_HAS___FORCEINLINE
# define V8_INLINE __forceinline
#else
# define V8_INLINE inline
#endif
#if V8_HAS_BUILTIN_ASSUME_ALIGNED
# define V8_ASSUME_ALIGNED(ptr, alignment) \
__builtin_assume_aligned((ptr), (alignment))
#else
# define V8_ASSUME_ALIGNED(ptr, alignment) (ptr)
#endif
// A macro to mark specific arguments as non-null.
// Use like:
// int add(int* x, int y, int* z) V8_NONNULL(1, 3) { return *x + y + *z; }
#if V8_HAS_ATTRIBUTE_NONNULL
# define V8_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
#else
# define V8_NONNULL(...) /* NOT SUPPORTED */
#endif
// A macro used to tell the compiler to never inline a particular function.
// Use like:
// V8_NOINLINE int GetMinusOne() { return -1; }
#if V8_HAS_ATTRIBUTE_NOINLINE
# define V8_NOINLINE __attribute__((noinline))
#elif V8_HAS_DECLSPEC_NOINLINE
# define V8_NOINLINE __declspec(noinline)
#else
# define V8_NOINLINE /* NOT SUPPORTED */
#endif
// A macro (V8_DEPRECATED) to mark classes or functions as deprecated.
#if defined(V8_DEPRECATION_WARNINGS)
# define V8_DEPRECATED(message) [[deprecated(message)]]
#else
# define V8_DEPRECATED(message)
#endif
// A macro (V8_DEPRECATE_SOON) to make it easier to see what will be deprecated.
#if defined(V8_IMMINENT_DEPRECATION_WARNINGS)
# define V8_DEPRECATE_SOON(message) [[deprecated(message)]]
#else
# define V8_DEPRECATE_SOON(message)
#endif
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 6)
# define V8_ENUM_DEPRECATED(message)
# define V8_ENUM_DEPRECATE_SOON(message)
#else
# define V8_ENUM_DEPRECATED(message) V8_DEPRECATED(message)
# define V8_ENUM_DEPRECATE_SOON(message) V8_DEPRECATE_SOON(message)
#endif
// A macro to provide the compiler with branch prediction information.
#if V8_HAS_BUILTIN_EXPECT
# define V8_UNLIKELY(condition) (__builtin_expect(!!(condition), 0))
# define V8_LIKELY(condition) (__builtin_expect(!!(condition), 1))
#else
# define V8_UNLIKELY(condition) (condition)
# define V8_LIKELY(condition) (condition)
#endif
// Annotate a function indicating the caller must examine the return value.
// Use like:
// int foo() V8_WARN_UNUSED_RESULT;
#if V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT
#define V8_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define V8_WARN_UNUSED_RESULT /* NOT SUPPORTED */
#endif
// Annotate a class or constructor indicating the caller must assign the
// constructed instances.
// Apply to the whole class like:
// class V8_NODISCARD Foo() { ... };
// or apply to just one constructor like:
// V8_NODISCARD Foo() { ... };
// [[nodiscard]] comes in C++17 but supported in clang with -std >= c++11.
#if V8_HAS_CPP_ATTRIBUTE_NODISCARD
#define V8_NODISCARD [[nodiscard]]
#else
#define V8_NODISCARD /* NOT SUPPORTED */
#endif
// Helper macro to define no_sanitize attributes only with clang.
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
#define V8_CLANG_NO_SANITIZE(what) __attribute__((no_sanitize(what)))
#endif
#endif
#if !defined(V8_CLANG_NO_SANITIZE)
#define V8_CLANG_NO_SANITIZE(what)
#endif
#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED)
#error Inconsistent build configuration: To build the V8 shared library \
set BUILDING_V8_SHARED, to include its headers for linking against the \
V8 shared library set USING_V8_SHARED.
#endif
#ifdef V8_OS_WIN
// Setup for Windows DLL export/import. When building the V8 DLL the
// BUILDING_V8_SHARED needs to be defined. When building a program which uses
// the V8 DLL USING_V8_SHARED needs to be defined. When either building the V8
// static library or building a program which uses the V8 static library neither
// BUILDING_V8_SHARED nor USING_V8_SHARED should be defined.
#ifdef BUILDING_V8_SHARED
# define V8_EXPORT __declspec(dllexport)
#elif USING_V8_SHARED
# define V8_EXPORT __declspec(dllimport)
#else
# define V8_EXPORT
#endif // BUILDING_V8_SHARED
#else // V8_OS_WIN
// Setup for Linux shared library export.
#if V8_HAS_ATTRIBUTE_VISIBILITY
# ifdef BUILDING_V8_SHARED
# define V8_EXPORT __attribute__ ((visibility("default")))
# else
# define V8_EXPORT
# endif
#else
# define V8_EXPORT
#endif
#endif // V8_OS_WIN
// clang-format on
#undef V8_HAS_CPP_ATTRIBUTE
#endif // V8CONFIG_H_

View File

@ -1,72 +0,0 @@
# The V8 public C++ API
# Overview
The V8 public C++ API aims to support four use cases:
1. Enable applications that embed V8 (called the embedder) to configure and run
one or more instances of V8.
2. Expose ECMAScript-like capabilities to the embedder.
3. Enable the embedder to interact with ECMAScript by exposing API objects.
4. Provide access to the V8 debugger (inspector).
# Configuring and running an instance of V8
V8 requires access to certain OS-level primitives such as the ability to
schedule work on threads, or allocate memory.
The embedder can define how to access those primitives via the v8::Platform
interface. While V8 bundles a basic implementation, embedders are highly
encouraged to implement v8::Platform themselves.
Currently, the v8::ArrayBuffer::Allocator is passed to the v8::Isolate factory
method, however, conceptually it should also be part of the v8::Platform since
all instances of V8 should share one allocator.
Once the v8::Platform is configured, an v8::Isolate can be created. All
further interactions with V8 should explicitly reference the v8::Isolate they
refer to. All API methods should eventually take an v8::Isolate parameter.
When a given instance of V8 is no longer needed, it can be destroyed by
disposing the respective v8::Isolate. If the embedder wishes to free all memory
associated with the v8::Isolate, it has to first clear all global handles
associated with that v8::Isolate.
# ECMAScript-like capabilities
In general, the C++ API shouldn't enable capabilities that aren't available to
scripts running in V8. Experience has shown that it's not possible to maintain
such API methods in the long term. However, capabilities also available to
scripts, i.e., ones that are defined in the ECMAScript standard are there to
stay, and we can safely expose them to embedders.
The C++ API should also be pleasant to use, and not require learning new
paradigms. Similarly to how the API exposed to scripts aims to provide good
ergonomics, we should aim to provide a reasonable developer experience for this
API surface.
ECMAScript makes heavy use of exceptions, however, V8's C++ code doesn't use
C++ exceptions. Therefore, all API methods that can throw exceptions should
indicate so by returning a v8::Maybe&lt;&gt; or v8::MaybeLocal&lt;&gt; result,
and by taking a v8::Local&lt;v8::Context&gt; parameter that indicates in which
context a possible exception should be thrown.
# API objects
V8 allows embedders to define special objects that expose additional
capabilities and APIs to scripts. The most prominent example is exposing the
HTML DOM in Blink. Other examples are e.g. node.js. It is less clear what kind
of capabilities we want to expose via this API surface. As a rule of thumb, we
want to expose operations as defined in the WebIDL and HTML spec: we
assume that those requirements are somewhat stable, and that they are a
superset of the requirements of other embedders including node.js.
Ideally, the API surfaces defined in those specs hook into the ECMAScript spec
which in turn guarantees long-term stability of the API.
# The V8 inspector
All debugging capabilities of V8 should be exposed via the inspector protocol.
The exception to this are profiling features exposed via v8-profiler.h.
Changes to the inspector protocol need to ensure backwards compatibility and
commitment to maintain.

View File

@ -1,10 +0,0 @@
include_rules = [
# v8-inspector-protocol.h depends on generated files under include/inspector.
"+inspector",
"+cppgc/common.h",
# Used by v8-cppgc.h to bridge to cppgc.
"+cppgc/custom-space.h",
"+cppgc/heap-statistics.h",
"+cppgc/internal/write-barrier.h",
"+cppgc/visitor.h",
]

View File

@ -1,11 +0,0 @@
# Metadata information for this directory.
#
# For more information on DIR_METADATA files, see:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
#
# For the schema of this file, see Metadata message:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
monorail {
component: "Blink>JavaScript>API"
}

View File

@ -1,18 +0,0 @@
adamk@chromium.org
cbruni@chromium.org
leszeks@chromium.org
mlippautz@chromium.org
ulan@chromium.org
verwaest@chromium.org
yangguo@chromium.org
per-file *DEPS=file:../COMMON_OWNERS
per-file v8-internal.h=file:../COMMON_OWNERS
per-file v8-inspector.h=file:../src/inspector/OWNERS
per-file v8-inspector-protocol.h=file:../src/inspector/OWNERS
per-file js_protocol.pdl=file:../src/inspector/OWNERS
# For branch updates:
per-file v8-version.h=file:../INFRA_OWNERS
per-file v8-version.h=hablich@chromium.org
per-file v8-version.h=vahl@chromium.org

View File

@ -1,8 +0,0 @@
include_rules = [
"-include",
"+v8config.h",
"+v8-platform.h",
"+cppgc",
"-src",
"+libplatform/libplatform.h",
]

View File

@ -1,2 +0,0 @@
bikineev@chromium.org
omerkatz@chromium.org

View File

@ -1,5 +0,0 @@
# C++ Garbage Collection
This directory provides an open-source garbage collection library for C++.
The library is under construction, meaning that *all APIs in this directory are incomplete and considered unstable and should not be used*.

View File

@ -1,232 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_ALLOCATION_H_
#define INCLUDE_CPPGC_ALLOCATION_H_
#include <stdint.h>
#include <atomic>
#include "cppgc/custom-space.h"
#include "cppgc/garbage-collected.h"
#include "cppgc/internal/api-constants.h"
#include "cppgc/internal/gc-info.h"
namespace cppgc {
template <typename T>
class MakeGarbageCollectedTraitBase;
namespace internal {
class ObjectAllocator;
} // namespace internal
/**
* AllocationHandle is used to allocate garbage-collected objects.
*/
class AllocationHandle;
namespace internal {
class V8_EXPORT MakeGarbageCollectedTraitInternal {
protected:
static inline void MarkObjectAsFullyConstructed(const void* payload) {
// See api_constants for an explanation of the constants.
std::atomic<uint16_t>* atomic_mutable_bitfield =
reinterpret_cast<std::atomic<uint16_t>*>(
const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
reinterpret_cast<const uint8_t*>(payload) -
api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
atomic_mutable_bitfield->fetch_or(api_constants::kFullyConstructedBitMask,
std::memory_order_release);
}
template <typename U, typename CustomSpace>
struct SpacePolicy {
static void* Allocate(AllocationHandle& handle, size_t size) {
// Custom space.
static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
"Custom space must inherit from CustomSpaceBase.");
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, internal::GCInfoTrait<U>::Index(),
CustomSpace::kSpaceIndex);
}
};
template <typename U>
struct SpacePolicy<U, void> {
static void* Allocate(AllocationHandle& handle, size_t size) {
// Default space.
return MakeGarbageCollectedTraitInternal::Allocate(
handle, size, internal::GCInfoTrait<U>::Index());
}
};
private:
static void* Allocate(cppgc::AllocationHandle& handle, size_t size,
GCInfoIndex index);
static void* Allocate(cppgc::AllocationHandle& handle, size_t size,
GCInfoIndex index, CustomSpaceIndex space_index);
friend class HeapObjectHeader;
};
} // namespace internal
/**
* Base trait that provides utilities for advancers users that have custom
* allocation needs (e.g., overriding size). It's expected that users override
* MakeGarbageCollectedTrait (see below) and inherit from
* MakeGarbageCollectedTraitBase and make use of the low-level primitives
* offered to allocate and construct an object.
*/
template <typename T>
class MakeGarbageCollectedTraitBase
: private internal::MakeGarbageCollectedTraitInternal {
private:
static_assert(internal::IsGarbageCollectedType<T>::value,
"T needs to be a garbage collected object");
static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
sizeof(T) <=
internal::api_constants::kLargeObjectSizeThreshold,
"GarbageCollectedMixin may not be a large object");
protected:
/**
* Allocates memory for an object of type T.
*
* \param handle AllocationHandle identifying the heap to allocate the object
* on.
* \param size The size that should be reserved for the object.
* \returns the memory to construct an object of type T on.
*/
V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
return SpacePolicy<
typename internal::GCInfoFolding<
T, typename T::ParentMostGarbageCollectedType>::ResultType,
typename SpaceTrait<T>::Space>::Allocate(handle, size);
}
/**
* Marks an object as fully constructed, resulting in precise handling by the
* garbage collector.
*
* \param payload The base pointer the object is allocated at.
*/
V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
payload);
}
};
/**
* Passed to MakeGarbageCollected to specify how many bytes should be appended
* to the allocated object.
*
* Example:
* \code
* class InlinedArray final : public GarbageCollected<InlinedArray> {
* public:
* explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
* void Trace(Visitor*) const {}
* size_t size;
* char* byte_array;
* };
*
* auto* inlined_array = MakeGarbageCollected<InlinedArray(
* GetAllocationHandle(), AdditionalBytes(4), 4);
* for (size_t i = 0; i < 4; i++) {
* Process(inlined_array->byte_array[i]);
* }
* \endcode
*/
struct AdditionalBytes {
constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
const size_t value;
};
/**
* Default trait class that specifies how to construct an object of type T.
* Advanced users may override how an object is constructed using the utilities
* that are provided through MakeGarbageCollectedTraitBase.
*
* Any trait overriding construction must
* - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
* - mark the object as fully constructed using
* `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
*/
template <typename T>
class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> {
public:
template <typename... Args>
static T* Call(AllocationHandle& handle, Args&&... args) {
void* memory =
MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
T* object = ::new (memory) T(std::forward<Args>(args)...);
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
return object;
}
template <typename... Args>
static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
Args&&... args) {
void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
handle, sizeof(T) + additional_bytes.value);
T* object = ::new (memory) T(std::forward<Args>(args)...);
MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
return object;
}
};
/**
* Allows users to specify a post-construction callback for specific types. The
* callback is invoked on the instance of type T right after it has been
* constructed. This can be useful when the callback requires a
* fully-constructed object to be able to dispatch to virtual methods.
*/
template <typename T, typename = void>
struct PostConstructionCallbackTrait {
static void Call(T*) {}
};
/**
* Constructs a managed object of type T where T transitively inherits from
* GarbageCollected.
*
* \param args List of arguments with which an instance of T will be
* constructed.
* \returns an instance of type T.
*/
template <typename T, typename... Args>
T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
T* object =
MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
PostConstructionCallbackTrait<T>::Call(object);
return object;
}
/**
* Constructs a managed object of type T where T transitively inherits from
* GarbageCollected. Created objects will have additional bytes appended to
* it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
*
* \param additional_bytes Denotes how many bytes to append to T.
* \param args List of arguments with which an instance of T will be
* constructed.
* \returns an instance of type T.
*/
template <typename T, typename... Args>
T* MakeGarbageCollected(AllocationHandle& handle,
AdditionalBytes additional_bytes, Args&&... args) {
T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
std::forward<Args>(args)...);
PostConstructionCallbackTrait<T>::Call(object);
return object;
}
} // namespace cppgc
#endif // INCLUDE_CPPGC_ALLOCATION_H_

View File

@ -1,29 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_COMMON_H_
#define INCLUDE_CPPGC_COMMON_H_
// TODO(chromium:1056170): Remove dependency on v8.
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* Indicator for the stack state of the embedder.
*/
enum class EmbedderStackState {
/**
* Stack may contain interesting heap pointers.
*/
kMayContainHeapPointers,
/**
* Stack does not contain any interesting heap pointers.
*/
kNoHeapPointers,
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_COMMON_H_

View File

@ -1,384 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
#include <atomic>
#include "cppgc/internal/persistent-node.h"
#include "cppgc/internal/pointer-policies.h"
#include "cppgc/persistent.h"
#include "cppgc/visitor.h"
namespace cppgc {
namespace internal {
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
typename CheckingPolicy>
class BasicCrossThreadPersistent final : public PersistentBase,
public LocationPolicy,
private WeaknessPolicy,
private CheckingPolicy {
public:
using typename WeaknessPolicy::IsStrongPersistent;
using PointeeType = T;
~BasicCrossThreadPersistent() { Clear(); }
BasicCrossThreadPersistent( // NOLINT
const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicCrossThreadPersistent( // NOLINT
std::nullptr_t, const SourceLocation& loc = SourceLocation::Current())
: LocationPolicy(loc) {}
BasicCrossThreadPersistent( // NOLINT
SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(s), LocationPolicy(loc) {}
BasicCrossThreadPersistent( // NOLINT
T* raw, const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(raw), LocationPolicy(loc) {
if (!IsValid(raw)) return;
PersistentRegionLock guard;
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
SetNode(region.AllocateNode(this, &Trace));
this->CheckPointer(raw);
}
class UnsafeCtorTag {
private:
UnsafeCtorTag() = default;
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy>
friend class BasicCrossThreadPersistent;
};
BasicCrossThreadPersistent( // NOLINT
UnsafeCtorTag, T* raw,
const SourceLocation& loc = SourceLocation::Current())
: PersistentBase(raw), LocationPolicy(loc) {
if (!IsValid(raw)) return;
CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
SetNode(region.AllocateNode(this, &Trace));
this->CheckPointer(raw);
}
BasicCrossThreadPersistent( // NOLINT
T& raw, const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(&raw, loc) {}
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent( // NOLINT
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy>
member,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(member.Get(), loc) {}
BasicCrossThreadPersistent(
const BasicCrossThreadPersistent& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(loc) {
// Invoke operator=.
*this = other;
}
// Heterogeneous ctor.
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent( // NOLINT
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
OtherLocationPolicy,
OtherCheckingPolicy>& other,
const SourceLocation& loc = SourceLocation::Current())
: BasicCrossThreadPersistent(loc) {
*this = other;
}
BasicCrossThreadPersistent(
BasicCrossThreadPersistent&& other,
const SourceLocation& loc = SourceLocation::Current()) noexcept {
// Invoke operator=.
*this = std::move(other);
}
BasicCrossThreadPersistent& operator=(
const BasicCrossThreadPersistent& other) {
PersistentRegionLock guard;
AssignUnsafe(other.Get());
return *this;
}
template <typename U, typename OtherWeaknessPolicy,
typename OtherLocationPolicy, typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent& operator=(
const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
OtherLocationPolicy,
OtherCheckingPolicy>& other) {
PersistentRegionLock guard;
AssignUnsafe(other.Get());
return *this;
}
BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
if (this == &other) return *this;
Clear();
PersistentRegionLock guard;
PersistentBase::operator=(std::move(other));
LocationPolicy::operator=(std::move(other));
if (!IsValid(GetValue())) return *this;
GetNode()->UpdateOwner(this);
other.SetValue(nullptr);
other.SetNode(nullptr);
this->CheckPointer(GetValue());
return *this;
}
BasicCrossThreadPersistent& operator=(T* other) {
Assign(other);
return *this;
}
// Assignment from member.
template <typename U, typename MemberBarrierPolicy,
typename MemberWeaknessTag, typename MemberCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicCrossThreadPersistent& operator=(
internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
MemberCheckingPolicy>
member) {
return operator=(member.Get());
}
BasicCrossThreadPersistent& operator=(std::nullptr_t) {
Clear();
return *this;
}
BasicCrossThreadPersistent& operator=(SentinelPointer s) {
Assign(s);
return *this;
}
/**
* Returns a pointer to the stored object.
*
* Note: **Not thread-safe.**
*
* \returns a pointer to the stored object.
*/
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
return static_cast<T*>(const_cast<void*>(GetValue()));
}
/**
* Clears the stored object.
*/
void Clear() {
// Simplified version of `Assign()` to allow calling without a complete type
// `T`.
const void* old_value = GetValue();
if (IsValid(old_value)) {
PersistentRegionLock guard;
old_value = GetValue();
// The fast path check (IsValid()) does not acquire the lock. Reload
// the value to ensure the reference has not been cleared.
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
region.FreeNode(GetNode());
SetNode(nullptr);
} else {
CPPGC_DCHECK(!GetNode());
}
}
SetValue(nullptr);
}
/**
* Returns a pointer to the stored object and releases it.
*
* Note: **Not thread-safe.**
*
* \returns a pointer to the stored object.
*/
T* Release() {
T* result = Get();
Clear();
return result;
}
/**
* Conversio to boolean.
*
* Note: **Not thread-safe.**
*
* \returns true if an actual object has been stored and false otherwise.
*/
explicit operator bool() const { return Get(); }
/**
* Conversion to object of type T.
*
* Note: **Not thread-safe.**
*
* \returns the object.
*/
operator T*() const { return Get(); } // NOLINT
/**
* Dereferences the stored object.
*
* Note: **Not thread-safe.**
*/
T* operator->() const { return Get(); }
T& operator*() const { return *Get(); }
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
typename OtherLocationPolicy = LocationPolicy,
typename OtherCheckingPolicy = CheckingPolicy>
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>
To() const {
using OtherBasicCrossThreadPersistent =
BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
OtherCheckingPolicy>;
PersistentRegionLock guard;
return OtherBasicCrossThreadPersistent(
typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
static_cast<U*>(Get()));
}
template <typename U = T,
typename = typename std::enable_if<!BasicCrossThreadPersistent<
U, WeaknessPolicy>::IsStrongPersistent::value>::type>
BasicCrossThreadPersistent<U, internal::StrongCrossThreadPersistentPolicy>
Lock() const {
return BasicCrossThreadPersistent<
U, internal::StrongCrossThreadPersistentPolicy>(*this);
}
private:
static bool IsValid(const void* ptr) {
return ptr && ptr != kSentinelPointer;
}
static void Trace(Visitor* v, const void* ptr) {
const auto* handle = static_cast<const BasicCrossThreadPersistent*>(ptr);
v->TraceRoot(*handle, handle->Location());
}
void Assign(T* ptr) {
const void* old_value = GetValue();
if (IsValid(old_value)) {
PersistentRegionLock guard;
old_value = GetValue();
// The fast path check (IsValid()) does not acquire the lock. Reload
// the value to ensure the reference has not been cleared.
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
if (IsValid(ptr) && (&region == &this->GetPersistentRegion(ptr))) {
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
region.FreeNode(GetNode());
SetNode(nullptr);
} else {
CPPGC_DCHECK(!GetNode());
}
}
SetValue(ptr);
if (!IsValid(ptr)) return;
PersistentRegionLock guard;
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace));
this->CheckPointer(ptr);
}
void AssignUnsafe(T* ptr) {
PersistentRegionLock::AssertLocked();
const void* old_value = GetValue();
if (IsValid(old_value)) {
CrossThreadPersistentRegion& region =
this->GetPersistentRegion(old_value);
if (IsValid(ptr) && (&region == &this->GetPersistentRegion(ptr))) {
SetValue(ptr);
this->CheckPointer(ptr);
return;
}
region.FreeNode(GetNode());
SetNode(nullptr);
}
SetValue(ptr);
if (!IsValid(ptr)) return;
SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace));
this->CheckPointer(ptr);
}
void ClearFromGC() const {
if (IsValid(GetValue())) {
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
PersistentBase::ClearFromGC();
}
}
friend class cppgc::Visitor;
};
template <typename T, typename LocationPolicy, typename CheckingPolicy>
struct IsWeak<
BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy,
LocationPolicy, CheckingPolicy>>
: std::true_type {};
} // namespace internal
namespace subtle {
/**
* **DO NOT USE: Has known caveats, see below.**
*
* CrossThreadPersistent allows retaining objects from threads other than the
* thread the owning heap is operating on.
*
* Known caveats:
* - Does not protect the heap owning an object from terminating.
* - Reaching transitively through the graph is unsupported as objects may be
* moved concurrently on the thread owning the object.
*/
template <typename T>
using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
T, internal::StrongCrossThreadPersistentPolicy>;
/**
* **DO NOT USE: Has known caveats, see below.**
*
* CrossThreadPersistent allows weakly retaining objects from threads other than
* the thread the owning heap is operating on.
*
* Known caveats:
* - Does not protect the heap owning an object from terminating.
* - Reaching transitively through the graph is unsupported as objects may be
* moved concurrently on the thread owning the object.
*/
template <typename T>
using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
T, internal::WeakCrossThreadPersistentPolicy>;
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_

View File

@ -1,97 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_
#define INCLUDE_CPPGC_CUSTOM_SPACE_H_
#include <stddef.h>
namespace cppgc {
/**
* Index identifying a custom space.
*/
struct CustomSpaceIndex {
constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT
size_t value;
};
/**
* Top-level base class for custom spaces. Users must inherit from CustomSpace
* below.
*/
class CustomSpaceBase {
public:
virtual ~CustomSpaceBase() = default;
virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0;
virtual bool IsCompactable() const = 0;
};
/**
* Base class custom spaces should directly inherit from. The class inheriting
* from `CustomSpace` must define `kSpaceIndex` as unique space index. These
* indices need for form a sequence starting at 0.
*
* Example:
* \code
* class CustomSpace1 : public CustomSpace<CustomSpace1> {
* public:
* static constexpr CustomSpaceIndex kSpaceIndex = 0;
* };
* class CustomSpace2 : public CustomSpace<CustomSpace2> {
* public:
* static constexpr CustomSpaceIndex kSpaceIndex = 1;
* };
* \endcode
*/
template <typename ConcreteCustomSpace>
class CustomSpace : public CustomSpaceBase {
public:
/**
* Compaction is only supported on spaces that manually manage slots
* recording.
*/
static constexpr bool kSupportsCompaction = false;
CustomSpaceIndex GetCustomSpaceIndex() const final {
return ConcreteCustomSpace::kSpaceIndex;
}
bool IsCompactable() const final {
return ConcreteCustomSpace::kSupportsCompaction;
}
};
/**
* User-overridable trait that allows pinning types to custom spaces.
*/
template <typename T, typename = void>
struct SpaceTrait {
using Space = void;
};
namespace internal {
template <typename CustomSpace>
struct IsAllocatedOnCompactableSpaceImpl {
static constexpr bool value = CustomSpace::kSupportsCompaction;
};
template <>
struct IsAllocatedOnCompactableSpaceImpl<void> {
// Non-custom spaces are by default not compactable.
static constexpr bool value = false;
};
template <typename T>
struct IsAllocatedOnCompactableSpace {
public:
static constexpr bool value =
IsAllocatedOnCompactableSpaceImpl<typename SpaceTrait<T>::Space>::value;
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_

View File

@ -1,75 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
#include <memory>
#include <vector>
#include "cppgc/platform.h"
#include "libplatform/libplatform.h"
#include "v8config.h" // NOLINT(build/include_directory)
namespace cppgc {
/**
* Platform provided by cppgc. Uses V8's DefaultPlatform provided by
* libplatform internally. Exception: `GetForegroundTaskRunner()`, see below.
*/
class V8_EXPORT DefaultPlatform : public Platform {
public:
/**
* Use this method instead of 'cppgc::InitializeProcess' when using
* 'cppgc::DefaultPlatform'. 'cppgc::DefaultPlatform::InitializeProcess'
* will initialize cppgc and v8 if needed (for non-standalone builds).
*
* \param platform DefaultPlatform instance used to initialize cppgc/v8.
*/
static void InitializeProcess(DefaultPlatform* platform);
using IdleTaskSupport = v8::platform::IdleTaskSupport;
explicit DefaultPlatform(
int thread_pool_size = 0,
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
std::unique_ptr<TracingController> tracing_controller = {})
: v8_platform_(v8::platform::NewDefaultPlatform(
thread_pool_size, idle_task_support,
v8::platform::InProcessStackDumping::kDisabled,
std::move(tracing_controller))) {}
cppgc::PageAllocator* GetPageAllocator() override {
return v8_platform_->GetPageAllocator();
}
double MonotonicallyIncreasingTime() override {
return v8_platform_->MonotonicallyIncreasingTime();
}
std::shared_ptr<cppgc::TaskRunner> GetForegroundTaskRunner() override {
// V8's default platform creates a new task runner when passed the
// `v8::Isolate` pointer the first time. For non-default platforms this will
// require getting the appropriate task runner.
return v8_platform_->GetForegroundTaskRunner(kNoIsolate);
}
std::unique_ptr<cppgc::JobHandle> PostJob(
cppgc::TaskPriority priority,
std::unique_ptr<cppgc::JobTask> job_task) override {
return v8_platform_->PostJob(priority, std::move(job_task));
}
TracingController* GetTracingController() override {
return v8_platform_->GetTracingController();
}
protected:
static constexpr v8::Isolate* kNoIsolate = nullptr;
std::unique_ptr<v8::Platform> v8_platform_;
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_

View File

@ -1,30 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_
#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_
#include "cppgc/liveness-broker.h"
#include "cppgc/member.h"
namespace cppgc {
/**
* An ephemeron pair is used to conditionally retain an object.
* The `value` will be kept alive only if the `key` is alive.
*/
template <typename K, typename V>
struct EphemeronPair {
EphemeronPair(K* k, V* v) : key(k), value(v) {}
WeakMember<K> key;
Member<V> value;
void ClearValueIfKeyIsDead(const LivenessBroker& broker) {
if (!broker.IsHeapObjectAlive(key)) value = nullptr;
}
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_

View File

@ -1,73 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#include <cstddef>
#include "cppgc/allocation.h"
#include "cppgc/internal/logging.h"
#include "cppgc/type-traits.h"
namespace cppgc {
namespace internal {
V8_EXPORT void FreeUnreferencedObject(void*);
V8_EXPORT bool Resize(void*, size_t);
} // namespace internal
namespace subtle {
/**
* Informs the garbage collector that `object` can be immediately reclaimed. The
* destructor may not be invoked immediately but only on next garbage
* collection.
*
* It is up to the embedder to guarantee that no other object holds a reference
* to `object` after calling `FreeUnreferencedObject()`. In case such a
* reference exists, it's use results in a use-after-free.
*
* \param object Reference to an object that is of type `GarbageCollected` and
* should be immediately reclaimed.
*/
template <typename T>
void FreeUnreferencedObject(T* object) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
if (!object) return;
internal::FreeUnreferencedObject(object);
}
/**
* Tries to resize `object` of type `T` with additional bytes on top of
* sizeof(T). Resizing is only useful with trailing inlined storage, see e.g.
* `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`.
*
* `Resize()` performs growing or shrinking as needed and may skip the operation
* for internal reasons, see return value.
*
* It is up to the embedder to guarantee that in case of shrinking a larger
* object down, the reclaimed area is not used anymore. Any subsequent use
* results in a use-after-free.
*
* \param object Reference to an object that is of type `GarbageCollected` and
* should be resized.
* \param additional_bytes Bytes in addition to sizeof(T) that the object should
* provide.
* \returns true when the operation was successful and the result can be relied
* on, and false otherwise.
*/
template <typename T>
bool Resize(T& object, AdditionalBytes additional_bytes) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
return internal::Resize(&object, sizeof(T) + additional_bytes.value);
}
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_

View File

@ -1,117 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_
#include <type_traits>
#include "cppgc/internal/api-constants.h"
#include "cppgc/platform.h"
#include "cppgc/trace-trait.h"
#include "cppgc/type-traits.h"
namespace cppgc {
class Visitor;
namespace internal {
class GarbageCollectedBase {
public:
// Must use MakeGarbageCollected.
void* operator new(size_t) = delete;
void* operator new[](size_t) = delete;
// The garbage collector is taking care of reclaiming the object. Also,
// virtual destructor requires an unambiguous, accessible 'operator delete'.
void operator delete(void*) {
#ifdef V8_ENABLE_CHECKS
internal::Abort();
#endif // V8_ENABLE_CHECKS
}
void operator delete[](void*) = delete;
protected:
GarbageCollectedBase() = default;
};
} // namespace internal
/**
* Base class for managed objects. Only descendent types of `GarbageCollected`
* can be constructed using `MakeGarbageCollected()`. Must be inherited from as
* left-most base class.
*
* Types inheriting from GarbageCollected must provide a method of
* signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
* pointers to the visitor and delegates to garbage-collected base classes.
* The method must be virtual if the type is not directly a child of
* GarbageCollected and marked as final.
*
* \code
* // Example using final class.
* class FinalType final : public GarbageCollected<FinalType> {
* public:
* void Trace(cppgc::Visitor* visitor) const {
* // Dispatch using visitor->Trace(...);
* }
* };
*
* // Example using non-final base class.
* class NonFinalBase : public GarbageCollected<NonFinalBase> {
* public:
* virtual void Trace(cppgc::Visitor*) const {}
* };
*
* class FinalChild final : public NonFinalBase {
* public:
* void Trace(cppgc::Visitor* visitor) const final {
* // Dispatch using visitor->Trace(...);
* NonFinalBase::Trace(visitor);
* }
* };
* \endcode
*/
template <typename T>
class GarbageCollected : public internal::GarbageCollectedBase {
public:
using IsGarbageCollectedTypeMarker = void;
using ParentMostGarbageCollectedType = T;
protected:
GarbageCollected() = default;
};
/**
* Base class for managed mixin objects. Such objects cannot be constructed
* directly but must be mixed into the inheritance hierarchy of a
* GarbageCollected object.
*
* Types inheriting from GarbageCollectedMixin must override a virtual method
* of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed
* pointers to the visitor and delegates to base classes.
*
* \code
* class Mixin : public GarbageCollectedMixin {
* public:
* void Trace(cppgc::Visitor* visitor) const override {
* // Dispatch using visitor->Trace(...);
* }
* };
* \endcode
*/
class GarbageCollectedMixin : public internal::GarbageCollectedBase {
public:
using IsGarbageCollectedMixinTypeMarker = void;
/**
* This Trace method must be overriden by objects inheriting from
* GarbageCollectedMixin.
*/
virtual void Trace(cppgc::Visitor*) const {}
};
} // namespace cppgc
#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_

Some files were not shown because too many files have changed in this diff Show More