8145486: jjs should support documentation key shortcut in interactive mode
authorsundar
Wed, 16 Dec 2015 16:42:03 +0530
changeset 34735 0f41d334aa24
parent 34734 d3a1bd20f5b3
child 34736 52e9e61d937f
8145486: jjs should support documentation key shortcut in interactive mode Reviewed-by: mhaupt, hannesw
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java
nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java
nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Wed Dec 16 16:42:03 2015 +0530
@@ -59,6 +59,8 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
@@ -291,6 +293,13 @@
             mi.push(memInfo.getArity());
             mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
         }
+
+        String doc = memInfo.getDocumentation();
+        if (doc != null) {
+            mi.dup();
+            mi.loadLiteral(memInfo.getDocumentation());
+            mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION, SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
+        }
     }
 
     static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java	Wed Dec 16 16:42:03 2015 +0530
@@ -42,6 +42,8 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC4;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
@@ -159,6 +161,13 @@
                 mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY,
                         SCRIPTFUNCTION_SETARITY_DESC);
             }
+            final String doc = constructor.getDocumentation();
+            if (doc != null) {
+                mi.loadThis();
+                mi.loadLiteral(doc);
+                mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION,
+                        SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
+            }
         }
         mi.returnVoid();
         mi.computeMaxs();
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Wed Dec 16 16:42:03 2015 +0530
@@ -85,6 +85,8 @@
     private MemberInfo.Kind kind;
     // script property name
     private String name;
+    // documentation for this member
+    private String documentation;
     // script property attributes
     private int attributes;
     // name of the java member
@@ -137,6 +139,20 @@
     }
 
     /**
+     * @return the documentation
+     */
+    public String getDocumentation() {
+        return documentation;
+    }
+
+    /**
+     * @param doc the documentation to set
+     */
+    public void setDocumentation(final String doc) {
+        this.documentation = doc;
+    }
+
+    /**
      * Tag something as specialized constructor or not
      * @param isSpecializedConstructor boolean, true if specialized constructor
      */
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Wed Dec 16 16:42:03 2015 +0530
@@ -206,6 +206,7 @@
                         // These could be "null" if values are not supplied,
                         // in which case we have to use the default values.
                         private String  name;
+                        private String  documentation;
                         private Integer attributes;
                         private Integer arity;
                         private Where   where;
@@ -222,6 +223,13 @@
                                     name = null;
                                 }
                                 break;
+                            case "documentation":
+                                this.documentation = (String)annotationValue;
+                                if (documentation.isEmpty()) {
+                                    documentation = null;
+                                }
+
+                                break;
                             case "attributes":
                                 this.attributes = (Integer)annotationValue;
                                 break;
@@ -270,6 +278,8 @@
                             } else {
                                 memInfo.setName(name == null ? methodName : name);
                             }
+
+                            memInfo.setDocumentation(documentation);
                             memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
 
                             memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity);
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Wed Dec 16 16:42:03 2015 +0530
@@ -118,6 +118,8 @@
     static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
     static final String SCRIPTFUNCTION_SETARITY = "setArity";
     static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+    static final String SCRIPTFUNCTION_SETDOCUMENTATION = "setDocumentation";
+    static final String SCRIPTFUNCTION_SETDOCUMENTATION_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING);
     static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
     static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
     static final String SCRIPTFUNCTION_CREATEBUILTIN = "createBuiltin";
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Wed Dec 16 16:42:03 2015 +0530
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.tools.jjs;
 
