| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| // |
| // Created by Darin on 11/02/2018. |
| // |
| |
| #include "android/jsengine/weex_jsc_utils.h" |
| |
| #include <iostream> |
| #include <fstream> |
| |
| #include "android/jsengine/object/weex_global_object.h" |
| #include "android/jsengine/object/weex_env.h" |
| #include "core/bridge/script_bridge.h" |
| |
| //extern WEEX_CORE_JS_API_FUNCTIONS *weex_core_js_api_functions; |
| |
| using namespace JSC; |
| void printLogOnFileWithNameS(const char * name, const char *log) { |
| std::string string("/data/data/com.alibaba.weex/"); |
| string.append(name); |
| std::ofstream mcfile; |
| mcfile.open(string.c_str(), std::ios::app); |
| mcfile << log << std::endl; |
| mcfile.close(); |
| } |
| |
| String jString2String(const uint16_t *str, size_t length) { |
| UChar *dst; |
| String s = String::createUninitialized(length, dst); |
| memcpy(dst, str, length * sizeof(UChar)); |
| return s; |
| } |
| |
| |
| String weexString2String(const WeexString *weexString) { |
| if (weexString != nullptr) { |
| return jString2String(weexString->content, weexString->length); |
| } |
| |
| return String(""); |
| } |
| |
| String char2String(const char *string) { |
| if (string == nullptr) |
| return String::fromUTF8(""); |
| |
| return String::fromUTF8(string); |
| } |
| |
| std::unique_ptr<char[]> newCharString(const char *str, size_t length) { |
| auto count = length + 1; |
| |
| std::unique_ptr<char[]> buffer(new char[count]); |
| |
| if (buffer == nullptr) |
| return nullptr; |
| |
| char *result = reinterpret_cast<char *>(buffer.get()); |
| |
| if (result == nullptr) |
| return nullptr; |
| |
| memset(result, 0, count); |
| memcpy(result, str, length); |
| result[length] = '\0'; |
| return buffer; |
| } |
| |
| std::unique_ptr<char[]> getCharJSONStringFromState(ExecState *state, int argument) { |
| if (argument >= state->argumentCount()) { |
| return nullptr; |
| } |
| JSValue val = state->argument(argument); |
| VM &vm = state->vm(); |
| if (val.isObject()) { |
| VM &vm = state->vm(); |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| String str = JSONStringify(state, val, 0); |
| if (UNLIKELY(scope.exception())) { |
| scope.clearException(); |
| return nullptr; |
| } |
| CString data = str.utf8(); |
| return newCharString(data.data(), data.length()); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| std::unique_ptr<char[]> getCharOrJSONStringFromState(ExecState *state, int argument) { |
| if (argument >= state->argumentCount()) { |
| return nullptr; |
| } |
| JSValue val = state->argument(argument); |
| if (val.isString() || val.isNumber()) { |
| String str(val.toWTFString(state)); |
| CString data = str.utf8(); |
| return newCharString(data.data(), data.length()); |
| } else if (val.isObject()) { |
| VM &vm = state->vm(); |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| String str = JSONStringify(state, val, 0); |
| if (UNLIKELY(scope.exception())) { |
| scope.clearException(); |
| return nullptr; |
| } |
| CString data = str.utf8(); |
| return newCharString(data.data(), data.length()); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| void getWsonOrJsonArgsFromState(ExecState *state, int argument, Args& args){ |
| |
| bool useWson = WeexEnv::getEnv()->useWson(); |
| |
| if(useWson){ |
| if (argument >= state->argumentCount()) { |
| args.setWson((wson_buffer*)nullptr); |
| return; |
| } |
| JSValue val = state->argument(argument); |
| wson_buffer* buffer = wson::toWson(state, val); |
| args.setWson(buffer); |
| return; |
| }else{ |
| if (argument >= state->argumentCount()) { |
| String str(""); |
| args.setString(str); |
| return; |
| } |
| JSValue val = state->argument(argument); |
| if(val.isString()){ |
| String str = val.toWTFString(state); |
| args.setString(str); |
| return; |
| }else if(val.isObject()){ |
| VM &vm = state->vm(); |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| String str = JSONStringify(state, val, 0); |
| args.setString(str); |
| return; |
| } |
| } |
| String str(""); |
| args.setString(str); |
| return; |
| } |
| |
| void getStringArgsFromState(ExecState *state, int argument,Args& args){ |
| if (argument >= state->argumentCount()) { |
| String str(""); |
| args.setString(str); |
| return; |
| } |
| JSValue val = state->argument(argument); |
| String str = val.toWTFString(state); |
| args.setString(str); |
| return; |
| } |
| |
| void getWsonArgsFromState(ExecState *state, int argument, Args& args){ |
| if (argument >= state->argumentCount()) { |
| args.setWson((wson_buffer*)nullptr); |
| return; |
| } |
| JSValue val = state->argument(argument); |
| wson_buffer* buffer = wson::toWson(state, val); |
| args.setWson(buffer); |
| return; |
| } |
| |
| void getJSONArgsFromState(ExecState *state, int argument, Args& args){ |
| JSValue val = state->argument(argument); |
| if(val.isString()){ |
| String str = val.toWTFString(state); |
| args.setString(str); |
| return; |
| }else if(val.isObject()){ |
| VM &vm = state->vm(); |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| String str = JSONStringify(state, val, 0); |
| args.setString(str); |
| return; |
| } |
| String str(""); |
| args.setString(str); |
| return; |
| } |
| |
| |
| |
| void addObjectArgsToIPC(IPCSerializer *serializer, Args& args){ |
| if(args.getType() == ARGS_TYPE_WSON){ |
| wson_buffer* buffer = args.wson; |
| if(buffer != nullptr && (((char*)buffer->data)[0] != WSON_NULL_TYPE) ){ |
| serializer->add((const char*)buffer->data, buffer->position); |
| }else{ |
| serializer->addJSUndefined(); |
| } |
| }else { |
| String str = args.json; |
| CString data = str.utf8(); |
| serializer->add(data.data(), data.length()); |
| } |
| } |
| |
| void addStringArgsToIPC(IPCSerializer *serializer, Args& args){ |
| if(args.json.length() > 0){ |
| String str = args.json; |
| CString data = str.utf8(); |
| serializer->add(data.data(), data.length()); |
| }else{ |
| serializer->addJSUndefined(); |
| } |
| } |
| |
| std::unique_ptr<char[]> getCharStringFromState(ExecState *state, int argument) { |
| JSValue val = state->argument(argument); |
| String s = val.toWTFString(state); |
| return newCharString(s.utf8().data(), s.length()); |
| } |
| |
| void getArgumentAsCString(IPCSerializer *serializer, ExecState *state, int argument) { |
| JSValue val = state->argument(argument); |
| String s = val.toWTFString(state); |
| serializer->add(s.utf8().data(), s.length()); |
| } |
| |
| |
| void addString(IPCSerializer *serializer, const String &s) { |
| if (s.is8Bit()) { |
| CString data = s.utf8(); |
| const char *cstr = data.data(); |
| size_t length = data.length(); |
| Vector<UChar, 1024> buffer(length); |
| UChar *p = buffer.data(); |
| bool sourceIsAllASCII; |
| if (WTF::Unicode::conversionOK == |
| WTF::Unicode::convertUTF8ToUTF16(&cstr, cstr + length, &p, p + length, &sourceIsAllASCII)) { |
| serializer->add(buffer.data(), std::distance(buffer.data(), p)); |
| } else { |
| uint16_t tmp = 0; |
| serializer->add(&tmp, 0); |
| } |
| } else { |
| serializer->add(s.characters16(), s.length()); |
| } |
| } |
| |
| |
| void getArgumentAsJString(IPCSerializer *serializer, ExecState *state, int argument) { |
| JSValue val = state->argument(argument); |
| String s = val.toWTFString(state); |
| addString(serializer, s); |
| } |
| |
| |
| void getArgumentAsJByteArrayJSON(IPCSerializer *serializer, ExecState *state, int argument) { |
| jbyteArray ba = nullptr; |
| if (argument >= state->argumentCount()) { |
| serializer->addJSUndefined(); |
| return; |
| } |
| JSValue val = state->argument(argument); |
| VM &vm = state->vm(); |
| if (val.isObject()) { |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| String str = JSONStringify(state, val, 0); |
| JSC::VM &vm = state->vm(); |
| if (UNLIKELY(scope.exception())) { |
| scope.clearException(); |
| serializer->addJSUndefined(); |
| return; |
| } |
| CString data = str.utf8(); |
| serializer->add(data.data(), data.length()); |
| } |
| } |
| |
| |
| WeexByteArray *getArgumentAsWeexByteArrayJSON(ExecState *state, int argument) { |
| if (argument >= state->argumentCount()) { |
| return nullptr; |
| } |
| JSValue val = state->argument(argument); |
| VM &vm = state->vm(); |
| if (val.isObject()) { |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| String str = JSONStringify(state, val, 0); |
| JSC::VM &vm = state->vm(); |
| if (UNLIKELY(scope.exception())) { |
| scope.clearException(); |
| return nullptr; |
| } |
| CString data = str.utf8(); |
| |
| //serializer->add(data.data(), data.length()); |
| |
| return genWeexByteArraySS(data.data(), data.length()); |
| } |
| |
| return nullptr; |
| } |
| |
| WeexString *genWeexStringSS(const uint16_t *str, size_t length) { |
| size_t byteSize = length * sizeof(uint16_t); |
| auto *string = (WeexString *) malloc(byteSize + sizeof(WeexString)); |
| if (string == nullptr) |
| return nullptr; |
| |
| memset(string, 0, byteSize + sizeof(WeexString)); |
| string->length = length; |
| memcpy(string->content, str, byteSize); |
| return string; |
| } |
| WeexByteArray *genWeexByteArraySS(const char *str, size_t strLen) { |
| auto *ret = (WeexByteArray *) malloc(strLen + sizeof(WeexByteArray)); |
| |
| if (ret == nullptr) |
| return nullptr; |
| |
| memset(ret, 0, strLen + sizeof(WeexByteArray)); |
| |
| ret->length = strLen; |
| memcpy(ret->content, str, strLen); |
| |
| ret->content[strLen] = '\0'; |
| |
| return const_cast<WeexByteArray *> (ret); |
| } |
| |
| JSValue jString2JSValue(ExecState *state, const uint16_t *str, size_t length) { |
| String s = jString2String(str, length); |
| if (s.isEmpty()) { |
| return jsEmptyString(&state->vm()); |
| } else if (s.length() == 1) { |
| return jsSingleCharacterString(&state->vm(), s[0]); |
| } |
| return jsNontrivialString(&state->vm(), WTFMove(s)); |
| } |
| |
| JSValue String2JSValue(ExecState *state, String s) { |
| if (s.isEmpty()) { |
| return jsEmptyString(&state->vm()); |
| } else if (s.length() == 1) { |
| return jsSingleCharacterString(&state->vm(), s[0]); |
| } |
| return jsNontrivialString(&state->vm(), WTFMove(s)); |
| } |
| |
| JSValue parseToObject(ExecState *state, const String &data) { |
| VM &vm = state->vm(); |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| JSValue ret = JSONParse(state, data); |
| if (UNLIKELY(scope.exception())) { |
| scope.clearException(); |
| return jsUndefined(); |
| } |
| if (!ret) |
| return jsUndefined(); |
| return ret; |
| } |
| |
| void getArgumentAsJByteArray(IPCSerializer *serializer, ExecState *state, int argument) { |
| jbyteArray ba = nullptr; |
| if (argument >= state->argumentCount()) { |
| serializer->addJSUndefined(); |
| return; |
| } |
| JSValue val = state->argument(argument); |
| if (val.isString()) { |
| String str(val.toWTFString(state)); |
| CString data = str.utf8(); |
| serializer->add(data.data(), data.length()); |
| } else { |
| getArgumentAsJByteArrayJSON(serializer, state, argument); |
| } |
| } |
| void freeInitFrameworkParams(std::vector<INIT_FRAMEWORK_PARAMS *> ¶ms) { |
| for (auto ¶m : params) { |
| free(param->type); |
| free(param->value); |
| free(param); |
| } |
| } |
| |
| void freeParams(std::vector<VALUE_WITH_TYPE *> ¶ms) { |
| for (auto ¶m : params) { |
| if (param->type == ParamsType::STRING || |
| param->type == ParamsType::JSONSTRING) { |
| free(param->value.string); |
| } |
| if (param->type == ParamsType::BYTEARRAY) { |
| free(param->value.byteArray); |
| } |
| free(param); |
| } |
| } |
| |
| void FillVectorOfInitFramework(std::vector<INIT_FRAMEWORK_PARAMS *> ¶ms, |
| IPCArguments *arguments, size_t start, |
| size_t end) { |
| for (size_t i = start; i < end; i += 2) { |
| if (arguments->getType(i) != IPCType::BYTEARRAY) { |
| continue; |
| } |
| if (arguments->getType(1 + i) != IPCType::BYTEARRAY) { |
| continue; |
| } |
| const IPCByteArray *ba = arguments->getByteArray(1 + i); |
| const IPCByteArray *ba_type = arguments->getByteArray(i); |
| auto init_framework_params = |
| (INIT_FRAMEWORK_PARAMS *) malloc(sizeof(INIT_FRAMEWORK_PARAMS)); |
| if (init_framework_params == nullptr) { |
| break; |
| } |
| memset(init_framework_params, 0, sizeof(INIT_FRAMEWORK_PARAMS)); |
| init_framework_params->type = IPCByteArrayToWeexByteArray(ba_type); |
| init_framework_params->value = IPCByteArrayToWeexByteArray(ba); |
| params.push_back(init_framework_params); |
| } |
| } |
| |
| void initHeapTimer() { |
| HeapTimer::startTimerThread(); |
| } |
| |
| void deinitHeapTimer() { |
| HeapTimer::stopTimerThread(); |
| } |
| |
| void markupStateInternally() { |
| } |
| |
| |
| void doUpdateGlobalSwitchConfig(const char *config) { |
| if (!config) { |
| return; |
| } |
| LOGE("doUpdateGlobalSwitchConfig %s", config); |
| if (strstr(config, "wson_off") != NULL) { |
| WeexEnv::getEnv()->setUseWson(false); |
| } else { |
| WeexEnv::getEnv()->setUseWson(true); |
| } |
| } |
| |
| |
| String exceptionToString(JSGlobalObject *globalObject, JSValue exception) { |
| StringBuilder sb; |
| VM &vm = globalObject->vm(); |
| auto scope = DECLARE_CATCH_SCOPE(vm); |
| |
| #define CHECK_EXCEPTION() \ |
| do { \ |
| if (scope.exception()) { \ |
| scope.clearException(); \ |
| return String(); \ |
| } \ |
| } while (false) |
| |
| sb.append(String::format("Exception: %s\n", exception.toWTFString(globalObject->globalExec()).utf8().data())); |
| |
| Identifier nameID = Identifier::fromString(globalObject->globalExec(), "name"); |
| CHECK_EXCEPTION(); |
| Identifier fileNameID = Identifier::fromString(globalObject->globalExec(), "sourceURL"); |
| CHECK_EXCEPTION(); |
| Identifier lineNumberID = Identifier::fromString(globalObject->globalExec(), "line"); |
| CHECK_EXCEPTION(); |
| Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack"); |
| CHECK_EXCEPTION(); |
| |
| JSValue nameValue = exception.get(globalObject->globalExec(), nameID); |
| CHECK_EXCEPTION(); |
| JSValue fileNameValue = exception.get(globalObject->globalExec(), fileNameID); |
| CHECK_EXCEPTION(); |
| JSValue lineNumberValue = exception.get(globalObject->globalExec(), lineNumberID); |
| CHECK_EXCEPTION(); |
| JSValue stackValue = exception.get(globalObject->globalExec(), stackID); |
| CHECK_EXCEPTION(); |
| |
| if (nameValue.toWTFString(globalObject->globalExec()) == "SyntaxError" |
| && (!fileNameValue.isUndefinedOrNull() || !lineNumberValue.isUndefinedOrNull())) { |
| sb.append(String::format( |
| "at %s:%s\n", |
| fileNameValue.toWTFString(globalObject->globalExec()).utf8().data(), |
| lineNumberValue.toWTFString(globalObject->globalExec()).utf8().data())); |
| } |
| |
| if (!stackValue.isUndefinedOrNull()) |
| sb.append(String::format("%s\n", stackValue.toWTFString(globalObject->globalExec()).utf8().data())); |
| |
| #undef CHECK_EXCEPTION |
| return sb.toString(); |
| } |
| |
| void setJSFVersion(WeexGlobalObject *globalObject) { |
| VM &vm = globalObject->vm(); |
| PropertyName getJSFMVersionProperty(Identifier::fromString(&vm, "getJSFMVersion")); |
| ExecState *state = globalObject->globalExec(); |
| JSValue getJSFMVersionFunction = globalObject->get(state, getJSFMVersionProperty); |
| MarkedArgumentBuffer args; |
| CallData callData; |
| CallType callType = getCallData(getJSFMVersionFunction, callData); |
| NakedPtr<Exception> returnedException; |
| JSValue version = call(globalObject->globalExec(), getJSFMVersionFunction, callType, callData, globalObject, args, |
| returnedException); |
| if (returnedException) { |
| ReportException(globalObject, returnedException.get(), "", ""); |
| } |
| String str = version.toWTFString(state); |
| CString data = str.utf8(); |
| |
| globalObject->js_bridge()->core_side()->SetJSVersion(data.data()); |
| } |
| |
| |
| void ReportException(JSGlobalObject *_globalObject, Exception *exception, const char *instanceid, |
| const char *func) { |
| String exceptionInfo = exceptionToString(_globalObject, exception->value()); |
| CString data = exceptionInfo.utf8(); |
| |
| auto *globalObject = static_cast<WeexGlobalObject *>(_globalObject); |
| globalObject->js_bridge()->core_side()->ReportException(instanceid, func, data.data()); |
| } |
| |
| |
| uint64_t microTime() { |
| struct timeval tv; |
| |
| gettimeofday(&tv, nullptr); |
| |
| return (((uint64_t) tv.tv_sec) * MICROSEC + tv.tv_usec); |
| } |
| |
| |
| int __atomic_inc(volatile int *ptr) { |
| return __sync_fetch_and_add(ptr,1); |
| } |
| static int taskIdGenerator = 0; |
| int genTaskId(){ |
| return __atomic_inc(&taskIdGenerator); |
| } |
| |
| /** |
| * this function is to execute a section of JavaScript content. |
| */ |
| bool ExecuteJavaScript(JSGlobalObject *globalObject, |
| const String &source, |
| const String &url, |
| bool report_exceptions, |
| const char *func, |
| const char *instanceId) { |
| SourceOrigin sourceOrigin(String::fromUTF8("(weex)")); |
| NakedPtr<Exception> evaluationException; |
| JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, sourceOrigin, url), JSValue(), |
| evaluationException); |
| |
| if (report_exceptions && evaluationException) { |
| ReportException(globalObject, evaluationException.get(), instanceId, func); |
| return false; |
| } |
| |
| if (evaluationException) |
| return false; |
| |
| globalObject->vm().drainMicrotasks(); |
| |
| return true; |
| } |
| |
| char *getCharFromUniquePtr(std::unique_ptr<char[]> str) { |
| return str == nullptr ? nullptr : str.get(); |
| } |
| |
| WeexByteArray *IPCByteArrayToWeexByteArray(const IPCByteArray *byteArray) { |
| return genWeexByteArraySS(byteArray->content, byteArray->length); |
| } |
| |
| |
| namespace WEEXICU { |
| unique_fd::unique_fd(int fd) |
| : m_fd(fd) { |
| } |
| |
| unique_fd::~unique_fd() { |
| close(m_fd); |
| } |
| |
| int unique_fd::get() const { |
| return m_fd; |
| } |
| } |