From 569d6fa3e8bf1e1145d5a786d5cf922f09e10e9e Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 7 Aug 2014 14:12:08 +0400 Subject: [PATCH] Multiple small improvements --- .../teavm/chromerdp/ChromeRDPDebugger.java | 116 ++++++++++++++---- .../java/org/teavm/chromerdp/RDPValue.java | 24 ++-- .../org/teavm/chromerdp/data/Response.java | 9 ++ .../org/teavm/classlib/impl/JCLPlugin.java | 1 + .../classlib/impl/ObjectEnrichRenderer.java | 62 ++++++++++ .../org/teavm/debugging/DebugInformation.java | 18 ++- .../debugging/DebugInformationBuilder.java | 16 ++- .../debugging/DebugInformationEmitter.java | 2 +- .../debugging/DebugInformationReader.java | 14 ++- .../debugging/DebugInformationWriter.java | 13 +- .../java/org/teavm/debugging/Debugger.java | 9 +- .../DummyDebugInformationEmitter.java | 2 +- .../java/org/teavm/javascript/Renderer.java | 2 +- .../resources/org/teavm/javascript/runtime.js | 61 ++++++++- 14 files changed, 287 insertions(+), 62 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/impl/ObjectEnrichRenderer.java diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java index 2c0814d8d..c421957e6 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java @@ -62,30 +62,45 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC private ChromeRDPExchangeListener exchangeListener = new ChromeRDPExchangeListener() { @Override public void received(String messageText) throws IOException { - JsonNode jsonMessage = mapper.readTree(messageText); - if (jsonMessage.has("id")) { - Response response = mapper.reader(Response.class).readValue(jsonMessage); - responseHandlers.remove(response.getId()).received(response.getResult()); - } else { - Message message = mapper.reader(Message.class).readValue(messageText); - if (message.getMethod() == null) { - return; - } - switch (message.getMethod()) { - case "Debugger.paused": - firePaused(parseJson(SuspendedNotification.class, message.getParams())); - break; - case "Debugger.resumed": - fireResumed(); - break; - case "Debugger.scriptParsed": - scriptParsed(parseJson(ScriptParsedNotification.class, message.getParams())); - break; - } - } + receiveMessage(messageText); } }; + private void receiveMessage(final String messageText) { + new Thread() { + @Override public void run() { + try { + JsonNode jsonMessage = mapper.readTree(messageText); + if (jsonMessage.has("id")) { + Response response = mapper.reader(Response.class).readValue(jsonMessage); + if (response.getError() != null) { + System.err.println(response.getError().toString()); + } + responseHandlers.remove(response.getId()).received(response.getResult()); + } else { + Message message = mapper.reader(Message.class).readValue(messageText); + if (message.getMethod() == null) { + return; + } + switch (message.getMethod()) { + case "Debugger.paused": + firePaused(parseJson(SuspendedNotification.class, message.getParams())); + break; + case "Debugger.resumed": + fireResumed(); + break; + case "Debugger.scriptParsed": + scriptParsed(parseJson(ScriptParsedNotification.class, message.getParams())); + break; + } + } + } catch (Exception e) { + // TODO: logging + e.printStackTrace(); + } + } + }.start(); + } private synchronized void firePaused(SuspendedNotification params) { suspended = true; @@ -256,8 +271,12 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC message.setParams(mapper.valueToTree(params)); ResponseHandler handler = new ResponseHandler() { @Override public void received(JsonNode node) throws IOException { - SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node); - breakpoint.chromeId = response.getBreakpointId(); + if (node != null) { + SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node); + breakpoint.chromeId = response.getBreakpointId(); + } else { + breakpoint.chromeId = null; + } for (JavaScriptDebuggerListener listener : getListeners()) { listener.breakpointChanged(breakpoint); } @@ -314,7 +333,8 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC sync.add(""); } else { CallFunctionResponse response = mapper.reader(CallFunctionResponse.class).readValue(node); - sync.add(response.getResult().getValue().getTextValue()); + RemoteObjectDTO result = response.getResult(); + sync.add(result.getValue() != null ? result.getValue().getTextValue() : ""); } } }); @@ -327,6 +347,51 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } } + String getRepresentation(String objectId) { + if (exchange == null) { + return null; + } + Message message = new Message(); + message.setId(messageIdGenerator.incrementAndGet()); + message.setMethod("Runtime.callFunctionOn"); + CallFunctionCommand params = new CallFunctionCommand(); + CallArgumentDTO arg = new CallArgumentDTO(); + arg.setObjectId(objectId); + params.setObjectId(objectId); + params.setArguments(new CallArgumentDTO[] { arg }); + params.setFunctionDeclaration("$dbg_repr"); + message.setParams(mapper.valueToTree(params)); + final BlockingQueue sync = new LinkedTransferQueue<>(); + responseHandlers.put(message.getId(), new ResponseHandler() { + @Override public void received(JsonNode node) throws IOException { + if (node == null) { + sync.add(new RepresentationWrapper(null)); + } else { + CallFunctionResponse response = mapper.reader(CallFunctionResponse.class).readValue(node); + RemoteObjectDTO result = response.getResult(); + sync.add(new RepresentationWrapper(result.getValue() != null ? + result.getValue().getTextValue() : null)); + } + } + }); + sendMessage(message); + try { + RepresentationWrapper result = sync.take(); + return result.repr; + } catch (InterruptedException e) { + return null; + } + } + + private static class RepresentationWrapper { + String repr; + + public RepresentationWrapper(String repr) { + super(); + this.repr = repr; + } + } + private List parseProperties(PropertyDescriptorDTO[] properties) { List variables = new ArrayList<>(); if (properties != null) { @@ -339,8 +404,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC break; case "object": case "function": - value = new RDPValue(this, remoteValue.getDescription(), remoteValue.getType(), - remoteValue.getObjectId()); + value = new RDPValue(this, null, remoteValue.getType(), remoteValue.getObjectId()); break; default: value = new RDPValue(this, remoteValue.getValue().asText(), remoteValue.getType(), diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPValue.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPValue.java index d959f8429..3e1d3e806 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPValue.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPValue.java @@ -2,6 +2,7 @@ package org.teavm.chromerdp; import java.util.Collections; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import org.teavm.debugging.JavaScriptValue; import org.teavm.debugging.JavaScriptVariable; @@ -10,14 +11,15 @@ import org.teavm.debugging.JavaScriptVariable; * @author Alexey Andreev */ public class RDPValue implements JavaScriptValue { - private String representation; + private AtomicReference representation = new AtomicReference<>(); + private AtomicReference className = new AtomicReference<>(); private String typeName; private ChromeRDPDebugger debugger; private String objectId; private Map properties; public RDPValue(ChromeRDPDebugger debugger, String representation, String typeName, String objectId) { - this.representation = representation; + this.representation.set(representation == null && objectId == null ? "" : representation); this.typeName = typeName; this.debugger = debugger; this.objectId = objectId; @@ -27,17 +29,23 @@ public class RDPValue implements JavaScriptValue { @Override public String getRepresentation() { - return representation; + if (representation.get() == null) { + representation.compareAndSet(null, debugger.getRepresentation(objectId)); + } + return representation.get(); } @Override public String getClassName() { - if (objectId != null) { - String className = debugger.getClassName(objectId); - return className != null ? className : "object"; - } else { - return typeName; + if (className.get() == null) { + if (objectId != null) { + String computedClassName = debugger.getClassName(objectId); + className.compareAndSet(null, computedClassName != null ? computedClassName : "@Object"); + } else { + className.compareAndSet(null, "@" + typeName); + } } + return className.get(); } @SuppressWarnings("unchecked") diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/Response.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/Response.java index 682259fa0..adcbb2c40 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/Response.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/Response.java @@ -26,6 +26,7 @@ import org.codehaus.jackson.annotate.JsonIgnoreProperties; public class Response { private int id; private JsonNode result; + private JsonNode error; public int getId() { return id; @@ -42,4 +43,12 @@ public class Response { public void setResult(JsonNode result) { this.result = result; } + + public JsonNode getError() { + return error; + } + + public void setError(JsonNode error) { + this.error = error; + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index e03445ded..4f13a986d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -33,6 +33,7 @@ public class JCLPlugin implements TeaVMPlugin { host.add(new EnumTransformer()); host.add(new ClassLookupDependencySupport()); host.add(new NewInstanceDependencySupport()); + host.add(new ObjectEnrichRenderer()); ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader()); host.add(serviceLoaderSupp); MethodReference loadServicesMethod = new MethodReference("java.util.ServiceLoader", new MethodDescriptor( diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/ObjectEnrichRenderer.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/ObjectEnrichRenderer.java new file mode 100644 index 000000000..97d66f1b4 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/ObjectEnrichRenderer.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.impl; + +import java.io.IOException; +import org.teavm.javascript.RenderingContext; +import org.teavm.model.ClassReader; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReader; +import org.teavm.vm.BuildTarget; +import org.teavm.vm.spi.RendererListener; + +/** + * + * @author Alexey Andreev + */ +public class ObjectEnrichRenderer implements RendererListener { + private RenderingContext context; + + @Override + public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { + this.context = context; + } + + @Override + public void beforeClass(ClassReader cls) throws IOException { + } + + @Override + public void afterClass(ClassReader cls) throws IOException { + if (cls.getName().equals("java.lang.Object")) { + MethodReader toString = cls.getMethod(new MethodDescriptor("toString", String.class)); + if (toString != null) { + String clsName = context.getNaming().getNameFor(cls.getName()); + String toStringName = context.getNaming().getNameFor(toString.getReference()); + context.getWriter().append(clsName).append(".prototype.toString").ws().append('=').ws() + .append("function()").ws().append('{').indent().softNewLine(); + context.getWriter().append("return this.").append(toStringName).ws().append('?').ws() + .append("$rt_ustr(this.").append(toStringName).append("())").ws().append(':') + .append("Object.prototype.toString.call(this);").softNewLine(); + context.getWriter().outdent().append("}").newLine(); + } + } + } + + @Override + public void complete() throws IOException { + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java index c628fc071..821ff1c05 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -45,7 +45,7 @@ public class DebugInformation { Mapping methodMapping; Mapping lineMapping; MultiMapping[] variableMappings; - List> classesMetadata; + List classesMetadata; public String[] getCoveredSourceFiles() { return fileNames.clone(); @@ -130,8 +130,15 @@ public class DebugInformation { if (jsIndex == null) { return null; } - Integer fieldIndex = classesMetadata.get(classIndex).get(jsIndex); - return fieldIndex != null ? fields[fieldIndex] : null; + while (classIndex != null) { + ClassMetadata cls = classesMetadata.get(classIndex); + Integer fieldIndex = cls.fieldMap.get(jsIndex); + if (fieldIndex != null) { + return fields[fieldIndex]; + } + classIndex = cls.parentId; + } + return null; } private T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { @@ -372,4 +379,9 @@ public class DebugInformation { return lines.length; } } + + static class ClassMetadata { + Integer parentId; + Map fieldMap = new HashMap<>(); + } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java index 964ba4cb8..981a467bf 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java @@ -104,12 +104,14 @@ public class DebugInformationBuilder implements DebugInformationEmitter { } @Override - public void addClass(String className) { + public void addClass(String className, String parentName) { int classIndex = classes.index(className); + int parentIndex = classes.index(parentName); while (classIndex >= classesMetadata.size()) { classesMetadata.add(new ClassMetadata()); } currentClassMetadata = classIndex; + classesMetadata.get(currentClassMetadata).parentIndex = parentIndex; } @Override @@ -140,13 +142,16 @@ public class DebugInformationBuilder implements DebugInformationEmitter { debugInformation.variableMappings[var] = mapping.build(); } - List> builtMetadata = new ArrayList<>(classes.list.size()); + List builtMetadata = new ArrayList<>(classes.list.size()); for (int i = 0; i < classes.list.size(); ++i) { if (i >= classesMetadata.size()) { - builtMetadata.add(new HashMap()); + builtMetadata.add(new DebugInformation.ClassMetadata()); } else { - Map map = new HashMap<>(classesMetadata.get(i).fieldMap); - builtMetadata.add(map); + ClassMetadata origMetadata = classesMetadata.get(i); + DebugInformation.ClassMetadata mappedMetadata = new DebugInformation.ClassMetadata(); + mappedMetadata.fieldMap.putAll(origMetadata.fieldMap); + mappedMetadata.parentId = origMetadata.parentIndex >= 0 ? origMetadata.parentIndex : null; + builtMetadata.add(mappedMetadata); } } debugInformation.classesMetadata = builtMetadata; @@ -285,6 +290,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter { } static class ClassMetadata { + int parentIndex; Map fieldMap = new HashMap<>(); } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java index cf5e19276..5e9cc499a 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java @@ -33,7 +33,7 @@ public interface DebugInformationEmitter { void emitVariable(String[] sourceNames, String generatedName); - void addClass(String className); + void addClass(String className, String parentName); void addField(String fieldName, String jsName); } \ No newline at end of file diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java index 3be13f8de..2558e6a41 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java @@ -19,9 +19,7 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * @@ -64,17 +62,21 @@ class DebugInformationReader { return mappings; } - private List> readClassesMetadata(int count) throws IOException { - List> classes = new ArrayList<>(count); + private List readClassesMetadata(int count) throws IOException { + List classes = new ArrayList<>(count); for (int i = 0; i < count; ++i) { - Map cls = new HashMap<>(); + DebugInformation.ClassMetadata cls = new DebugInformation.ClassMetadata(); classes.add(cls); + cls.parentId = readUnsignedNumber() - 1; + if (cls.parentId.equals(-1)) { + cls.parentId = null; + } int entryCount = readUnsignedNumber(); resetRelativeNumber(); for (int j = 0; j < entryCount; ++j) { int key = readRelativeNumber(); int value = readUnsignedNumber(); - cls.put(key, value); + cls.fieldMap.put(key, value); } } return classes; diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java index 7f6243b4e..de3eecb87 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java @@ -20,7 +20,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; +import org.teavm.debugging.DebugInformation.ClassMetadata; /** * @@ -63,16 +63,17 @@ class DebugInformationWriter { } } - private void writeClassMetadata(List> classes) throws IOException { + private void writeClassMetadata(List classes) throws IOException { for (int i = 0; i < classes.size(); ++i) { - Map cls = classes.get(i); - writeUnsignedNumber(cls.size()); - List keys = new ArrayList<>(cls.keySet()); + ClassMetadata cls = classes.get(i); + writeUnsignedNumber(cls.parentId != null ? cls.parentId + 1 : 0); + writeUnsignedNumber(cls.fieldMap.size()); + List keys = new ArrayList<>(cls.fieldMap.keySet()); Collections.sort(keys); resetRelativeNumber(); for (int key : keys) { writeRelativeNumber(key); - writeUnsignedNumber(cls.get(key)); + writeUnsignedNumber(cls.fieldMap.get(key)); } } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java index 23f67a513..21d72ab30 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -26,8 +26,6 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -// TODO: variable name handling -// TODO: class fields handling public class Debugger { private static final Object dummyObject = new Object(); private ConcurrentMap listeners = new ConcurrentHashMap<>(); @@ -198,13 +196,16 @@ public class Debugger { private void addScript(String name) { if (debugInformationMap.containsKey(name)) { + updateBreakpoints(); return; } DebugInformation debugInfo = debugInformationProvider.getDebugInformation(name); if (debugInfo == null) { + updateBreakpoints(); return; } if (debugInformationMap.putIfAbsent(name, debugInfo) != null) { + updateBreakpoints(); return; } for (String sourceFile : debugInfo.getCoveredSourceFiles()) { @@ -220,6 +221,10 @@ public class Debugger { list.put(debugInfo, dummyObject); } scriptMap.put(debugInfo, name); + updateBreakpoints(); + } + + private void updateBreakpoints() { for (Breakpoint breakpoint : breakpoints.keySet()) { updateInternalBreakpoints(breakpoint); updateBreakpointStatus(breakpoint, true); diff --git a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java index 8754cfc9a..edfbf2e3d 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java @@ -45,7 +45,7 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter { } @Override - public void addClass(String className) { + public void addClass(String className, String parentName) { } @Override diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index b897e1bfd..eb0291963 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -243,7 +243,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext public void render(ClassNode cls) throws RenderingException { debugEmitter.emitClass(cls.getName()); - debugEmitter.addClass(cls.getName()); + debugEmitter.addClass(cls.getName(), cls.getParentName()); try { writer.append("function ").appendClass(cls.getName()).append("()").ws().append("{") .indent().softNewLine(); diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 5a395f015..9571d489f 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -108,6 +108,17 @@ $rt_arraycls = function(cls) { }; arraycls.prototype = new ($rt_objcls())(); arraycls.prototype.constructor = arraycls; + arraycls.prototype.toString = function() { + var str = "["; + for (var i = 0; i < this.data.length; ++i) { + if (i > 0) { + str += ", "; + } + str += this.data[i].toString(); + } + str += "]"; + return str; + } arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls() }; cls.$array = arraycls; } @@ -392,20 +403,64 @@ function $rt_s(index) { } function $dbg_repr(obj) { - return obj.toString(); + return obj.toString ? obj.toString() : ""; } function $dbg_class(obj) { if (obj instanceof Long) { return "long"; } - var meta = obj.constructor.$meta; - return meta ? meta.name : ""; + var cls = obj.constructor; + var arrayDegree = 0; + while (cls.$meta && cls.$meta.item) { + ++arrayDegree; + cls = cls.$meta.item; + } + var clsName = ""; + if (cls === $rt_booleancls()) { + clsName = "boolean"; + } else if (cls === $rt_bytecls()) { + clsName = "byte"; + } else if (cls === $rt_shortcls()) { + clsName = "short"; + } else if (cls === $rt_charcls()) { + clsName = "char"; + } else if (cls === $rt_intcls()) { + clsName = "int"; + } else if (cls === $rt_longcls()) { + clsName = "long"; + } else if (cls === $rt_floatcls()) { + clsName = "float"; + } else if (cls === $rt_doublecls()) { + clsName = "double"; + } else { + clsName = cls.$meta ? cls.$meta.name : "@" + cls.name; + } + while (arrayDegree-- > 0) { + clsName += "[]"; + } + return clsName; } Long = function(lo, hi) { this.lo = lo | 0; this.hi = hi | 0; } +Long.prototype.toString = function() { + var result = []; + var n = this; + var positive = Long_isPositive(n); + if (!positive) { + n = Long_neg(n); + } + var radix = new Long(10, 0); + do { + var divRem = Long_divRem(n, radix); + result.push(String.fromCharCode(48 + divRem[1].lo)); + n = divRem[0]; + } while (n.lo != 0 || n.hi != 0); + result = result.reverse().join(''); + return positive ? result : "-" + result; +} Long_ZERO = new Long(0, 0); Long_fromInt = function(val) { return val >= 0 ? new Long(val, 0) : new Long(val, -1);