+import java.awt.event.ActionListener;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -34,21 +35,24 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Function;
 import jdk.internal.jline.NoInterruptUnixTerminal;
 import jdk.internal.jline.Terminal;
 import jdk.internal.jline.TerminalFactory;
 import jdk.internal.jline.TerminalFactory.Flavor;
 import jdk.internal.jline.WindowsTerminal;
 import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.KeyMap;
 import jdk.internal.jline.console.completer.Completer;
 import jdk.internal.jline.console.history.FileHistory;
 
 class Console implements AutoCloseable {
+    private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
     private final ConsoleReader in;
     private final FileHistory history;
 
     Console(final InputStream cmdin, final PrintStream cmdout, final File historyFile,
-            final Completer completer) throws IOException {
+            final Completer completer, final Function<String, String> docHelper) throws IOException {
         TerminalFactory.registerFlavor(Flavor.WINDOWS, isCygwin()? JJSUnixTerminal::new : JJSWindowsTerminal::new);
         TerminalFactory.registerFlavor(Flavor.UNIX, JJSUnixTerminal::new);
         in = new ConsoleReader(cmdin, cmdout);
@@ -58,6 +62,7 @@
         in.setHistory(history = new FileHistory(historyFile));
         in.addCompleter(completer);
         Runtime.getRuntime().addShutdownHook(new Thread((Runnable)this::saveHistory));
+        bind(DOCUMENTATION_SHORTCUT, (ActionListener)evt -> showDocumentation(docHelper));
     }
 
     String readLine(final String prompt) throws IOException {
@@ -138,4 +143,34 @@
     private static boolean isCygwin() {
         return System.getenv("SHELL") != null;
     }
+
+    private void bind(String shortcut, Object action) {
+        KeyMap km = in.getKeys();
+        for (int i = 0; i < shortcut.length(); i++) {
+            final Object value = km.getBound(Character.toString(shortcut.charAt(i)));
+            if (value instanceof KeyMap) {
+                km = (KeyMap) value;
+            } else {
+                km.bind(shortcut.substring(i), action);
+            }
+        }
+    }
+
+    private void showDocumentation(final Function<String, String> docHelper) {
+        final String buffer = in.getCursorBuffer().buffer.toString();
+        final int cursor = in.getCursorBuffer().cursor;
+        final String doc = docHelper.apply(buffer.substring(0, cursor));
+        try {
+            if (doc != null) {
+                in.println();
+                in.println(doc);
+                in.redrawLine();
+                in.flush();
+            } else {
+                in.beep();
+            }
+        } catch (IOException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Wed Dec 16 16:42:03 2015 +0530
@@ -25,6 +25,9 @@
 
 package jdk.nashorn.tools.jjs;
 
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
+import java.awt.Desktop;
 import java.awt.GraphicsEnvironment;
 import java.io.BufferedReader;
 import java.io.File;
@@ -33,15 +36,21 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.net.URI;
+import java.util.concurrent.Callable;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import jdk.internal.jline.console.completer.Completer;
 import jdk.internal.jline.console.UserInterruptException;
 import jdk.nashorn.api.scripting.NashornException;
 import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeJava;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.NativeJavaPackage;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
+import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.tools.Shell;
 
@@ -109,7 +118,32 @@
         final PropertiesHelper propsHelper = new PropertiesHelper(env._classpath);
         final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper);
 
-        try (final Console in = new Console(System.in, System.out, HIST_FILE, completer)) {
+        try (final Console in = new Console(System.in, System.out, HIST_FILE, completer,
+                str -> {
+                    try {
+                        final Object res = context.eval(global, str, global, "<shell>");
+                        if (res != null && res != UNDEFINED) {
+                            // Special case Java types: show the javadoc for the class.
+                            if (NativeJava.isType(UNDEFINED, res)) {
+                                final String typeName = NativeJava.typeName(UNDEFINED, res).toString();
+                                final String url = typeName.replace('.', '/').replace('$', '.') + ".html";
+                                openBrowserForJavadoc(url);
+                            } else if (res instanceof NativeJavaPackage) {
+                                final String pkgName = ((NativeJavaPackage)res).getName();
+                                final String url = pkgName.replace('.', '/') + "/package-summary.html";
+                                openBrowserForJavadoc(url);
+                            } else if (res instanceof ScriptFunction) {
+                                return ((ScriptFunction)res).getDocumentation();
+                            }
+
+                            // FIXME: better than toString for other cases?
+                            return JSType.toString(res);
+                        }
+                     } catch (Exception ignored) {
+                     }
+                     return null;
+                })) {
+
             if (globalChanged) {
                 Context.setGlobal(global);
             }
@@ -164,7 +198,7 @@
 
                 try {
                     final Object res = context.eval(global, source, global, "<shell>");
-                    if (res != ScriptRuntime.UNDEFINED) {
+                    if (res != UNDEFINED) {
                         err.println(toString(res, global));
                     }
                 } catch (final Exception exp) {
@@ -218,7 +252,7 @@
             final PrintWriter err, final boolean doe) {
         try {
             final Object res = context.eval(global, source, global, "<shell>");
-            if (res != ScriptRuntime.UNDEFINED) {
+            if (res != UNDEFINED) {
                 err.println(JSType.toString(res));
             }
         } catch (final Exception e) {
@@ -228,4 +262,15 @@
             }
         }
     }
+
+    // FIXME: needs to be changed to use javase 9 docs later
+    private static String JAVADOC_BASE = "http://download.java.net/jdk9/docs/api/";
+
+    private static void openBrowserForJavadoc(String relativeUrl) {
+        try {
+            final URI uri = new URI(JAVADOC_BASE + relativeUrl);
+            Desktop.getDesktop().browse(uri);
+        } catch (Exception ignored) {
+        }
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Wed Dec 16 16:42:03 2015 +0530
@@ -148,7 +148,8 @@
      * @param buf external buffer - should be a nio ByteBuffer
      * @return the 'obj' object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "sets ByteBuffer to hold indexed data (nashorn extension)")
     public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) {
         Global.checkObject(obj);
         final ScriptObject sobj = (ScriptObject)obj;
@@ -168,7 +169,8 @@
      * @param  obj object to get prototype from
      * @return the prototype of an object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "returns the prototype of the specified object")
     public static Object getPrototypeOf(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).getProto();
@@ -195,7 +197,8 @@
      * @param  proto prototype object to be used
      * @return object whose prototype is set
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "sets the prototype of the given object (ES6)")
     public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
         if (obj instanceof ScriptObject) {
             ((ScriptObject)obj).setPrototypeOf(proto);
@@ -216,7 +219,8 @@
      * @param prop  property descriptor
      * @return property descriptor
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "returns a property descriptor for an own property (not inherited property)")
     public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
         if (obj instanceof ScriptObject) {
             final String       key  = JSType.toString(prop);
@@ -240,7 +244,8 @@
      * @param obj  object to query for property names
      * @return array of property names
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "returns an array of all properties (enumerable or not) found directly on the given object")
     public static ScriptObject getOwnPropertyNames(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
@@ -258,7 +263,8 @@
      * @param obj  object to query for property names
      * @return array of property names
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "returns an array of all symbol properties found directly on the given object (ES6)")
     public static ScriptObject getOwnPropertySymbols(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return new NativeArray(((ScriptObject)obj).getOwnSymbols(true));
@@ -276,7 +282,8 @@
      * @param props properties to define
      * @return object created
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "creates a new object with the specified prototype object and properties")
     public static ScriptObject create(final Object self, final Object proto, final Object props) {
         if (proto != null) {
             Global.checkObject(proto);
@@ -302,7 +309,8 @@
      * @param attr attributes for property descriptor
      * @return object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "adds an own property and/or update the attributes of an existing own property of an object")
     public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
         final ScriptObject sobj = Global.checkObject(obj);
         sobj.defineOwnProperty(JSType.toPropertyKey(prop), attr, true);
@@ -317,7 +325,8 @@
      * @param props properties
      * @return object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "defines new or modifies existing properties directly on the given object")
     public static ScriptObject defineProperties(final Object self, final Object obj, final Object props) {
         final ScriptObject sobj     = Global.checkObject(obj);
         final Object       propsObj = Global.toObject(props);
@@ -339,7 +348,8 @@
      * @param obj  object to seal
      * @return sealed object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "prevents new properties from being added to the given object and marks existing properties as non-configurable")
     public static Object seal(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).seal();
@@ -358,7 +368,8 @@
      * @param obj object to freeze
      * @return frozen object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "prevents new properties from being added to the given object and prevents existing properties from being removed or re-configured")
     public static Object freeze(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).freeze();
@@ -376,7 +387,8 @@
      * @param obj  object, for which to set the internal extensible property to false
      * @return object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "prevents new properties from ever being added to the given object")
     public static Object preventExtensions(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).preventExtensions();
@@ -394,7 +406,8 @@
      * @param obj check whether an object is sealed
      * @return true if sealed, false otherwise
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "tells if an object is sealed or not")
     public static boolean isSealed(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).isSealed();
@@ -412,7 +425,8 @@
      * @param obj check whether an object
      * @return true if object is frozen, false otherwise
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "tells if an object is fronzen or not")
     public static boolean isFrozen(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).isFrozen();
