Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NativeScript/runtime/Interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,11 @@ class Interop {
static id CallInitializer(v8::Local<v8::Context> context, const MethodMeta* methodMeta, id target, Class clazz, V8Args& args);
static v8::Local<v8::Value> CallFunction(ObjCMethodCall& methodCall);
static v8::Local<v8::Value> CallFunction(CMethodCall& methodCall);
static v8::Local<v8::Value> GetResultByType(v8::Local<v8::Context> context, BaseDataWrapper* typeWrapper, BaseCall* call, std::shared_ptr<v8::Persistent<v8::Value>> parentStruct = nullptr);
static v8::Local<v8::Value> GetResult(v8::Local<v8::Context> context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr<v8::Persistent<v8::Value>> parentStruct = nullptr, bool isStructMember = false, bool ownsReturnedObject = false, bool returnsUnmanaged = false, bool isInitializer = false);
static void SetStructPropertyValue(v8::Local<v8::Context> context, StructWrapper* wrapper, StructField field, v8::Local<v8::Value> value);
static void InitializeStruct(v8::Local<v8::Context> context, void* destBuffer, std::vector<StructField> fields, v8::Local<v8::Value> inititalizer);
static void WriteTypeValue(v8::Local<v8::Context> context, BaseDataWrapper* typeWrapper, void* dest, v8::Local<v8::Value> arg);
static void WriteValue(v8::Local<v8::Context> context, const TypeEncoding* typeEncoding, void* dest, v8::Local<v8::Value> arg);
static id ToObject(v8::Local<v8::Context> context, v8::Local<v8::Value> arg);
static v8::Local<v8::Value> GetPrimitiveReturnType(v8::Local<v8::Context> context, BinaryTypeEncodingType type, BaseCall* call);
Expand Down
61 changes: 56 additions & 5 deletions NativeScript/runtime/Interop.mm
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,44 @@ inline bool isBool() {
IsOfType _isObject = UNDEFINED;
};

void Interop::WriteTypeValue(Local<Context> context, BaseDataWrapper* typeWrapper, void* dest, Local<Value> arg) {
Isolate* isolate = context->GetIsolate();
ValueCache argHelper(arg);
bool isEmptyOrUndefined = arg.IsEmpty() || arg->IsNullOrUndefined();
bool success = false;

if (typeWrapper->Type() == WrapperType::StructType) {
if (isEmptyOrUndefined) {
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(typeWrapper);
StructInfo structInfo = structTypeWrapper->StructInfo();

memset(dest, 0, structInfo.FFIType()->size);
success = true;
} else if (argHelper.isObject()) {
BaseDataWrapper* wrapper = tns::GetValue(isolate, arg);
if (wrapper != nullptr) {
if (wrapper->Type() == WrapperType::Struct) {
StructWrapper* structWrapper = static_cast<StructWrapper*>(wrapper);
void* buffer = structWrapper->Data();
size_t size = structWrapper->StructInfo().FFIType()->size;
memcpy(dest, buffer, size);
success = true;
}
} else {
// Create the structure using the struct initializer syntax
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(typeWrapper);
StructInfo structInfo = structTypeWrapper->StructInfo();
Interop::InitializeStruct(context, dest, structInfo.Fields(), arg.As<Object>());
success = true;
}
}
}

if (!success) {
tns::Assert(false, isolate);
}
}

void Interop::WriteValue(Local<Context> context, const TypeEncoding* typeEncoding, void* dest, Local<Value> arg) {
Isolate* isolate = context->GetIsolate();
ExecuteWriteValueDebugValidationsIfInDebug(context, typeEncoding, dest, arg);
Expand Down Expand Up @@ -806,6 +844,21 @@ inline bool isBool() {
*static_cast<T*>((void*)((uint8_t*)destBuffer + position)) = result;
}

Local<Value> Interop::GetResultByType(Local<Context> context, BaseDataWrapper* typeWrapper, BaseCall* call, std::shared_ptr<Persistent<Value>> parentStruct) {
Isolate* isolate = context->GetIsolate();

if (typeWrapper->Type() == WrapperType::StructType) {
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(typeWrapper);
StructInfo structInfo = structTypeWrapper->StructInfo();

void* result = call->ResultBuffer();
Local<Value> value = Interop::StructToValue(context, result, structInfo, parentStruct);
return value;
}

return Null(isolate);
}

Local<Value> Interop::GetResult(Local<Context> context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr<Persistent<Value>> parentStruct, bool isStructMember, bool ownsReturnedObject, bool returnsUnmanaged, bool isInitializer) {
Isolate* isolate = context->GetIsolate();

Expand Down Expand Up @@ -1031,18 +1084,16 @@ inline bool isBool() {
}

const TypeEncoding* innerType = typeEncoding->details.pointer.getInnerType();
Local<Value> pointer = Pointer::NewInstance(context, result);

if (innerType->type == BinaryTypeEncodingType::VoidEncoding) {
Local<Value> instance = Pointer::NewInstance(context, result);
return instance;
return pointer;
}

BaseCall c(result);
Local<Value> value = Interop::GetResult(context, innerType, &c, true);
Local<Value> type = Interop::GetInteropType(context, innerType->type);

std::vector<Local<Value>> args;
args.push_back(value);
args.push_back(pointer);
if (!type.IsEmpty()) {
args.insert(args.begin(), type);
}
Expand Down
112 changes: 78 additions & 34 deletions NativeScript/runtime/Reference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,20 @@ void Reference::IndexedPropertyGetCallback(uint32_t index, const PropertyCallbac
Local<Object> thiz = info.This();
Local<Context> context = isolate->GetCurrentContext();

DataPair pair = Reference::GetTypeEncodingDataPair(thiz);
DataPair pair = Reference::GetDataPair(thiz);
const TypeEncoding* typeEncoding = pair.typeEncoding_;
size_t size = pair.size_;
void* data = pair.data_;

void* ptr = (uint8_t*)data + index * size;
BaseCall call((uint8_t*)ptr);
Local<Value> result = Interop::GetResult(context, typeEncoding, &call, false);

Local<Value> result;
if (typeEncoding != nullptr) {
result = Interop::GetResult(context, typeEncoding, &call, false);
} else {
result = Interop::GetResultByType(context, pair.typeWrapper_, &call);
}
info.GetReturnValue().Set(result);
}

Expand All @@ -115,13 +121,17 @@ void Reference::IndexedPropertySetCallback(uint32_t index, Local<Value> value, c
Local<Context> context = isolate->GetCurrentContext();
Local<Object> thiz = info.This();

DataPair pair = Reference::GetTypeEncodingDataPair(thiz);
DataPair pair = Reference::GetDataPair(thiz);
const TypeEncoding* typeEncoding = pair.typeEncoding_;
size_t size = pair.size_;
void* data = pair.data_;

void* ptr = (uint8_t*)data + index * size;
Interop::WriteValue(context, typeEncoding, ptr, value);

if (typeEncoding != nullptr) {
Interop::WriteValue(context, typeEncoding, ptr, value);
} else {
Interop::WriteTypeValue(context, pair.typeWrapper_, ptr, value);
}
}

void Reference::GetValueCallback(Local<v8::Name> name, const PropertyCallbackInfo<Value>& info) {
Expand Down Expand Up @@ -186,11 +196,17 @@ Local<Value> Reference::GetReferredValue(Local<Context> context, Local<Value> va
}

BaseDataWrapper* typeWrapper = wrapper->TypeWrapper();
if (typeWrapper != nullptr && typeWrapper->Type() == WrapperType::Primitive && baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Pointer) {
Reference::DataPair pair = GetTypeEncodingDataPair(value.As<Object>());
if (pair.data_ != nullptr && pair.typeEncoding_ != nullptr) {
if (typeWrapper != nullptr && Reference::IsSupportedType(typeWrapper->Type()) && baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Pointer) {
Reference::DataPair pair = Reference::GetDataPair(value.As<Object>());
if (pair.data_ != nullptr) {
BaseCall call((uint8_t*)pair.data_);
Local<Value> result = Interop::GetResult(context, pair.typeEncoding_, &call, false);
Local<Value> result;

if (pair.typeEncoding_ != nullptr) {
result = Interop::GetResult(context, pair.typeEncoding_, &call, false);
} else {
result = Interop::GetResultByType(context, typeWrapper, &call);
}
return result;
}
}
Expand All @@ -203,7 +219,6 @@ void* Reference::GetWrappedPointer(Local<Context> context, Local<Value> referenc
return nullptr;
}


Isolate* isolate = context->GetIsolate();
BaseDataWrapper* wrapper = tns::GetValue(isolate, reference);
tns::Assert(wrapper != nullptr && wrapper->Type() == WrapperType::Reference, isolate);
Expand Down Expand Up @@ -313,47 +328,76 @@ void Reference::RegisterToStringMethod(Local<Context> context, Local<Object> pro
tns::Assert(success, isolate);
}

Reference::DataPair Reference::GetTypeEncodingDataPair(Local<Object> obj) {
Reference::DataPair Reference::GetDataPair(Local<Object> obj) {
Local<Context> context;
bool success = obj->GetCreationContext().ToLocal(&context);
tns::Assert(success);
Isolate* isolate = context->GetIsolate();
BaseDataWrapper* wrapper = tns::GetValue(isolate, obj);
tns::Assert(wrapper != nullptr && wrapper->Type() == WrapperType::Reference, isolate);
ReferenceWrapper* refWrapper = static_cast<ReferenceWrapper*>(wrapper);

BaseDataWrapper* typeWrapper = refWrapper->TypeWrapper();
if (typeWrapper == nullptr) {
// TODO: Missing type when creating the Reference instance
tns::Assert(false, isolate);
}

if (typeWrapper->Type() != WrapperType::Primitive) {
// TODO: Currently only PrimitiveDataWrappers are supported as type parameters
// Objective C class classes and structures should also be handled
tns::Assert(false, isolate);
}

PrimitiveDataWrapper* primitiveWrapper = static_cast<PrimitiveDataWrapper*>(typeWrapper);

size_t size = 0;

if (typeWrapper != nullptr) {
const TypeEncoding* typeEncoding = nullptr;

if (Reference::IsSupportedType(typeWrapper->Type())) {
switch(typeWrapper->Type()) {
case WrapperType::Primitive: {
PrimitiveDataWrapper* primitiveWrapper = static_cast<PrimitiveDataWrapper*>(typeWrapper);

size = primitiveWrapper->Size();
typeEncoding = primitiveWrapper->TypeEncoding();
break;
}
case WrapperType::StructType: {
StructTypeWrapper* structTypeWrapper = static_cast<StructTypeWrapper*>(refWrapper->TypeWrapper());
StructInfo structInfo = structTypeWrapper->StructInfo();

size = structInfo.FFIType()->size;
break;
}
default: {
break;
}
}
} else {
// TODO: Currently only PrimitiveDataWrappers and Structs are supported as type parameters
// Objective C class classes should also be handled
tns::Assert(false, isolate);
}

Local<Value> value = refWrapper->Value()->Get(isolate);
BaseDataWrapper* wrappedValue = tns::GetValue(isolate, value);
if (wrappedValue != nullptr && wrappedValue->Type() == WrapperType::Pointer) {
const TypeEncoding* typeEncoding = primitiveWrapper->TypeEncoding();
PointerWrapper* pw = static_cast<PointerWrapper*>(wrappedValue);
void* data = pw->Data();
Local<Value> value = refWrapper->Value()->Get(isolate);
BaseDataWrapper* wrappedValue = tns::GetValue(isolate, value);
if (wrappedValue != nullptr && wrappedValue->Type() == WrapperType::Pointer) {
PointerWrapper* pw = static_cast<PointerWrapper*>(wrappedValue);
void* data = pw->Data();

DataPair pair(typeEncoding, data, primitiveWrapper->Size());
return pair;
DataPair pair(typeWrapper, typeEncoding, data, size);
return pair;
}
}

if (refWrapper->Encoding() != nullptr && refWrapper->Data() != nullptr) {
DataPair pair(refWrapper->Encoding(), refWrapper->Data(), primitiveWrapper->Size());
const TypeEncoding* typeEncoding = refWrapper->Encoding();

if (typeWrapper == nullptr) {
ffi_type* ffiType = FFICall::GetArgumentType(typeEncoding);
size = ffiType->size;
FFICall::DisposeFFIType(ffiType, typeEncoding);
}

DataPair pair(typeWrapper, typeEncoding, refWrapper->Data(), size);
return pair;
}

tns::Assert(false, isolate);
return DataPair(nullptr, nullptr, 0);
return DataPair(typeWrapper, nullptr, nullptr, size);
}

bool Reference::IsSupportedType(WrapperType type) {
return type == WrapperType::Primitive || type == WrapperType::StructType;
}
}
6 changes: 4 additions & 2 deletions NativeScript/runtime/Reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ class Reference {
static void* GetWrappedPointer(v8::Local<v8::Context> context, v8::Local<v8::Value> reference, const TypeEncoding* typeEncoding);
private:
struct DataPair {
DataPair(const TypeEncoding* typeEncoding, void* data, size_t size): typeEncoding_(typeEncoding), data_(data), size_(size) {
DataPair(BaseDataWrapper* typeWrapper, const TypeEncoding* typeEncoding, void* data, size_t size): typeWrapper_(typeWrapper), typeEncoding_(typeEncoding), data_(data), size_(size) {
}

BaseDataWrapper* typeWrapper_;
const TypeEncoding* typeEncoding_;
void* data_;
size_t size_;
Expand All @@ -30,7 +31,8 @@ class Reference {
static void GetValueCallback(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info);
static void SetValueCallback(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info);
static void RegisterToStringMethod(v8::Local<v8::Context> context, v8::Local<v8::Object> prototype);
static DataPair GetTypeEncodingDataPair(v8::Local<v8::Object> obj);
static DataPair GetDataPair(v8::Local<v8::Object> obj);
static bool IsSupportedType(WrapperType type);
};

}
Expand Down
13 changes: 13 additions & 0 deletions TestFixtures/Interfaces/TNSPointCollection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

#import <Foundation/Foundation.h>

typedef struct TNSPoint {
int x;
int y;
} TNSPoint;

@interface TNSPointCollection : NSObject
- (instancetype)initWithPoints:(const TNSPoint *)points count:(NSUInteger)count;
@property (nonatomic, readonly) TNSPoint *points NS_RETURNS_INNER_POINTER;
@property (nonatomic, readonly) NSUInteger pointCount;
@end
42 changes: 42 additions & 0 deletions TestFixtures/Interfaces/TNSPointCollection.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#import "TNSPointCollection.h"

NS_ASSUME_NONNULL_BEGIN

@implementation TNSPointCollection
{
TNSPoint *_points;
NSUInteger _pointCount;
}

- (instancetype)initWithPoints:(const TNSPoint *)points count:(NSUInteger)count
{
self = [super init];
if (self)
{
_pointCount = count;
if (count > 0)
{
_points = malloc(sizeof(TNSPoint) * count);
memcpy(_points, points, sizeof(TNSPoint) * count);
}
else
{
_points = NULL;
}
}
return self;
}

- (NSUInteger)pointCount
{
return _pointCount;
}

- (TNSPoint *)points
{
return _points;
}

@end

NS_ASSUME_NONNULL_END
1 change: 1 addition & 0 deletions TestFixtures/TestFixtures.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import "Interfaces/TNSConstructorResolution.h"
#import "Interfaces/TNSInheritance.h"
#import "Interfaces/TNSMethodCalls.h"
#import "Interfaces/TNSPointCollection.h"
#import "Interfaces/TNSSwiftLike.h"

#import "Marshalling/TNSAllocLog.h"
Expand Down
Loading