JRE-469 Console with emoji output becomes slow

The fix consists of two parts:
* Making CCharToGlyphMapper remember that a particular character
  cannot be displayed (isn't mapped to glyph with given font). Checking
  this repeatedly in native code is very slow.
* Make CCompositeGlyphMapper remember the results of char-to-glyph
  mapping, this was missing in previous implementation. This reuses
  caching code in CompositeGlyphMapper, extending the range of
  characters for which the results are cached to include Supplementary
  Multilingual Plane (most emoji characters belong to it).
diff --git a/src/macosx/classes/sun/font/CCharToGlyphMapper.java b/src/macosx/classes/sun/font/CCharToGlyphMapper.java
index e33cfb4..c48c382 100644
--- a/src/macosx/classes/sun/font/CCharToGlyphMapper.java
+++ b/src/macosx/classes/sun/font/CCharToGlyphMapper.java
@@ -28,6 +28,8 @@
 import java.util.HashMap;
 
 public class CCharToGlyphMapper extends CharToGlyphMapper {
+    private static final int UNMAPPED_CHAR = Integer.MIN_VALUE;
+
     private static native int countGlyphs(final long nativeFontPtr);
 
     private Cache cache = new Cache();
@@ -90,15 +92,16 @@
 
     public synchronized int charToGlyph(char unicode) {
         final int glyph = cache.get(unicode);
-        if (glyph != 0) return glyph;
+        if (glyph != 0) return glyph == UNMAPPED_CHAR ? 0 : glyph;
 
         final char[] unicodeArray = new char[] { unicode };
         final int[] glyphArray = new int[1];
 
         nativeCharsToGlyphs(fFont.getNativeFontPtr(), 1, unicodeArray, glyphArray);
-        cache.put(unicode, glyphArray[0]);
+        int result = glyphArray[0];
+        cache.put(unicode, result == 0 ? UNMAPPED_CHAR : result);
 
-        return glyphArray[0];
+        return result;
     }
 
     public synchronized int charToGlyph(int unicode) {
@@ -243,7 +246,7 @@
 
                 final int value = get(code);
                 if (value != 0 && value != -1) {
-                    values[i] = value;
+                    values[i] = value == UNMAPPED_CHAR ? 0 : value;
                     if (code >= 0x10000) {
                         values[i+1] = INVISIBLE_GLYPH_ID;
                         i++;
@@ -288,9 +291,10 @@
                             low - LO_SURROGATE_START + 0x10000;
                     }
                 }
-               values[i] = glyphCodes[m];
-               put(code, values[i]);
-               if (code >= 0x10000) {
+                values[i] = glyphCodes[m];
+                int glyphCode = values[i];
+                put(code, glyphCode == 0 ? UNMAPPED_CHAR : glyphCode);
+                if (code >= 0x10000) {
                    m++;
                    values[i + 1] = INVISIBLE_GLYPH_ID;
                 }
diff --git a/src/macosx/classes/sun/font/CCompositeGlyphMapper.java b/src/macosx/classes/sun/font/CCompositeGlyphMapper.java
index bc47304..cc2a9e2 100644
--- a/src/macosx/classes/sun/font/CCompositeGlyphMapper.java
+++ b/src/macosx/classes/sun/font/CCompositeGlyphMapper.java
@@ -39,12 +39,15 @@
         String[] fallbackFontInfo = new String[2];
         int glyphCode = nativeCodePointToGlyph(mainFont.getNativeFontPtr(), unicode, fallbackFontInfo);
         if (glyphCode == missingGlyph) {
+            setCachedGlyphCode(unicode, missingGlyph);
             return missingGlyph;
         }
         String fallbackFontName = fallbackFontInfo[0];
         String fallbackFontFamilyName = fallbackFontInfo[1];
         if (fallbackFontName == null || fallbackFontFamilyName == null) {
-            return compositeGlyphCode(0, glyphCode);
+            int result = compositeGlyphCode(0, glyphCode);
+            setCachedGlyphCode(unicode, result);
+            return result;
         }
 
         int slot = compositeFont.findSlot(fallbackFontName);
@@ -65,7 +68,9 @@
             slot = compositeFont.addSlot((CFont) fallbackFont);
         }
 
-        return compositeGlyphCode(slot, glyphCode);
+        int result = compositeGlyphCode(slot, glyphCode);
+        setCachedGlyphCode(unicode, result);
+        return result;
     }
 
     // This invokes native font fallback mechanism, returning information about font (its Postscript and family names)
diff --git a/src/share/classes/sun/font/CompositeGlyphMapper.java b/src/share/classes/sun/font/CompositeGlyphMapper.java
index d5c4668..856f24d 100644
--- a/src/share/classes/sun/font/CompositeGlyphMapper.java
+++ b/src/share/classes/sun/font/CompositeGlyphMapper.java
@@ -31,15 +31,6 @@
  * and T2K others. That needs to be dealt with somewhere, but
  * here we can just always get the same glyph code without
  * needing a strike.
- *
- * The C implementation would cache the results of anything up
- * to the maximum surrogate pair code point.
- * This implementation will not cache as much, since the storage
- * requirements are not justifiable. Even so it still can use up
- * to 216*256*4 bytes of storage per composite font. If an app
- * calls canDisplay on this range for all 20 composite fonts that's
- * over 1Mb of cached data. May need to employ WeakReferences if
- * this appears to cause problems.
  */
 
 public class CompositeGlyphMapper extends CharToGlyphMapper {
@@ -47,7 +38,7 @@
     public static final int SLOTMASK =  0xff000000;
     public static final int GLYPHMASK = 0x00ffffff;
 
-    public static final int NBLOCKS = 216;
+    public static final int NBLOCKS = 512; // covering BMP and SMP
     public static final int BLOCKSZ = 256;
     public static final int MAXUNICODE = NBLOCKS*BLOCKSZ;
 
@@ -85,7 +76,7 @@
 
     private int getCachedGlyphCode(int unicode) {
         if (unicode >= MAXUNICODE) {
-            return UNINITIALIZED_GLYPH; // don't cache surrogates
+            return UNINITIALIZED_GLYPH;
         }
         int[] gmap;
         if ((gmap = glyphMaps[unicode >> 8]) == null) {
@@ -94,9 +85,9 @@
         return gmap[unicode & 0xff];
     }
 
-    private void setCachedGlyphCode(int unicode, int glyphCode) {
+    void setCachedGlyphCode(int unicode, int glyphCode) {
         if (unicode >= MAXUNICODE) {
-            return;     // don't cache surrogates
+            return;
         }
         int index0 = unicode >> 8;
         if (glyphMaps[index0] == null) {