Code Review for hotspot-dvm

Prepared by:jrose on Tue Jan 20 02:15:40 PST 2009
Workspace:/Users/jrose/Projects/hotspot/hotspot-dvm
Compare against: http://hg.openjdk.java.net/jdk7/hotspot-comp-gate/hotspot
Compare against version:521
Summary of changes: 7334 lines changed: 7123 ins; 87 del; 124 mod; 100657 unchg
Patch of changes: hotspot-dvm.patch
Author comments:
For putback to http://hg.openjdk.java.net/jdk7/hotspot-comp-gate/hotspot
6655638: dynamic languages need method handles
Summary: first working version of method handles
Reviewed-by: kvn
This group of changes implements method handles, and is the second (and largest) in a series of three changes to support the JSR 292 Reference Implementation.

A method handle is a lightweight and direct reference to a Java method. (It is a small wrapper around a methodOop in HotSpot.) It implements the method java.dyn.MethodHandle.invoke, for the exact signature of its Java method. That is, the MethodHandle type implements all possible signatures of the invoke method name. Invoking a method handle with the wrong signature safely produces a WrongMethodTypeException.

There is as low-level API which privileged Java code uses to create and inspect method handles. All communication between the JVM and this Java code goes through native methods on the class java.dyn.impl.MH. Method handles can be formed which correspond to any of the standard "invoke***" instructions. A limited number of bound and adapter method handles are also supported, which allow types to be adjusted and closures to be created (as is necessary in dynamic languages).

This change group builds on top of anonymous classes (project info) and lays the groundwork for the invokedynamic instruction (project info).

module-by-module change summary

The assembler changes let coders work more flexibly with values which may or may not be assembly-time constants. In particular, the RegisterConstant type is a trivial tagged union of a Register or an intptr_t constant, which selects the correct assembly instruction format automatically. New assembler macros factor code which used to be repeated in several places, for interface dispatch, type checking, and interpreter argument parsing. (Pre-existing copies of these are marked and left to be cleaned up later.) There are also macros for the two method handle operations: type checking and calling.

Interpreter changes create a new kind of interpreter entry point for the MethodHandle.invoke methods; see generate_method_handle_entry. We also ensure (referring to methodOopDesc::extra_stack) that bound method handles have enough stack space to push an extra hidden argument (the bound receiver). There is also a new exception throwing stub, for WrongMethodTypeExceptions.

A new module, "methodHandles.cpp", defines the new native method entry points. Its header file also defines the various subtypes of method handle (invokers and adapters), and creates a framework for both interpreted and compiled code to efficiently invoke method handles. (The compiled side of this framework is not implemented yet; compiled code presently uses C2I adapters to invoke method handles.)

Each subtype of method handle has a distinct "handler" function, an assembled stub which executes that method handle's semantics, apart from the actual method being called. For example, an "invokevirtual" method handle looks up its target method in the vtable of its receiver, while a "checkcast" adapter performs a Java-level cast on one of its arguments, before permitting control to pass to the target method. The full set of handlers is generated by generate_method_handle_stub.

The link resolver is extended with a notion of "implicit methods". When resolving an invokevirtual instruction, an invoke method on the type java.dyn.MethodHandle is constructed on the fly, once for each distinct signature. There is a new global table (a SymbolPropertyTable) which holds these methods; this table adds to the set of "strong" GC roots. The queries is_method_handle_invoke and method_handle_type apply to these new implicitly generated methods. The "method handle type" of such a method is a Java-level data structure of type java.dyn.MethodType, part of the JSR 292 API. There is a 1-1 correspondence between JVM signatures (symbolOops) and MethodType instances, as the corresponding invoke methods are created. An up-call to Java code obtains the MethodType object required for each new method handle invoker method.

The set of built-in, well-known symbols, classes, and class layouts is extended as need (in the classfile subdirectory, files vmSymbols, systemDictionary, and javaClasses).

There are occasional minor cleanups, such as the rewriting of old comments, deletion of dead code, or the improvement of debugging code.

Currently, compiler changes are minimal. Method handle invocation sites are not candidates for inlining, and always go through C2I adapters.

