forked from mirrors/gecko-dev
		
	 2f1001ccab
			
		
	
	
		2f1001ccab
		
	
	
	
	
		
			
			Differential Revision: https://phabricator.services.mozilla.com/D65845 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			209 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html>
 | |
| <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=900784 -->
 | |
| <!-- The JS bytecode cache is not supposed to be observable. To make it
 | |
|      observable, the ScriptLoader is instrumented to trigger events on the
 | |
|      script tag. These events are followed to reconstruct the code path taken by
 | |
|      the script loader and associate a simple name which is checked in these
 | |
|      test cases.
 | |
| -->
 | |
| <head>
 | |
|   <meta charset="utf-8">
 | |
|   <title>Test for saving and loading bytecode in/from the necko cache</title>
 | |
|   <script src="/resources/testharness.js"></script>
 | |
|   <script src="/resources/testharnessreport.js"></script>
 | |
|   <script type="application/javascript">
 | |
|     // This is the state machine of the trace events produced by the
 | |
|     // ScriptLoader. This state machine is used to give a name to each
 | |
|     // code path, such that we can assert each code path with a single word.
 | |
|     var scriptLoaderStateMachine = {
 | |
|       "scriptloader_load_source": {
 | |
|         "scriptloader_execute": {
 | |
|           "scriptloader_encode": {
 | |
|             "scriptloader_bytecode_saved": "bytecode_saved",
 | |
|             "scriptloader_bytecode_failed": "bytecode_failed"
 | |
|           },
 | |
|           "scriptloader_no_encode": "source_exec"
 | |
|         },
 | |
|         "scriptloader_evaluate_module": {
 | |
|           "scriptloader_no_encode": "source_exec"
 | |
|         },
 | |
|       },
 | |
|       "scriptloader_load_bytecode": {
 | |
|         "scriptloader_fallback": {
 | |
|           // Replicate the top-level state machine without
 | |
|           // "scriptloader_load_bytecode" transition.
 | |
|           "scriptloader_load_source": {
 | |
|             "scriptloader_execute": {
 | |
|               "scriptloader_encode": {
 | |
|                 "scriptloader_bytecode_saved": "fallback_bytecode_saved",
 | |
|                 "scriptloader_bytecode_failed": "fallback_bytecode_failed"
 | |
|               },
 | |
|               "scriptloader_no_encode": "fallback_source_exec"
 | |
|             }
 | |
|           }
 | |
|         },
 | |
|         "scriptloader_execute": "bytecode_exec"
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     function WaitForScriptTagEvent(url) {
 | |
|       var iframe = document.createElement("iframe");
 | |
|       document.body.appendChild(iframe);
 | |
| 
 | |
|       var stateMachine = scriptLoaderStateMachine;
 | |
|       var stateHistory = [];
 | |
|       var stateMachineResolve, stateMachineReject;
 | |
|       var statePromise = new Promise((resolve, reject) => {
 | |
|         stateMachineResolve = resolve;
 | |
|         stateMachineReject = reject;
 | |
|       });
 | |
|       var ping = 0;
 | |
| 
 | |
|       // Walk the script loader state machine with the emitted events.
 | |
|       function log_event(evt) {
 | |
|         // If we have multiple script tags in the loaded source, make sure
 | |
|         // we only watch a single one.
 | |
|         if (evt.target.id != "watchme")
 | |
|           return;
 | |
| 
 | |
|         dump("## ScriptLoader event: " + evt.type + "\n");
 | |
|         stateHistory.push(evt.type)
 | |
|         if (typeof stateMachine == "object")
 | |
|           stateMachine = stateMachine[evt.type];
 | |
|         if (typeof stateMachine == "string") {
 | |
|           // We arrived to a final state, report the name of it.
 | |
|           var result = stateMachine;
 | |
|           if (ping) {
 | |
|             result = `${result} & ping(=${ping})`;
 | |
|           }
 | |
|           stateMachineResolve(result);
 | |
|         } else if (stateMachine === undefined) {
 | |
|           // We followed an unknown transition, report the known history.
 | |
|           stateMachineReject(stateHistory);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       var iwin = iframe.contentWindow;
 | |
|       iwin.addEventListener("scriptloader_load_source", log_event);
 | |
|       iwin.addEventListener("scriptloader_load_bytecode", log_event);
 | |
|       iwin.addEventListener("scriptloader_generate_bytecode", log_event);
 | |
|       iwin.addEventListener("scriptloader_execute", log_event);
 | |
|       iwin.addEventListener("scriptloader_evaluate_module", log_event);
 | |
|       iwin.addEventListener("scriptloader_encode", log_event);
 | |
|       iwin.addEventListener("scriptloader_no_encode", log_event);
 | |
|       iwin.addEventListener("scriptloader_bytecode_saved", log_event);
 | |
|       iwin.addEventListener("scriptloader_bytecode_failed", log_event);
 | |
|       iwin.addEventListener("scriptloader_fallback", log_event);
 | |
|       iwin.addEventListener("ping", (evt) => {
 | |
|         ping += 1;
 | |
|         dump(`## Content event: ${evt.type} (=${ping})\n`);
 | |
|       });
 | |
|       iframe.src = url;
 | |
| 
 | |
|       statePromise.then(() => {
 | |
|         document.body.removeChild(iframe);
 | |
|       });
 | |
|       return statePromise;
 | |
|     }
 | |
| 
 | |
|     promise_test(async function() {
 | |
|       // Setting dom.expose_test_interfaces pref causes the
 | |
|       // nsScriptLoadRequest to fire event on script tags, with information
 | |
|       // about its internal state. The ScriptLoader source send events to
 | |
|       // trace these and resolve a promise with the path taken by the
 | |
|       // script loader.
 | |
|       //
 | |
|       // Setting dom.script_loader.bytecode_cache.strategy to -1 causes the
 | |
|       // nsScriptLoadRequest to force all the conditions necessary to make a
 | |
|       // script be saved as bytecode in the alternate data storage provided
 | |
|       // by the channel (necko cache).
 | |
|       await SpecialPowers.pushPrefEnv({set: [
 | |
|         ['dom.script_loader.bytecode_cache.enabled', true],
 | |
|         ['dom.expose_test_interfaces', true],
 | |
|         ['dom.script_loader.bytecode_cache.strategy', -1]
 | |
|       ]});
 | |
| 
 | |
|       // Load the test page, and verify that the code path taken by the
 | |
|       // nsScriptLoadRequest corresponds to the code path which is loading a
 | |
|       // source and saving it as bytecode.
 | |
|       var stateMachineResult = WaitForScriptTagEvent("file_js_cache.html");
 | |
|       assert_equals(await stateMachineResult, "bytecode_saved",
 | |
|                     "[1] ScriptLoadRequest status after the first visit");
 | |
| 
 | |
|       // Reload the same test page, and verify that the code path taken by
 | |
|       // the nsScriptLoadRequest corresponds to the code path which is
 | |
|       // loading bytecode and executing it.
 | |
|       stateMachineResult = WaitForScriptTagEvent("file_js_cache.html");
 | |
|       assert_equals(await stateMachineResult, "bytecode_exec",
 | |
|                     "[2] ScriptLoadRequest status after the second visit");
 | |
| 
 | |
|       // Load another page which loads the same script with an SRI, while
 | |
|       // the cached bytecode does not have any. This should fallback to
 | |
|       // loading the source before saving the bytecode once more.
 | |
|       stateMachineResult = WaitForScriptTagEvent("file_js_cache_with_sri.html");
 | |
|       assert_equals(await stateMachineResult, "fallback_bytecode_saved",
 | |
|                     "[3] ScriptLoadRequest status after the SRI hash");
 | |
| 
 | |
|       // Loading a page, which has the same SRI should verify the SRI and
 | |
|       // continue by executing the bytecode.
 | |
|       var stateMachineResult1 = WaitForScriptTagEvent("file_js_cache_with_sri.html");
 | |
| 
 | |
|       // Loading a page which does not have a SRI while we have one in the
 | |
|       // cache should not change anything. We should also be able to load
 | |
|       // the cache simultanesouly.
 | |
|       var stateMachineResult2 = WaitForScriptTagEvent("file_js_cache.html");
 | |
| 
 | |
|       assert_equals(await stateMachineResult1, "bytecode_exec",
 | |
|                     "[4] ScriptLoadRequest status after same SRI hash");
 | |
|       assert_equals(await stateMachineResult2, "bytecode_exec",
 | |
|                     "[5] ScriptLoadRequest status after visit with no SRI");
 | |
| 
 | |
|       // Load a page that uses the same script as a module and verify that we
 | |
|       // re-parse it from source.
 | |
|       stateMachineResult = WaitForScriptTagEvent("file_js_cache_module.html");
 | |
|       assert_equals(await stateMachineResult, "source_exec",
 | |
|                     "[6] ScriptLoadRequest status for a module");
 | |
|     }, "Check the JS bytecode cache");
 | |
| 
 | |
|     promise_test(async function() {
 | |
|       // (see above)
 | |
|       await SpecialPowers.pushPrefEnv({set: [
 | |
|         ['dom.script_loader.bytecode_cache.enabled', true],
 | |
|         ['dom.expose_test_interfaces', true],
 | |
|         ['dom.script_loader.bytecode_cache.strategy', -1]
 | |
|       ]});
 | |
| 
 | |
|       // The test page add a new script which generate a "ping" event, which
 | |
|       // should be recorded before the bytecode is stored in the cache.
 | |
|       var stateMachineResult =
 | |
|           WaitForScriptTagEvent("file_js_cache_save_after_load.html");
 | |
|       assert_equals(await stateMachineResult, "bytecode_saved & ping(=3)",
 | |
|                     "Wait on all scripts to be executed");
 | |
| 
 | |
|     }, "Save bytecode after the initialization of the page");
 | |
| 
 | |
|     promise_test(async function() {
 | |
|       // (see above)
 | |
|       await SpecialPowers.pushPrefEnv({set: [
 | |
|         ['dom.script_loader.bytecode_cache.enabled', true],
 | |
|         ['dom.expose_test_interfaces', true],
 | |
|         ['dom.script_loader.bytecode_cache.strategy', -1]
 | |
|       ]});
 | |
| 
 | |
|       // The test page loads a script which contains a syntax error, we should
 | |
|       // not attempt to encode any bytecode for it.
 | |
|       var stateMachineResult =
 | |
|           WaitForScriptTagEvent("file_js_cache_syntax_error.html");
 | |
|       assert_equals(await stateMachineResult, "source_exec",
 | |
|                     "Check the lack of bytecode encoding");
 | |
| 
 | |
|     }, "Do not save bytecode on compilation errors");
 | |
| 
 | |
|     done();
 | |
|   </script>
 | |
| </head>
 | |
| <body>
 | |
|   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=900784">Mozilla Bug 900784</a>
 | |
| </body>
 | |
| </html>
 |