Skip to content

Commit

Permalink
Add external object sample and crossplat-fy other samples
Browse files Browse the repository at this point in the history
  • Loading branch information
liminzhu committed Dec 1, 2017
1 parent eb7fdbf commit 5b42098
Showing 1 changed file with 64 additions and 33 deletions.
97 changes: 64 additions & 33 deletions JavaScript-Runtime-(JSRT)-Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,29 +107,33 @@ JsValueRef CALLBACK LogCB(JsValueRef callee, bool isConstructCall, JsValueRef *a
{
if (index > 1)
{
wprintf(L" ");
printf(" ");
}
JsValueRef stringValue;
JsConvertValueToString(arguments[index], &stringValue);
const wchar_t *string;
char *string = nullptr;
size_t length;
JsStringToPointer(stringValue, &string, &length);
wprintf(L"%s", string);
JsCopyString(stringValue, nullptr, 0, &length);
string = (char*)malloc(length + 1);
JsCopyString(stringValue, string, length+1, nullptr);
printf("%s", string);
}
wprintf(L"\n");
printf("\n");
return JS_INVALID_REFERENCE;
}

JsValueRef console, logFunc, global;
JsPropertyIdRef consolePropId, logPropId;
const char* logString = "log";
const char* consoleString = "console";
// create console object, log function, and set log function as property of console
JsCreateObject(&console);
JsCreateFunction(LogCB, nullptr, &logFunc);
JsGetPropertyIdFromName(L"log", &logPropId);
JsCreatePropertyId(logString, strlen(logString), &logPropId);
JsSetProperty(console, logPropId, logFunc, true);
// set console as property of global object
JsGetGlobalObject(&global);
JsGetPropertyIdFromName(L"console", &consolePropId);
JsCreatePropertyId(consoleString, strlen(consoleString), &consolePropId);
JsSetProperty(global, consolePropId, console, true);
```
Expand All @@ -139,7 +143,29 @@ Now in JavaScript, you can do:
console.log('Hello world');
```

If you need to expose an object that hosts data not directly exposed to JS, you can create an external object via `JsCreateExternalObject`.
You can also create external objects that host data not directly exposed to JS via `JsCreateExternalObject` or `JsCreateExternalObjectWithPrototype`.

```cpp
// creates an external object holding an int
JsValueRef null, extObj;
JsGetNullValue(&null);
int data = 0;
JsCreateExternalObjectWithPrototype(&data, nullptr, null, &extObj);
```
You can define native methods on the external object and have access to the external data.
```cpp
// a native method that type casts the external data and adds one.
JsValueRef CALLBACK addOne(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
{
void* extData;
JsGetExternalData(arguments[0], &extData);
int* data = (int*)(extData);
*data += 1;
return JS_INVALID_REFERENCE;
}
```

### Call JavaScript functions from native

Expand All @@ -150,7 +176,8 @@ JsValueRef func, funcPropId, global, undefined, result;
JsGetGlobalObject(&global);
JsGetUndefinedValue(&undefined);
JsValueRef args[] = { undefined };
JsGetPropertyIdFromName(L"func", &funcPropId);
const char* funcString = "func";
JsCreatePropertyId(funcString, strlen(funcString), &funcPropId);
JsGetProperty(global, funcPropId, &func);
// note that args[0] is thisArg of the call; actual args start at index 1
JsCallFunction(func, args, 1, &result);
Expand All @@ -160,38 +187,42 @@ JsCallFunction(func, args, 1, &result);
To support startup and execution efficiency, JSRT APIs provide the capability of pre-parsing, generating syntax trees and caching the bytecode for scripts. It is especially useful for server scenarios where the same script could get executed thousands of times.
The basic idea is to use variants of `JsSerializeScript` to parse and store the bytecode and then use `JsParse/RunSerializedScript` to parse or run the bytecode. Source is typically not needed for running serialized code, therefore you can also lazy-load the source script using `JsRunSerialized/JsRunSerializedScriptWithCallback`.
The basic idea is to use variants of `JsSerializeScript` to parse and store the bytecode and then use variants of `JsRunSerialized` to parse or run the bytecode. Source is typically not needed for running serialized code, therefore you can also lazy-load the source script using `JsRunSerialized/JsRunSerializedScriptWithCallback`.
```cpp
// serialize script and cache the bytecode on disk
void serializeScript(const wchar_t *script, const wchar_t *bytecodeBufferPath) {
JsValueRef result;
unsigned long bufferSize = 0;
BYTE *buffer = nullptr;
JsSerializeScript(script, nullptr, &bufferSize); // get correct buffer size
buffer = new BYTE[bufferSize];
JsSerializeScript(script, buffer, &bufferSize); // actual serialization
SaveByteCode(buffer, bytecodecachePath);
// serialize script
void serializeScript(char* scriptPath, char* script) {
JsValueRef scriptSource, bytecodeBuffer;
JsCreateExternalArrayBuffer((void*)script, (unsigned int)strlen(script), nullptr, nullptr, &scriptSource);
JsSerialize(scriptSource, &bytecodeBuffer, JsParseScriptAttributeNone);
JsAddRef(bytecodeBuffer, nullptr);
SerializedSourceContext* context = new SerializedSourceContext();
context->script = script;
context->scriptPath = scriptPath;
context->bytecodeBuffer = bytecodeBuffer;
bytecodeStore[scriptPath] = context;
}
// load and run bytecode
void runSerializeScript(const wchar_t *bytecodeBufferPath, const wchar_t *scriptBufferPath) {
// load and run bytecode
void runSerializeScript(char* scriptPath) {
JsValueRef result;
BYTE *buffer = LoadByteCode(bytecodeBufferPath);
SerializedSourceContext* context = new SerializedSourceContext();
context->scriptPath = scriptBufferPath;
JsRunSerializedScriptWithCallback(
[](JsSourceContext sourceContext, const WCHAR** scriptBuffer)
SerializedSourceContext* context = bytecodeStore[scriptPath];
JsRunSerialized(
context->bytecodeBuffer,
[](JsSourceContext sourceContext, JsValueRef* scriptBuffer, JsParseScriptAttributes* parseAttributes)
{
// load script when necessary
*scriptBuffer = LoadScript(((SerializedSourceContext*)sourceContext)->scriptPath);
SerializedSourceContext* scontext = reinterpret_cast<SerializedSourceContext*>(sourceContext);
if (scontext->script == nullptr) {
scontext->script = LoadScript(scontext->scriptPath);
}
scriptBuffer = scontext->script;
*parseAttributes = JsParseScriptAttributeNone;
return true;
},
[](JsSourceContext sourceContext)
{
// free resources
},
buffer, (JsSourceContext)context, L"", &result);
(JsSourceContext)context,
nullptr,
&result
);
}
```

Expand Down

0 comments on commit 5b42098

Please sign in to comment.