The Da Vinci Machine Project has been incubating this change as a patch named meth.patch. Along with this patch there are patches which create (as NetBeans projects) Java APIs on top of these JVM changes. See meth.proj.patch. These APIs are currently under review by the JSR 292 EG.

Legend: Modified file
Deleted file
New file

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/assembler_sparc.cpp

rev 522 : [mq]: meth.patch
94 lines changed: 94 ins; 0 del; 0 mod; 4218 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/assembler_sparc.hpp

rev 522 : [mq]: meth.patch
82 lines changed: 79 ins; 0 del; 3 mod; 2318 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/assembler_sparc.inline.hpp

rev 522 : [mq]: meth.patch
57 lines changed: 57 ins; 0 del; 0 mod; 687 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/cppInterpreter_sparc.cpp

rev 522 : [mq]: meth.patch
8 lines changed: 6 ins; 0 del; 2 mod; 2235 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/interpreterGenerator_sparc.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 40 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/interpreter_sparc.cpp

rev 522 : [mq]: meth.patch
32 lines changed: 32 ins; 0 del; 0 mod; 420 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/register_definitions_sparc.cpp

rev 522 : [mq]: meth.patch
2 lines changed: 2 ins; 0 del; 0 mod; 176 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/sharedRuntime_sparc.cpp

rev 522 : [mq]: meth.patch
5 lines changed: 0 ins; 0 del; 5 mod; 3745 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/sparc/vm/templateInterpreter_sparc.cpp

rev 522 : [mq]: meth.patch
31 lines changed: 30 ins; 0 del; 1 mod; 1968 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/assembler_x86.cpp

rev 522 : [mq]: meth.patch
257 lines changed: 257 ins; 0 del; 0 mod; 7716 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/assembler_x86.hpp

rev 522 : [mq]: meth.patch
100 lines changed: 100 ins; 0 del; 0 mod; 2070 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 47 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/cppInterpreter_x86.cpp

rev 522 : [mq]: meth.patch
11 lines changed: 6 ins; 0 del; 5 mod; 2408 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interp_masm_x86_32.cpp

rev 522 : [mq]: meth.patch
10 lines changed: 7 ins; 2 del; 1 mod; 1549 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interp_masm_x86_32.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 244 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interp_masm_x86_64.cpp

rev 522 : [mq]: meth.patch
10 lines changed: 7 ins; 2 del; 1 mod; 1628 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interp_masm_x86_64.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 260 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interpreterGenerator_x86.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 42 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interpreter_x86_32.cpp

rev 522 : [mq]: meth.patch
32 lines changed: 28 ins; 2 del; 2 mod; 246 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/interpreter_x86_64.cpp

rev 522 : [mq]: meth.patch
13 lines changed: 13 ins; 0 del; 0 mod; 357 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/stubGenerator_x86_32.cpp

rev 522 : [mq]: meth.patch
13 lines changed: 13 ins; 0 del; 0 mod; 2268 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/templateInterpreter_x86_32.cpp

rev 522 : [mq]: meth.patch
41 lines changed: 39 ins; 0 del; 2 mod; 1777 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/templateInterpreter_x86_64.cpp

rev 522 : [mq]: meth.patch
34 lines changed: 32 ins; 1 del; 1 mod; 1825 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/templateTable_x86_32.cpp

rev 522 : [mq]: meth.patch
62 lines changed: 52 ins; 3 del; 7 mod; 3611 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/templateTable_x86_64.cpp

rev 522 : [mq]: meth.patch
53 lines changed: 51 ins; 0 del; 2 mod; 3621 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/cpu/x86/vm/vtableStubs_x86_32.cpp

rev 522 : [mq]: meth.patch
82 lines changed: 73 ins; 0 del; 9 mod; 207 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/asm/assembler.cpp

rev 522 : [mq]: meth.patch
63 lines changed: 63 ins; 0 del; 0 mod; 288 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/asm/assembler.hpp

rev 522 : [mq]: meth.patch
8 lines changed: 8 ins; 0 del; 0 mod; 309 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/ci/ciMethod.cpp

