Bläddra i källkod

jsrt: JsCreateExternalObjectWithPrototype

Oguz Bastemur 8 år sedan
förälder
incheckning
7bf59d1286

+ 22 - 0
lib/Jsrt/ChakraCore.h

@@ -792,6 +792,28 @@ CHAKRA_API
         _In_ JsValueRef object2,
         _Out_ bool *result);
 
+/// <summary>
+///     Creates a new object (with prototype) that stores some external data.
+/// </summary>
+/// <remarks>
+///     Requires an active script context.
+/// </remarks>
+/// <param name="data">External data that the object will represent. May be null.</param>
+/// <param name="finalizeCallback">
+///     A callback for when the object is finalized. May be null.
+/// </param>
+/// <param name="prototype">Prototype object or nullptr.</param>
+/// <param name="object">The new object.</param>
+/// <returns>
+///     The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.
+/// </returns>
+CHAKRA_API
+    JsCreateExternalObjectWithPrototype(
+        _In_opt_ void *data,
+        _In_opt_ JsFinalizeCallback finalizeCallback,
+        _In_ JsValueRef prototype,
+        _Out_ JsValueRef *object);
+
 /// <summary>
 ///     Gets an object's property.
 /// </summary>

+ 34 - 2
lib/Jsrt/Jsrt.cpp

@@ -208,7 +208,7 @@ void CALLBACK CreateExternalObject_TTDCallback(Js::ScriptContext* ctx, Js::Var*
 {
     TTDAssert(object != nullptr, "This should always be a valid location");
 
-    *object = JsrtExternalObject::Create(nullptr, nullptr, ctx);
+    *object = JsrtExternalObject::Create(nullptr, nullptr, nullptr, ctx);
 }
 
 void CALLBACK TTDDummyPromiseContinuationCallback(JsValueRef task, void *callbackState)
@@ -1285,7 +1285,7 @@ CHAKRA_API JsCreateExternalObject(_In_opt_ void *data, _In_opt_ JsFinalizeCallba
 
         PARAM_NOT_NULL(object);
 
-        *object = JsrtExternalObject::Create(data, finalizeCallback, scriptContext);
+        *object = JsrtExternalObject::Create(data, finalizeCallback, nullptr, scriptContext);
 
         PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object);
 
@@ -1293,6 +1293,38 @@ CHAKRA_API JsCreateExternalObject(_In_opt_ void *data, _In_opt_ JsFinalizeCallba
     });
 }
 
