Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1086)

Side by Side Diff: tools/servicec/lib/src/plugins/java.dart

Issue 2035023003: Remove service-compiler related code. (Closed) Base URL: git@github.com:dartino/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/servicec/lib/src/plugins/dart.dart ('k') | tools/servicec/lib/src/plugins/shared.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library old_servicec.plugins.java;
6
7 import 'dart:core' hide Type;
8 import 'dart:io';
9
10 import 'package:path/path.dart' show
11 basenameWithoutExtension,
12 join,
13 relative;
14 import 'package:servicec/util.dart' as strings;
15
16 import 'shared.dart';
17 import '../emitter.dart';
18 import '../struct_layout.dart';
19 import '../primitives.dart' as primitives;
20
21 import 'cc.dart' show CcVisitor;
22
23 const HEADER = """
24 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
25 // for details. All rights reserved. Use of this source code is governed by a
26 // BSD-style license that can be found in the LICENSE.md file.
27
28 // Generated file. Do not edit.
29 """;
30
31 const HEADER_MK = """
32 # Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
33 # for details. All rights reserved. Use of this source code is governed by a
34 # BSD-style license that can be found in the LICENSE.md file.
35
36 # Generated file. Do not edit.
37 """;
38
39 const READER_HEADER = """
40 package dartino;
41 """;
42
43 const DARTINO_API_JAVA = """
44 package dartino;
45
46 public class DartinoApi {
47 public static abstract class PrintInterceptor {
48 public abstract void Out(String message);
49 public abstract void Error(String message);
50 private long nativePtr = 0;
51 }
52 public static native void Setup();
53 public static native void TearDown();
54 public static native void RunSnapshot(byte[] snapshot);
55 public static native void WaitForDebuggerConnection(int port);
56 public static native void AddDefaultSharedLibrary(String library);
57 public static native void RegisterPrintInterceptor(PrintInterceptor intercepto r);
58 public static native void UnregisterPrintInterceptor(PrintInterceptor intercep tor);
59 }
60 """;
61
62 const DARTINO_SERVICE_API_JAVA = """
63 package dartino;
64
65 public class DartinoServiceApi {
66 public static native void Setup();
67 public static native void TearDown();
68 }
69 """;
70
71 const DARTINO_API_JAVA_IMPL = """
72 #include <jni.h>
73 #include <stdlib.h>
74
75 #include "dartino_api.h"
76
77 #ifdef ANDROID
78 typedef JNIEnv* AttachEnvType;
79 #else
80 typedef void* AttachEnvType;
81 #endif
82
83 static JNIEnv* AttachCurrentThreadAndGetEnv(JavaVM* vm) {
84 AttachEnvType result = NULL;
85 if (vm->AttachCurrentThread(&result, NULL) != JNI_OK) {
86 // TODO(zerny): Nicer error recovery?
87 exit(1);
88 }
89 return reinterpret_cast<JNIEnv*>(result);
90 }
91
92 class JNIPrintInterceptorInfo {
93 public:
94 JNIPrintInterceptorInfo(JavaVM* vm, jobject obj)
95 : vm(vm), obj(obj), interceptor(NULL) {}
96 JavaVM* vm;
97 jobject obj;
98 DartinoPrintInterceptor interceptor;
99 };
100
101 static void JNIPrintInterceptorFunction(
102 const char* message, int out, void* raw) {
103 JNIPrintInterceptorInfo* info =
104 reinterpret_cast<JNIPrintInterceptorInfo*>(raw);
105 JNIEnv* env = AttachCurrentThreadAndGetEnv(info->vm);
106 jobject obj = info->obj;
107 jclass clazz = env->GetObjectClass(obj);
108 jmethodID method = NULL;
109 const char* methodName = (out == 2) ? "Out" : (out == 3) ? "Error" : NULL;
110 const char* methodSig = "(Ljava/lang/String;)V";
111 if (methodName == NULL) exit(1);
112 method = env->GetMethodID(clazz, methodName, methodSig);
113 jstring argument = env->NewStringUTF(message);
114 env->CallVoidMethod(obj, method, argument);
115 info->vm->DetachCurrentThread();
116 }
117
118 static void RegisterPrintInterceptor(JNIEnv* env, jobject obj) {
119 // TODO(zerny): Associate the Java object and native object in a map.
120 jclass clazz = env->GetObjectClass(obj);
121 jfieldID nativePtr = env->GetFieldID(clazz, "nativePtr", "J");
122 jlong nativePtrValue = env->GetLongField(obj, nativePtr);
123 if (nativePtrValue != 0) return;
124 obj = env->NewGlobalRef(obj);
125 JavaVM* vm = NULL;
126 env->GetJavaVM(&vm);
127 JNIPrintInterceptorInfo* info = new JNIPrintInterceptorInfo(vm, obj);
128 info->interceptor = DartinoRegisterPrintInterceptor(
129 JNIPrintInterceptorFunction, reinterpret_cast<void*>(info));
130 env->SetLongField(obj, nativePtr, reinterpret_cast<jlong>(info));
131 }
132
133 static void UnregisterPrintInterceptor(JNIEnv* env, jobject obj) {
134 // TODO(zerny): Retrieve the native object from the Java object via a map.
135 jclass clazz = env->GetObjectClass(obj);
136 jfieldID nativePtr = env->GetFieldID(clazz, "nativePtr", "J");
137 jlong nativePtrValue = env->GetLongField(obj, nativePtr);
138 if (nativePtrValue == 0) return;
139 env->SetLongField(obj, nativePtr, 0);
140 JNIPrintInterceptorInfo* info =
141 reinterpret_cast<JNIPrintInterceptorInfo*>(nativePtrValue);
142 DartinoUnregisterPrintInterceptor(info->interceptor);
143 env->DeleteGlobalRef(info->obj);
144 delete info;
145 }
146
147 #ifdef __cplusplus
148 extern "C" {
149 #endif
150
151 JNIEXPORT void JNICALL Java_dartino_DartinoApi_Setup(JNIEnv*, jclass) {
152 DartinoSetup();
153 }
154
155 JNIEXPORT void JNICALL Java_dartino_DartinoApi_TearDown(JNIEnv*, jclass) {
156 DartinoTearDown();
157 }
158
159 JNIEXPORT void JNICALL Java_dartino_DartinoApi_RunSnapshot(JNIEnv* env,
160 jclass,
161 jbyteArray snapshot) {
162 int len = env->GetArrayLength(snapshot);
163 unsigned char* copy = new unsigned char[len];
164 env->GetByteArrayRegion(snapshot, 0, len, reinterpret_cast<jbyte*>(copy));
165 DartinoProgram program = DartinoLoadSnapshot(copy, len);
166 delete[] copy;
167 DartinoRunMain(program, 0, NULL);
168 DartinoDeleteProgram(program);
169 }
170
171 JNIEXPORT void JNICALL Java_dartino_DartinoApi_AddDefaultSharedLibrary(
172 JNIEnv* env, jclass, jstring str) {
173 const char* library = env->GetStringUTFChars(str, 0);
174 DartinoAddDefaultSharedLibrary(library);
175 env->ReleaseStringUTFChars(str, library);
176 }
177
178 JNIEXPORT void JNICALL Java_dartino_DartinoApi_RegisterPrintInterceptor(
179 JNIEnv* env, jclass, jobject obj) {
180 RegisterPrintInterceptor(env, obj);
181 }
182
183 JNIEXPORT void JNICALL Java_dartino_DartinoApi_UnregisterPrintInterceptor(
184 JNIEnv* env, jclass, jobject obj) {
185 UnregisterPrintInterceptor(env, obj);
186 }
187
188 #ifdef __cplusplus
189 }
190 #endif
191 """;
192
193 const DARTINO_SERVICE_API_JAVA_IMPL = """
194 #include <jni.h>
195
196 #include "service_api.h"
197
198 #ifdef __cplusplus
199 extern "C" {
200 #endif
201
202 JNIEXPORT void JNICALL Java_dartino_DartinoServiceApi_Setup(JNIEnv*, jclass) {
203 ServiceApiSetup();
204 }
205
206 JNIEXPORT void JNICALL Java_dartino_DartinoServiceApi_TearDown(JNIEnv*, jclass) {
207 ServiceApiTearDown();
208 }
209
210 #ifdef __cplusplus
211 }
212 #endif
213 """;
214
215 String JNI_UTILS = """
216 static JNIEnv* AttachCurrentThreadAndGetEnv(JavaVM* vm) {
217 AttachEnvType result = NULL;
218 if (vm->AttachCurrentThread(&result, NULL) != JNI_OK) {
219 // TODO(ager): Nicer error recovery?
220 exit(1);
221 }
222 return reinterpret_cast<JNIEnv*>(result);
223 }
224
225 static void DetachCurrentThread(JavaVM* vm) {
226 if (vm->DetachCurrentThread() != JNI_OK) {
227 // TODO(ager): Nicer error recovery?
228 exit(1);
229 }
230 }
231
232 static jobject CreateByteArray(JNIEnv* env, char* memory, int size) {
233 jbyteArray result = env->NewByteArray(size);
234 jbyte* contents = reinterpret_cast<jbyte*>(memory);
235 env->SetByteArrayRegion(result, 0, size, contents);
236 free(memory);
237 return result;
238 }
239
240 static jobject CreateByteArrayArray(JNIEnv* env, char* memory, int size) {
241 jobjectArray array = env->NewObjectArray(size, env->FindClass("[B"), NULL);
242 for (int i = 0; i < size; i++) {
243 int64_t address = *reinterpret_cast<int64_t*>(memory + 8 + (i * 16));
244 int size = *reinterpret_cast<int*>(memory + 16 + (i * 16));
245 char* contents = reinterpret_cast<char*>(address);
246 env->SetObjectArrayElement(array, i, CreateByteArray(env, contents, size));
247 }
248 free(memory);
249 return array;
250 }
251
252 static jobject GetRootSegment(JNIEnv* env, char* memory) {
253 int32_t segments = *reinterpret_cast<int32_t*>(memory);
254 if (segments == 0) {
255 int32_t size = *reinterpret_cast<int32_t*>(memory + 4);
256 return CreateByteArray(env, memory, size);
257 }
258 return CreateByteArrayArray(env, memory, segments);
259 }
260
261 class CallbackInfo {
262 public:
263 CallbackInfo(jobject jcallback, JavaVM* jvm)
264 : callback(jcallback), vm(jvm) { }
265 jobject callback;
266 JavaVM* vm;
267 };
268
269 static char* ExtractByteArrayData(JNIEnv* env,
270 jbyteArray segment,
271 jint segment_length) {
272 jbyte* data = env->GetByteArrayElements(segment, NULL);
273 char* segment_copy = reinterpret_cast<char*>(malloc(segment_length));
274 memcpy(segment_copy, data, segment_length);
275 env->ReleaseByteArrayElements(segment, data, JNI_ABORT);
276 return segment_copy;
277 }
278
279 static int ComputeMessage(JNIEnv* env,
280 jobject builder,
281 jobject callback,
282 JavaVM* vm,
283 char** buffer) {
284 CallbackInfo* info = NULL;
285 if (callback != NULL) {
286 info = new CallbackInfo(callback, vm);
287 }
288
289 jclass clazz = env->GetObjectClass(builder);
290 jmethodID method_id = env->GetMethodID(clazz, "getSegments", "()[Ljava/lang/Ob ject;");
291 jobjectArray array = (jobjectArray)env->CallObjectMethod(builder, method_id);
292 jobjectArray segments = (jobjectArray)env->GetObjectArrayElement(array, 0);
293 jintArray sizes_array = (jintArray)env->GetObjectArrayElement(array, 1);
294 int* sizes = env->GetIntArrayElements(sizes_array, NULL);
295 int number_of_segments = env->GetArrayLength(segments);
296
297 if (number_of_segments > 1) {
298 int size = $REQUEST_HEADER_SIZE + 8 + (number_of_segments * 16);
299 *buffer = reinterpret_cast<char*>(malloc(size));
300 int offset = $REQUEST_HEADER_SIZE + 8;
301 for (int i = 0; i < number_of_segments; i++) {
302 jbyteArray segment = (jbyteArray)env->GetObjectArrayElement(segments, i);
303 jint segment_length = sizes[i];
304 char* segment_copy = ExtractByteArrayData(env, segment, segment_length);
305 *reinterpret_cast<void**>(*buffer + offset) = segment_copy;
306 *reinterpret_cast<int*>(*buffer + offset + 8) = segment_length;
307 offset += 16;
308 }
309
310 env->ReleaseIntArrayElements(sizes_array, sizes, JNI_ABORT);
311 // Mark the request as being segmented.
312 *${pointerToArgument('*buffer', -8, 'int64_t')} = number_of_segments;
313 // Set the callback information.
314 *${pointerToArgument('*buffer', -16, 'CallbackInfo*')} = info;
315 return size;
316 }
317
318 jbyteArray segment = (jbyteArray)env->GetObjectArrayElement(segments, 0);
319 jint segment_length = sizes[0];
320 *buffer = ExtractByteArrayData(env, segment, segment_length);
321 env->ReleaseIntArrayElements(sizes_array, sizes, JNI_ABORT);
322 // Mark the request as being non-segmented.
323 *${pointerToArgument('*buffer', -8, 'int64_t')} = 0;
324 // Set the callback information.
325 *${pointerToArgument('*buffer', -16, 'CallbackInfo*')} = info;
326 return segment_length;
327 }
328
329 static void DeleteMessage(char* message) {
330 int32_t segments = *${pointerToArgument('message', -8, 'int32_t')};
331 for (int i = 0; i < segments; i++) {
332 int64_t address = *reinterpret_cast<int64_t*>(message + ${REQUEST_HEADER_SIZ E + 8} + (i * 16));
333 char* memory = reinterpret_cast<char*>(address);
334 free(memory);
335 }
336 free(message);
337 }""";
338
339 const int REQUEST_HEADER_SIZE = 56;
340
341 String pointerToArgument(String buffer, int offset, String type) {
342 offset += REQUEST_HEADER_SIZE;
343 return 'reinterpret_cast<$type*>($buffer + $offset)';
344 }
345
346 const List<String> JAVA_RESOURCES = const [
347 "Builder.java",
348 "BuilderSegment.java",
349 "ListBuilder.java",
350 "ListReader.java",
351 "MessageBuilder.java",
352 "MessageReader.java",
353 "Reader.java",
354 "Segment.java"
355 ];
356
357 void generate(String path,
358 Unit unit,
359 String resourcesDirectory,
360 String outputDirectory) {
361 _generateDartinoApis(outputDirectory);
362 _generateServiceJava(path, unit, outputDirectory);
363 _generateServiceJni(path, unit, outputDirectory);
364 _generateServiceJniMakeFiles(path, unit, resourcesDirectory, outputDirectory);
365
366 resourcesDirectory = join(resourcesDirectory, 'java', 'dartino');
367 String dartinoDirectory = join(outputDirectory, 'java', 'dartino');
368 for (String resource in JAVA_RESOURCES) {
369 String resourcePath = join(resourcesDirectory, resource);
370 File file = new File(resourcePath);
371 String contents = file.readAsStringSync();
372 writeToFile(dartinoDirectory, resource, contents);
373 }
374 }
375
376 void _generateDartinoApis(String outputDirectory) {
377 String dartinoDirectory = join(outputDirectory, 'java', 'dartino');
378 String jniDirectory = join(outputDirectory, 'java', 'jni');
379
380 StringBuffer buffer = new StringBuffer(HEADER);
381 buffer.writeln();
382 buffer.write(DARTINO_API_JAVA);
383 writeToFile(dartinoDirectory, 'DartinoApi', buffer.toString(),
384 extension: 'java');
385
386 buffer = new StringBuffer(HEADER);
387 buffer.writeln();
388 buffer.write(DARTINO_SERVICE_API_JAVA);
389 writeToFile(dartinoDirectory, 'DartinoServiceApi', buffer.toString(),
390 extension: 'java');
391
392 buffer = new StringBuffer(HEADER);
393 buffer.writeln();
394 buffer.write(DARTINO_API_JAVA_IMPL);
395 writeToFile(jniDirectory, 'dartino_api_wrapper', buffer.toString(),
396 extension: 'cc');
397
398 buffer = new StringBuffer(HEADER);
399 buffer.writeln();
400 buffer.write(DARTINO_SERVICE_API_JAVA_IMPL);
401 writeToFile(jniDirectory, 'dartino_service_api_wrapper',
402 buffer.toString(), extension: 'cc');
403 }
404
405 void _generateServiceJava(String path, Unit unit, String outputDirectory) {
406 _JavaVisitor visitor = new _JavaVisitor(path, outputDirectory);
407 visitor.visit(unit);
408 String contents = visitor.buffer.toString();
409 String directory = join(outputDirectory, 'java', 'dartino');
410 // TODO(ager): We should generate a file per service here.
411 if (unit.services.length > 1) {
412 print('Java plugin: multiple services in one file is not supported.');
413 }
414 String serviceName = unit.services.first.name;
415 writeToFile(directory, serviceName, contents, extension: 'java');
416 }
417
418 void _generateServiceJni(String path, Unit unit, String outputDirectory) {
419 _JniVisitor visitor = new _JniVisitor(path);
420 visitor.visit(unit);
421 String contents = visitor.buffer.toString();
422 String directory = join(outputDirectory, 'java', 'jni');
423 // TODO(ager): We should generate a file per service here.
424 if (unit.services.length > 1) {
425 print('Java plugin: multiple services in one file is not supported.');
426 }
427 String projectName = basenameWithoutExtension(path);
428 String file = '${projectName}_wrapper';
429 writeToFile(directory, file, contents, extension: 'cc');
430 }
431
432 class _JavaVisitor extends CodeGenerationVisitor {
433 final Set<Type> neededListTypes;
434 final String outputDirectory;
435
436 static Map<String, String> _GETTERS = const {
437 'bool' : 'segment.getBoolean',
438
439 'uint8' : 'segment.getUnsigned',
440 'uint16' : 'segment.getUnsignedChar',
441
442 'int8' : 'segment.buffer().get',
443 'int16' : 'segment.buffer().getShort',
444 'int32' : 'segment.buffer().getInt',
445 'int64' : 'segment.buffer().getLong',
446
447 'float32' : 'segment.buffer().getFloat',
448 'float64' : 'segment.buffer().getDouble',
449 };
450
451 static Map<String, String> _SETTERS = const {
452 'bool' : 'segment.buffer().put',
453
454 'uint8' : 'segment.buffer().put',
455 'uint16' : 'segment.buffer().putChar',
456
457 'int8' : 'segment.buffer().put',
458 'int16' : 'segment.buffer().putShort',
459 'int32' : 'segment.buffer().putInt',
460 'int64' : 'segment.buffer().putLong',
461
462 'float32' : 'segment.buffer().putFloat',
463 'float64' : 'segment.buffer().pubDouble',
464 };
465
466 static Map<String, String> _SETTER_TYPES = const {
467 'bool' : 'byte',
468
469 'uint8' : 'byte',
470 'uint16' : 'char',
471
472 'int8' : 'byte',
473 'int16' : 'char',
474 'int32' : 'int',
475 'int64' : 'long',
476
477 'float32' : 'float',
478 'float64' : 'double',
479 };
480
481 _JavaVisitor(String path, String this.outputDirectory)
482 : neededListTypes = new Set<Type>(),
483 super(path);
484
485 static const PRIMITIVE_TYPES = const <String, String> {
486 'void' : 'void',
487 'bool' : 'boolean',
488
489 'uint8' : 'int',
490 'uint16' : 'int',
491
492 'int8' : 'int',
493 'int16' : 'int',
494 'int32' : 'int',
495 'int64' : 'long',
496
497 'float32' : 'float',
498 'float64' : 'double',
499 };
500
501 static const PRIMITIVE_LIST_TYPES = const <String, String> {
502 'bool' : 'boolean',
503
504 'uint8' : 'int',
505 'uint16' : 'int',
506
507 'int8' : 'int',
508 'int16' : 'int',
509 'int32' : 'int',
510 'int64' : 'long',
511
512 'float32' : 'float',
513 'float64' : 'double',
514 };
515
516 String getType(Type node) {
517 Node resolved = node.resolved;
518 if (resolved != null) {
519 return '${node.identifier}Builder';
520 } else {
521 String type = PRIMITIVE_TYPES[node.identifier];
522 return type;
523 }
524 }
525
526 String getReturnType(Type node) {
527 Node resolved = node.resolved;
528 if (resolved != null) {
529 return '${node.identifier}';
530 } else {
531 String type = PRIMITIVE_TYPES[node.identifier];
532 return type;
533 }
534 }
535
536 String getListType(Type node) {
537 Node resolved = node.resolved;
538 if (resolved != null) {
539 return '${node.identifier}';
540 } else {
541 String type = PRIMITIVE_LIST_TYPES[node.identifier];
542 return type;
543 }
544 }
545
546 void writeType(Type node) => write(getType(node));
547 void writeTypeToBuffer(Type node, StringBuffer buffer) {
548 buffer.write(getType(node));
549 }
550
551 void writeReturnType(Type node) => write(getReturnType(node));
552 void writeReturnTypeToBuffer(Type node, StringBuffer buffer) {
553 buffer.write(getReturnType(node));
554 }
555
556 void writeListTypeToBuffer(Type node, StringBuffer buffer) {
557 buffer.write(getListType(node));
558 }
559
560 visitUnit(Unit node) {
561 writeln(HEADER);
562 writeln('package dartino;');
563 writeln();
564 node.structs.forEach(visit);
565 node.services.forEach(visit);
566 neededListTypes.forEach(writeListReaderImplementation);
567 neededListTypes.forEach(writeListBuilderImplementation);
568 }
569
570 visitService(Service node) {
571 writeln('public class ${node.name} {');
572 writeln(' public static native void Setup();');
573 writeln(' public static native void TearDown();');
574 node.methods.forEach(visit);
575 writeln('}');
576 }
577
578 visitMethod(Method node) {
579 String name = node.name;
580 String camelName = name.substring(0, 1).toUpperCase() + name.substring(1);
581 writeln();
582 writeln(' public static abstract class ${camelName}Callback {');
583 if (!node.returnType.isVoid && !node.returnType.isPrimitive) {
584 write(' public final java.lang.Class returnType = ');
585 writeReturnType(node.returnType);
586 writeln('.class;');
587 }
588 write(' public abstract void handle(');
589 if (!node.returnType.isVoid) {
590 writeReturnType(node.returnType);
591 write(' result');
592 }
593 writeln(');');
594 writeln(' }');
595
596 writeln();
597 write(' public static native ');
598 writeReturnType(node.returnType);
599 write(' $name(');
600 visitArguments(node.arguments);
601 writeln(');');
602 write(' public static native void ${name}Async(');
603 visitArguments(node.arguments);
604 if (node.arguments.isNotEmpty) write(', ');
605 writeln('${camelName}Callback callback);');
606 }
607
608 visitArguments(List<Formal> formals) {
609 visitNodes(formals, (first) => first ? '' : ', ');
610 }
611
612 visitFormal(Formal node) {
613 writeType(node.type);
614 write(' ${node.name}');
615 }
616
617 visitStruct(Struct node) {
618 writeReader(node);
619 writeBuilder(node);
620 }
621
622 void writeReader(Struct node) {
623 String dartinoDirectory = join(outputDirectory, 'java', 'dartino');
624 String name = node.name;
625 StructLayout layout = node.layout;
626
627 StringBuffer buffer = new StringBuffer(HEADER);
628 buffer.writeln();
629 buffer.writeln(READER_HEADER);
630
631 buffer.writeln('import java.util.List;');
632 buffer.writeln();
633
634 buffer.writeln('public class $name extends Reader {');
635 buffer.writeln(' public $name() { }');
636 buffer.writeln();
637 buffer.writeln(' public $name(byte[] memory, int offset) {');
638 buffer.writeln(' super(memory, offset);');
639 buffer.writeln(' }');
640 buffer.writeln();
641 buffer.writeln(' public $name(Segment segment, int offset) {');
642 buffer.writeln(' super(segment, offset);');
643 buffer.writeln(' }');
644 buffer.writeln();
645 buffer.writeln(' public $name(byte[][] segments, int offset) {');
646 buffer.writeln(' super(segments, offset);');
647 buffer.writeln(' }');
648 buffer.writeln();
649 buffer.writeln(' public static $name create(Object rawData) {');
650 buffer.writeln(' if (rawData instanceof byte[]) {');
651 buffer.writeln(' return new $name((byte[])rawData, 8);');
652 buffer.writeln(' }');
653 buffer.writeln(' return new $name((byte[][])rawData, 8);');
654 buffer.writeln(' }');
655
656 for (StructSlot slot in layout.slots) {
657 buffer.writeln();
658 Type slotType = slot.slot.type;
659 String camel = camelize(slot.slot.name);
660
661 if (slot.isUnionSlot) {
662 String tagName = camelize(slot.union.tag.name);
663 int tag = slot.unionTag;
664 buffer.writeln(
665 ' public boolean is$camel() { return $tag == get$tagName(); }');
666 }
667
668 if (slotType.isList) {
669 neededListTypes.add(slotType);
670 String list = '${camelize(slotType.identifier)}List';
671 buffer.writeln(' public $list get$camel() {');
672 buffer.writeln(' ListReader reader = new ListReader();');
673 buffer.writeln(' readList(reader, ${slot.offset});');
674 buffer.writeln(' return new $list(reader);');
675 buffer.writeln(' }');
676 } else if (slotType.isVoid) {
677 // No getters for void slots.
678 } else if (slotType.isString) {
679 buffer.write(' public String get$camel() { ');
680 buffer.writeln('return readString(${slot.offset}); }');
681 // TODO(ager): This is nasty. Maybe inject this type earler in the
682 // pipeline?
683 Type uint16ListType = new ListType(new SimpleType("uint16", false));
684 uint16ListType.primitiveType = primitives.lookup("uint16");
685 neededListTypes.add(uint16ListType);
686 buffer.writeln(' public Uint16List get${camel}Data() {');
687 buffer.writeln(' ListReader reader = new ListReader();');
688 buffer.writeln(' readList(reader, ${slot.offset});');
689 buffer.writeln(' return new Uint16List(reader);');
690 buffer.writeln(' }');
691 } else if (slotType.isPrimitive) {
692 // TODO(ager): Dealing with unsigned numbers in Java is annoying.
693 if (camel == 'Tag') {
694 String getter = 'getUnsigned';
695 String offset = 'base + ${slot.offset}';
696 buffer.writeln(' public int getTag() {');
697 buffer.writeln(' short shortTag = segment.$getter($offset);');
698 buffer.writeln(' int tag = (int)shortTag;');
699 buffer.writeln(' return tag < 0 ? -tag : tag;');
700 buffer.writeln(' }');
701 } else {
702 String getter = _GETTERS[slotType.identifier];
703 String offset = "base + ${slot.offset}";
704 buffer.write(' public ${getType(slotType)} get$camel() { ');
705 buffer.writeln('return $getter($offset); }');
706 }
707 } else {
708 String returnType = getReturnType(slotType);
709 buffer.write(' public $returnType get$camel() {');
710 if (!slotType.isPointer) {
711 String offset = 'base + ${slot.offset}';
712 buffer.writeln(' return new $returnType(segment, $offset); }');
713 } else {
714 buffer.writeln();
715 int offset = slot.offset;
716 buffer.writeln(' $returnType reader = new $returnType();');
717 buffer.writeln(' return ($returnType)readStruct(reader, $offset);') ;
718 buffer.writeln(' }');
719 }
720 }
721 }
722
723 buffer.writeln('}');
724
725 writeToFile(dartinoDirectory, '$name', buffer.toString(),
726 extension: 'java');
727 }
728
729 void writeBuilder(Struct node) {
730 String dartinoDirectory = join(outputDirectory, 'java', 'dartino');
731 String name = '${node.name}Builder';
732 StructLayout layout = node.layout;
733
734 StringBuffer buffer = new StringBuffer(HEADER);
735 buffer.writeln();
736 buffer.writeln(READER_HEADER);
737
738 buffer.write('import java.util.List;');
739 buffer.writeln();
740 buffer.writeln('public class $name extends Builder {');
741 buffer.writeln(' public static int kSize = ${layout.size};');
742 buffer.writeln(' public $name(BuilderSegment segment, int offset) {');
743 buffer.writeln(' super(segment, offset);');
744 buffer.writeln(' }');
745 buffer.writeln();
746 buffer.writeln(' public $name() {');
747 buffer.writeln(' super();');
748 buffer.writeln(' }');
749
750 for (StructSlot slot in layout.slots) {
751 buffer.writeln();
752 String slotName = slot.slot.name;
753 String camel = camelize(slotName);
754 Type slotType = slot.slot.type;
755
756 String updateTag = '';
757 if (slot.isUnionSlot) {
758 String tagName = camelize(slot.union.tag.name);
759 int tag = slot.unionTag;
760 updateTag = ' set$tagName($tag);\n';
761 }
762
763 if (slotType.isList) {
764 String listBuilder = '';
765 if (slotType.isPrimitive) {
766 listBuilder = '${camelize(slotType.identifier)}ListBuilder';
767 } else {
768 listBuilder = '${getListType(slotType)}ListBuilder';
769 }
770 buffer.writeln(' public $listBuilder init$camel(int length) {');
771 buffer.write(updateTag);
772 int size = 0;
773 if (slotType.isPrimitive) {
774 size = primitives.size(slotType.primitiveType);
775 } else {
776 Struct element = slotType.resolved;
777 StructLayout elementLayout = element.layout;
778 size = elementLayout.size;
779 }
780 buffer.writeln(' ListBuilder builder = new ListBuilder();');
781 buffer.writeln(' newList(builder, ${slot.offset}, length, $size);');
782 buffer.writeln(' return new ${listBuilder}(builder);');
783 buffer.writeln(' }');
784 } else if (slotType.isVoid) {
785 assert(slot.isUnionSlot);
786 String tagName = camelize(slot.union.tag.name);
787 int tag = slot.unionTag;
788 buffer.writeln(' public void set$camel() {'
789 ' set$tagName($tag); }');
790 } else if (slotType.isString) {
791 buffer.writeln(' public void set$camel(String value) {');
792 buffer.write(updateTag);
793 buffer.writeln(' newString(${slot.offset}, value);');
794 buffer.writeln(' }');
795 buffer.writeln();
796 buffer.writeln(' public Uint16ListBuilder init${camel}Data(int length) {');
797 buffer.write(updateTag);
798 buffer.writeln(' ListBuilder builder = new ListBuilder();');
799 buffer.writeln(' newList(builder, ${slot.offset}, length, 2);');
800 buffer.writeln(' return new Uint16ListBuilder(builder);');
801 buffer.writeln(' }');
802 } else if (slotType.isPrimitive) {
803 String setter = _SETTERS[slotType.identifier];
804 String setterType = _SETTER_TYPES[slotType.identifier];
805 String offset = 'base + ${slot.offset}';
806 buffer.writeln(' public void set$camel(${getType(slotType)} value) {');
807 buffer.write(updateTag);
808 if (slotType.isBool) {
809 buffer.writeln(' $setter($offset,'
810 ' (byte)(value ? 1 : 0));');
811 } else {
812 buffer.writeln(' $setter($offset, (${setterType})value);');
813 }
814 buffer.writeln(' }');
815 } else {
816 buffer.writeln(' public ${getType(slotType)} init$camel() {');
817 buffer.write(updateTag);
818 String builderType = getType(slotType);
819 if (!slotType.isPointer) {
820 buffer.writeln(' $builderType result = new $builderType();');
821 buffer.writeln(' result.segment = segment;');
822 buffer.writeln(' result.base = base + ${slot.offset};');
823 buffer.writeln(' return result;');
824 } else {
825 Struct element = slotType.resolved;
826 StructLayout elementLayout = element.layout;
827 int size = elementLayout.size;
828 buffer.writeln(' $builderType result = new $builderType();');
829 buffer.writeln(' newStruct(result, ${slot.offset}, $size);');
830 buffer.writeln(' return result;');
831 }
832 buffer.writeln(' }');
833 }
834 }
835
836 buffer.writeln('}');
837
838 writeToFile(dartinoDirectory, '$name', buffer.toString(),
839 extension: 'java');
840 }
841
842 void writeListReaderImplementation(Type type) {
843 String dartinoDirectory = join(outputDirectory, 'java', 'dartino');
844 String name = '${camelize(type.identifier)}List';
845 String listType = getListType(type);
846
847 StringBuffer buffer = new StringBuffer(HEADER);
848 buffer.writeln();
849 buffer.writeln(READER_HEADER);
850
851 buffer.writeln('public class $name {');
852 if (type.isPrimitive) {
853 int elementSize = primitives.size(type.primitiveType);
854 String offset = 'reader.base + index * $elementSize';
855
856 buffer.writeln(' private ListReader reader;');
857 buffer.writeln();
858 buffer.writeln(' public $name(ListReader reader) {'
859 ' this.reader = reader; }');
860 buffer.writeln();
861 buffer.writeln(' public $listType get(int index) {');
862 buffer.write(' return ');
863 buffer.writeln('reader.${_GETTERS[type.identifier]}($offset);');
864 buffer.writeln(' }');
865 } else {
866 Struct element = type.resolved;
867 StructLayout elementLayout = element.layout;;
868 int elementSize = elementLayout.size;
869 String returnType = getReturnType(type);
870
871 buffer.writeln(' private ListReader reader;');
872 buffer.writeln();
873 buffer.writeln(' public $name(ListReader reader) {'
874 ' this.reader = reader; }');
875 buffer.writeln();
876 buffer.writeln(' public $returnType get(int index) {');
877 buffer.writeln(' $returnType result = new $returnType();');
878 buffer.writeln(' reader.readListElement('
879 'result, index, $elementSize);');
880 buffer.writeln(' return result;');
881 buffer.writeln(' }');
882 }
883
884 buffer.writeln();
885 buffer.writeln(' public int size() { return reader.length; }');
886
887 buffer.writeln('}');
888
889 writeToFile(dartinoDirectory, '$name', buffer.toString(),
890 extension: 'java');
891 }
892
893 void writeListBuilderImplementation(Type type) {
894 String dartinoDirectory = join(outputDirectory, 'java', 'dartino');
895 String name = '${camelize(type.identifier)}ListBuilder';
896
897 StringBuffer buffer = new StringBuffer(HEADER);
898 buffer.writeln();
899 buffer.writeln(READER_HEADER);
900
901 buffer.writeln('public class $name {');
902 buffer.writeln(' private ListBuilder builder;');
903 buffer.writeln();
904 buffer.writeln(' public $name(ListBuilder builder) {'
905 ' this.builder = builder; }');
906 buffer.writeln();
907
908 if (type.isPrimitive) {
909 int elementSize = primitives.size(type.primitiveType);
910 String offset = 'builder.base + index * $elementSize';
911 String listType = getListType(type);
912 String getter = _GETTERS[type.identifier];
913
914 buffer.writeln(' public $listType get(int index) {');
915 buffer.writeln(' return builder.$getter($offset);');
916 buffer.writeln(' }');
917
918 buffer.writeln();
919 String setter = _SETTERS[type.identifier];
920 String setterType = _SETTER_TYPES[type.identifier];
921 buffer.writeln(' public $listType set(int index, $listType value) {');
922 buffer.write(' builder.$setter($offset, (${setterType})value);');
923 buffer.writeln(' return value;');
924 buffer.writeln(' }');
925 } else {
926 Struct element = type.resolved;
927 StructLayout elementLayout = element.layout;;
928 int elementSize = elementLayout.size;
929 String structType = getType(type);
930
931 buffer.writeln(' public $structType get(int index) {');
932 buffer.writeln(' $structType result = new $structType();');
933 buffer.writeln(' builder.readListElement('
934 'result, index, $elementSize);');
935 buffer.writeln(' return result;');
936 buffer.writeln(' }');
937 }
938
939 buffer.writeln();
940 buffer.writeln(' public int size() { return builder.length; }');
941
942 buffer.writeln('}');
943
944 writeToFile(dartinoDirectory, '$name', buffer.toString(),
945 extension: 'java');
946 }
947 }
948
949 class _JniVisitor extends CcVisitor {
950 static const int REQUEST_HEADER_SIZE = 48 + 8;
951 static const int RESPONSE_HEADER_SIZE = 8;
952
953 int methodId = 1;
954 String serviceName;
955
956 _JniVisitor(String path) : super(path);
957
958 visitUnit(Unit node) {
959 writeln(HEADER);
960 writeln('#include <jni.h>');
961 writeln('#include <stdlib.h>');
962 writeln('#include <string.h>');
963 writeln();
964 writeln('#include "service_api.h"');
965 node.services.forEach(visit);
966 }
967
968 visitService(Service node) {
969 serviceName = node.name;
970
971 writeln();
972
973 writeln('#ifdef __cplusplus');
974 writeln('extern "C" {');
975 writeln('#endif');
976
977 // TODO(ager): Get rid of this if we can. For some reason
978 // the jni.h header that is used by the NDK differs.
979 writeln();
980 writeln('#ifdef ANDROID');
981 writeln(' typedef JNIEnv* AttachEnvType;');
982 writeln('#else');
983 writeln(' typedef void* AttachEnvType;');
984 writeln('#endif');
985
986 writeln();
987 writeln('static ServiceId service_id_ = kNoServiceId;');
988
989 writeln();
990 write('JNIEXPORT void JNICALL Java_dartino_');
991 writeln('${serviceName}_Setup(JNIEnv*, jclass) {');
992 writeln(' service_id_ = ServiceApiLookup("$serviceName");');
993 writeln('}');
994
995 writeln();
996 write('JNIEXPORT void JNICALL Java_dartino_');
997 writeln('${serviceName}_TearDown(JNIEnv*, jclass) {');
998 writeln(' ServiceApiTerminate(service_id_);');
999 writeln('}');
1000
1001 // TODO(ager): Put this in resources and copy as a file instead.
1002 writeln();
1003 writeln(JNI_UTILS);
1004
1005 node.methods.forEach(visit);
1006
1007 writeln();
1008 writeln('#ifdef __cplusplus');
1009 writeln('}');
1010 writeln('#endif');
1011 }
1012
1013 visitMethod(Method node) {
1014 String name = node.name;
1015 String id = '_k${name}Id';
1016
1017 writeln();
1018 write('static const MethodId $id = ');
1019 writeln('reinterpret_cast<MethodId>(${methodId++});');
1020
1021 writeln();
1022 write('JNIEXPORT ');
1023 writeReturnType(node.returnType);
1024 write(' JNICALL Java_dartino_${serviceName}_${name}(');
1025 write('JNIEnv* _env, jclass');
1026 if (node.arguments.isNotEmpty) write(', ');
1027 if (node.inputKind != InputKind.PRIMITIVES) {
1028 write('jobject ${node.arguments.single.name}');
1029 } else {
1030 visitArguments(node.arguments);
1031 }
1032 writeln(') {');
1033 if (node.inputKind != InputKind.PRIMITIVES) {
1034 visitStructArgumentMethodBody(id, node);
1035 } else {
1036 visitMethodBody(id, node);
1037 }
1038 writeln('}');
1039
1040 String callback;
1041 if (node.inputKind == InputKind.STRUCT) {
1042 Struct struct = node.arguments.single.type.resolved;
1043 StructLayout layout = struct.layout;
1044 callback = ensureCallback(node.returnType, layout);
1045 } else {
1046 callback =
1047 ensureCallback(node.returnType, node.inputPrimitiveStructLayout);
1048 }
1049
1050 writeln();
1051 write('JNIEXPORT void JNICALL ');
1052 write('Java_dartino_${serviceName}_${name}Async(');
1053 write('JNIEnv* _env, jclass');
1054 if (node.arguments.isNotEmpty) write(', ');
1055 if (node.inputKind != InputKind.PRIMITIVES) {
1056 write('jobject ${node.arguments.single.name}');
1057 } else {
1058 visitArguments(node.arguments);
1059 }
1060 writeln(', jobject _callback) {');
1061 writeln(' jobject callback = NULL;');
1062 writeln(' JavaVM* vm = NULL;');
1063 writeln(' if (_callback) {');
1064 writeln(' callback = _env->NewGlobalRef(_callback);');
1065 writeln(' _env->GetJavaVM(&vm);');
1066 writeln(' }');
1067 // TODO(zerny): Issue #45. Store VM pointer in 'callback data' header field.
1068 if (node.inputKind != InputKind.PRIMITIVES) {
1069 visitStructArgumentMethodBody(id,
1070 node,
1071 extraArguments: [ 'vm' ],
1072 callback: callback);
1073 } else {
1074 visitMethodBody(id,
1075 node,
1076 extraArguments: [ 'vm' ],
1077 callback: callback);
1078 }
1079 writeln('}');
1080 }
1081
1082 visitMethodBody(String id,
1083 Method method,
1084 {bool cStyle: false,
1085 List<String> extraArguments: const [],
1086 String callback}) {
1087 String cast(String type) => CcVisitor.cast(type, false);
1088
1089 String pointerToArgument(int offset, int pointers, String type) {
1090 offset += REQUEST_HEADER_SIZE;
1091 String prefix = cast('$type*');
1092 if (pointers == 0) return '$prefix(_buffer + $offset)';
1093 return '$prefix(_buffer + $offset + $pointers * sizeof(void*))';
1094 }
1095
1096 List<Formal> arguments = method.arguments;
1097 assert(method.inputKind == InputKind.PRIMITIVES);
1098 StructLayout layout = method.inputPrimitiveStructLayout;
1099 final bool async = callback != null;
1100 int size = REQUEST_HEADER_SIZE + layout.size;
1101 if (async) {
1102 write(' static const int kSize = ');
1103 writeln('${size} + ${extraArguments.length} * sizeof(void*);');
1104 } else {
1105 writeln(' static const int kSize = ${size};');
1106 }
1107
1108 if (async) {
1109 writeln(' char* _buffer = ${cast("char*")}(malloc(kSize));');
1110 } else {
1111 writeln(' char _bits[kSize];');
1112 writeln(' char* _buffer = _bits;');
1113 }
1114
1115 // Mark the message as being non-segmented.
1116 writeln(' *${pointerToArgument(-8, 0, "int64_t")} = 0;');
1117
1118 int arity = arguments.length;
1119 for (int i = 0; i < arity; i++) {
1120 String name = arguments[i].name;
1121 int offset = layout[arguments[i]].offset;
1122 String type = PRIMITIVE_TYPES[arguments[i].type.identifier];
1123 writeln(' *${pointerToArgument(offset, 0, type)} = $name;');
1124 }
1125
1126 if (async) {
1127 writeln(' CallbackInfo* info = callback ? new CallbackInfo(callback, vm) : NULL;');
1128 writeln(' *${pointerToArgument(-16, 0, "CallbackInfo*")} = info;');
1129 write(' ServiceApiInvokeAsync(service_id_, $id, $callback, ');
1130 writeln('_buffer, kSize);');
1131 } else {
1132 writeln(' ServiceApiInvoke(service_id_, $id, _buffer, kSize);');
1133 if (method.outputKind == OutputKind.STRUCT) {
1134 Type type = method.returnType;
1135 writeln(' int64_t result = *${pointerToArgument(0, 0, 'int64_t')};');
1136 writeln(' char* memory = reinterpret_cast<char*>(result);');
1137 writeln(' jobject rootSegment = GetRootSegment(_env, memory);');
1138 writeln(' jclass resultClass = '
1139 '_env->FindClass("dartino/${type.identifier}");');
1140 writeln(' jmethodID create = _env->GetStaticMethodID('
1141 'resultClass, "create", '
1142 '"(Ljava/lang/Object;)Ldartino/${type.identifier};");');
1143 writeln(' jobject resultObject = _env->CallStaticObjectMethod('
1144 'resultClass, create, rootSegment);');
1145 writeln(' return resultObject;');
1146 } else if (!method.returnType.isVoid) {
1147 writeln(' return *${pointerToArgument(0, 0, 'int64_t')};');
1148 }
1149 }
1150 }
1151
1152 visitStructArgumentMethodBody(String id,
1153 Method method,
1154 {bool cStyle: false,
1155 List<String> extraArguments: const [],
1156 String callback}) {
1157 String cast(String type) => CcVisitor.cast(type, false);
1158
1159 String pointerToArgument(int offset, int pointers, String type) {
1160 offset += REQUEST_HEADER_SIZE;
1161 String prefix = cast('$type*');
1162 if (pointers == 0) return '$prefix(buffer + $offset)';
1163 return '$prefix(buffer + $offset + $pointers * sizeof(void*))';
1164 }
1165
1166 String argumentName = method.arguments.single.name;
1167
1168 bool async = callback != null;
1169 String javaCallback = async ? 'callback' : 'NULL';
1170 String javaVM = async ? 'vm' : 'NULL';
1171
1172 writeln(' char* buffer = NULL;');
1173 writeln(' int size = ComputeMessage('
1174 '_env, $argumentName, $javaCallback, $javaVM, &buffer);');
1175
1176 if (async) {
1177 write(' ServiceApiInvokeAsync(service_id_, $id, $callback, ');
1178 writeln('buffer, size);');
1179 } else {
1180 writeln(' ServiceApiInvoke(service_id_, $id, buffer, size);');
1181 writeln(' int64_t result = *${pointerToArgument(0, 0, 'int64_t')};');
1182 writeln(' DeleteMessage(buffer);');
1183 if (method.outputKind == OutputKind.STRUCT) {
1184 Type type = method.returnType;
1185 writeln(' char* memory = reinterpret_cast<char*>(result);');
1186 writeln(' jobject rootSegment = GetRootSegment(_env, memory);');
1187 writeln(' jclass resultClass = '
1188 '_env->FindClass("dartino/${type.identifier}");');
1189 writeln(' jmethodID create = _env->GetStaticMethodID('
1190 'resultClass, "create", '
1191 '"(Ljava/lang/Object;)Ldartino/${type.identifier};");');
1192 writeln(' jobject resultObject = _env->CallStaticObjectMethod('
1193 'resultClass, create, rootSegment);');
1194 writeln(' return resultObject;');
1195 } else {
1196 if (!method.returnType.isVoid) writeln(' return result;');
1197 }
1198 }
1199 }
1200
1201 static const Map<String, String> PRIMITIVE_TYPES = const {
1202 'void' : 'void',
1203 'bool' : 'jboolean',
1204
1205 'uint8' : 'jboolean',
1206 'uint16' : 'jchar',
1207
1208 'int8' : 'jbyte',
1209 'int16' : 'jshort',
1210 'int32' : 'jint',
1211 'int64' : 'jlong',
1212
1213 'float32' : 'jfloat',
1214 'float64' : 'jdouble',
1215 };
1216
1217 void writeType(Type node) {
1218 String type = PRIMITIVE_TYPES[node.identifier];
1219 write(type);
1220 }
1221
1222 void writeReturnType(Type node) {
1223 Node resolved = node.resolved;
1224 if (resolved != null) {
1225 write('jobject');
1226 } else {
1227 String type = PRIMITIVE_TYPES[node.identifier];
1228 write(type);
1229 }
1230 }
1231
1232 static const Map<String, String> PRIMITIVE_JNI_SIG = const {
1233 'void' : '',
1234 'bool' : 'Z',
1235
1236 'uint8' : 'Z',
1237 'uint16' : 'C',
1238
1239 'int8' : 'B',
1240 'int16' : 'S',
1241 'int32' : 'I',
1242 'int64' : 'J',
1243
1244 'float32' : 'F',
1245 'float64' : 'D',
1246 };
1247
1248 String getJNISignatureType(Type type) {
1249 String name = type.identifier;
1250 if (type.isPrimitive) return PRIMITIVE_JNI_SIG[name];
1251 return 'Ldartino/$name;';
1252 }
1253
1254 final Map<String, String> callbacks = {};
1255 String ensureCallback(Type type,
1256 StructLayout layout,
1257 {bool cStyle: false}) {
1258 String key = '${type.identifier}_${layout.size}';
1259 return callbacks.putIfAbsent(key, () {
1260 String cast(String type) => CcVisitor.cast(type, cStyle);
1261 String pointerToArgument(int offset, String type) {
1262 offset += REQUEST_HEADER_SIZE;
1263 String prefix = cast('$type*');
1264 return '$prefix(buffer + $offset)';
1265 }
1266 String name = 'Unwrap_$key';
1267 writeln();
1268 writeln('static void $name(void* raw) {');
1269 writeln(' char* buffer = ${cast('char*')}(raw);');
1270 write(' CallbackInfo* info =');
1271 writeln(' *${pointerToArgument(-16, "CallbackInfo*")};');
1272 writeln(' if (info == NULL) return;');
1273 writeln(' JNIEnv* env = AttachCurrentThreadAndGetEnv(info->vm);');
1274 writeln(' jclass clazz = env->GetObjectClass(info->callback);');
1275 if (!type.isVoid) {
1276 write(' int64_t result =');
1277 writeln(' *${pointerToArgument(0, 'int64_t')};');
1278 writeln(' DeleteMessage(buffer);');
1279 if (!type.isPrimitive) {
1280 writeln(' char* memory = reinterpret_cast<char*>(result);');
1281 writeln(' jobject rootSegment = GetRootSegment(env, memory);');
1282 write(' jfieldID returnTypeField = env->GetFieldID(');
1283 writeln('clazz, "returnType", "Ljava/lang/Class;");');
1284 write(' jclass resultClass = (jclass)');
1285 writeln('env->GetObjectField(info->callback, returnTypeField);');
1286 writeln(' jmethodID create = env->GetStaticMethodID('
1287 'resultClass, "create", '
1288 '"(Ljava/lang/Object;)Ldartino/${type.identifier};");');
1289 writeln(' jobject resultObject = env->CallStaticObjectMethod('
1290 'resultClass, create, rootSegment);');
1291 }
1292 } else {
1293 writeln(' DeleteMessage(buffer);');
1294 }
1295 write(' jmethodID methodId = env->GetMethodID');
1296 write('(clazz, "handle", ');
1297 if (type.isVoid) {
1298 writeln('"()V");');
1299 writeln(' env->CallVoidMethod(info->callback, methodId);');
1300 } else {
1301 String signatureType = getJNISignatureType(type);
1302 writeln('"($signatureType)V");');
1303 write(' env->CallVoidMethod(info->callback, methodId,');
1304 if (!type.isPrimitive) {
1305 writeln(' resultObject);');
1306 } else {
1307 writeln(' result);');
1308 }
1309 }
1310 writeln(' env->DeleteGlobalRef(info->callback);');
1311 writeln(' DetachCurrentThread(info->vm);');
1312 writeln(' delete info;');
1313 writeln('}');
1314 return name;
1315 });
1316 }
1317 }
1318
1319 void _generateServiceJniMakeFiles(String path,
1320 Unit unit,
1321 String resourcesDirectory,
1322 String outputDirectory) {
1323 String out = join(outputDirectory, 'java');
1324 // TODO(stanm): pass dartino root directly
1325 String dartinoRoot = join(resourcesDirectory, '..', '..', '..', '..', '..');
1326 String dartinoLibraryBuildDir = join(dartinoRoot,
1327 'tools',
1328 'android_build',
1329 'jni');
1330
1331 String dartinoIncludeDir = join(dartinoRoot, 'include');
1332
1333 String modulePath = relative(dartinoLibraryBuildDir, from: out);
1334 String includePath = relative(dartinoIncludeDir, from: out);
1335
1336 StringBuffer buffer = new StringBuffer(HEADER_MK);
1337
1338 buffer.writeln();
1339 buffer.writeln('LOCAL_PATH := \$(call my-dir)');
1340
1341 buffer.writeln();
1342 buffer.writeln('include \$(CLEAR_VARS)');
1343 buffer.writeln('LOCAL_MODULE := dartino');
1344 buffer.writeln('LOCAL_CFLAGS := -DDARTINO32');
1345 buffer.writeln('LOCAL_LDLIBS := -llog -ldl -rdynamic');
1346
1347 buffer.writeln();
1348 buffer.writeln('LOCAL_SRC_FILES := \\');
1349 buffer.writeln('\tdartino_api_wrapper.cc \\');
1350 buffer.writeln('\tdartino_service_api_wrapper.cc \\');
1351
1352 if (unit.services.length > 1) {
1353 print('Java plugin: multiple services in one file is not supported.');
1354 }
1355 String projectName = basenameWithoutExtension(path);
1356 String file = '${projectName}_wrapper';
1357
1358 buffer.writeln('\t${file}.cc');
1359
1360 buffer.writeln();
1361 buffer.writeln('LOCAL_C_INCLUDES += \$(LOCAL_PATH)');
1362 buffer.writeln('LOCAL_C_INCLUDES += ${includePath}');
1363 buffer.writeln('LOCAL_STATIC_LIBRARIES := dartino-library');
1364
1365 buffer.writeln();
1366 buffer.writeln('include \$(BUILD_SHARED_LIBRARY)');
1367
1368 buffer.writeln();
1369 buffer.writeln('\$(call import-module, ${modulePath})');
1370
1371 writeToFile(join(out, 'jni'), 'Android', buffer.toString(),
1372 extension: 'mk');
1373
1374 buffer = new StringBuffer(HEADER_MK);
1375 buffer.writeln('APP_STL := gnustl_static');
1376 buffer.writeln('APP_ABI := x86 armeabi-v7a');
1377 // TODO(zerny): Is this the right place and way to ensure ABI >= 8?
1378 buffer.writeln('APP_PLATFORM := android-8');
1379 writeToFile(join(out, 'jni'), 'Application', buffer.toString(),
1380 extension: 'mk');
1381 }
OLDNEW
« no previous file with comments | « tools/servicec/lib/src/plugins/dart.dart ('k') | tools/servicec/lib/src/plugins/shared.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698