rev 522 : [mq]: meth.patch
24 lines changed: 24 ins; 0 del; 0 mod; 1042 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/ci/ciMethod.hpp

rev 522 : [mq]: meth.patch
2 lines changed: 2 ins; 0 del; 0 mod; 246 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/classFileParser.cpp

rev 522 : [mq]: meth.patch
85 lines changed: 84 ins; 0 del; 1 mod; 4179 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/classFileParser.hpp

rev 522 : [mq]: meth.patch
13 lines changed: 12 ins; 0 del; 1 mod; 265 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/dictionary.cpp

rev 522 : [mq]: meth.patch
57 lines changed: 57 ins; 0 del; 0 mod; 609 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/dictionary.hpp

rev 522 : [mq]: meth.patch
104 lines changed: 104 ins; 0 del; 0 mod; 219 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/javaClasses.cpp

rev 522 : [mq]: meth.patch
432 lines changed: 413 ins; 9 del; 10 mod; 2569 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/javaClasses.hpp

rev 522 : [mq]: meth.patch
255 lines changed: 255 ins; 0 del; 0 mod; 942 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/loaderConstraints.hpp

rev 522 : [mq]: meth.patch
4 lines changed: 2 ins; 0 del; 2 mod; 131 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/symbolTable.cpp

rev 522 : [mq]: meth.patch
43 lines changed: 34 ins; 9 del; 0 mod; 475 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/symbolTable.hpp

rev 522 : [mq]: meth.patch
12 lines changed: 11 ins; 0 del; 1 mod; 212 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/systemDictionary.cpp

rev 522 : [mq]: meth.patch
166 lines changed: 165 ins; 0 del; 1 mod; 2459 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/systemDictionary.hpp

rev 522 : [mq]: meth.patch
42 lines changed: 42 ins; 0 del; 0 mod; 597 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/classfile/vmSymbols.hpp

rev 522 : [mq]: meth.patch
36 lines changed: 35 ins; 0 del; 1 mod; 912 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 956 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/includeDB_core

rev 522 : [mq]: meth.patch
24 lines changed: 24 ins; 0 del; 0 mod; 4661 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/includeDB_gc_parallel

rev 522 : [mq]: meth.patch
6 lines changed: 6 ins; 0 del; 0 mod; 166 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/abstractInterpreter.hpp

rev 522 : [mq]: meth.patch
3 lines changed: 1 ins; 2 del; 0 mod; 243 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/cppInterpreter.cpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 135 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/interpreter.cpp

rev 522 : [mq]: meth.patch
5 lines changed: 5 ins; 0 del; 0 mod; 409 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/interpreterRuntime.cpp

rev 522 : [mq]: meth.patch
18 lines changed: 18 ins; 0 del; 0 mod; 1151 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/interpreterRuntime.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 151 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/linkResolver.cpp

rev 522 : [mq]: meth.patch
19 lines changed: 19 ins; 0 del; 0 mod; 1000 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/linkResolver.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 171 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/templateInterpreter.cpp

rev 522 : [mq]: meth.patch
3 lines changed: 3 ins; 0 del; 0 mod; 597 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/templateInterpreter.hpp

rev 522 : [mq]: meth.patch
2 lines changed: 2 ins; 0 del; 0 mod; 177 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/interpreter/templateInterpreterGenerator.hpp

rev 522 : [mq]: meth.patch
1 line changed: 1 ins; 0 del; 0 mod; 90 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/memory/dump.cpp

rev 522 : [mq]: meth.patch
3 lines changed: 3 ins; 0 del; 0 mod; 1496 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/instanceKlass.cpp

rev 522 : [mq]: meth.patch
85 lines changed: 77 ins; 2 del; 6 mod; 2631 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/instanceKlass.hpp

rev 522 : [mq]: meth.patch
16 lines changed: 16 ins; 0 del; 0 mod; 961 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/instanceKlassKlass.cpp

rev 522 : [mq]: meth.patch
40 lines changed: 7 ins; 1 del; 32 mod; 799 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/klassVtable.cpp

rev 522 : [mq]: meth.patch
20 lines changed: 20 ins; 0 del; 0 mod; 1319 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/klassVtable.hpp