+#ifndef NTBUILD
+CHAKRA_API JsCreateExternalObjectWithPrototype(_In_opt_ void *data,
+    _In_opt_ JsFinalizeCallback finalizeCallback,
+    _In_ JsValueRef prototype,
+    _Out_ JsValueRef *object)
+{
+    return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
+        PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalObject);
+
+        PARAM_NOT_NULL(object);
+
+        Js::RecyclableObject * prototypeObject = nullptr;
+        if (prototype != nullptr)
+        {
+            VALIDATE_INCOMING_OBJECT(prototype, scriptContext);
+            prototypeObject = Js::RecyclableObject::FromVar(prototype);
+        }
+
+        *object = JsrtExternalObject::Create(data, finalizeCallback, prototypeObject, scriptContext);
+
+        PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object);
+
+        if (prototypeObject != nullptr)
+        {
+            PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetPrototype, *object, prototypeObject);
+        }
+
+        return JsNoError;
+    });
+}
+#endif
+
 CHAKRA_API JsConvertValueToObject(_In_ JsValueRef value, _Out_ JsValueRef *result)
 {
     return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {

+ 8 - 0
lib/Jsrt/JsrtCommonExports.inc

@@ -122,4 +122,12 @@
     JsHasOwnProperty
     JsCopyStringOneByte
     JsGetDataViewInfo
+    JsCreateExternalObjectWithPrototype
+    JsObjectGetProperty
+    JsObjectHasProperty
+    JsObjectSetProperty
+    JsObjectDeleteProperty
+    JsObjectHasOwnProperty
+    JsObjectGetOwnPropertyDescriptor
+    JsObjectDefineProperty
 #endif

+ 9 - 2
lib/Jsrt/JsrtExternalObject.cpp

@@ -28,7 +28,7 @@ JsrtExternalObject::JsrtExternalObject(JsrtExternalType * type, void *data) :
 }
 
 /* static */
-JsrtExternalObject* JsrtExternalObject::Create(void *data, JsFinalizeCallback finalizeCallback, Js::ScriptContext *scriptContext)
+JsrtExternalObject* JsrtExternalObject::Create(void *data, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext)
 {
     Js::DynamicType * dynamicType = scriptContext->GetLibrary()->GetCachedJsrtExternalType(reinterpret_cast<uintptr_t>(finalizeCallback));
 
@@ -41,7 +41,14 @@ JsrtExternalObject* JsrtExternalObject::Create(void *data, JsFinalizeCallback fi
     Assert(dynamicType->IsJsrtExternal());
     Assert(dynamicType->GetIsShared());
 
-    return RecyclerNewFinalized(scriptContext->GetRecycler(), JsrtExternalObject, static_cast<JsrtExternalType*>(dynamicType), data);
+    JsrtExternalObject * externalObject = RecyclerNewFinalized(scriptContext->GetRecycler(), JsrtExternalObject, static_cast<JsrtExternalType*>(dynamicType), data);
+
+    if (prototype != nullptr)
+    {
+        externalObject->SetPrototype(prototype);
+    }
+
+    return externalObject;
 }
 
 bool JsrtExternalObject::Is(Js::Var value)

+ 1 - 1
lib/Jsrt/JsrtExternalObject.h

@@ -50,7 +50,7 @@ public:
     static bool Is(Js::Var value);
     static JsrtExternalObject * FromVar(Js::Var value);
     static JsrtExternalObject * UnsafeFromVar(Js::Var value);
-    static JsrtExternalObject * Create(void *data, JsFinalizeCallback finalizeCallback, Js::ScriptContext *scriptContext);
+    static JsrtExternalObject * Create(void *data, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext);
 
     JsrtExternalType * GetExternalType() const { return (JsrtExternalType *)this->GetType(); }
 

+ 52 - 0
test/native-tests/test-static-external/Platform.js

@@ -0,0 +1,52 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+var isWindows = !WScript.Platform || WScript.Platform.OS == 'win32';
+var path_sep = isWindows ? '\\' : '/';
+var isStaticBuild = WScript.Platform && WScript.Platform.LINK_TYPE == 'static';
+
+if (!isStaticBuild) {
+    // test will be ignored
+    print("# IGNORE_THIS_TEST");
+} else {
+    var platform = WScript.Platform.OS;
+    var binaryPath = WScript.Platform.BINARY_PATH;
+    // discard `ch` from path
+    binaryPath = binaryPath.substr(0, binaryPath.lastIndexOf(path_sep));
+    var makefile =
+"IDIR=" + binaryPath + "/../../lib/Jsrt \n\
+\n\
+LIBRARY_PATH=" + binaryPath + "/lib\n\
+PLATFORM=" + platform + "\n\
+LDIR=$(LIBRARY_PATH)/libChakraCoreStatic.a \n\
+\n\
+ifeq (darwin, ${PLATFORM})\n\
+\tICU4C_LIBRARY_PATH ?= /usr/local/opt/icu4c\n\
+\tCFLAGS=-lstdc++ -std=c++11 -I$(IDIR)\n\
+\tFORCE_STARTS=-Wl,-force_load,\n\
+\tFORCE_ENDS=\n\
+\tLIBS=-framework CoreFoundation -framework Security -lm -ldl -Wno-c++11-compat-deprecated-writable-strings \
+    -Wno-deprecated-declarations -Wno-unknown-warning-option -o sample.o\n\
+\tLDIR+=$(ICU4C_LIBRARY_PATH)/lib/libicudata.a \
+    $(ICU4C_LIBRARY_PATH)/lib/libicuuc.a \
+    $(ICU4C_LIBRARY_PATH)/lib/libicui18n.a\n\
+else\n\
+\tCFLAGS=-lstdc++ -std=c++0x -I$(IDIR)\n\
+\tFORCE_STARTS=-Wl,--whole-archive\n\
+\tFORCE_ENDS=-Wl,--no-whole-archive\n\
+\tLIBS=-pthread -lm -ldl -licuuc -Wno-c++11-compat-deprecated-writable-strings \
+    -Wno-deprecated-declarations -Wno-unknown-warning-option -o sample.o\n\
+endif\n\
+\n\
+testmake:\n\
+\t$(CC) sample.cpp $(CFLAGS) $(FORCE_STARTS) $(LDIR) $(FORCE_ENDS) $(LIBS)\n\
+\n\
+.PHONY: clean\n\
+\n\
+clean:\n\
+\trm sample.o\n";
+
+    print(makefile)
+}

+ 153 - 0
test/native-tests/test-static-external/sample.cpp

@@ -0,0 +1,153 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+#include "ChakraCore.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <cstring>
+
+#define FAIL_CHECK(cmd)                          \
+    do                                           \
+    {                                            \
+        JsErrorCode errCode = (JsErrorCode) cmd; \
+        if (errCode != JsNoError)                \
+        {                                        \
+            printf("Error %d at '%s'\n",         \
+                errCode, #cmd);                  \
+            return 1;                            \
+        }                                        \
+    } while(0)
+
+using namespace std;
+
+unsigned int AddMethodProperty(JsValueRef target, const char* str,
+                               JsNativeFunction func)
+{
+    JsPropertyIdRef Id;
+    FAIL_CHECK(JsCreatePropertyId(str, strlen(str), &Id));
+
+    JsValueRef nameVar;
+    FAIL_CHECK(JsCreateString(str, strlen(str), &nameVar));
+
+    JsValueRef functionVar;
+    FAIL_CHECK(JsCreateNamedFunction(nameVar, func, nullptr, &functionVar));
+
+    FAIL_CHECK(JsSetProperty(target, Id, functionVar, true));
+
+    return JsNoError;
+}
+
+JsValueRef CHECK(JsValueRef callee, bool isConstructCall,
+    JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
+{
+    void * data;
+    if (JsGetExternalData(arguments[1], &data) == JsNoError &&
+        ((size_t*)data)[122] - ((size_t*)data)[0] == 41976)
+    {
+        fprintf(stdout, "SU"); // CCESS will be printed during finalizer call
+    }
+    else
+    {
+        fprintf(stderr, "External data corrupt?");
+    }
+
+    return nullptr;
+}
+
+JsValueRef createWithProto(JsValueRef callee, bool isConstructCall,
+    JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
+{
+    size_t *data = new size_t[123];
+    data[0] = 12345;
+    data[122] = 54321;
+
+    JsValueRef obj;
+
+    JsErrorCode code = JsCreateExternalObjectWithPrototype(data, [](void* buffer)
+    {
+        size_t * mem = (size_t*)buffer;
+        if(!(mem[122] - mem[0] == 41976)) abort();
+        delete mem;
+
+        // test tool needs to see `SUCCESS` to determine if script was
+        // successful. So far the test printed `SU`,
+        // this should print the last part `CCESS`
+        fprintf(stdout, "CCESS\n");
+    }, arguments[1], &obj);
+
+    if (code != JsNoError)
+    {
+        printf("FAILED to create external object %d \n", code);
+    }
+
+    return obj;
+}
+
+int main()
+{
+    JsRuntimeHandle runtime;
+    JsContextRef context;
+    JsValueRef result;
+    unsigned currentSourceContext = 0;
+
+    const char* script = "\
+    (function(){\
+        var proto = { sub: 3 }; \
+        var ext = CreateWithProto(proto); \
+        if (ext.sub === 3) CHECK(ext); \
+        return \'\'; \
+    })();\
+    ";
+
+    // Create a runtime.
+    JsCreateRuntime(JsRuntimeAttributeNone, nullptr, &runtime);
+
+    // Create an execution context.
+    JsCreateContext(runtime, &context);
+
+    // Now set the current execution context.
+    JsSetCurrentContext(context);
+
+    JsValueRef fname;
+    FAIL_CHECK(JsCreateString("sample", strlen("sample"), &fname));
+
+    JsValueRef scriptSource;
+    FAIL_CHECK(JsCreateExternalArrayBuffer((void*)script,
+                                           (unsigned)strlen(script),
+                                           nullptr, nullptr, &scriptSource));
+
+    JsValueRef global;
+    FAIL_CHECK(JsGetGlobalObject(&global));
+
+    FAIL_CHECK(AddMethodProperty(global, "CreateWithProto", &createWithProto));
+    FAIL_CHECK(AddMethodProperty(global, "CHECK", &CHECK));
+
+    // Run the script.
+    FAIL_CHECK(JsRun(scriptSource, currentSourceContext++, fname,
+                     JsParseScriptAttributeNone, &result));
+
+    // Convert your script result to String in JavaScript;
+    // redundant if your script returns a String
+    JsValueRef resultJSString;
+    FAIL_CHECK(JsConvertValueToString(result, &resultJSString));
+
+    // Project script result back to C++.
+    char *resultSTR = nullptr;
+    size_t stringLength;
+    FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, &stringLength));
+    resultSTR = (char*)malloc(stringLength + 1);
+    FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength, nullptr));
+    resultSTR[stringLength] = 0;
+
+    fprintf(stdout, "%s", resultSTR); // prints an empty string ``
+    free(resultSTR);
+
+    // Dispose runtime
+    JsSetCurrentContext(JS_INVALID_REFERENCE);
+    JsDisposeRuntime(runtime);
+
+    return 0;
+}