1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "v8_native_function.h"
17
18 #include "utils/log.h"
19
V8NativeFunction(V8NativeEngine * engine,v8::Local<v8::Value> value)20 V8NativeFunction::V8NativeFunction(V8NativeEngine* engine, v8::Local<v8::Value> value) : V8NativeObject(engine, value)
21 {
22 }
23
V8NativeFunction(V8NativeEngine * engine,const char * name,size_t length,NativeCallback cb,void * value)24 V8NativeFunction::V8NativeFunction(V8NativeEngine* engine,
25 const char* name,
26 size_t length,
27 NativeCallback cb,
28 void* value)
29 : V8NativeFunction(engine, v8::Local<v8::Value>())
30 {
31 auto context = engine->GetContext();
32 auto isolate = engine->GetIsolate();
33 v8::Local<v8::Array> cbdata = v8::Array::New(isolate);
34
35 int32_t index = 0;
36 cbdata->Set(context, index++, v8::External::New(isolate, (void*)engine)).FromJust();
37 cbdata->Set(context, index++, v8::External::New(isolate, (void*)cb)).FromJust();
38 cbdata->Set(context, index, v8::External::New(isolate, value)).FromJust();
39
40 v8::Local<v8::Function> fn =
41 v8::Function::New(context, NativeFunctionCallback, cbdata).ToLocalChecked();
42
43 v8::Local<v8::String> fnName = v8::String::NewFromUtf8(isolate, name).ToLocalChecked();
44
45 fn->SetName(fnName);
46
47 value_ = fn;
48 }
49
~V8NativeFunction()50 V8NativeFunction::~V8NativeFunction() {}
51
GetInterface(int interfaceId)52 void* V8NativeFunction::GetInterface(int interfaceId)
53 {
54 return (NativeFunction::INTERFACE_ID == interfaceId) ? (NativeFunction*)this
55 : V8NativeObject::GetInterface(interfaceId);
56 }
57
NativeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value> & info)58 void V8NativeFunction::NativeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
59 {
60 v8::Isolate::Scope isolateScope(info.GetIsolate());
61 v8::HandleScope handleScope(info.GetIsolate());
62 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
63 v8::Local<v8::Array> cbdata = info.Data().As<v8::Array>();
64
65 int32_t index = 0;
66 V8NativeEngine* engine =
67 (V8NativeEngine*)cbdata->Get(context, index++).ToLocalChecked().As<v8::External>()->Value();
68 if (engine == nullptr) {
69 HILOG_ERROR("engine is nullptr");
70 return;
71 }
72 NativeCallback cb = (NativeCallback)cbdata->Get(context, index++).ToLocalChecked().As<v8::External>()->Value();
73 void* data = cbdata->Get(context, index).ToLocalChecked().As<v8::External>()->Value();
74
75 auto funcinfo = new NativeFunctionInfo();
76 if (funcinfo == nullptr) {
77 HILOG_ERROR("create native function info failed");
78 return;
79 }
80
81 funcinfo->engine = engine;
82 funcinfo->callback = cb;
83 funcinfo->data = data;
84
85 NativeScopeManager* scopeManager = engine->GetScopeManager();
86 if (scopeManager == nullptr) {
87 HILOG_ERROR("Get scope manager failed");
88 delete funcinfo;
89 return;
90 }
91 NativeScope* scope = scopeManager->Open();
92 if (scope == nullptr) {
93 HILOG_ERROR("Open scope failed");
94 delete funcinfo;
95 return;
96 }
97
98 NativeCallbackInfo cbinfo = { 0 };
99 cbinfo.thisVar = V8NativeEngine::V8ValueToNativeValue(engine, info.This());
100 cbinfo.function = V8NativeEngine::V8ValueToNativeValue(engine, info.NewTarget());
101 cbinfo.argc = info.Length();
102 cbinfo.argv = nullptr;
103 cbinfo.functionInfo = funcinfo;
104 if (cbinfo.argc > 0) {
105 cbinfo.argv = new NativeValue* [cbinfo.argc];
106 for (size_t i = 0; i < cbinfo.argc && cbinfo.argv != nullptr; i++) {
107 cbinfo.argv[i] = V8NativeEngine::V8ValueToNativeValue(engine, info[i]);
108 }
109 }
110
111 NativeValue* result = nullptr;
112 if (cb != nullptr) {
113 result = cb(engine, &cbinfo);
114 }
115
116 if (cbinfo.argv != nullptr) {
117 delete []cbinfo.argv;
118 }
119 delete funcinfo;
120
121 v8::Local<v8::Value> v8Result;
122 if (result == nullptr) {
123 if (engine->IsExceptionPending()) {
124 NativeValue* error = engine->GetAndClearLastException();
125 if (error != nullptr) {
126 v8Result = *error;
127 }
128 } else {
129 v8Result = v8::Undefined(engine->GetIsolate());
130 }
131 } else {
132 v8Result = *result;
133 }
134
135 info.GetReturnValue().Set<v8::Value>(v8Result);
136 scopeManager->Close(scope);
137 }
138