rev 522 : [mq]: meth.patch
2 lines changed: 2 ins; 0 del; 0 mod; 316 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/methodKlass.cpp

rev 522 : [mq]: meth.patch
15 lines changed: 13 ins; 0 del; 2 mod; 359 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/methodOop.cpp

rev 522 : [mq]: meth.patch
100 lines changed: 99 ins; 0 del; 1 mod; 1280 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/methodOop.hpp

rev 522 : [mq]: meth.patch
11 lines changed: 11 ins; 0 del; 0 mod; 745 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/objArrayKlass.cpp

rev 522 : [mq]: meth.patch
16 lines changed: 14 ins; 0 del; 2 mod; 533 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/oop.cpp

rev 522 : [mq]: meth.patch
5 lines changed: 0 ins; 4 del; 1 mod; 134 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/oop.hpp

rev 522 : [mq]: meth.patch
3 lines changed: 3 ins; 0 del; 0 mod; 407 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/oops/oop.inline.hpp

rev 522 : [mq]: meth.patch
3 lines changed: 3 ins; 0 del; 0 mod; 734 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/prims/jvm.cpp

rev 522 : [mq]: meth.patch
47 lines changed: 32 ins; 3 del; 12 mod; 4552 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/prims/nativeLookup.cpp

rev 522 : [mq]: meth.patch
4 lines changed: 4 ins; 0 del; 0 mod; 290 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/arguments.cpp

rev 522 : [mq]: meth.patch
7 lines changed: 7 ins; 0 del; 0 mod; 2839 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/fieldDescriptor.cpp

rev 522 : [mq]: meth.patch
7 lines changed: 2 ins; 0 del; 5 mod; 163 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/frame.hpp

rev 522 : [mq]: meth.patch
1 line changed: 0 ins; 1 del; 0 mod; 474 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/globals.hpp

rev 522 : [mq]: meth.patch
15 lines changed: 15 ins; 0 del; 0 mod; 3342 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/handles.hpp

rev 522 : [mq]: meth.patch
8 lines changed: 8 ins; 0 del; 0 mod; 348 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/reflection.cpp

rev 522 : [mq]: meth.patch
14 lines changed: 12 ins; 0 del; 2 mod; 1609 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/reflection.hpp

rev 522 : [mq]: meth.patch
3 lines changed: 2 ins; 0 del; 1 mod; 161 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/sharedRuntime.cpp

rev 522 : [mq]: meth.patch
109 lines changed: 65 ins; 43 del; 1 mod; 2219 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/runtime/sharedRuntime.hpp

rev 522 : [mq]: meth.patch
26 lines changed: 22 ins; 3 del; 1 mod; 566 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/utilities/accessFlags.hpp

rev 522 : [mq]: meth.patch
20 lines changed: 20 ins; 0 del; 0 mod; 204 unchg

Cdiffs Udiffs Sdiffs Frames Old New Patch Raw src/share/vm/utilities/globalDefinitions.hpp

rev 522 : [mq]: meth.patch
9 lines changed: 9 ins; 0 del; 0 mod; 1132 unchg

------ ------ ------ ------ --- New Patch Raw src/cpu/sparc/vm/methodHandles_sparc.cpp

rev 522 : [mq]: meth.patch
443 lines changed: 443 ins; 0 del; 0 mod; 0 unchg

------ ------ ------ ------ --- New Patch Raw src/cpu/x86/vm/methodHandles_x86.cpp

rev 522 : [mq]: meth.patch
1132 lines changed: 1132 ins; 0 del; 0 mod; 0 unchg

------ ------ ------ ------ --- New Patch Raw src/share/vm/prims/methodHandles.cpp

rev 522 : [mq]: meth.patch
2290 lines changed: 2290 ins; 0 del; 0 mod; 0 unchg

------ ------ ------ ------ --- New Patch Raw src/share/vm/prims/methodHandles.hpp

rev 522 : [mq]: meth.patch
415 lines changed: 415 ins; 0 del; 0 mod; 0 unchg

This code review page was prepared using /Users/jrose/bin/hgwebrev (vers 23.12-hg-never).