001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj.demangling; 032 033import java.io.EOFException; 034import org.bridj.ann.Convention.Style; 035import java.lang.reflect.*; 036import java.lang.annotation.*; 037import java.util.Arrays; 038import java.util.regex.Pattern; 039import org.bridj.AbstractBridJRuntime; 040import org.bridj.BridJ; 041import org.bridj.CRuntime; 042import org.bridj.FlagSet; 043import org.bridj.JNI; 044import org.bridj.NativeLibrary; 045import org.bridj.NativeObject; 046import org.bridj.Platform; 047 048import org.bridj.Pointer; 049import org.bridj.TimeT; 050import org.bridj.SizeT; 051import org.bridj.CLong; 052import org.bridj.Callback; 053import org.bridj.ValuedEnum; 054import org.bridj.ann.Constructor; 055import org.bridj.ann.Ptr; 056import org.bridj.ann.Convention; 057import org.bridj.ann.Name; 058import org.bridj.ann.Namespace; 059import org.bridj.ann.Template; 060import org.bridj.util.AnnotationUtils; 061import static org.bridj.util.AnnotationUtils.*; 062import org.bridj.util.DefaultParameterizedType; 063import org.bridj.util.Utils; 064 065/* 066 mvn compile exec:java -Dexec.mainClass=org.bridj.demangling.Demangler -e "-Dexec.args=?method_name@class_name@@QAEPAPADPAD0@Z" 067 068 ??4Class1@TestLib@@QAEAAV01@ABV01@@Z 069 ?f@Class1@TestLib@@QAEPADPAD0@Z 070 071 class TestLib::Class1 & TestLib::Class1::operator=(class TestLib::Class1 const &) 072 char * TestLib::Class1::f(char *,char *) 073 */ 074/** 075 * Base class and core structures for symbol demanglers (typically, for C++ 076 * symbols). 077 */ 078public abstract class Demangler { 079 080 public static void main(String[] args) { 081// try { 082//// String s = "?f@@YA?AW4E@@W41@@Z"; 083// String s = "?f@@YAPADPADPAF1@Z"; // "byte* f(byte*, short*, short*)" 084// //String s = "?m@C@@SAPAV1@XZ"; 085// MemberRef mr = new VC9Demangler(null, s).parseSymbol(); 086// System.out.println(mr); 087// } catch (DemanglingException ex) { 088// Logger.getLogger(Demangler.class.getName()).error(null, ex); 089// } 090 for (String arg : args) { 091 try { 092 System.out.println("VC9: " + new VC9Demangler(null, arg).parseSymbol()); 093 } catch (Exception ex) { 094 ex.printStackTrace(); 095 } 096 try { 097 System.out.println("GCC4: " + new GCC4Demangler(null, arg).parseSymbol()); 098 } catch (Exception ex) { 099 ex.printStackTrace(); 100 } 101 } 102 } 103 104 public interface Annotations { 105 106 <A extends Annotation> A getAnnotation(Class<A> c); 107 108 boolean isAnnotationPresent(Class<? extends Annotation> c); 109 } 110 111 public static Annotations annotations(final Annotation[] aa) { 112 return new Annotations() { 113 //@Override 114 public <A extends Annotation> A getAnnotation(Class<A> c) { 115 if (aa == null) { 116 return null; 117 } 118 119 for (Annotation a : aa) { 120 if (c.isInstance(a)) { 121 return (A) a; 122 } 123 } 124 return null; 125 } 126 127 public boolean isAnnotationPresent(Class<? extends Annotation> c) { 128 return AnnotationUtils.isAnnotationPresent(c, aa); 129 } 130 }; 131 } 132 133 public static Annotations annotations(final Type e) { 134 return annotations((AnnotatedElement) Utils.getClass(e)); 135 } 136 137 public static Annotations annotations(final AnnotatedElement e) { 138 return new Annotations() { 139 //@Override 140 public <A extends Annotation> A getAnnotation(Class<A> c) { 141 return e.getAnnotation(c); 142 } 143 144 public boolean isAnnotationPresent(Class<? extends Annotation> c) { 145 return AnnotationUtils.isAnnotationPresent(c, e); 146 } 147 }; 148 } 149 150 public class DemanglingException extends Exception { 151 152 public DemanglingException(String mess) { 153 this(mess, null); 154 } 155 156 public DemanglingException(String mess, Throwable cause) { 157 super(mess + " (in symbol '" + str + "')", cause); 158 } 159 } 160 161 public abstract MemberRef parseSymbol() throws DemanglingException; 162 protected final String str; 163 protected final int length; 164 protected int position = 0; 165 protected final NativeLibrary library; 166 167 public Demangler(NativeLibrary library, String str) { 168 this.str = str; 169 this.length = str.length(); 170 this.library = library; 171 } 172 173 public String getString() { 174 return str; 175 } 176 177 protected void expectChars(char... cs) throws DemanglingException { 178 for (char c : cs) { 179 char cc = consumeChar(); 180 if (cc != c) { 181 throw error("Expected char '" + c + "', found '" + cc + "'"); 182 } 183 } 184 } 185 186 protected void expectAnyChar(char... cs) throws DemanglingException { 187 char cc = consumeChar(); 188 for (char c : cs) { 189 if (cc == c) { 190 return; 191 } 192 } 193 throw error("Expected any of " + Arrays.toString(cs) + ", found '" + cc + "'"); 194 } 195 196 public static StringBuilder implode(StringBuilder b, Object[] items, String sep) { 197 return implode(b, Arrays.asList(items), sep); 198 } 199 200 public static StringBuilder implode(StringBuilder b, Iterable<?> items, String sep) { 201 boolean first = true; 202 for (Object item : items) { 203 if (first) { 204 first = false; 205 } else { 206 b.append(sep); 207 } 208 b.append(item); 209 } 210 return b; 211 } 212 213 protected char peekChar() { 214 return peekChar(1); 215 } 216 217 protected char peekChar(int dist) { 218 int p = position + dist - 1; 219 return p >= length ? 0 : str.charAt(p); 220 } 221 222 protected char lastChar() { 223 return position == 0 ? 0 : str.charAt(position - 1); 224 } 225 226 protected char consumeChar() throws DemanglingException { 227 char c = peekChar(); 228 if (c != 0) { 229 position++; 230 } else { 231 throw new DemanglingException("Reached end of string '" + str + "'"); 232 } 233 return c; 234 } 235 236 protected boolean consumeCharsIf(char... nextChars) { 237 int initialPosition = position; 238 try { 239 for (char c : nextChars) { 240 char cc = consumeChar(); 241 if (cc != c) { 242 position = initialPosition; 243 return false; 244 } 245 } 246 return true; 247 } catch (DemanglingException ex) { 248 position = initialPosition; 249 return false; 250 } 251 } 252 253 protected boolean consumeCharIf(char... allowedChars) { 254 char c = peekChar(); 255 for (char allowedChar : allowedChars) { 256 if (allowedChar == c) { 257 position++; 258 return true; 259 } 260 } 261 return false; 262 } 263 264 protected DemanglingException error(int deltaPosition) { 265 return error(null, deltaPosition); 266 } 267 268 protected DemanglingException error(String mess) { 269 return error(mess, -1); 270 } 271 272 protected DemanglingException error(String mess, int deltaPosition) { 273 StringBuilder err = new StringBuilder(position + 1); 274 int position = this.position + deltaPosition; 275 for (int i = 0; i < position; i++) { 276 err.append(' '); 277 } 278 err.append('^'); 279 return new DemanglingException("Parsing error at position " + position + (mess == null ? "" : ": " + mess) + " \n\t" + str + "\n\t" + err); 280 } 281 282 public interface TemplateArg { 283 284 public boolean matchesParam(Object param, Annotations annotations); 285 } 286 287 public static String getMethodName(Method method) { 288 Name name = method.getAnnotation(Name.class); 289 return name == null ? method.getName() : name.value(); 290 } 291 292 public static String getClassName(Type type) { 293 assert type != null; 294 Class<?> typeClass = Utils.getClass(type);//getTypeClass(type); 295 Name name = typeClass.getAnnotation(Name.class); 296 return name == null ? typeClass.getSimpleName() : name.value(); 297 } 298 299 public static String getFullClassName(Type type) { 300 Class<?> typeClass = Utils.getClass(type);//getTypeClass(type); 301 String simpleName = getClassName(typeClass); 302 Namespace namespace = typeClass.getAnnotation(Namespace.class); 303 return namespace != null ? namespace.value().replaceAll("::", ".") + "." + simpleName : simpleName; 304 } 305 306 public static class Symbol { 307 308 final String symbol; 309 long address; 310 MemberRef ref; 311 boolean refParsed; 312 final NativeLibrary library; 313 314 public Symbol(String symbol, NativeLibrary library) { 315 this.symbol = symbol; 316 this.library = library; 317 318 } 319 320 public NativeLibrary getLibrary() { 321 return library; 322 } 323 324 public MemberRef getRef() { 325 return ref; 326 } 327 328 public Style getStyle() { 329 return style; 330 } 331 332 public String getSymbol() { 333 return symbol; 334 } 335 336 @Override 337 public String toString() { 338 return symbol + (ref == null ? "" : " (" + ref + ")"); 339 } 340 341 public long getAddress() { 342 if (address == 0) { 343 address = library.getSymbolAddress(symbol); 344 } 345 return address; 346 } 347 348 public void setAddress(long address) { 349 this.address = address; 350 } 351 private Convention.Style style; 352 353 public Convention.Style getInferredCallingConvention() { 354 if (style == null) { 355 //System.out.println("Symbol " + symbol + " stdcall = " + symbol.matches("_.*?@\\d+")); 356 if (symbol.matches("_.*?@\\d+")) { 357 style = Convention.Style.StdCall; 358 } else if (symbol.matches("@.*?@\\d+")) { 359 style = Convention.Style.FastCall; 360 } else if (Platform.isWindows() && symbol.contains("@")) { 361 try { 362 MemberRef mr = getParsedRef(); 363 if (mr != null) { 364 style = mr.callingConvention; 365 } 366 } catch (Throwable th) { 367 } 368 } 369 } 370 return style; 371 } 372 373 public boolean matches(Method method) { 374 if (!symbol.contains(getMethodName(method))) { 375 return false; 376 } 377 378 //if (!Modifier.isStatic(method.getModifiers()) && !symbol.contains(method.getDeclaringClass().getSimpleName())) 379 // return false; 380 381 parse(); 382 383 try { 384 if (ref != null) { 385 boolean res = ref.matches(method); 386 if (!res && BridJ.debug) { 387 BridJ.debug("Symbol " + symbol + " was a good candidate but expected demangled signature " + ref + " did not match the method " + method); 388 } 389 return res; 390 } 391 } catch (Exception ex) { 392 ex.printStackTrace(); 393 } 394 return false; 395 } 396 397 public MemberRef getParsedRef() { 398 parse(); 399 return ref; 400 } 401 402 synchronized void parse() { 403 if (!refParsed) { 404 try { 405 ref = library.parseSymbol(symbol); 406 } catch (DemanglingException ex) { 407 if (BridJ.debug) { 408 ex.printStackTrace(); 409 } 410 if (BridJ.verbose) { 411 BridJ.warning("Symbol parsing failed : " + ex.getMessage()); 412 } 413 } 414 refParsed = true; 415 } 416 } 417 418 public String getName() { 419 return symbol; 420 } 421 422 public boolean matchesVirtualTable(Class<?> type) { 423 if (!symbol.contains(type.getSimpleName())) { 424 return false; 425 } 426 427 parse(); 428 429 try { 430 if (ref != null) { 431 return ref.matchesVirtualTable(type); 432 } 433 } catch (Exception ex) { 434 ex.printStackTrace(); 435 } 436 return false; 437 } 438 439 public boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) { 440 if (!symbol.contains(getClassName(type))) { 441 return false; 442 } 443 444 parse(); 445 446 try { 447 if (ref != null) { 448 return ref.matchesConstructor(type, constr); 449 } 450 } catch (Exception ex) { 451 ex.printStackTrace(); 452 } 453 return false; 454 } 455 456 public boolean matchesDestructor(Class<?> type) { 457 if (!symbol.contains(type.getSimpleName())) { 458 return false; 459 } 460 461 parse(); 462 463 try { 464 if (ref != null) { 465 return ref.matchesDestructor(type); 466 } 467 } catch (Exception ex) { 468 ex.printStackTrace(); 469 } 470 return false; 471 } 472 473 public boolean isVirtualTable() { 474 // TODO Auto-generated method stub 475 return false; 476 } 477 } 478 479 public static abstract class TypeRef implements TemplateArg { 480 481 public abstract StringBuilder getQualifiedName(StringBuilder b, boolean generic); 482 483 public String getQualifiedName(boolean generic) { 484 StringBuilder sb = getQualifiedName(new StringBuilder(), generic); 485 return sb == null ? null : sb.toString(); 486 } 487 488 public boolean matchesParam(Object param, Annotations annotations) { 489 return (param instanceof Type) && matches((Type) param, annotations); 490 } 491 492 public boolean matches(Type type, Annotations annotations) { 493 String thisName = getQualifiedName(false); 494 if (thisName == null) 495 return false; 496 Class<?> typeClass = getTypeClass(type); 497 String name = getClassName(typeClass); 498 if (thisName.equals(name)) 499 return true; 500 Namespace ns = typeClass.getAnnotation(Namespace.class); 501 String pack; 502 if (ns == null) { 503 if (typeClass.getPackage() == null) 504 pack = ""; 505 else 506 pack = typeClass.getPackage().getName(); 507 } else { 508 pack = ns.value().replaceAll("\b::\b", ".").trim(); 509 } 510 if (pack.length() == 0) 511 return false; 512 String qname = pack + "." + name; 513 if (thisName.matches("\b" + Pattern.quote(qname))) 514 return true; 515 return false; 516 } 517 518 @Override 519 public boolean equals(Object obj) { 520 return toString().equals(obj.toString()); 521 } 522 } 523 524 public static class Constant implements TemplateArg { 525 526 Object value; 527 528 public Constant(Object value) { 529 this.value = value; 530 } 531 532 public boolean matchesParam(Object param, Annotations annotations) { 533 return value.equals(param); 534 } 535 536 @Override 537 public String toString() { 538 return value.toString(); 539 } 540 } 541 542 public static class NamespaceRef extends TypeRef { 543 544 Object[] namespace; 545 546 public NamespaceRef(Object... namespace) { 547 this.namespace = namespace; 548 } 549 550 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 551 return implode(b, namespace, "."); 552 } 553 554 @Override 555 public String toString() { 556 return getQualifiedName(new StringBuilder(), true).toString(); 557 } 558 } 559 560 public static class PointerTypeRef extends TypeRef { 561 562 public TypeRef pointedType; 563 564 public PointerTypeRef(TypeRef pointedType) { 565 assert pointedType != null; 566 this.pointedType = pointedType; 567 } 568 569 @Override 570 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 571 return b.append("org.bridj.Pointer"); 572 } 573 574 @Override 575 public String toString() { 576 return pointedType + "*"; 577 } 578 579 @Override 580 public boolean matches(Type type, Annotations annotations) { 581 if (super.matches(type, annotations)) 582 return true; 583 584 if (type == Long.TYPE && annotations.isAnnotationPresent(Ptr.class)) 585 return true; 586 587 Class typeClass = getTypeClass(type); 588 if (!Pointer.class.isAssignableFrom(typeClass)) 589 return false; 590// return true; 591 Type pointedType = normalize(Utils.getUniqueParameterizedTypeParameter(type)); 592 if (this.pointedType == null || this.pointedType.toString().equals("void")) 593 return pointedType == null; 594 if (pointedType == null) { 595 return true; 596 } 597 return this.pointedType.matches(pointedType, annotations); 598 } 599 600 601 } 602 603 protected static TypeRef pointerType(TypeRef tr) { 604 return new PointerTypeRef(tr); 605 } 606 607 protected static TypeRef classType(final Class<?> c, Class<? extends Annotation>... annotations) { 608 return classType(c, null, annotations); 609 } 610 611 protected static TypeRef classType(final Class<?> c, final java.lang.reflect.Type[] genericTypes, Class<? extends Annotation>... annotations) { 612 JavaTypeRef tr = new JavaTypeRef(); 613 if (genericTypes == null) { 614 tr.type = c; 615 } else { 616 tr.type = new DefaultParameterizedType(c, genericTypes); 617 } 618 619 tr.annotations = annotations; 620 return tr; 621 } 622 623 protected static TypeRef simpleType(String name, TemplateArg... args) { 624 return new ClassRef(new Ident(name, args)); 625 } 626 627 protected static TypeRef simpleType(Ident ident) { 628 return new ClassRef(ident); 629 } 630 631 static Class<?> getTypeClass(Type type) { 632 633 if (type instanceof Class<?>) { 634 return (Class<?>) type; 635 } 636 if (type instanceof ParameterizedType) { 637 ParameterizedType pt = (ParameterizedType) type; 638 Class<?> c = (Class<?>) pt.getRawType(); 639 if (ValuedEnum.class.isAssignableFrom(c)) { 640 Type[] types = pt.getActualTypeArguments(); 641 if (types == null || types.length != 1) { 642 c = int.class; 643 } else { 644 c = getTypeClass(pt.getActualTypeArguments()[0]); 645 } 646 } 647 return c; 648 } 649 if (type instanceof GenericArrayType) { 650 if (Object.class.isAssignableFrom(getTypeClass(((GenericArrayType) type).getGenericComponentType()))) { 651 return Object[].class; 652 } 653 } 654 return null; 655// throw new UnsupportedOperationException("Unknown type type : " + (type == null ? null : type.getClass().getName())); 656 } 657 658 private static Type normalize(Type t) { 659 if (t instanceof WildcardType) { 660 WildcardType wt = (WildcardType) t; 661 if (wt.getLowerBounds().length == 1) 662 return normalize(wt.getLowerBounds()[0]); 663 return null; 664 } 665 Class<?> c = Utils.getClass(t); 666 if (c != null && c.isPrimitive()) { 667 if (t == float.class) return Float.class; 668 if (t == double.class) return Double.class; 669 if (t == byte.class) return Byte.class; 670 if (t == char.class) return Character.class; 671 if (t == short.class) return Short.class; 672 if (t == int.class) return Integer.class; 673 if (t == long.class) return Long.class; 674 if (t == boolean.class) return Boolean.class; 675 if (t == void.class) return Void.class; 676 } 677 return t; 678 } 679 static boolean equivalentTypes(Type a, Class ac, Annotations aAnnotations, Type b, Class bc, Annotations bAnnotations) { 680 if (normalize(a).equals(normalize(b))) { 681 return true; 682 } 683 684 if (aAnnotations != null && bAnnotations != null) { 685 if (xor(isPointerLike(a, ac, aAnnotations), isPointerLike(b, bc, bAnnotations))) { 686 return false; 687 } 688 if (xor(isCLong(a, ac, aAnnotations), isCLong(b, bc, bAnnotations))) { 689 return false; 690 } 691 } 692 int as = getIntegralSize(a, ac, aAnnotations); 693 int bs = getIntegralSize(b, bc, bAnnotations); 694 return as != -1 && as == bs; 695 } 696 697 static boolean xor(boolean a, boolean b) { 698 return a && !b || !a && b; 699 } 700 static boolean isPointerLike(Type type, Class typec, Annotations annotations) { 701 if (type == long.class || type == Long.class) { 702 return annotations == null && Pointer.SIZE == 8 || 703 annotations != null && annotations.isAnnotationPresent(Ptr.class) && 704 !annotations.isAnnotationPresent(org.bridj.ann.CLong.class); 705 } 706 return type == SizeT.class || Pointer.class.isAssignableFrom(typec); 707 } 708 709 static boolean isCLong(Type type, Class typec, Annotations annotations) { 710 if (type == long.class || type == Long.class) { 711 return annotations == null && CLong.SIZE == 8 || 712 annotations != null && annotations.isAnnotationPresent(org.bridj.ann.CLong.class); 713 } 714 return type == CLong.class; 715 } 716 717 static int getIntegralSize(Type type, Class typec, Annotations annotations) { 718 if (type == int.class || type == Integer.class) { 719 return 4; 720 } 721 if (type == long.class || type == Long.class) { 722 if (annotations != null) { 723 if (annotations.isAnnotationPresent(Ptr.class)) { 724 return Pointer.SIZE; 725 } 726 if (annotations.isAnnotationPresent(org.bridj.ann.CLong.class)) { 727 return CLong.SIZE; 728 } 729 } 730 return 8; 731 } 732 if (type == CLong.class) { 733 return CLong.SIZE; 734 } 735 if (type == SizeT.class) { 736 return SizeT.SIZE; 737 } 738 if (type == TimeT.class) { 739 return TimeT.SIZE; 740 } 741 if (type == byte.class || type == Byte.class) { 742 return 1; 743 } 744 if (type == char.class || type == Character.class || type == short.class || type == Short.class) { 745 return 2; 746 } 747 if (ValuedEnum.class.isAssignableFrom(typec)) { 748 return 4; 749 } 750 if (Pointer.class.isAssignableFrom(typec)) { 751 return SizeT.SIZE; 752 } 753 return -1; 754 } 755 756 public static boolean equivalentTypes(Type a, Annotations aAnnotations, Type b, Annotations bAnnotations) { 757 return equivalentTypes(a, getTypeClass(a), aAnnotations, b, getTypeClass(b), bAnnotations); 758 } 759 760 public static class JavaTypeRef extends TypeRef { 761 762 java.lang.reflect.Type type; 763 Class<? extends Annotation>[] annotations; 764 765 @Override 766 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 767 return b.append(getFullClassName(this.type)); 768 } 769 770 @Override 771 public boolean matches(Type type, Annotations annotations) { 772 Class<?> tc = getTypeClass(this.type); 773 Class<?> typec = getTypeClass(type); 774 if (typec == null) 775 return true; // TODO check 776 if (tc == typec || tc.equals(typec)) { 777 return true; 778 } 779 780 if ((type == Long.TYPE && Pointer.class.isAssignableFrom(tc)) 781 || (Pointer.class.isAssignableFrom(typec) && tc == Long.TYPE)) { 782 return true; 783 } 784 785 return equivalentTypes(type, typec, annotations, this.type, tc, null); // TODO isAssignableFrom or the opposite, depending on context 786 } 787 788 @Override 789 public String toString() { 790 StringBuilder b = new StringBuilder(); 791 for (Class<?> ann : annotations) { 792 b.append(ann.getSimpleName()).append(' '); 793 } 794 b.append((type instanceof Class<?>) ? ((Class<?>) type).getSimpleName() : type.toString()); 795 return b.toString(); 796 } 797 } 798 799 public interface IdentLike { 800 } 801 802 public static class Ident implements IdentLike { 803 804 Object simpleName; 805 TemplateArg[] templateArguments; 806 807 public Ident(String simpleName, TemplateArg... templateArguments) { 808 this.simpleName = simpleName; 809 this.templateArguments = templateArguments; 810 } 811 812 @Override 813 public boolean equals(Object o) { 814 if (o == null || !(o instanceof Ident)) { 815 return false; 816 } 817 818 Ident ident = (Ident) o; 819 if (!simpleName.equals(ident.simpleName)) { 820 return false; 821 } 822 823 int n = templateArguments.length; 824 if (ident.templateArguments.length != n) { 825 return false; 826 } 827 828 for (int i = 0; i < n; i++) { 829 if (!templateArguments[i].equals(ident.templateArguments[i])) { 830 return false; 831 } 832 } 833 834 return true; 835 } 836 837 @Override 838 public String toString() { 839 StringBuilder b = new StringBuilder(); 840 841 b.append(simpleName); 842 appendTemplateArgs(b, templateArguments); 843 return b.toString(); 844 } 845 } 846 847 public static class ClassRef extends TypeRef { 848 849 private TypeRef enclosingType; 850 //private Object simpleName; 851 //TemplateArg[] templateArguments; 852 final Ident ident; 853 854 public ClassRef(Ident ident) { 855 this.ident = ident; 856 } 857 858 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 859 if (getEnclosingType() instanceof ClassRef) { 860 getEnclosingType().getQualifiedName(b, generic).append('$'); 861 } else if (getEnclosingType() instanceof NamespaceRef) { 862 getEnclosingType().getQualifiedName(b, generic).append('.'); 863 } 864 b.append(ident.simpleName); 865 if (generic && ident.templateArguments != null) { 866 int args = 0; 867 for (int i = 0, n = ident.templateArguments.length; i < n; i++) { 868 TemplateArg arg = ident.templateArguments[i]; 869 if (!(arg instanceof TypeRef)) { 870 continue; 871 } 872 873 if (args == 0) { 874 b.append('<'); 875 } else { 876 b.append(", "); 877 } 878 ((TypeRef) arg).getQualifiedName(b, generic); 879 args++; 880 } 881 if (args > 0) { 882 b.append('>'); 883 } 884 } 885 return b; 886 } 887 888 public Ident getIdent() { 889 return ident; 890 } 891 892 public void setEnclosingType(TypeRef enclosingType) { 893 this.enclosingType = enclosingType; 894 } 895 896 public TypeRef getEnclosingType() { 897 return enclosingType; 898 } 899 900 @Override 901 public boolean matches(Type type, Annotations annotations) { 902 Class<?> typeClass = getTypeClass(type); 903 if (typeClass == null) { 904 return false; 905 } 906 String fullName = getFullClassName( 907 ValuedEnum.class.isAssignableFrom(typeClass) ? 908 normalize(Utils.getUniqueParameterizedTypeParameter(type)) : 909 typeClass); 910 String qname = getQualifiedName(false); 911 if (fullName != null && fullName.equals(qname)) { 912 return true; 913 } 914 915 return false; 916 } 917 918 @Override 919 public String toString() { 920 StringBuilder b = new StringBuilder(); 921 922 if (enclosingType != null) { 923 b.append(enclosingType).append('.'); 924 } 925 926 b.append(ident); 927 return b.toString(); 928 } 929 } 930 931 static void appendTemplateArgs(StringBuilder b, Object[] params) { 932 if (params == null || params.length == 0) { 933 return; 934 } 935 appendArgs(b, '<', '>', params); 936 } 937 938 static void appendArgs(StringBuilder b, char pre, char post, Object[] params) { 939 b.append(pre); 940 if (params != null) { 941 for (int i = 0; i < params.length; i++) { 942 if (i != 0) { 943 b.append(", "); 944 } 945 b.append(params[i]); 946 } 947 } 948 b.append(post); 949 } 950 951 public static class FunctionTypeRef extends TypeRef { 952 953 MemberRef function; 954 955 public FunctionTypeRef(MemberRef function) { 956 this.function = function; 957 } 958 959 @Override 960 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 961 // TODO Auto-generated method stub 962 return null; 963 } 964 965 @Override 966 public boolean matches(Type type, Annotations annotations) { 967 Class<?> typeClass = getTypeClass(type); 968 if (!Callback.class.isAssignableFrom(typeClass)) 969 return false; 970 Method method = CRuntime.getInstance().getFastestCallbackMethod(typeClass); 971 if (method == null) 972 return false; 973 return function.matches(method); 974 } 975 976 @Override 977 public String toString() { 978 return function.toString(); 979 } 980 } 981 982 public enum SpecialName implements IdentLike { 983 984 Constructor("", true, true), 985 SpecialConstructor("", true, true), 986 Destructor("", true, true), 987 SelfishDestructor("", true, true), 988 DeletingDestructor("", true, true), 989 New("new", true, true), 990 Delete("delete", true, true), 991 NewArray("new[]", true, true), 992 DeleteArray("delete[]", true, true), 993 VFTable("vftable", false, true), 994 VBTable("vbtable", false, true), 995 VCall("vcall", false, false), // What is that ??? 996 TypeOf("typeof", false, false), 997 ScalarDeletingDestructor("'scalar deleting destructor'", true, true), 998 VectorDeletingDestructor("'vector deleting destructor'", true, true), 999 OperatorAssign("operator=", true, true), 1000 OperatorRShift("operator>>", true, true), 1001 OperatorDivideAssign("operator/=", true, true), 1002 OperatorModuloAssign("operator%=", true, true), 1003 OperatorRShiftAssign("operator>>=", true, true), 1004 OperatorLShiftAssign("operator<<=", true, true), 1005 OperatorBitAndAssign("operator&=", true, true), 1006 OperatorBitOrAssign("operator|=", true, true), 1007 OperatorXORAssign("operator^=", true, true), 1008 OperatorLShift("operator<<", true, true), 1009 OperatorLogicNot("operator!", true, true), 1010 OperatorEquals("operator==", true, true), 1011 OperatorDifferent("operator!=", true, true), 1012 OperatorSquareBrackets("operator[]", true, true), 1013 OperatorCast("'some cast operator'", true, true), 1014 OperatorArrow("operator->", true, true), 1015 OperatorMultiply("operator*", true, true), 1016 OperatorIncrement("operator++", true, true), 1017 OperatorDecrement("operator--", true, true), 1018 OperatorSubstract("operator-", true, true), 1019 OperatorAdd("operator+", true, true), 1020 OperatorBitAnd("operator&=", true, true), 1021 /// Member pointer selector 1022 OperatorArrowStar("operator->*", true, true), 1023 OperatorDivide("operator/", true, true), 1024 OperatorModulo("operator%", true, true), 1025 OperatorLower("operator<", true, true), 1026 OperatorLowerEquals("operator<=", true, true), 1027 OperatorGreater("operator>", true, true), 1028 OperatorGreaterEquals("operator>=", true, true), 1029 OperatorComma("operator,", true, true), 1030 OperatorParenthesis("operator()", true, true), 1031 OperatorBitNot("operator~", true, true), 1032 OperatorXOR("operator^", true, true), 1033 OperatorBitOr("operator|", true, true), 1034 OperatorLogicAnd("operator&&", true, true), 1035 OperatorLogicOr("operator||", true, true), 1036 OperatorMultiplyAssign("operator*=", true, true), 1037 OperatorAddAssign("operator+=", true, true), 1038 OperatorSubstractAssign("operator-=", true, true); 1039 1040 private SpecialName(String name, boolean isFunction, boolean isMember) { 1041 this.name = name; 1042 this.isFunction = isFunction; 1043 this.isMember = isMember; 1044 } 1045 final String name; 1046 final boolean isFunction; 1047 final boolean isMember; 1048 1049 @Override 1050 public String toString() { 1051 return name; 1052 } 1053 1054 public boolean isFunction() { 1055 return isFunction; 1056 } 1057 1058 public boolean isMember() { 1059 return isMember; 1060 } 1061 } 1062 1063 public static class MemberRef { 1064 1065 private Integer argumentsStackSize; 1066 private TypeRef enclosingType; 1067 private TypeRef valueType; 1068 private IdentLike memberName; 1069 Boolean isStatic, isProtected, isPrivate; 1070 public int modifiers; 1071 public TypeRef[] paramTypes, throwTypes; 1072 TemplateArg[] templateArguments; 1073 public Style callingConvention; 1074 1075 public void setTemplateArguments(TemplateArg[] templateArguments) { 1076 this.templateArguments = templateArguments; 1077 } 1078 1079 public Integer getArgumentsStackSize() { 1080 return argumentsStackSize; 1081 } 1082 1083 public void setArgumentsStackSize(Integer argumentsStackSize) { 1084 this.argumentsStackSize = argumentsStackSize; 1085 } 1086 1087 protected boolean matchesEnclosingType(Type type) { 1088 return getEnclosingType() != null && getEnclosingType().matches(type, annotations(type)); 1089 } 1090 1091 protected boolean matchesVirtualTable(Type type) { 1092 return memberName == SpecialName.VFTable && matchesEnclosingType(type); 1093 } 1094 1095 protected boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) { 1096 if (memberName != SpecialName.Constructor) { 1097 return false; 1098 } 1099 1100 if (!matchesEnclosingType(type)) { 1101 return false; 1102 } 1103 1104 Template temp = Utils.getClass(type).getAnnotation(Template.class); 1105 Annotation[][] anns = constr.getParameterAnnotations(); 1106 Type[] parameterTypes = constr.getGenericParameterTypes(); 1107 1108 int overrideOffset = Utils.getEnclosedConstructorParametersOffset(constr); 1109 if (!matchesArgs(parameterTypes, anns, overrideOffset + (temp == null ? 0 : temp.value().length))) { 1110 return false; 1111 } 1112 1113 return true; 1114 } 1115 1116 protected boolean matchesDestructor(Type type) { 1117 return memberName == SpecialName.Destructor && matchesEnclosingType(type); 1118 } 1119 1120 static boolean hasInstance(Object[] array, Class<? extends Annotation>... cs) { 1121 for (Object o : array) { 1122 for (Class<?> c : cs) { 1123 if (c.isInstance(o)) { 1124 return true; 1125 } 1126 } 1127 } 1128 return false; 1129 } 1130 1131 static int getArgumentsStackSize(Method method) { 1132 int total = 0; 1133 Type[] paramTypes = method.getGenericParameterTypes(); 1134 Annotation[][] anns = method.getParameterAnnotations(); 1135 for (int iArg = 0, nArgs = paramTypes.length; iArg < nArgs; iArg++) { 1136 Class<?> paramType = getTypeClass(paramTypes[iArg]); 1137 if (paramType == int.class) { 1138 total += 4; 1139 } else if (paramType == long.class) { 1140 Annotation[] as = anns[iArg]; 1141 if (isAnnotationPresent(Ptr.class, as) || isAnnotationPresent(org.bridj.ann.CLong.class, as)) //if (hasInstance(anns[iArg], Ptr.class, CLong.class)) 1142 { 1143 total += Pointer.SIZE; 1144 } else { 1145 total += 8; 1146 } 1147 } else if (paramType == float.class) { 1148 total += 4; 1149 } else if (paramType == double.class) { 1150 total += 8; 1151 } else if (paramType == byte.class) { 1152 total += 1; 1153 } else if (paramType == char.class) { 1154 total += Platform.WCHAR_T_SIZE; 1155 } else if (paramType == CLong.class) { 1156 total += Platform.CLONG_SIZE; 1157 } else if (paramType == SizeT.class) { 1158 total += Platform.SIZE_T_SIZE; 1159 } else if (paramType == TimeT.class) { 1160 total += Platform.TIME_T_SIZE; 1161 } else if (paramType == short.class) { 1162 total += 2; 1163 } else if (paramType == boolean.class) { 1164 total += 1; 1165 } else if (Pointer.class.isAssignableFrom(paramType)) { 1166 total += Pointer.SIZE; 1167 } else if (NativeObject.class.isAssignableFrom(paramType)) { 1168 total += ((CRuntime) BridJ.getRuntime(paramType)).sizeOf(paramTypes[iArg], null); 1169 } else if (FlagSet.class.isAssignableFrom(paramType)) { 1170 total += 4; // TODO 1171 } else { 1172 throw new RuntimeException("Type not handled : " + paramType.getName()); 1173 } 1174 } 1175 return total; 1176 } 1177 1178 protected boolean matches(Method method) { 1179 1180 if (memberName instanceof SpecialName) { 1181 return false; // use matchesConstructor... 1182 } 1183 if (!matchesEnclosingType(method)) { 1184 return false; 1185 } 1186 1187 return matchesSignature(method); 1188 } 1189 1190 public boolean matchesEnclosingType(Method method) { 1191 TypeRef et = getEnclosingType(); 1192 if (et == null) { 1193 return true; 1194 } 1195 1196 Annotations annotations = annotations(method); 1197 Class dc = method.getDeclaringClass(); 1198 do { 1199 if (et.matches(dc, annotations)) { 1200 return true; 1201 } 1202 1203 dc = dc.getSuperclass(); 1204 } while (dc != null && dc != Object.class); 1205 1206 return false; 1207 } 1208 1209 public boolean matchesSignature(Method method) { 1210 1211 if (getArgumentsStackSize() != null && getArgumentsStackSize().intValue() != getArgumentsStackSize(method)) { 1212 return false; 1213 } 1214 1215 if (getMemberName() != null && !getMemberName().toString().equals(getMethodName(method))) { 1216 return false; 1217 } 1218 1219 if (getValueType() != null && !getValueType().matches(method.getReturnType(), annotations(method))) { 1220 return false; 1221 } 1222 1223 Template temp = method.getAnnotation(Template.class); 1224 Annotation[][] anns = method.getParameterAnnotations(); 1225// Class<?>[] methodArgTypes = method.getParameterTypes(); 1226 Type[] parameterTypes = method.getGenericParameterTypes(); 1227 //boolean hasThisAsFirstArgument = BridJ.hasThisAsFirstArgument(method);//methodArgTypes, anns, true); 1228 1229 if (paramTypes != null && !matchesArgs(parameterTypes, anns, temp == null ? 0 : temp.value().length))///*, hasThisAsFirstArgument*/)) 1230 { 1231 return false; 1232 } 1233 1234 //int thisDirac = hasThisAsFirstArgument ? 1 : 0; 1235 /* 1236 switch (type) { 1237 case Constructor: 1238 case Destructor: 1239 Annotation ann = method.getAnnotation(type == SpecialName.Constructor ? Constructor.class : Destructor.class); 1240 if (ann == null) 1241 return false; 1242 if (!hasThisAsFirstArgument) 1243 return false; 1244 if (methodArgTypes.length - thisDirac != 0 ) 1245 return false; 1246 break; 1247 case InstanceMethod: 1248 if (!hasThisAsFirstArgument) 1249 return false; 1250 break; 1251 case StaticMethod: 1252 if (hasThisAsFirstArgument) 1253 return false; 1254 break; 1255 }*/ 1256 1257 return true; 1258 } 1259 1260 private boolean matchesArgs(Type[] parameterTypes, Annotation[][] anns, int offset) { 1261 int totalArgs = offset; 1262 for (int i = 0, n = templateArguments == null ? 0 : templateArguments.length; i < n; i++) { 1263 if (totalArgs >= parameterTypes.length) { 1264 return false; 1265 } 1266 1267 Type paramType = parameterTypes[offset + i]; 1268 1269 TemplateArg arg = templateArguments[i]; 1270 if (arg instanceof TypeRef) { 1271 if (!paramType.equals(Class.class)) { 1272 return false; 1273 } 1274 } else if (arg instanceof Constant) { 1275 try { 1276 getTypeClass(paramType).cast(((Constant) arg).value); 1277 } catch (ClassCastException ex) { 1278 return false; 1279 } 1280 } 1281 totalArgs++; 1282 } 1283 1284 for (int i = 0, n = paramTypes == null ? 0 : paramTypes.length; i < n; i++) { 1285 if (totalArgs >= parameterTypes.length) { 1286 return false; 1287 } 1288 1289 TypeRef paramType = paramTypes[i]; 1290 Type parameterType = parameterTypes[totalArgs]; 1291 if (!paramType.matches(parameterType, annotations(anns == null ? null : anns[i]))) { 1292 return false; 1293 } 1294 1295 totalArgs++; 1296 } 1297 1298 if (totalArgs != parameterTypes.length) { 1299 BridJ.error("Not enough args for " + this); 1300 return false; 1301 } 1302 1303 return true; 1304 } 1305 1306 @Override 1307 public String toString() { 1308 StringBuilder b = new StringBuilder(); 1309 1310 b.append(valueType).append(' '); 1311 boolean nameWritten = false; 1312 if (enclosingType != null) { 1313 b.append(enclosingType); 1314 b.append('.'); 1315 if (memberName instanceof SpecialName) { 1316 switch ((SpecialName) memberName) { 1317 case Destructor: 1318 b.append('~'); 1319 case Constructor: 1320 b.append(((ClassRef) enclosingType).ident.simpleName); 1321 nameWritten = true; 1322 break; 1323 } 1324 } 1325 } 1326 if (!nameWritten) { 1327 b.append(memberName); 1328 } 1329 1330 appendTemplateArgs(b, templateArguments); 1331 appendArgs(b, '(', ')', paramTypes); 1332 return b.toString(); 1333 } 1334 1335 public void setMemberName(IdentLike memberName) { 1336 this.memberName = memberName; 1337 } 1338 1339 public IdentLike getMemberName() { 1340 return memberName; 1341 } 1342 1343 public void setValueType(TypeRef valueType) { 1344 this.valueType = valueType; 1345 } 1346 1347 public TypeRef getValueType() { 1348 return valueType; 1349 } 1350 1351 public void setEnclosingType(TypeRef enclosingType) { 1352 this.enclosingType = enclosingType; 1353 } 1354 1355 public TypeRef getEnclosingType() { 1356 return enclosingType; 1357 } 1358 } 1359}