• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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