Index: tools/servicec/lib/src/plugins/java.dart |
diff --git a/tools/servicec/lib/src/plugins/java.dart b/tools/servicec/lib/src/plugins/java.dart |
deleted file mode 100644 |
index a0e60900ae4b25786d27decf44ba475cb0485968..0000000000000000000000000000000000000000 |
--- a/tools/servicec/lib/src/plugins/java.dart |
+++ /dev/null |
@@ -1,1381 +0,0 @@ |
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library old_servicec.plugins.java; |
- |
-import 'dart:core' hide Type; |
-import 'dart:io'; |
- |
-import 'package:path/path.dart' show |
- basenameWithoutExtension, |
- join, |
- relative; |
-import 'package:servicec/util.dart' as strings; |
- |
-import 'shared.dart'; |
-import '../emitter.dart'; |
-import '../struct_layout.dart'; |
-import '../primitives.dart' as primitives; |
- |
-import 'cc.dart' show CcVisitor; |
- |
-const HEADER = """ |
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE.md file. |
- |
-// Generated file. Do not edit. |
-"""; |
- |
-const HEADER_MK = """ |
-# Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
-# for details. All rights reserved. Use of this source code is governed by a |
-# BSD-style license that can be found in the LICENSE.md file. |
- |
-# Generated file. Do not edit. |
-"""; |
- |
-const READER_HEADER = """ |
-package dartino; |
-"""; |
- |
-const DARTINO_API_JAVA = """ |
-package dartino; |
- |
-public class DartinoApi { |
- public static abstract class PrintInterceptor { |
- public abstract void Out(String message); |
- public abstract void Error(String message); |
- private long nativePtr = 0; |
- } |
- public static native void Setup(); |
- public static native void TearDown(); |
- public static native void RunSnapshot(byte[] snapshot); |
- public static native void WaitForDebuggerConnection(int port); |
- public static native void AddDefaultSharedLibrary(String library); |
- public static native void RegisterPrintInterceptor(PrintInterceptor interceptor); |
- public static native void UnregisterPrintInterceptor(PrintInterceptor interceptor); |
-} |
-"""; |
- |
-const DARTINO_SERVICE_API_JAVA = """ |
-package dartino; |
- |
-public class DartinoServiceApi { |
- public static native void Setup(); |
- public static native void TearDown(); |
-} |
-"""; |
- |
-const DARTINO_API_JAVA_IMPL = """ |
-#include <jni.h> |
-#include <stdlib.h> |
- |
-#include "dartino_api.h" |
- |
-#ifdef ANDROID |
- typedef JNIEnv* AttachEnvType; |
-#else |
- typedef void* AttachEnvType; |
-#endif |
- |
-static JNIEnv* AttachCurrentThreadAndGetEnv(JavaVM* vm) { |
- AttachEnvType result = NULL; |
- if (vm->AttachCurrentThread(&result, NULL) != JNI_OK) { |
- // TODO(zerny): Nicer error recovery? |
- exit(1); |
- } |
- return reinterpret_cast<JNIEnv*>(result); |
-} |
- |
-class JNIPrintInterceptorInfo { |
- public: |
- JNIPrintInterceptorInfo(JavaVM* vm, jobject obj) |
- : vm(vm), obj(obj), interceptor(NULL) {} |
- JavaVM* vm; |
- jobject obj; |
- DartinoPrintInterceptor interceptor; |
-}; |
- |
-static void JNIPrintInterceptorFunction( |
- const char* message, int out, void* raw) { |
- JNIPrintInterceptorInfo* info = |
- reinterpret_cast<JNIPrintInterceptorInfo*>(raw); |
- JNIEnv* env = AttachCurrentThreadAndGetEnv(info->vm); |
- jobject obj = info->obj; |
- jclass clazz = env->GetObjectClass(obj); |
- jmethodID method = NULL; |
- const char* methodName = (out == 2) ? "Out" : (out == 3) ? "Error" : NULL; |
- const char* methodSig = "(Ljava/lang/String;)V"; |
- if (methodName == NULL) exit(1); |
- method = env->GetMethodID(clazz, methodName, methodSig); |
- jstring argument = env->NewStringUTF(message); |
- env->CallVoidMethod(obj, method, argument); |
- info->vm->DetachCurrentThread(); |
-} |
- |
-static void RegisterPrintInterceptor(JNIEnv* env, jobject obj) { |
- // TODO(zerny): Associate the Java object and native object in a map. |
- jclass clazz = env->GetObjectClass(obj); |
- jfieldID nativePtr = env->GetFieldID(clazz, "nativePtr", "J"); |
- jlong nativePtrValue = env->GetLongField(obj, nativePtr); |
- if (nativePtrValue != 0) return; |
- obj = env->NewGlobalRef(obj); |
- JavaVM* vm = NULL; |
- env->GetJavaVM(&vm); |
- JNIPrintInterceptorInfo* info = new JNIPrintInterceptorInfo(vm, obj); |
- info->interceptor = DartinoRegisterPrintInterceptor( |
- JNIPrintInterceptorFunction, reinterpret_cast<void*>(info)); |
- env->SetLongField(obj, nativePtr, reinterpret_cast<jlong>(info)); |
-} |
- |
-static void UnregisterPrintInterceptor(JNIEnv* env, jobject obj) { |
- // TODO(zerny): Retrieve the native object from the Java object via a map. |
- jclass clazz = env->GetObjectClass(obj); |
- jfieldID nativePtr = env->GetFieldID(clazz, "nativePtr", "J"); |
- jlong nativePtrValue = env->GetLongField(obj, nativePtr); |
- if (nativePtrValue == 0) return; |
- env->SetLongField(obj, nativePtr, 0); |
- JNIPrintInterceptorInfo* info = |
- reinterpret_cast<JNIPrintInterceptorInfo*>(nativePtrValue); |
- DartinoUnregisterPrintInterceptor(info->interceptor); |
- env->DeleteGlobalRef(info->obj); |
- delete info; |
-} |
- |
-#ifdef __cplusplus |
-extern "C" { |
-#endif |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoApi_Setup(JNIEnv*, jclass) { |
- DartinoSetup(); |
-} |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoApi_TearDown(JNIEnv*, jclass) { |
- DartinoTearDown(); |
-} |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoApi_RunSnapshot(JNIEnv* env, |
- jclass, |
- jbyteArray snapshot) { |
- int len = env->GetArrayLength(snapshot); |
- unsigned char* copy = new unsigned char[len]; |
- env->GetByteArrayRegion(snapshot, 0, len, reinterpret_cast<jbyte*>(copy)); |
- DartinoProgram program = DartinoLoadSnapshot(copy, len); |
- delete[] copy; |
- DartinoRunMain(program, 0, NULL); |
- DartinoDeleteProgram(program); |
-} |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoApi_AddDefaultSharedLibrary( |
- JNIEnv* env, jclass, jstring str) { |
- const char* library = env->GetStringUTFChars(str, 0); |
- DartinoAddDefaultSharedLibrary(library); |
- env->ReleaseStringUTFChars(str, library); |
-} |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoApi_RegisterPrintInterceptor( |
- JNIEnv* env, jclass, jobject obj) { |
- RegisterPrintInterceptor(env, obj); |
-} |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoApi_UnregisterPrintInterceptor( |
- JNIEnv* env, jclass, jobject obj) { |
- UnregisterPrintInterceptor(env, obj); |
-} |
- |
-#ifdef __cplusplus |
-} |
-#endif |
-"""; |
- |
-const DARTINO_SERVICE_API_JAVA_IMPL = """ |
-#include <jni.h> |
- |
-#include "service_api.h" |
- |
-#ifdef __cplusplus |
-extern "C" { |
-#endif |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoServiceApi_Setup(JNIEnv*, jclass) { |
- ServiceApiSetup(); |
-} |
- |
-JNIEXPORT void JNICALL Java_dartino_DartinoServiceApi_TearDown(JNIEnv*, jclass) { |
- ServiceApiTearDown(); |
-} |
- |
-#ifdef __cplusplus |
-} |
-#endif |
-"""; |
- |
-String JNI_UTILS = """ |
-static JNIEnv* AttachCurrentThreadAndGetEnv(JavaVM* vm) { |
- AttachEnvType result = NULL; |
- if (vm->AttachCurrentThread(&result, NULL) != JNI_OK) { |
- // TODO(ager): Nicer error recovery? |
- exit(1); |
- } |
- return reinterpret_cast<JNIEnv*>(result); |
-} |
- |
-static void DetachCurrentThread(JavaVM* vm) { |
- if (vm->DetachCurrentThread() != JNI_OK) { |
- // TODO(ager): Nicer error recovery? |
- exit(1); |
- } |
-} |
- |
-static jobject CreateByteArray(JNIEnv* env, char* memory, int size) { |
- jbyteArray result = env->NewByteArray(size); |
- jbyte* contents = reinterpret_cast<jbyte*>(memory); |
- env->SetByteArrayRegion(result, 0, size, contents); |
- free(memory); |
- return result; |
-} |
- |
-static jobject CreateByteArrayArray(JNIEnv* env, char* memory, int size) { |
- jobjectArray array = env->NewObjectArray(size, env->FindClass("[B"), NULL); |
- for (int i = 0; i < size; i++) { |
- int64_t address = *reinterpret_cast<int64_t*>(memory + 8 + (i * 16)); |
- int size = *reinterpret_cast<int*>(memory + 16 + (i * 16)); |
- char* contents = reinterpret_cast<char*>(address); |
- env->SetObjectArrayElement(array, i, CreateByteArray(env, contents, size)); |
- } |
- free(memory); |
- return array; |
-} |
- |
-static jobject GetRootSegment(JNIEnv* env, char* memory) { |
- int32_t segments = *reinterpret_cast<int32_t*>(memory); |
- if (segments == 0) { |
- int32_t size = *reinterpret_cast<int32_t*>(memory + 4); |
- return CreateByteArray(env, memory, size); |
- } |
- return CreateByteArrayArray(env, memory, segments); |
-} |
- |
-class CallbackInfo { |
- public: |
- CallbackInfo(jobject jcallback, JavaVM* jvm) |
- : callback(jcallback), vm(jvm) { } |
- jobject callback; |
- JavaVM* vm; |
-}; |
- |
-static char* ExtractByteArrayData(JNIEnv* env, |
- jbyteArray segment, |
- jint segment_length) { |
- jbyte* data = env->GetByteArrayElements(segment, NULL); |
- char* segment_copy = reinterpret_cast<char*>(malloc(segment_length)); |
- memcpy(segment_copy, data, segment_length); |
- env->ReleaseByteArrayElements(segment, data, JNI_ABORT); |
- return segment_copy; |
-} |
- |
-static int ComputeMessage(JNIEnv* env, |
- jobject builder, |
- jobject callback, |
- JavaVM* vm, |
- char** buffer) { |
- CallbackInfo* info = NULL; |
- if (callback != NULL) { |
- info = new CallbackInfo(callback, vm); |
- } |
- |
- jclass clazz = env->GetObjectClass(builder); |
- jmethodID method_id = env->GetMethodID(clazz, "getSegments", "()[Ljava/lang/Object;"); |
- jobjectArray array = (jobjectArray)env->CallObjectMethod(builder, method_id); |
- jobjectArray segments = (jobjectArray)env->GetObjectArrayElement(array, 0); |
- jintArray sizes_array = (jintArray)env->GetObjectArrayElement(array, 1); |
- int* sizes = env->GetIntArrayElements(sizes_array, NULL); |
- int number_of_segments = env->GetArrayLength(segments); |
- |
- if (number_of_segments > 1) { |
- int size = $REQUEST_HEADER_SIZE + 8 + (number_of_segments * 16); |
- *buffer = reinterpret_cast<char*>(malloc(size)); |
- int offset = $REQUEST_HEADER_SIZE + 8; |
- for (int i = 0; i < number_of_segments; i++) { |
- jbyteArray segment = (jbyteArray)env->GetObjectArrayElement(segments, i); |
- jint segment_length = sizes[i]; |
- char* segment_copy = ExtractByteArrayData(env, segment, segment_length); |
- *reinterpret_cast<void**>(*buffer + offset) = segment_copy; |
- *reinterpret_cast<int*>(*buffer + offset + 8) = segment_length; |
- offset += 16; |
- } |
- |
- env->ReleaseIntArrayElements(sizes_array, sizes, JNI_ABORT); |
- // Mark the request as being segmented. |
- *${pointerToArgument('*buffer', -8, 'int64_t')} = number_of_segments; |
- // Set the callback information. |
- *${pointerToArgument('*buffer', -16, 'CallbackInfo*')} = info; |
- return size; |
- } |
- |
- jbyteArray segment = (jbyteArray)env->GetObjectArrayElement(segments, 0); |
- jint segment_length = sizes[0]; |
- *buffer = ExtractByteArrayData(env, segment, segment_length); |
- env->ReleaseIntArrayElements(sizes_array, sizes, JNI_ABORT); |
- // Mark the request as being non-segmented. |
- *${pointerToArgument('*buffer', -8, 'int64_t')} = 0; |
- // Set the callback information. |
- *${pointerToArgument('*buffer', -16, 'CallbackInfo*')} = info; |
- return segment_length; |
-} |
- |
-static void DeleteMessage(char* message) { |
- int32_t segments = *${pointerToArgument('message', -8, 'int32_t')}; |
- for (int i = 0; i < segments; i++) { |
- int64_t address = *reinterpret_cast<int64_t*>(message + ${REQUEST_HEADER_SIZE + 8} + (i * 16)); |
- char* memory = reinterpret_cast<char*>(address); |
- free(memory); |
- } |
- free(message); |
-}"""; |
- |
-const int REQUEST_HEADER_SIZE = 56; |
- |
-String pointerToArgument(String buffer, int offset, String type) { |
- offset += REQUEST_HEADER_SIZE; |
- return 'reinterpret_cast<$type*>($buffer + $offset)'; |
-} |
- |
-const List<String> JAVA_RESOURCES = const [ |
- "Builder.java", |
- "BuilderSegment.java", |
- "ListBuilder.java", |
- "ListReader.java", |
- "MessageBuilder.java", |
- "MessageReader.java", |
- "Reader.java", |
- "Segment.java" |
-]; |
- |
-void generate(String path, |
- Unit unit, |
- String resourcesDirectory, |
- String outputDirectory) { |
- _generateDartinoApis(outputDirectory); |
- _generateServiceJava(path, unit, outputDirectory); |
- _generateServiceJni(path, unit, outputDirectory); |
- _generateServiceJniMakeFiles(path, unit, resourcesDirectory, outputDirectory); |
- |
- resourcesDirectory = join(resourcesDirectory, 'java', 'dartino'); |
- String dartinoDirectory = join(outputDirectory, 'java', 'dartino'); |
- for (String resource in JAVA_RESOURCES) { |
- String resourcePath = join(resourcesDirectory, resource); |
- File file = new File(resourcePath); |
- String contents = file.readAsStringSync(); |
- writeToFile(dartinoDirectory, resource, contents); |
- } |
-} |
- |
-void _generateDartinoApis(String outputDirectory) { |
- String dartinoDirectory = join(outputDirectory, 'java', 'dartino'); |
- String jniDirectory = join(outputDirectory, 'java', 'jni'); |
- |
- StringBuffer buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.write(DARTINO_API_JAVA); |
- writeToFile(dartinoDirectory, 'DartinoApi', buffer.toString(), |
- extension: 'java'); |
- |
- buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.write(DARTINO_SERVICE_API_JAVA); |
- writeToFile(dartinoDirectory, 'DartinoServiceApi', buffer.toString(), |
- extension: 'java'); |
- |
- buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.write(DARTINO_API_JAVA_IMPL); |
- writeToFile(jniDirectory, 'dartino_api_wrapper', buffer.toString(), |
- extension: 'cc'); |
- |
- buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.write(DARTINO_SERVICE_API_JAVA_IMPL); |
- writeToFile(jniDirectory, 'dartino_service_api_wrapper', |
- buffer.toString(), extension: 'cc'); |
-} |
- |
-void _generateServiceJava(String path, Unit unit, String outputDirectory) { |
- _JavaVisitor visitor = new _JavaVisitor(path, outputDirectory); |
- visitor.visit(unit); |
- String contents = visitor.buffer.toString(); |
- String directory = join(outputDirectory, 'java', 'dartino'); |
- // TODO(ager): We should generate a file per service here. |
- if (unit.services.length > 1) { |
- print('Java plugin: multiple services in one file is not supported.'); |
- } |
- String serviceName = unit.services.first.name; |
- writeToFile(directory, serviceName, contents, extension: 'java'); |
-} |
- |
-void _generateServiceJni(String path, Unit unit, String outputDirectory) { |
- _JniVisitor visitor = new _JniVisitor(path); |
- visitor.visit(unit); |
- String contents = visitor.buffer.toString(); |
- String directory = join(outputDirectory, 'java', 'jni'); |
- // TODO(ager): We should generate a file per service here. |
- if (unit.services.length > 1) { |
- print('Java plugin: multiple services in one file is not supported.'); |
- } |
- String projectName = basenameWithoutExtension(path); |
- String file = '${projectName}_wrapper'; |
- writeToFile(directory, file, contents, extension: 'cc'); |
-} |
- |
-class _JavaVisitor extends CodeGenerationVisitor { |
- final Set<Type> neededListTypes; |
- final String outputDirectory; |
- |
- static Map<String, String> _GETTERS = const { |
- 'bool' : 'segment.getBoolean', |
- |
- 'uint8' : 'segment.getUnsigned', |
- 'uint16' : 'segment.getUnsignedChar', |
- |
- 'int8' : 'segment.buffer().get', |
- 'int16' : 'segment.buffer().getShort', |
- 'int32' : 'segment.buffer().getInt', |
- 'int64' : 'segment.buffer().getLong', |
- |
- 'float32' : 'segment.buffer().getFloat', |
- 'float64' : 'segment.buffer().getDouble', |
- }; |
- |
- static Map<String, String> _SETTERS = const { |
- 'bool' : 'segment.buffer().put', |
- |
- 'uint8' : 'segment.buffer().put', |
- 'uint16' : 'segment.buffer().putChar', |
- |
- 'int8' : 'segment.buffer().put', |
- 'int16' : 'segment.buffer().putShort', |
- 'int32' : 'segment.buffer().putInt', |
- 'int64' : 'segment.buffer().putLong', |
- |
- 'float32' : 'segment.buffer().putFloat', |
- 'float64' : 'segment.buffer().pubDouble', |
- }; |
- |
- static Map<String, String> _SETTER_TYPES = const { |
- 'bool' : 'byte', |
- |
- 'uint8' : 'byte', |
- 'uint16' : 'char', |
- |
- 'int8' : 'byte', |
- 'int16' : 'char', |
- 'int32' : 'int', |
- 'int64' : 'long', |
- |
- 'float32' : 'float', |
- 'float64' : 'double', |
- }; |
- |
- _JavaVisitor(String path, String this.outputDirectory) |
- : neededListTypes = new Set<Type>(), |
- super(path); |
- |
- static const PRIMITIVE_TYPES = const <String, String> { |
- 'void' : 'void', |
- 'bool' : 'boolean', |
- |
- 'uint8' : 'int', |
- 'uint16' : 'int', |
- |
- 'int8' : 'int', |
- 'int16' : 'int', |
- 'int32' : 'int', |
- 'int64' : 'long', |
- |
- 'float32' : 'float', |
- 'float64' : 'double', |
- }; |
- |
- static const PRIMITIVE_LIST_TYPES = const <String, String> { |
- 'bool' : 'boolean', |
- |
- 'uint8' : 'int', |
- 'uint16' : 'int', |
- |
- 'int8' : 'int', |
- 'int16' : 'int', |
- 'int32' : 'int', |
- 'int64' : 'long', |
- |
- 'float32' : 'float', |
- 'float64' : 'double', |
- }; |
- |
- String getType(Type node) { |
- Node resolved = node.resolved; |
- if (resolved != null) { |
- return '${node.identifier}Builder'; |
- } else { |
- String type = PRIMITIVE_TYPES[node.identifier]; |
- return type; |
- } |
- } |
- |
- String getReturnType(Type node) { |
- Node resolved = node.resolved; |
- if (resolved != null) { |
- return '${node.identifier}'; |
- } else { |
- String type = PRIMITIVE_TYPES[node.identifier]; |
- return type; |
- } |
- } |
- |
- String getListType(Type node) { |
- Node resolved = node.resolved; |
- if (resolved != null) { |
- return '${node.identifier}'; |
- } else { |
- String type = PRIMITIVE_LIST_TYPES[node.identifier]; |
- return type; |
- } |
- } |
- |
- void writeType(Type node) => write(getType(node)); |
- void writeTypeToBuffer(Type node, StringBuffer buffer) { |
- buffer.write(getType(node)); |
- } |
- |
- void writeReturnType(Type node) => write(getReturnType(node)); |
- void writeReturnTypeToBuffer(Type node, StringBuffer buffer) { |
- buffer.write(getReturnType(node)); |
- } |
- |
- void writeListTypeToBuffer(Type node, StringBuffer buffer) { |
- buffer.write(getListType(node)); |
- } |
- |
- visitUnit(Unit node) { |
- writeln(HEADER); |
- writeln('package dartino;'); |
- writeln(); |
- node.structs.forEach(visit); |
- node.services.forEach(visit); |
- neededListTypes.forEach(writeListReaderImplementation); |
- neededListTypes.forEach(writeListBuilderImplementation); |
- } |
- |
- visitService(Service node) { |
- writeln('public class ${node.name} {'); |
- writeln(' public static native void Setup();'); |
- writeln(' public static native void TearDown();'); |
- node.methods.forEach(visit); |
- writeln('}'); |
- } |
- |
- visitMethod(Method node) { |
- String name = node.name; |
- String camelName = name.substring(0, 1).toUpperCase() + name.substring(1); |
- writeln(); |
- writeln(' public static abstract class ${camelName}Callback {'); |
- if (!node.returnType.isVoid && !node.returnType.isPrimitive) { |
- write(' public final java.lang.Class returnType = '); |
- writeReturnType(node.returnType); |
- writeln('.class;'); |
- } |
- write(' public abstract void handle('); |
- if (!node.returnType.isVoid) { |
- writeReturnType(node.returnType); |
- write(' result'); |
- } |
- writeln(');'); |
- writeln(' }'); |
- |
- writeln(); |
- write(' public static native '); |
- writeReturnType(node.returnType); |
- write(' $name('); |
- visitArguments(node.arguments); |
- writeln(');'); |
- write(' public static native void ${name}Async('); |
- visitArguments(node.arguments); |
- if (node.arguments.isNotEmpty) write(', '); |
- writeln('${camelName}Callback callback);'); |
- } |
- |
- visitArguments(List<Formal> formals) { |
- visitNodes(formals, (first) => first ? '' : ', '); |
- } |
- |
- visitFormal(Formal node) { |
- writeType(node.type); |
- write(' ${node.name}'); |
- } |
- |
- visitStruct(Struct node) { |
- writeReader(node); |
- writeBuilder(node); |
- } |
- |
- void writeReader(Struct node) { |
- String dartinoDirectory = join(outputDirectory, 'java', 'dartino'); |
- String name = node.name; |
- StructLayout layout = node.layout; |
- |
- StringBuffer buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.writeln(READER_HEADER); |
- |
- buffer.writeln('import java.util.List;'); |
- buffer.writeln(); |
- |
- buffer.writeln('public class $name extends Reader {'); |
- buffer.writeln(' public $name() { }'); |
- buffer.writeln(); |
- buffer.writeln(' public $name(byte[] memory, int offset) {'); |
- buffer.writeln(' super(memory, offset);'); |
- buffer.writeln(' }'); |
- buffer.writeln(); |
- buffer.writeln(' public $name(Segment segment, int offset) {'); |
- buffer.writeln(' super(segment, offset);'); |
- buffer.writeln(' }'); |
- buffer.writeln(); |
- buffer.writeln(' public $name(byte[][] segments, int offset) {'); |
- buffer.writeln(' super(segments, offset);'); |
- buffer.writeln(' }'); |
- buffer.writeln(); |
- buffer.writeln(' public static $name create(Object rawData) {'); |
- buffer.writeln(' if (rawData instanceof byte[]) {'); |
- buffer.writeln(' return new $name((byte[])rawData, 8);'); |
- buffer.writeln(' }'); |
- buffer.writeln(' return new $name((byte[][])rawData, 8);'); |
- buffer.writeln(' }'); |
- |
- for (StructSlot slot in layout.slots) { |
- buffer.writeln(); |
- Type slotType = slot.slot.type; |
- String camel = camelize(slot.slot.name); |
- |
- if (slot.isUnionSlot) { |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- buffer.writeln( |
- ' public boolean is$camel() { return $tag == get$tagName(); }'); |
- } |
- |
- if (slotType.isList) { |
- neededListTypes.add(slotType); |
- String list = '${camelize(slotType.identifier)}List'; |
- buffer.writeln(' public $list get$camel() {'); |
- buffer.writeln(' ListReader reader = new ListReader();'); |
- buffer.writeln(' readList(reader, ${slot.offset});'); |
- buffer.writeln(' return new $list(reader);'); |
- buffer.writeln(' }'); |
- } else if (slotType.isVoid) { |
- // No getters for void slots. |
- } else if (slotType.isString) { |
- buffer.write(' public String get$camel() { '); |
- buffer.writeln('return readString(${slot.offset}); }'); |
- // TODO(ager): This is nasty. Maybe inject this type earler in the |
- // pipeline? |
- Type uint16ListType = new ListType(new SimpleType("uint16", false)); |
- uint16ListType.primitiveType = primitives.lookup("uint16"); |
- neededListTypes.add(uint16ListType); |
- buffer.writeln(' public Uint16List get${camel}Data() {'); |
- buffer.writeln(' ListReader reader = new ListReader();'); |
- buffer.writeln(' readList(reader, ${slot.offset});'); |
- buffer.writeln(' return new Uint16List(reader);'); |
- buffer.writeln(' }'); |
- } else if (slotType.isPrimitive) { |
- // TODO(ager): Dealing with unsigned numbers in Java is annoying. |
- if (camel == 'Tag') { |
- String getter = 'getUnsigned'; |
- String offset = 'base + ${slot.offset}'; |
- buffer.writeln(' public int getTag() {'); |
- buffer.writeln(' short shortTag = segment.$getter($offset);'); |
- buffer.writeln(' int tag = (int)shortTag;'); |
- buffer.writeln(' return tag < 0 ? -tag : tag;'); |
- buffer.writeln(' }'); |
- } else { |
- String getter = _GETTERS[slotType.identifier]; |
- String offset = "base + ${slot.offset}"; |
- buffer.write(' public ${getType(slotType)} get$camel() { '); |
- buffer.writeln('return $getter($offset); }'); |
- } |
- } else { |
- String returnType = getReturnType(slotType); |
- buffer.write(' public $returnType get$camel() {'); |
- if (!slotType.isPointer) { |
- String offset = 'base + ${slot.offset}'; |
- buffer.writeln(' return new $returnType(segment, $offset); }'); |
- } else { |
- buffer.writeln(); |
- int offset = slot.offset; |
- buffer.writeln(' $returnType reader = new $returnType();'); |
- buffer.writeln(' return ($returnType)readStruct(reader, $offset);'); |
- buffer.writeln(' }'); |
- } |
- } |
- } |
- |
- buffer.writeln('}'); |
- |
- writeToFile(dartinoDirectory, '$name', buffer.toString(), |
- extension: 'java'); |
- } |
- |
- void writeBuilder(Struct node) { |
- String dartinoDirectory = join(outputDirectory, 'java', 'dartino'); |
- String name = '${node.name}Builder'; |
- StructLayout layout = node.layout; |
- |
- StringBuffer buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.writeln(READER_HEADER); |
- |
- buffer.write('import java.util.List;'); |
- buffer.writeln(); |
- buffer.writeln('public class $name extends Builder {'); |
- buffer.writeln(' public static int kSize = ${layout.size};'); |
- buffer.writeln(' public $name(BuilderSegment segment, int offset) {'); |
- buffer.writeln(' super(segment, offset);'); |
- buffer.writeln(' }'); |
- buffer.writeln(); |
- buffer.writeln(' public $name() {'); |
- buffer.writeln(' super();'); |
- buffer.writeln(' }'); |
- |
- for (StructSlot slot in layout.slots) { |
- buffer.writeln(); |
- String slotName = slot.slot.name; |
- String camel = camelize(slotName); |
- Type slotType = slot.slot.type; |
- |
- String updateTag = ''; |
- if (slot.isUnionSlot) { |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- updateTag = ' set$tagName($tag);\n'; |
- } |
- |
- if (slotType.isList) { |
- String listBuilder = ''; |
- if (slotType.isPrimitive) { |
- listBuilder = '${camelize(slotType.identifier)}ListBuilder'; |
- } else { |
- listBuilder = '${getListType(slotType)}ListBuilder'; |
- } |
- buffer.writeln(' public $listBuilder init$camel(int length) {'); |
- buffer.write(updateTag); |
- int size = 0; |
- if (slotType.isPrimitive) { |
- size = primitives.size(slotType.primitiveType); |
- } else { |
- Struct element = slotType.resolved; |
- StructLayout elementLayout = element.layout; |
- size = elementLayout.size; |
- } |
- buffer.writeln(' ListBuilder builder = new ListBuilder();'); |
- buffer.writeln(' newList(builder, ${slot.offset}, length, $size);'); |
- buffer.writeln(' return new ${listBuilder}(builder);'); |
- buffer.writeln(' }'); |
- } else if (slotType.isVoid) { |
- assert(slot.isUnionSlot); |
- String tagName = camelize(slot.union.tag.name); |
- int tag = slot.unionTag; |
- buffer.writeln(' public void set$camel() {' |
- ' set$tagName($tag); }'); |
- } else if (slotType.isString) { |
- buffer.writeln(' public void set$camel(String value) {'); |
- buffer.write(updateTag); |
- buffer.writeln(' newString(${slot.offset}, value);'); |
- buffer.writeln(' }'); |
- buffer.writeln(); |
- buffer.writeln(' public Uint16ListBuilder init${camel}Data(int length) {'); |
- buffer.write(updateTag); |
- buffer.writeln(' ListBuilder builder = new ListBuilder();'); |
- buffer.writeln(' newList(builder, ${slot.offset}, length, 2);'); |
- buffer.writeln(' return new Uint16ListBuilder(builder);'); |
- buffer.writeln(' }'); |
- } else if (slotType.isPrimitive) { |
- String setter = _SETTERS[slotType.identifier]; |
- String setterType = _SETTER_TYPES[slotType.identifier]; |
- String offset = 'base + ${slot.offset}'; |
- buffer.writeln(' public void set$camel(${getType(slotType)} value) {'); |
- buffer.write(updateTag); |
- if (slotType.isBool) { |
- buffer.writeln(' $setter($offset,' |
- ' (byte)(value ? 1 : 0));'); |
- } else { |
- buffer.writeln(' $setter($offset, (${setterType})value);'); |
- } |
- buffer.writeln(' }'); |
- } else { |
- buffer.writeln(' public ${getType(slotType)} init$camel() {'); |
- buffer.write(updateTag); |
- String builderType = getType(slotType); |
- if (!slotType.isPointer) { |
- buffer.writeln(' $builderType result = new $builderType();'); |
- buffer.writeln(' result.segment = segment;'); |
- buffer.writeln(' result.base = base + ${slot.offset};'); |
- buffer.writeln(' return result;'); |
- } else { |
- Struct element = slotType.resolved; |
- StructLayout elementLayout = element.layout; |
- int size = elementLayout.size; |
- buffer.writeln(' $builderType result = new $builderType();'); |
- buffer.writeln(' newStruct(result, ${slot.offset}, $size);'); |
- buffer.writeln(' return result;'); |
- } |
- buffer.writeln(' }'); |
- } |
- } |
- |
- buffer.writeln('}'); |
- |
- writeToFile(dartinoDirectory, '$name', buffer.toString(), |
- extension: 'java'); |
- } |
- |
- void writeListReaderImplementation(Type type) { |
- String dartinoDirectory = join(outputDirectory, 'java', 'dartino'); |
- String name = '${camelize(type.identifier)}List'; |
- String listType = getListType(type); |
- |
- StringBuffer buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.writeln(READER_HEADER); |
- |
- buffer.writeln('public class $name {'); |
- if (type.isPrimitive) { |
- int elementSize = primitives.size(type.primitiveType); |
- String offset = 'reader.base + index * $elementSize'; |
- |
- buffer.writeln(' private ListReader reader;'); |
- buffer.writeln(); |
- buffer.writeln(' public $name(ListReader reader) {' |
- ' this.reader = reader; }'); |
- buffer.writeln(); |
- buffer.writeln(' public $listType get(int index) {'); |
- buffer.write(' return '); |
- buffer.writeln('reader.${_GETTERS[type.identifier]}($offset);'); |
- buffer.writeln(' }'); |
- } else { |
- Struct element = type.resolved; |
- StructLayout elementLayout = element.layout;; |
- int elementSize = elementLayout.size; |
- String returnType = getReturnType(type); |
- |
- buffer.writeln(' private ListReader reader;'); |
- buffer.writeln(); |
- buffer.writeln(' public $name(ListReader reader) {' |
- ' this.reader = reader; }'); |
- buffer.writeln(); |
- buffer.writeln(' public $returnType get(int index) {'); |
- buffer.writeln(' $returnType result = new $returnType();'); |
- buffer.writeln(' reader.readListElement(' |
- 'result, index, $elementSize);'); |
- buffer.writeln(' return result;'); |
- buffer.writeln(' }'); |
- } |
- |
- buffer.writeln(); |
- buffer.writeln(' public int size() { return reader.length; }'); |
- |
- buffer.writeln('}'); |
- |
- writeToFile(dartinoDirectory, '$name', buffer.toString(), |
- extension: 'java'); |
- } |
- |
- void writeListBuilderImplementation(Type type) { |
- String dartinoDirectory = join(outputDirectory, 'java', 'dartino'); |
- String name = '${camelize(type.identifier)}ListBuilder'; |
- |
- StringBuffer buffer = new StringBuffer(HEADER); |
- buffer.writeln(); |
- buffer.writeln(READER_HEADER); |
- |
- buffer.writeln('public class $name {'); |
- buffer.writeln(' private ListBuilder builder;'); |
- buffer.writeln(); |
- buffer.writeln(' public $name(ListBuilder builder) {' |
- ' this.builder = builder; }'); |
- buffer.writeln(); |
- |
- if (type.isPrimitive) { |
- int elementSize = primitives.size(type.primitiveType); |
- String offset = 'builder.base + index * $elementSize'; |
- String listType = getListType(type); |
- String getter = _GETTERS[type.identifier]; |
- |
- buffer.writeln(' public $listType get(int index) {'); |
- buffer.writeln(' return builder.$getter($offset);'); |
- buffer.writeln(' }'); |
- |
- buffer.writeln(); |
- String setter = _SETTERS[type.identifier]; |
- String setterType = _SETTER_TYPES[type.identifier]; |
- buffer.writeln(' public $listType set(int index, $listType value) {'); |
- buffer.write(' builder.$setter($offset, (${setterType})value);'); |
- buffer.writeln(' return value;'); |
- buffer.writeln(' }'); |
- } else { |
- Struct element = type.resolved; |
- StructLayout elementLayout = element.layout;; |
- int elementSize = elementLayout.size; |
- String structType = getType(type); |
- |
- buffer.writeln(' public $structType get(int index) {'); |
- buffer.writeln(' $structType result = new $structType();'); |
- buffer.writeln(' builder.readListElement(' |
- 'result, index, $elementSize);'); |
- buffer.writeln(' return result;'); |
- buffer.writeln(' }'); |
- } |
- |
- buffer.writeln(); |
- buffer.writeln(' public int size() { return builder.length; }'); |
- |
- buffer.writeln('}'); |
- |
- writeToFile(dartinoDirectory, '$name', buffer.toString(), |
- extension: 'java'); |
- } |
-} |
- |
-class _JniVisitor extends CcVisitor { |
- static const int REQUEST_HEADER_SIZE = 48 + 8; |
- static const int RESPONSE_HEADER_SIZE = 8; |
- |
- int methodId = 1; |
- String serviceName; |
- |
- _JniVisitor(String path) : super(path); |
- |
- visitUnit(Unit node) { |
- writeln(HEADER); |
- writeln('#include <jni.h>'); |
- writeln('#include <stdlib.h>'); |
- writeln('#include <string.h>'); |
- writeln(); |
- writeln('#include "service_api.h"'); |
- node.services.forEach(visit); |
- } |
- |
- visitService(Service node) { |
- serviceName = node.name; |
- |
- writeln(); |
- |
- writeln('#ifdef __cplusplus'); |
- writeln('extern "C" {'); |
- writeln('#endif'); |
- |
- // TODO(ager): Get rid of this if we can. For some reason |
- // the jni.h header that is used by the NDK differs. |
- writeln(); |
- writeln('#ifdef ANDROID'); |
- writeln(' typedef JNIEnv* AttachEnvType;'); |
- writeln('#else'); |
- writeln(' typedef void* AttachEnvType;'); |
- writeln('#endif'); |
- |
- writeln(); |
- writeln('static ServiceId service_id_ = kNoServiceId;'); |
- |
- writeln(); |
- write('JNIEXPORT void JNICALL Java_dartino_'); |
- writeln('${serviceName}_Setup(JNIEnv*, jclass) {'); |
- writeln(' service_id_ = ServiceApiLookup("$serviceName");'); |
- writeln('}'); |
- |
- writeln(); |
- write('JNIEXPORT void JNICALL Java_dartino_'); |
- writeln('${serviceName}_TearDown(JNIEnv*, jclass) {'); |
- writeln(' ServiceApiTerminate(service_id_);'); |
- writeln('}'); |
- |
- // TODO(ager): Put this in resources and copy as a file instead. |
- writeln(); |
- writeln(JNI_UTILS); |
- |
- node.methods.forEach(visit); |
- |
- writeln(); |
- writeln('#ifdef __cplusplus'); |
- writeln('}'); |
- writeln('#endif'); |
- } |
- |
- visitMethod(Method node) { |
- String name = node.name; |
- String id = '_k${name}Id'; |
- |
- writeln(); |
- write('static const MethodId $id = '); |
- writeln('reinterpret_cast<MethodId>(${methodId++});'); |
- |
- writeln(); |
- write('JNIEXPORT '); |
- writeReturnType(node.returnType); |
- write(' JNICALL Java_dartino_${serviceName}_${name}('); |
- write('JNIEnv* _env, jclass'); |
- if (node.arguments.isNotEmpty) write(', '); |
- if (node.inputKind != InputKind.PRIMITIVES) { |
- write('jobject ${node.arguments.single.name}'); |
- } else { |
- visitArguments(node.arguments); |
- } |
- writeln(') {'); |
- if (node.inputKind != InputKind.PRIMITIVES) { |
- visitStructArgumentMethodBody(id, node); |
- } else { |
- visitMethodBody(id, node); |
- } |
- writeln('}'); |
- |
- String callback; |
- if (node.inputKind == InputKind.STRUCT) { |
- Struct struct = node.arguments.single.type.resolved; |
- StructLayout layout = struct.layout; |
- callback = ensureCallback(node.returnType, layout); |
- } else { |
- callback = |
- ensureCallback(node.returnType, node.inputPrimitiveStructLayout); |
- } |
- |
- writeln(); |
- write('JNIEXPORT void JNICALL '); |
- write('Java_dartino_${serviceName}_${name}Async('); |
- write('JNIEnv* _env, jclass'); |
- if (node.arguments.isNotEmpty) write(', '); |
- if (node.inputKind != InputKind.PRIMITIVES) { |
- write('jobject ${node.arguments.single.name}'); |
- } else { |
- visitArguments(node.arguments); |
- } |
- writeln(', jobject _callback) {'); |
- writeln(' jobject callback = NULL;'); |
- writeln(' JavaVM* vm = NULL;'); |
- writeln(' if (_callback) {'); |
- writeln(' callback = _env->NewGlobalRef(_callback);'); |
- writeln(' _env->GetJavaVM(&vm);'); |
- writeln(' }'); |
- // TODO(zerny): Issue #45. Store VM pointer in 'callback data' header field. |
- if (node.inputKind != InputKind.PRIMITIVES) { |
- visitStructArgumentMethodBody(id, |
- node, |
- extraArguments: [ 'vm' ], |
- callback: callback); |
- } else { |
- visitMethodBody(id, |
- node, |
- extraArguments: [ 'vm' ], |
- callback: callback); |
- } |
- writeln('}'); |
- } |
- |
- visitMethodBody(String id, |
- Method method, |
- {bool cStyle: false, |
- List<String> extraArguments: const [], |
- String callback}) { |
- String cast(String type) => CcVisitor.cast(type, false); |
- |
- String pointerToArgument(int offset, int pointers, String type) { |
- offset += REQUEST_HEADER_SIZE; |
- String prefix = cast('$type*'); |
- if (pointers == 0) return '$prefix(_buffer + $offset)'; |
- return '$prefix(_buffer + $offset + $pointers * sizeof(void*))'; |
- } |
- |
- List<Formal> arguments = method.arguments; |
- assert(method.inputKind == InputKind.PRIMITIVES); |
- StructLayout layout = method.inputPrimitiveStructLayout; |
- final bool async = callback != null; |
- int size = REQUEST_HEADER_SIZE + layout.size; |
- if (async) { |
- write(' static const int kSize = '); |
- writeln('${size} + ${extraArguments.length} * sizeof(void*);'); |
- } else { |
- writeln(' static const int kSize = ${size};'); |
- } |
- |
- if (async) { |
- writeln(' char* _buffer = ${cast("char*")}(malloc(kSize));'); |
- } else { |
- writeln(' char _bits[kSize];'); |
- writeln(' char* _buffer = _bits;'); |
- } |
- |
- // Mark the message as being non-segmented. |
- writeln(' *${pointerToArgument(-8, 0, "int64_t")} = 0;'); |
- |
- int arity = arguments.length; |
- for (int i = 0; i < arity; i++) { |
- String name = arguments[i].name; |
- int offset = layout[arguments[i]].offset; |
- String type = PRIMITIVE_TYPES[arguments[i].type.identifier]; |
- writeln(' *${pointerToArgument(offset, 0, type)} = $name;'); |
- } |
- |
- if (async) { |
- writeln(' CallbackInfo* info = callback ? new CallbackInfo(callback, vm) : NULL;'); |
- writeln(' *${pointerToArgument(-16, 0, "CallbackInfo*")} = info;'); |
- write(' ServiceApiInvokeAsync(service_id_, $id, $callback, '); |
- writeln('_buffer, kSize);'); |
- } else { |
- writeln(' ServiceApiInvoke(service_id_, $id, _buffer, kSize);'); |
- if (method.outputKind == OutputKind.STRUCT) { |
- Type type = method.returnType; |
- writeln(' int64_t result = *${pointerToArgument(0, 0, 'int64_t')};'); |
- writeln(' char* memory = reinterpret_cast<char*>(result);'); |
- writeln(' jobject rootSegment = GetRootSegment(_env, memory);'); |
- writeln(' jclass resultClass = ' |
- '_env->FindClass("dartino/${type.identifier}");'); |
- writeln(' jmethodID create = _env->GetStaticMethodID(' |
- 'resultClass, "create", ' |
- '"(Ljava/lang/Object;)Ldartino/${type.identifier};");'); |
- writeln(' jobject resultObject = _env->CallStaticObjectMethod(' |
- 'resultClass, create, rootSegment);'); |
- writeln(' return resultObject;'); |
- } else if (!method.returnType.isVoid) { |
- writeln(' return *${pointerToArgument(0, 0, 'int64_t')};'); |
- } |
- } |
- } |
- |
- visitStructArgumentMethodBody(String id, |
- Method method, |
- {bool cStyle: false, |
- List<String> extraArguments: const [], |
- String callback}) { |
- String cast(String type) => CcVisitor.cast(type, false); |
- |
- String pointerToArgument(int offset, int pointers, String type) { |
- offset += REQUEST_HEADER_SIZE; |
- String prefix = cast('$type*'); |
- if (pointers == 0) return '$prefix(buffer + $offset)'; |
- return '$prefix(buffer + $offset + $pointers * sizeof(void*))'; |
- } |
- |
- String argumentName = method.arguments.single.name; |
- |
- bool async = callback != null; |
- String javaCallback = async ? 'callback' : 'NULL'; |
- String javaVM = async ? 'vm' : 'NULL'; |
- |
- writeln(' char* buffer = NULL;'); |
- writeln(' int size = ComputeMessage(' |
- '_env, $argumentName, $javaCallback, $javaVM, &buffer);'); |
- |
- if (async) { |
- write(' ServiceApiInvokeAsync(service_id_, $id, $callback, '); |
- writeln('buffer, size);'); |
- } else { |
- writeln(' ServiceApiInvoke(service_id_, $id, buffer, size);'); |
- writeln(' int64_t result = *${pointerToArgument(0, 0, 'int64_t')};'); |
- writeln(' DeleteMessage(buffer);'); |
- if (method.outputKind == OutputKind.STRUCT) { |
- Type type = method.returnType; |
- writeln(' char* memory = reinterpret_cast<char*>(result);'); |
- writeln(' jobject rootSegment = GetRootSegment(_env, memory);'); |
- writeln(' jclass resultClass = ' |
- '_env->FindClass("dartino/${type.identifier}");'); |
- writeln(' jmethodID create = _env->GetStaticMethodID(' |
- 'resultClass, "create", ' |
- '"(Ljava/lang/Object;)Ldartino/${type.identifier};");'); |
- writeln(' jobject resultObject = _env->CallStaticObjectMethod(' |
- 'resultClass, create, rootSegment);'); |
- writeln(' return resultObject;'); |
- } else { |
- if (!method.returnType.isVoid) writeln(' return result;'); |
- } |
- } |
- } |
- |
- static const Map<String, String> PRIMITIVE_TYPES = const { |
- 'void' : 'void', |
- 'bool' : 'jboolean', |
- |
- 'uint8' : 'jboolean', |
- 'uint16' : 'jchar', |
- |
- 'int8' : 'jbyte', |
- 'int16' : 'jshort', |
- 'int32' : 'jint', |
- 'int64' : 'jlong', |
- |
- 'float32' : 'jfloat', |
- 'float64' : 'jdouble', |
- }; |
- |
- void writeType(Type node) { |
- String type = PRIMITIVE_TYPES[node.identifier]; |
- write(type); |
- } |
- |
- void writeReturnType(Type node) { |
- Node resolved = node.resolved; |
- if (resolved != null) { |
- write('jobject'); |
- } else { |
- String type = PRIMITIVE_TYPES[node.identifier]; |
- write(type); |
- } |
- } |
- |
- static const Map<String, String> PRIMITIVE_JNI_SIG = const { |
- 'void' : '', |
- 'bool' : 'Z', |
- |
- 'uint8' : 'Z', |
- 'uint16' : 'C', |
- |
- 'int8' : 'B', |
- 'int16' : 'S', |
- 'int32' : 'I', |
- 'int64' : 'J', |
- |
- 'float32' : 'F', |
- 'float64' : 'D', |
- }; |
- |
- String getJNISignatureType(Type type) { |
- String name = type.identifier; |
- if (type.isPrimitive) return PRIMITIVE_JNI_SIG[name]; |
- return 'Ldartino/$name;'; |
- } |
- |
- final Map<String, String> callbacks = {}; |
- String ensureCallback(Type type, |
- StructLayout layout, |
- {bool cStyle: false}) { |
- String key = '${type.identifier}_${layout.size}'; |
- return callbacks.putIfAbsent(key, () { |
- String cast(String type) => CcVisitor.cast(type, cStyle); |
- String pointerToArgument(int offset, String type) { |
- offset += REQUEST_HEADER_SIZE; |
- String prefix = cast('$type*'); |
- return '$prefix(buffer + $offset)'; |
- } |
- String name = 'Unwrap_$key'; |
- writeln(); |
- writeln('static void $name(void* raw) {'); |
- writeln(' char* buffer = ${cast('char*')}(raw);'); |
- write(' CallbackInfo* info ='); |
- writeln(' *${pointerToArgument(-16, "CallbackInfo*")};'); |
- writeln(' if (info == NULL) return;'); |
- writeln(' JNIEnv* env = AttachCurrentThreadAndGetEnv(info->vm);'); |
- writeln(' jclass clazz = env->GetObjectClass(info->callback);'); |
- if (!type.isVoid) { |
- write(' int64_t result ='); |
- writeln(' *${pointerToArgument(0, 'int64_t')};'); |
- writeln(' DeleteMessage(buffer);'); |
- if (!type.isPrimitive) { |
- writeln(' char* memory = reinterpret_cast<char*>(result);'); |
- writeln(' jobject rootSegment = GetRootSegment(env, memory);'); |
- write(' jfieldID returnTypeField = env->GetFieldID('); |
- writeln('clazz, "returnType", "Ljava/lang/Class;");'); |
- write(' jclass resultClass = (jclass)'); |
- writeln('env->GetObjectField(info->callback, returnTypeField);'); |
- writeln(' jmethodID create = env->GetStaticMethodID(' |
- 'resultClass, "create", ' |
- '"(Ljava/lang/Object;)Ldartino/${type.identifier};");'); |
- writeln(' jobject resultObject = env->CallStaticObjectMethod(' |
- 'resultClass, create, rootSegment);'); |
- } |
- } else { |
- writeln(' DeleteMessage(buffer);'); |
- } |
- write(' jmethodID methodId = env->GetMethodID'); |
- write('(clazz, "handle", '); |
- if (type.isVoid) { |
- writeln('"()V");'); |
- writeln(' env->CallVoidMethod(info->callback, methodId);'); |
- } else { |
- String signatureType = getJNISignatureType(type); |
- writeln('"($signatureType)V");'); |
- write(' env->CallVoidMethod(info->callback, methodId,'); |
- if (!type.isPrimitive) { |
- writeln(' resultObject);'); |
- } else { |
- writeln(' result);'); |
- } |
- } |
- writeln(' env->DeleteGlobalRef(info->callback);'); |
- writeln(' DetachCurrentThread(info->vm);'); |
- writeln(' delete info;'); |
- writeln('}'); |
- return name; |
- }); |
- } |
-} |
- |
-void _generateServiceJniMakeFiles(String path, |
- Unit unit, |
- String resourcesDirectory, |
- String outputDirectory) { |
- String out = join(outputDirectory, 'java'); |
- // TODO(stanm): pass dartino root directly |
- String dartinoRoot = join(resourcesDirectory, '..', '..', '..', '..', '..'); |
- String dartinoLibraryBuildDir = join(dartinoRoot, |
- 'tools', |
- 'android_build', |
- 'jni'); |
- |
- String dartinoIncludeDir = join(dartinoRoot, 'include'); |
- |
- String modulePath = relative(dartinoLibraryBuildDir, from: out); |
- String includePath = relative(dartinoIncludeDir, from: out); |
- |
- StringBuffer buffer = new StringBuffer(HEADER_MK); |
- |
- buffer.writeln(); |
- buffer.writeln('LOCAL_PATH := \$(call my-dir)'); |
- |
- buffer.writeln(); |
- buffer.writeln('include \$(CLEAR_VARS)'); |
- buffer.writeln('LOCAL_MODULE := dartino'); |
- buffer.writeln('LOCAL_CFLAGS := -DDARTINO32'); |
- buffer.writeln('LOCAL_LDLIBS := -llog -ldl -rdynamic'); |
- |
- buffer.writeln(); |
- buffer.writeln('LOCAL_SRC_FILES := \\'); |
- buffer.writeln('\tdartino_api_wrapper.cc \\'); |
- buffer.writeln('\tdartino_service_api_wrapper.cc \\'); |
- |
- if (unit.services.length > 1) { |
- print('Java plugin: multiple services in one file is not supported.'); |
- } |
- String projectName = basenameWithoutExtension(path); |
- String file = '${projectName}_wrapper'; |
- |
- buffer.writeln('\t${file}.cc'); |
- |
- buffer.writeln(); |
- buffer.writeln('LOCAL_C_INCLUDES += \$(LOCAL_PATH)'); |
- buffer.writeln('LOCAL_C_INCLUDES += ${includePath}'); |
- buffer.writeln('LOCAL_STATIC_LIBRARIES := dartino-library'); |
- |
- buffer.writeln(); |
- buffer.writeln('include \$(BUILD_SHARED_LIBRARY)'); |
- |
- buffer.writeln(); |
- buffer.writeln('\$(call import-module, ${modulePath})'); |
- |
- writeToFile(join(out, 'jni'), 'Android', buffer.toString(), |
- extension: 'mk'); |
- |
- buffer = new StringBuffer(HEADER_MK); |
- buffer.writeln('APP_STL := gnustl_static'); |
- buffer.writeln('APP_ABI := x86 armeabi-v7a'); |
- // TODO(zerny): Is this the right place and way to ensure ABI >= 8? |
- buffer.writeln('APP_PLATFORM := android-8'); |
- writeToFile(join(out, 'jni'), 'Application', buffer.toString(), |
- extension: 'mk'); |
-} |