pebble/applib-targets/emscripten/jerry_api.js

193 lines
5.6 KiB
JavaScript
Raw Permalink Normal View History

/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Polyfill Number.isNaN
if (Number.isNaN === undefined) {
Number.isNaN = Number.isNaN || function(value) {
return value !== value;
}
}
var __jerryRefs = {
// Jerryscript values (jerry_value_t) are integers which contain information
// about some javascript value that has been internally created.
// Create _objMap which will allow us to store and retrieve javascript values
// from a jerry_value_t, and perform refcounts on values that we still need an
// internal reference to, and avoid them from being garbage collected.
_objMap : {},
_nextObjectRef : 1,
_findValue : function(value) {
if (Number.isNaN(value)) {
// Special case to find NaN
for (var jerry_val in this._objMap) {
if (Number.isNaN(this._objMap[jerry_val].value)) {
return jerry_val;
}
}
} else {
for (var jerry_val in this._objMap) {
if (this._objMap[jerry_val].value === value) {
return jerry_val;
}
}
}
return 0;
},
_getEntry : function(jerry_value) {
var entry = this._objMap[jerry_value];
if (!entry) {
throw new Error('Entry at ' + jerry_value + ' does not exist');
}
return entry;
},
reset: function() {
this._objMap = {};
this._nextObjectRef = 1;
},
// Given a jerry value, return the stored javascript value.
get : function(jerry_value) {
return this._getEntry(jerry_value).value;
},
// Given a javascript value, return a jerry value that refers to it.
// If the value already exists in the map, increment its refcount and return
// the jerry value.
// Otherwise, create a new entry and return the jerry value.
ref : function(value) {
var jerry_value = this._findValue(value);
if (jerry_value) {
this._getEntry(jerry_value).refCount++;
return jerry_value;
}
jerry_value = this._nextObjectRef++;
this._objMap[jerry_value] = {
refCount : 1,
value : value,
error : false,
};
// console.log('created entry ' + jerry_value + ' for ' + value + ' at ' + stackTrace());
return jerry_value;
},
getRefCount : function(jerry_value) {
return this._getEntry(jerry_value).refCount;
},
// Increase the reference count of the given jerry value
acquire : function(jerry_value) {
this._getEntry(jerry_value).refCount++;
return jerry_value;
},
// Decrease the reference count of the given jerry value and delete it if
// there are no more internal references.
release : function(ref) {
var entry = this._getEntry(ref);
entry.refCount--;
if (entry.refCount <= 0) {
if (entry.freeCallbackPtr) {
Module.ccall(
'emscripten_call_jerry_object_free_callback',
null,
['number', 'number'],
[entry.freeCallbackPtr, entry.nativeHandlePtr]);
}
// console.log('deleting ' + ref + ' at ' + stackTrace());
delete this._objMap[ref];
}
},
setError : function(ref, state) {
this._getEntry(ref).error = state;
},
getError : function(ref) {
return this._getEntry(ref).error;
},
setNativeHandle : function(jerryValue, nativeHandlePtr, freeCallbackPtr) {
var entry = this._getEntry(jerryValue);
entry.nativeHandlePtr = nativeHandlePtr;
entry.freeCallbackPtr = freeCallbackPtr;
},
getNativeHandle : function(jerryValue) {
return this._getEntry(jerryValue).nativeHandlePtr;
}
};
function __jerry_create_external_function(function_ptr) {
var f = function() {
var nativeHandlerArgs = [
function_ptr, /* the function pointer for us to call */
__jerryRefs.ref(f), /* ref to the actual js function */
__jerryRefs.ref(this) /* our this object */
];
var numArgs = arguments.length;
var jsRefs = [];
for (var i = 0; i < numArgs; i++) {
jsRefs.push(__jerryRefs.ref(arguments[i]));
}
// Arg 4 is a uint32 array of jerry_value_t arguments
var jsArgs = Module._malloc(numArgs * 4);
for (var i = 0; i < numArgs; i++) {
Module.setValue(jsArgs + i*4, jsRefs[i], 'i32');
}
nativeHandlerArgs.push(jsArgs);
nativeHandlerArgs.push(numArgs);
// this is just the classy Emscripten calling. function_ptr is a C-pointer here
// and we know the signature of the C function as it needs to follow
var result_ref = Module.ccall('emscripten_call_jerry_function',
'number',
['number', 'number', 'number', 'number', 'number'],
nativeHandlerArgs);
// Free and release all js args
Module._free(jsArgs);
while (jsRefs.length > 0) {
__jerryRefs.release(jsRefs.pop());
}
// decrease refcount of native handler arguments
__jerryRefs.release(nativeHandlerArgs[1]); // jsFunctionRef
__jerryRefs.release(nativeHandlerArgs[2]); // our this object
// delete native handler arguments
nativeHandlerArgs.length = 0;
var result_val = __jerryRefs.get(result_ref);
var has_error = __jerryRefs.getError(result_ref);
__jerryRefs.release(result_ref);
if (has_error) {
throw result_val;
}
return result_val;
};
return __jerryRefs.ref(f);
}