mirror of
https://github.com/google/pebble.git
synced 2025-03-15 16:51:21 +00:00
193 lines
5.6 KiB
JavaScript
193 lines
5.6 KiB
JavaScript
|
/**
|
||
|
* 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);
|
||
|
}
|