1// Copyright (C) 2018 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {defer} from '../base/deferred'; 16import {assertExists, assertTrue} from '../base/logging'; 17import * as init_trace_processor from '../gen/trace_processor'; 18 19function writeToUIConsole(line: string) { 20 console.log(line); 21} 22 23export interface WasmBridgeRequest { 24 id: number; 25 serviceName: string; 26 methodName: string; 27 data: Uint8Array; 28} 29 30export interface WasmBridgeResponse { 31 id: number; 32 success: boolean; 33 data?: Uint8Array; 34} 35 36export class WasmBridge { 37 // When this promise has resolved it is safe to call callWasm. 38 whenInitialized: Promise<void>; 39 40 private aborted: boolean; 41 private currentRequestResult: WasmBridgeResponse|null; 42 private connection: init_trace_processor.Module; 43 44 constructor(init: init_trace_processor.InitWasm) { 45 this.aborted = false; 46 this.currentRequestResult = null; 47 48 const deferredRuntimeInitialized = defer<void>(); 49 this.connection = init({ 50 locateFile: (s: string) => s, 51 print: writeToUIConsole, 52 printErr: writeToUIConsole, 53 onRuntimeInitialized: () => deferredRuntimeInitialized.resolve(), 54 onAbort: () => this.aborted = true, 55 }); 56 this.whenInitialized = deferredRuntimeInitialized.then(() => { 57 const fn = this.connection.addFunction(this.onReply.bind(this), 'viiii'); 58 this.connection.ccall('Initialize', 'void', ['number'], [fn]); 59 }); 60 } 61 62 callWasm(req: WasmBridgeRequest): WasmBridgeResponse { 63 if (this.aborted) { 64 return { 65 id: req.id, 66 success: false, 67 data: undefined, 68 }; 69 } 70 // TODO(b/124805622): protoio can generate CamelCase names - normalize. 71 const methodName = req.methodName; 72 const name = methodName.charAt(0).toLowerCase() + methodName.slice(1); 73 this.connection.ccall( 74 `${req.serviceName}_${name}`, // C method name. 75 'void', // Return type. 76 ['number', 'array', 'number'], // Input args. 77 [req.id, req.data, req.data.length] // Args. 78 ); 79 80 const result = assertExists(this.currentRequestResult); 81 assertTrue(req.id === result.id); 82 this.currentRequestResult = null; 83 return result; 84 } 85 86 // This is invoked from ccall in the same call stack as callWasm. 87 private onReply( 88 reqId: number, success: boolean, heapPtr: number, size: number) { 89 const data = this.connection.HEAPU8.slice(heapPtr, heapPtr + size); 90 this.currentRequestResult = { 91 id: reqId, 92 success, 93 data, 94 }; 95 } 96} 97