@@ -430,7 +444,8 @@
      * @param obj check whether an object is extensible
      * @return true if object is extensible, false otherwise
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "tells if an object is extensible or not")
     public static boolean isExtensible(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             return ((ScriptObject)obj).isExtensible();
@@ -448,7 +463,8 @@
      * @param obj  object from which to extract keys
      * @return array of keys in object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "returns an array of the given object's own enumerable properties")
     public static ScriptObject keys(final Object self, final Object obj) {
         if (obj instanceof ScriptObject) {
             final ScriptObject sobj = (ScriptObject)obj;
@@ -471,7 +487,7 @@
      * @param value  value of object to be instantiated
      * @return the new NativeObject
      */
-    @Constructor
+    @Constructor(documentation = "creates a new script object or converts given value as a script object")
     public static Object construct(final boolean newObj, final Object self, final Object value) {
         final JSType type = JSType.ofNoFunction(value);
 
@@ -505,7 +521,8 @@
      * @param self self reference
      * @return ToString of object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    @Function(attributes = Attribute.NOT_ENUMERABLE,
+        documentation = "returns a string representing of this object")
     public static String toString(final Object self) {
         return ScriptRuntime.builtinObjectToString(self);
     }
@@ -558,7 +575,8 @@
      * @param v property to check for
      * @return true if property exists in object
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    @Function(attributes = Attribute.NOT_ENUMERABLE,
+        documentation = "tells whether this object has the specified property or not")
     public static boolean hasOwnProperty(final Object self, final Object v) {
         // Convert ScriptObjects to primitive with String.class hint
         // but no need to convert other primitives to string.
@@ -575,7 +593,8 @@
      * @param v v prototype object to check against
      * @return true if object is prototype of v
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    @Function(attributes = Attribute.NOT_ENUMERABLE,
+        documentation = "tests for this object in another object's prototype chain")
     public static boolean isPrototypeOf(final Object self, final Object v) {
         if (!(v instanceof ScriptObject)) {
             return false;
@@ -601,7 +620,8 @@
      * @param v property to check if enumerable
      * @return true if property is enumerable
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    @Function(attributes = Attribute.NOT_ENUMERABLE,
+        documentation = "tells whether the given property is enumerable or not")
     public static boolean propertyIsEnumerable(final Object self, final Object v) {
         final String str = JSType.toString(v);
         final Object obj = Global.toObject(self);
@@ -676,7 +696,8 @@
      * @param source the source object whose properties are bound to the target
      * @return the target object after property binding
      */
-    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
+        documentation = "binds the source object's properties to the target object (nashorn extension)")
     public static Object bindProperties(final Object self, final Object target, final Object source) {
         // target object has to be a ScriptObject
         final ScriptObject targetObj = Global.checkObject(target);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Constructor.java	Wed Dec 16 16:42:03 2015 +0530
@@ -48,4 +48,9 @@
      *         arity.
      */
     public int arity() default -2;
+
+    /**
+     * @return the documentation string for this constructor.
+     */
+    public String documentation() default "";
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/Function.java	Wed Dec 16 16:42:03 2015 +0530
@@ -60,4 +60,9 @@
      * @return where this function lives.
      */
     public Where where() default Where.PROTOTYPE;
+
+    /**
+     * @return return the documentation string for this function.
+     */
+    public String documentation() default "";
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Dec 16 16:42:03 2015 +0530
@@ -646,6 +646,24 @@
     }
 
     /**
+     * Get the documentation for this function
+     *
+     * @return the documentation
+     */
+    public final String getDocumentation() {
+        return data.getDocumentation();
+    }
+
+    /**
+     * Set the documentation for this function
+     *
+     * @param doc documentation String for this function
+     */
+    public final void setDocumentation(final String doc) {
+        data.setDocumentation(doc);
+    }
+
+    /**
      * Get the name for this function
      *
      * @return the name
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Mon Dec 14 17:38:56 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Dec 16 16:42:03 2015 +0530
@@ -70,6 +70,9 @@
     // value, the function might still be capable of receiving variable number of arguments, see isVariableArity.
     private int arity;
 
+    // this may be null, if not available
+    private String documentation;
+
     /**
      * A pair of method handles used for generic invoker and constructor. Field is volatile as it can be initialized by
      * multiple threads concurrently, but we still tolerate a race condition in it as all values stored into it are
@@ -118,6 +121,10 @@
         return arity;
     }
 
+    final String getDocumentation() {
+        return documentation != null? documentation : toSource();
+    }
+
     final boolean isVariableArity() {
         return (flags & IS_VARIABLE_ARITY) != 0;
     }
@@ -137,6 +144,15 @@
         this.arity = arity;
     }
 
+    /**
+     * Used from nasgen generated code.
+     *
+     * @param doc documentation for this function
+     */
+    void setDocumentation(final String doc) {
+        this.documentation = doc;
+    }
+
     CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
         final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);