Skip to content

Please provide a stringify-expression function in the C libarary #8716

@chharvey

Description

@chharvey

Greetings all, For those of you who don't know, a new effort to migrate JS to TS has been going on for a few weeks new. Please follow along the discussion here: #8656.

My specific question here is with the emitText() function, which hijacks out:

Module['emitText'] = function(expr) {
  if (typeof expr === 'object') {
    return expr.emitText();
  }
  const old = out;
  let ret = '';
  out = x => { ret += x + '\n' };
  Module['_BinaryenExpressionPrint'](expr);
  out = old;
  return ret;
};

Since this code is appended to the Emscripten preprocessed input, this mysterious out is able to be temporarily reassigned to a function that just updates the ret string.

(for reference:)

void BinaryenExpressionPrint(BinaryenExpressionRef expr) {
  std::cout << *(Expression*)expr << '\n';
}

But seeing as the TS effort will not have access to those internals (see #8656), my current rewrite looks like this:

(adding out & err to the EXPORTED_RUNTIME_METHODS)

  target_link_libraries(binaryen_js PRIVATE "-sEXPORTED_RUNTIME_METHODS=out,err,HEAP8,HEAPU8,HEAP32,HEAPU32,stackSave,stackRestore,stackAlloc,UTF8ToString,stringToAscii,stringToUTF8OnStack,getExceptionMessage")
  target_link_libraries(binaryen_js PRIVATE "-sEXPORTED_FUNCTIONS=_malloc,_free,__i32_load")

(calling it "BinaryenObj" instead of "Module" to avoid confusion)

const BinaryenObj = await Binaryen();

export function emitText(expr: ExpressionRef): string {
	let returned = "";
	const temp_out = BinaryenObj.out;
	BinaryenObj.out = (x: string): void => {
		returned += `${ x }\n`;
	};
	BinaryenObj["_BinaryenExpressionPrint"](expr);
	BinaryenObj.out = temp_out;
	return returned;
}

The problem is, it doesn't do anything. Calling this function still prints the text to the console, and then returns an empty string. I guess that's because temporarily reassigning BinaryenObj.out doesn't actually hijack the internals used in BinaryenExpressionPrint.

So my hope is we can offer a new function in the C++ library to return the expression stringified, which could then just be pulled into the TS library. We already do this in the Module class:

char* BinaryenModuleAllocateAndWriteText(BinaryenModuleRef module) {
  std::ostringstream os;
  bool colors = Colors::isEnabled();

  Colors::setEnabled(false); // do not use colors for writing
  os << *(Module*)module;
  Colors::setEnabled(colors); // restore colors state

  auto str = os.str();
  const size_t len = str.length() + 1;
  char* output = (char*)malloc(len);
  std::copy_n(str.c_str(), len, output);
  return output;
}
function wrapModule(module, self = {}) {
  // ...
  self['emitText'] = function() {
    let textPtr = Module['_BinaryenModuleAllocateAndWriteText'](module);
    let text = UTF8ToString(textPtr);
    if (textPtr) _free(textPtr);
    return text;
  };
}

(and my TS rewrite)

class Module {
	emitText(): string {
		const textPtr = BinaryenObj["_BinaryenModuleAllocateAndWriteText"](this[PTR]);
		const text = UTF8ToString(textPtr);
		if (textPtr) {
			_free(textPtr);
		}
		return text;
	}
}

Following this same pattern, we could have a new "BinaryenExpressionAllocateAndWriteText" function, which just spits out the string of the expression, and then I'd update the global emitText JS/TS function accordingly. Moreover, the original BinaryenExpressionPrint function could be updated to call that instead of duplicating code.

Please let me know if there'd be any problems with this approach. Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions