diff --git a/hotspot/make/ide/CreateVSProject.gmk b/hotspot/make/ide/CreateVSProject.gmk index d6f5324adb8..db0aca87e28 100644 --- a/hotspot/make/ide/CreateVSProject.gmk +++ b/hotspot/make/ide/CreateVSProject.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows) -buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \ -buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \ -makeBinary $(call FixPath, $(MAKE)) \ - -makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \ + -makeOutput $(call FixPath, $(JDK_OUTPUTDIR)/bin/server) \ -absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ -absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ $(EXTRACTED_DEFINES_client) \ diff --git a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java index d44fb04c588..50413e52792 100644 --- a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java +++ b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,8 +114,8 @@ public class WinGammaPlatformVC10 extends WinGammaPlatform { tag(cfg, "CodeAnalysisRuleAssemblies"); } for (BuildConfig cfg : allConfigs) { - tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile import-hotspot LOG=info"); - tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot import-hotspot LOG=info"); + tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info"); + tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info"); tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info"); tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll"); tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines())); diff --git a/hotspot/make/symbols/symbols-unix b/hotspot/make/symbols/symbols-unix index 90326d263dc..11add06efac 100644 --- a/hotspot/make/symbols/symbols-unix +++ b/hotspot/make/symbols/symbols-unix @@ -192,4 +192,3 @@ JVM_AddModulePackage JVM_AddReadsModule JVM_DefineModule JVM_SetBootLoaderUnnamedModule -JVM_GetModuleByPackageName diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 2294bab8db8..37e63dc9aba 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1042,8 +1042,10 @@ class HandlerImpl { bool is_card_mark_membar(const MemBarNode *barrier); bool is_CAS(int opcode); - MemBarNode *leading_to_trailing(MemBarNode *leading); - MemBarNode *card_mark_to_leading(const MemBarNode *barrier); + MemBarNode *leading_to_normal(MemBarNode *leading); + MemBarNode *normal_to_leading(const MemBarNode *barrier); + MemBarNode *card_mark_to_trailing(const MemBarNode *barrier); + MemBarNode *trailing_to_card_mark(const MemBarNode *trailing); MemBarNode *trailing_to_leading(const MemBarNode *trailing); // predicates controlling emit of ldr/ldar and associated dmb @@ -1420,28 +1422,23 @@ source %{ // leading MemBarRelease and a trailing MemBarVolatile as follows // // MemBarRelease - // { || } -- optional + // { || } -- optional // {MemBarCPUOrder} - // || \\ - // || StoreX[mo_release] - // | \ Bot / ??? - // | MergeMem - // | / + // || \\ + // || StoreX[mo_release] + // | \ / + // | MergeMem + // | / // MemBarVolatile // // where // || and \\ represent Ctl and Mem feeds via Proj nodes // | \ and / indicate further routing of the Ctl and Mem feeds // - // Note that the memory feed from the CPUOrder membar to the - // MergeMem node is an AliasIdxBot slice while the feed from the - // StoreX is for a slice determined by the type of value being - // written. - // - // the diagram above shows the graph we see for non-object stores. - // for a volatile Object store (StoreN/P) we may see other nodes - // below the leading membar because of the need for a GC pre- or - // post-write barrier. + // this is the graph we see for non-object stores. however, for a + // volatile Object store (StoreN/P) we may see other nodes below the + // leading membar because of the need for a GC pre- or post-write + // barrier. // // with most GC configurations we with see this simple variant which // includes a post-write barrier card mark. @@ -1449,7 +1446,7 @@ source %{ // MemBarRelease______________________________ // || \\ Ctl \ \\ // || StoreN/P[mo_release] CastP2X StoreB/CM - // | \ Bot / oop . . . / + // | \ / . . . / // | MergeMem // | / // || / @@ -1459,142 +1456,152 @@ source %{ // the object address to an int used to compute the card offset) and // Ctl+Mem to a StoreB node (which does the actual card mark). // - // n.b. a StoreCM node is only ever used when CMS (with or without - // CondCardMark) or G1 is configured. This abstract instruction - // differs from a normal card mark write (StoreB) because it implies - // a requirement to order visibility of the card mark (StoreCM) - // after that of the object put (StoreP/N) using a StoreStore memory - // barrier. Note that this is /not/ a requirement to order the - // instructions in the generated code (that is already guaranteed by - // the order of memory dependencies). Rather it is a requirement to - // ensure visibility order which only applies on architectures like - // AArch64 which do not implement TSO. This ordering is required for - // both non-volatile and volatile puts. - // - // That implies that we need to translate a StoreCM using the - // sequence + // n.b. a StoreCM node will only appear in this configuration when + // using CMS. StoreCM differs from a normal card mark write (StoreB) + // because it implies a requirement to order visibility of the card + // mark (StoreCM) relative to the object put (StoreP/N) using a + // StoreStore memory barrier (arguably this ought to be represented + // explicitly in the ideal graph but that is not how it works). This + // ordering is required for both non-volatile and volatile + // puts. Normally that means we need to translate a StoreCM using + // the sequence // // dmb ishst // stlrb // - // This dmb cannot be omitted even when the associated StoreX or - // CompareAndSwapX is implemented using stlr. However, as described - // below there are circumstances where a specific GC configuration - // requires a stronger barrier in which case it can be omitted. - // - // With the Serial or Parallel GC using +CondCardMark the card mark - // is performed conditionally on it currently being unmarked in - // which case the volatile put graph looks slightly different + // However, in the case of a volatile put if we can recognise this + // configuration and plant an stlr for the object write then we can + // omit the dmb and just plant an strb since visibility of the stlr + // is ordered before visibility of subsequent stores. StoreCM nodes + // also arise when using G1 or using CMS with conditional card + // marking. In these cases (as we shall see) we don't need to insert + // the dmb when translating StoreCM because there is already an + // intervening StoreLoad barrier between it and the StoreP/N. + // + // It is also possible to perform the card mark conditionally on it + // currently being unmarked in which case the volatile put graph + // will look slightly different // // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | - // | \ Bot / oop \ | + // | \ / \ | // | MergeMem . . . StoreB // | / / // || / // MemBarVolatile // - // It is worth noting at this stage that all the above + // It is worth noting at this stage that both the above // configurations can be uniquely identified by checking that the // memory flow includes the following subgraph: // // MemBarRelease // {MemBarCPUOrder} - // | \ . . . - // | StoreX[mo_release] . . . - // Bot | / oop - // MergeMem - // | + // | \ . . . + // | StoreX[mo_release] . . . + // | / + // MergeMem + // | // MemBarVolatile // - // This is referred to as a *normal* volatile store subgraph. It can - // easily be detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or MemBarVolatile node. + // This is referred to as a *normal* subgraph. It can easily be + // detected starting from any candidate MemBarRelease, + // StoreX[mo_release] or MemBarVolatile. // - // A small variation on this normal case occurs for an unsafe CAS - // operation. The basic memory flow subgraph for a non-object CAS is - // as follows + // A simple variation on this normal case occurs for an unsafe CAS + // operation. The basic graph for a non-object CAS is // // MemBarRelease // || // MemBarCPUOrder - // | \\ . . . - // | CompareAndSwapX - // | | - // Bot | SCMemProj - // \ / Bot - // MergeMem - // / + // || \\ . . . + // || CompareAndSwapX + // || | + // || SCMemProj + // | \ / + // | MergeMem + // | / // MemBarCPUOrder // || // MemBarAcquire // // The same basic variations on this arrangement (mutatis mutandis) - // occur when a card mark is introduced. i.e. the CPUOrder MemBar - // feeds the extra CastP2X, LoadB etc nodes but the above memory - // flow subgraph is still present. - // - // This is referred to as a *normal* CAS subgraph. It can easily be - // detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or MemBarAcquire node. + // occur when a card mark is introduced. i.e. we se the same basic + // shape but the StoreP/N is replaced with CompareAndSawpP/N and the + // tail of the graph is a pair comprising a MemBarCPUOrder + + // MemBarAcquire. // - // The code below uses two helper predicates, leading_to_trailing - // and trailing_to_leading to identify these normal graphs, one - // validating the layout starting from the top membar and searching - // down and the other validating the layout starting from the lower - // membar and searching up. + // So, in the case of a CAS the normal graph has the variant form // - // There are two special case GC configurations when the simple - // normal graphs above may not be generated: when using G1 (which - // always employs a conditional card mark); and when using CMS with - // conditional card marking (+CondCardMark) configured. These GCs - // are both concurrent rather than stop-the world GCs. So they - // introduce extra Ctl+Mem flow into the graph between the leading - // and trailing membar nodes, in particular enforcing stronger - // memory serialisation beween the object put and the corresponding - // conditional card mark. CMS employs a post-write GC barrier while - // G1 employs both a pre- and post-write GC barrier. + // MemBarRelease + // MemBarCPUOrder + // | \ . . . + // | CompareAndSwapX . . . + // | | + // | SCMemProj + // | / . . . + // MergeMem + // | + // MemBarCPUOrder + // MemBarAcquire // - // The post-write barrier subgraph for these configurations includes - // a MemBarVolatile node -- referred to as a card mark membar -- - // which is needed to order the card write (StoreCM) operation in - // the barrier, the preceding StoreX (or CompareAndSwapX) and Store - // operations performed by GC threads i.e. a card mark membar - // constitutes a StoreLoad barrier hence must be translated to a dmb - // ish (whether or not it sits inside a volatile store sequence). + // This graph can also easily be detected starting from any + // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire. // - // Of course, the use of the dmb ish for the card mark membar also - // implies theat the StoreCM which follows can omit the dmb ishst - // instruction. The necessary visibility ordering will already be - // guaranteed by the dmb ish. In sum, the dmb ishst instruction only - // needs to be generated for as part of the StoreCM sequence with GC - // configuration +CMS -CondCardMark. - // - // Of course all these extra barrier nodes may well be absent -- - // they are only inserted for object puts. Their potential presence - // significantly complicates the task of identifying whether a - // MemBarRelease, StoreX[mo_release], MemBarVolatile or - // MemBarAcquire forms part of a volatile put or CAS when using - // these GC configurations (see below) and also complicates the - // decision as to how to translate a MemBarVolatile and StoreCM. + // the code below uses two helper predicates, leading_to_normal and + // normal_to_leading to identify these normal graphs, one validating + // the layout starting from the top membar and searching down and + // the other validating the layout starting from the lower membar + // and searching up. // - // So, thjis means that a card mark MemBarVolatile occurring in the - // post-barrier graph it needs to be distinguished from a normal - // trailing MemBarVolatile. Resolving this is straightforward: a - // card mark MemBarVolatile always projects a Mem feed to a StoreCM - // node and that is a unique marker + // There are two special case GC configurations when a normal graph + // may not be generated: when using G1 (which always employs a + // conditional card mark); and when using CMS with conditional card + // marking configured. These GCs are both concurrent rather than + // stop-the world GCs. So they introduce extra Ctl+Mem flow into the + // graph between the leading and trailing membar nodes, in + // particular enforcing stronger memory serialisation beween the + // object put and the corresponding conditional card mark. CMS + // employs a post-write GC barrier while G1 employs both a pre- and + // post-write GC barrier. Of course the extra nodes may be absent -- + // they are only inserted for object puts. This significantly + // complicates the task of identifying whether a MemBarRelease, + // StoreX[mo_release] or MemBarVolatile forms part of a volatile put + // when using these GC configurations (see below). It adds similar + // complexity to the task of identifying whether a MemBarRelease, + // CompareAndSwapX or MemBarAcquire forms part of a CAS. + // + // In both cases the post-write subtree includes an auxiliary + // MemBarVolatile (StoreLoad barrier) separating the object put and + // the read of the corresponding card. This poses two additional + // problems. + // + // Firstly, a card mark MemBarVolatile needs to be distinguished + // from a normal trailing MemBarVolatile. Resolving this first + // problem is straightforward: a card mark MemBarVolatile always + // projects a Mem feed to a StoreCM node and that is a unique marker // // MemBarVolatile (card mark) // C | \ . . . // | StoreCM . . . // . . . // - // Returning to the task of translating the object put and the - // leading/trailing membar nodes: what do the node graphs look like - // for these 2 special cases? and how can we determine the status of - // a MemBarRelease, StoreX[mo_release] or MemBarVolatile in both - // normal and non-normal cases? + // The second problem is how the code generator is to translate the + // card mark barrier? It always needs to be translated to a "dmb + // ish" instruction whether or not it occurs as part of a volatile + // put. A StoreLoad barrier is needed after the object put to ensure + // i) visibility to GC threads of the object put and ii) visibility + // to the mutator thread of any card clearing write by a GC + // thread. Clearly a normal store (str) will not guarantee this + // ordering but neither will a releasing store (stlr). The latter + // guarantees that the object put is visible but does not guarantee + // that writes by other threads have also been observed. + // + // So, returning to the task of translating the object put and the + // leading/trailing membar nodes: what do the non-normal node graph + // look like for these 2 special cases? and how can we determine the + // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile + // in both normal and non-normal cases? // // A CMS GC post-barrier wraps its card write (StoreCM) inside an If // which selects conditonal execution based on the value loaded @@ -1605,117 +1612,91 @@ source %{ // which looks like this // // MemBarRelease - // MemBarCPUOrder_(leading)____________________ - // C | | M \ \\ M | C \ - // | | \ StoreN/P[mo_release] | CastP2X - // | | Bot \ / oop \ | - // | | MergeMem \ / - // | | / | / - // MemBarVolatile (card mark) | / - // C | || M | | / - // | LoadB | Bot oop | / Bot - // | | | / / - // | Cmp |\ / / - // | / | \ / / - // If | \ / / - // | \ | \ / / - // IfFalse IfTrue | \ / / - // \ / \ | | / / - // \ / StoreCM | / / - // \ / \ / / / - // Region Phi / / - // | \ Raw | / / - // | . . . | / / + // MemBarCPUOrder_(leading)__________________ + // C | M \ \\ C \ + // | \ StoreN/P[mo_release] CastP2X + // | Bot \ / + // | MergeMem + // | / + // MemBarVolatile (card mark) + // C | || M | + // | LoadB | + // | | | + // | Cmp |\ + // | / | \ + // If | \ + // | \ | \ + // IfFalse IfTrue | \ + // \ / \ | \ + // \ / StoreCM | + // \ / | | + // Region . . . | + // | \ / + // | . . . \ / Bot // | MergeMem - // | | + // | | // MemBarVolatile (trailing) // - // Notice that there are two MergeMem nodes below the leading - // membar. The first MergeMem merges the AliasIdxBot Mem slice from - // the leading membar and the oopptr Mem slice from the Store into - // the card mark membar. The trailing MergeMem merges the - // AliasIdxBot Mem slice from the leading membar, the AliasIdxRaw - // slice from the StoreCM and an oop slice from the StoreN/P node - // into the trailing membar (n.b. the raw slice proceeds via a Phi - // associated with the If region). + // The first MergeMem merges the AliasIdxBot Mem slice from the + // leading membar and the oopptr Mem slice from the Store into the + // card mark membar. The trailing MergeMem merges the AliasIdxBot + // Mem slice from the card mark membar and the AliasIdxRaw slice + // from the StoreCM into the trailing membar (n.b. the latter + // proceeds via a Phi associated with the If region). // - // So, in the case of CMS + CondCardMark the volatile object store - // graph still includes a normal volatile store subgraph from the - // leading membar to the trailing membar. However, it also contains - // the same shape memory flow to the card mark membar. The two flows - // can be distinguished by testing whether or not the downstream - // membar is a card mark membar. - // - // The graph for a CAS also varies with CMS + CondCardMark, in - // particular employing a control feed from the CompareAndSwapX node - // through a CmpI and If to the card mark membar and StoreCM which - // updates the associated card. This avoids executing the card mark - // if the CAS fails. However, it can be seen from the diagram below - // that the presence of the barrier does not alter the normal CAS - // memory subgraph where the leading membar feeds a CompareAndSwapX, - // an SCMemProj, a MergeMem then a final trailing MemBarCPUOrder and - // MemBarAcquire pair. + // The graph for a CAS varies slightly, the obvious difference being + // that the StoreN/P node is replaced by a CompareAndSwapP/N node + // and the trailing MemBarVolatile by a MemBarCPUOrder + + // MemBarAcquire pair. The other important difference is that the + // CompareAndSwap node's SCMemProj is not merged into the card mark + // membar - it still feeds the trailing MergeMem. This also means + // that the card mark membar receives its Mem feed directly from the + // leading membar rather than via a MergeMem. // // MemBarRelease - // MemBarCPUOrder__(leading)_______________________ - // C / M | \\ C \ - // . . . | Bot CompareAndSwapN/P CastP2X - // | C / M | - // | CmpI | - // | / | - // | . . . | - // | IfTrue | - // | / | - // MemBarVolatile (card mark) | - // C | || M | | - // | LoadB | Bot ______/| - // | | | / | - // | Cmp | / SCMemProj - // | / | / | - // If | / / - // | \ | / / Bot - // IfFalse IfTrue | / / - // | / \ / / prec / - // . . . | / StoreCM / - // \ | / | raw / - // Region . . . / - // | \ / - // | . . . \ / Bot - // | MergeMem - // | / - // MemBarCPUOrder - // MemBarAcquire (trailing) + // MemBarCPUOrder__(leading)_________________________ + // || \\ C \ + // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X + // C | || M | | + // | LoadB | ______/| + // | | | / | + // | Cmp | / SCMemProj + // | / | / | + // If | / / + // | \ | / / + // IfFalse IfTrue | / / + // \ / \ |/ prec / + // \ / StoreCM / + // \ / | / + // Region . . . / + // | \ / + // | . . . \ / Bot + // | MergeMem + // | | + // MemBarCPUOrder + // MemBarAcquire (trailing) // // This has a slightly different memory subgraph to the one seen - // previously but the core of it has a similar memory flow to the - // CAS normal subgraph: + // previously but the core of it is the same as for the CAS normal + // sungraph // // MemBarRelease // MemBarCPUOrder____ - // | \ . . . - // | CompareAndSwapX . . . - // | C / M | - // | CmpI | - // | / | - // | . . / - // Bot | IfTrue / - // | / / - // MemBarVolatile / - // | ... / - // StoreCM ... / - // | / - // . . . SCMemProj - // Raw \ / Bot - // MergeMem - // | + // || \ . . . + // MemBarVolatile CompareAndSwapX . . . + // | \ | + // . . . SCMemProj + // | / . . . + // MergeMem + // | // MemBarCPUOrder // MemBarAcquire // - // The G1 graph for a volatile object put is a lot more complicated. - // Nodes inserted on behalf of G1 may comprise: a pre-write graph - // which adds the old value to the SATB queue; the releasing store - // itself; and, finally, a post-write graph which performs a card - // mark. + // + // G1 is quite a lot more complicated. The nodes inserted on behalf + // of G1 may comprise: a pre-write graph which adds the old value to + // the SATB queue; the releasing store itself; and, finally, a + // post-write graph which performs a card mark. // // The pre-write graph may be omitted, but only when the put is // writing to a newly allocated (young gen) object and then only if @@ -1753,60 +1734,25 @@ source %{ // | CastP2X | StoreN/P[mo_release] | // | | | | // C | M | M | M | - // \ | Raw | oop / Bot + // \ | | / // . . . // (post write subtree elided) // . . . // C \ M / // MemBarVolatile (trailing) // - // Note that the three memory feeds into the post-write tree are an - // AliasRawIdx slice associated with the writes in the pre-write - // tree, an oop type slice from the StoreX specific to the type of - // the volatile field and the AliasBotIdx slice emanating from the - // leading membar. - // // n.b. the LoadB in this subgraph is not the card read -- it's a // read of the SATB queue active flag. // - // The CAS graph is once again a variant of the above with a - // CompareAndSwapX node and SCMemProj in place of the StoreX. The - // value from the CompareAndSwapX node is fed into the post-write - // graph aling with the AliasIdxRaw feed from the pre-barrier and - // the AliasIdxBot feeds from the leading membar and the ScMemProj. - // - // MemBarRelease (leading)____________ - // C | || M \ M \ M \ M \ . . . - // | LoadB \ LoadL LoadN \ - // | / \ \ - // If |\ \ - // | \ | \ \ - // IfFalse IfTrue | \ \ - // | | | \ \ - // | If | \ | - // | | \ | - // | \ | - // | . . . \ | - // | / | / \ | - // Region Phi[M] \ | - // | \ | \ | - // | \_____ | | | - // C | C \ | | | - // | CastP2X | CompareAndSwapX | - // | | res | | | - // C | M | | SCMemProj M | - // \ | Raw | | Bot / Bot - // . . . - // (post write subtree elided) - // . . . - // C \ M / - // MemBarVolatile (trailing) + // Once again the CAS graph is a minor variant on the above with the + // expected substitutions of CompareAndSawpX for StoreN/P and + // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile. // // The G1 post-write subtree is also optional, this time when the // new value being written is either null or can be identified as a // newly allocated (young gen) object with no intervening control // flow. The latter cannot happen but the former may, in which case - // the card mark membar is omitted and the memory feeds from the + // the card mark membar is omitted and the memory feeds form the // leading membar and the SToreN/P are merged direct into the // trailing membar as per the normal subgraph. So, the only special // case which arises is when the post-write subgraph is generated. @@ -1828,106 +1774,94 @@ source %{ // // (pre-write subtree elided) // . . . . . . . . . . . . - // C | M | M | M | - // Region Phi[M] StoreN | - // | Raw | oop | Bot | - // / \_______ |\ |\ |\ - // C / C \ . . . | \ | \ | \ - // If CastP2X . . . | \ | \ | \ - // / \ | \ | \ | \ - // / \ | \ | \ | \ - // IfFalse IfTrue | | | \ - // | | \ | / | - // | If \ | \ / \ | - // | / \ \ | / \ | - // | / \ \ | / \ | | - // | IfFalse IfTrue MergeMem \ | | - // | . . . / \ | \ | | - // | / \ | | | | - // | IfFalse IfTrue | | | | - // | . . . | | | | | - // | If / | | | - // | / \ / | | | - // | / \ / | | | - // | IfFalse IfTrue / | | | - // | . . . | / | | | - // | \ / | | | - // | \ / | | | - // | MemBarVolatile__(card mark ) | | | - // | || C | \ | | | - // | LoadB If | / | | - // | / \ Raw | / / / - // | . . . | / / / - // | \ | / / / - // | StoreCM / / / - // | | / / / - // | . . . / / - // | / / - // | . . . / / - // | | | / / / - // | | Phi[M] / / / - // | | | / / / - // | | | / / / - // | Region . . . Phi[M] / / - // | | | / / - // \ | | / / - // \ | . . . | / / - // \ | | / / - // Region Phi[M] / / - // | \ / / - // \ MergeMem - // \ / - // MemBarVolatile + // C | M | M | M | + // Region Phi[M] StoreN | + // | / \ | | + // / \_______ / \ | | + // C / C \ . . . \ | | + // If CastP2X . . . | | | + // / \ | | | + // / \ | | | + // IfFalse IfTrue | | | + // | | | | /| + // | If | | / | + // | / \ | | / | + // | / \ \ | / | + // | IfFalse IfTrue MergeMem | + // | . . . / \ / | + // | / \ / | + // | IfFalse IfTrue / | + // | . . . | / | + // | If / | + // | / \ / | + // | / \ / | + // | IfFalse IfTrue / | + // | . . . | / | + // | \ / | + // | \ / | + // | MemBarVolatile__(card mark) | + // | || C | M \ M \ | + // | LoadB If | | | + // | / \ | | | + // | . . . | | | + // | \ | | / + // | StoreCM | / + // | . . . | / + // | _________/ / + // | / _____________/ + // | . . . . . . | / / + // | | | / _________/ + // | | Phi[M] / / + // | | | / / + // | | | / / + // | Region . . . Phi[M] _____/ + // | / | / + // | | / + // | . . . . . . | / + // | / | / + // Region | | Phi[M] + // | | | / Bot + // \ MergeMem + // \ / + // MemBarVolatile // - // As with CMS + CondCardMark the first MergeMem merges the - // AliasIdxBot Mem slice from the leading membar and the oopptr Mem - // slice from the Store into the card mark membar. However, in this - // case it may also merge an AliasRawIdx mem slice from the pre - // barrier write. + // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice + // from the leading membar and the oopptr Mem slice from the Store + // into the card mark membar i.e. the memory flow to the card mark + // membar still looks like a normal graph. // - // The trailing MergeMem merges an AliasIdxBot Mem slice from the - // leading membar with an oop slice from the StoreN and an - // AliasRawIdx slice from the post barrier writes. In this case the - // AliasIdxRaw Mem slice is merged through a series of Phi nodes - // which combine feeds from the If regions in the post barrier - // subgraph. + // The trailing MergeMem merges an AliasIdxBot Mem slice with other + // Mem slices (from the StoreCM and other card mark queue stores). + // However in this case the AliasIdxBot Mem slice does not come + // direct from the card mark membar. It is merged through a series + // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow + // from the leading membar with the Mem feed from the card mark + // membar. Each Phi corresponds to one of the Ifs which may skip + // around the card mark membar. So when the If implementing the NULL + // value check has been elided the total number of Phis is 2 + // otherwise it is 3. // - // So, for G1 the same characteristic subgraph arises as for CMS + - // CondCardMark. There is a normal subgraph feeding the card mark - // membar and a normal subgraph feeding the trailing membar. + // The CAS graph when using G1GC also includes a pre-write subgraph + // and an optional post-write subgraph. Teh sam evarioations are + // introduced as for CMS with conditional card marking i.e. the + // StoreP/N is swapped for a CompareAndSwapP/N, the tariling + // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the + // Mem feed from the CompareAndSwapP/N includes a precedence + // dependency feed to the StoreCM and a feed via an SCMemProj to the + // trailing membar. So, as before the configuration includes the + // normal CAS graph as a subgraph of the memory flow. // - // The CAS graph when using G1GC also includes an optional - // post-write subgraph. It is very similar to the above graph except - // for a few details. - // - // - The control flow is gated by an additonal If which tests the - // result from the CompareAndSwapX node - // - // - The MergeMem which feeds the card mark membar only merges the - // AliasIdxBot slice from the leading membar and the AliasIdxRaw - // slice from the pre-barrier. It does not merge the SCMemProj - // AliasIdxBot slice. So, this subgraph does not look like the - // normal CAS subgraph. - // - // - The MergeMem which feeds the trailing membar merges the - // AliasIdxBot slice from the leading membar, the AliasIdxRaw slice - // from the post-barrier and the SCMemProj AliasIdxBot slice i.e. it - // has two AliasIdxBot input slices. However, this subgraph does - // still look like the normal CAS subgraph. - // - // So, the upshot is: - // - // In all cases a volatile put graph will include a *normal* - // volatile store subgraph betwen the leading membar and the - // trailing membar. It may also include a normal volatile store - // subgraph betwen the leading membar and the card mark membar. - // - // In all cases a CAS graph will contain a unique normal CAS graph - // feeding the trailing membar. - // - // In all cases where there is a card mark membar (either as part of - // a volatile object put or CAS) it will be fed by a MergeMem whose - // AliasIdxBot slice feed will be a leading membar. + // So, the upshot is that in all cases the volatile put graph will + // include a *normal* memory subgraph betwen the leading membar and + // its child membar, either a volatile put graph (including a + // releasing StoreX) or a CAS graph (including a CompareAndSwapX). + // When that child is not a card mark membar then it marks the end + // of the volatile put or CAS subgraph. If the child is a card mark + // membar then the normal subgraph will form part of a volatile put + // subgraph if and only if the child feeds an AliasIdxBot Mem feed + // to a trailing barrier via a MergeMem. That feed is either direct + // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier + // memory flow (for G1). // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described @@ -1971,24 +1905,24 @@ source %{ } - // leading_to_trailing + // leading_to_normal // //graph traversal helper which detects the normal case Mem feed from // a release membar (or, optionally, its cpuorder child) to a // dependent volatile membar i.e. it ensures that one or other of // the following Mem flow subgraph is present. // - // MemBarRelease {leading} - // {MemBarCPUOrder} {optional} - // Bot | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {not card mark} + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {trailing or card mark} // - // MemBarRelease {leading} - // {MemBarCPUOrder} {optional} + // MemBarRelease + // MemBarCPUOrder {leading} // | \ . . . // | CompareAndSwapX . . . // | @@ -1999,23 +1933,6 @@ source %{ // MemBarCPUOrder // MemBarAcquire {trailing} // - // the predicate needs to be capable of distinguishing the following - // volatile put graph which may arises when a GC post barrier - // inserts a card mark membar - // - // MemBarRelease {leading} - // {MemBarCPUOrder}__ - // Bot | \ \ - // | StoreN/P \ - // | / \ | - // MergeMem \ | - // | \ | - // MemBarVolatile \ | - // {card mark} \ | - // MergeMem - // | - // {not card mark} MemBarVolatile - // // if the correct configuration is present returns the trailing // membar otherwise NULL. // @@ -2026,7 +1943,7 @@ source %{ // the returned value may be a card mark or trailing membar // - MemBarNode *leading_to_trailing(MemBarNode *leading) + MemBarNode *leading_to_normal(MemBarNode *leading) { assert((leading->Opcode() == Op_MemBarRelease || leading->Opcode() == Op_MemBarCPUOrder), @@ -2043,21 +1960,15 @@ source %{ StoreNode * st = NULL; LoadStoreNode *cas = NULL; MergeMemNode *mm = NULL; - MergeMemNode *mm2 = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_MergeMem()) { if (mm != NULL) { - if (mm2 != NULL) { - // should not see more than 2 merge mems - return NULL; - } else { - mm2 = x->as_MergeMem(); - } - } else { - mm = x->as_MergeMem(); + return NULL; } + // two merge mems is one too many + mm = x->as_MergeMem(); } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { // two releasing stores/CAS nodes is one too many if (st != NULL || cas != NULL) { @@ -2077,13 +1988,13 @@ source %{ return NULL; } - // must have at least one merge if we also have st + // must have a merge if we also have st if (st && !mm) { return NULL; } + Node *y = NULL; if (cas) { - Node *y = NULL; // look for an SCMemProj for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) { x = cas->fast_out(i); @@ -2103,29 +2014,10 @@ source %{ break; } } - if (mm == NULL) { + if (mm == NULL) return NULL; - } - MemBarNode *mbar = NULL; - // ensure the merge feeds a trailing membar cpuorder + acquire pair - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarCPUOrder) { - MemBarNode *z = x->as_MemBar(); - z = child_membar(z); - if (z != NULL && z->Opcode() == Op_MemBarAcquire) { - mbar = z; - } - } - break; - } - } - return mbar; } else { - Node *y = NULL; - // ensure the store feeds the first mergemem; + // ensure the store feeds the existing mergemem; for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { if (st->fast_out(i) == mm) { y = st; @@ -2135,89 +2027,55 @@ source %{ if (y == NULL) { return NULL; } - if (mm2 != NULL) { - // ensure the store feeds the second mergemem; - y = NULL; - for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { - if (st->fast_out(i) == mm2) { - y = st; - } - } - if (y == NULL) { - return NULL; - } - } + } - MemBarNode *mbar = NULL; - // ensure the first mergemem feeds a volatile membar - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarVolatile) { - mbar = x->as_MemBar(); + MemBarNode *mbar = NULL; + // ensure the merge feeds to the expected type of membar + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile && st) { + mbar = x->as_MemBar(); + } else if (cas && opcode == Op_MemBarCPUOrder) { + MemBarNode *y = x->as_MemBar(); + y = child_membar(y); + if (y != NULL && y->Opcode() == Op_MemBarAcquire) { + mbar = y; } - break; - } - } - if (mm2 == NULL) { - // this is our only option for a trailing membar - return mbar; - } - // ensure the second mergemem feeds a volatile membar - MemBarNode *mbar2 = NULL; - for (DUIterator_Fast imax, i = mm2->fast_outs(imax); i < imax; i++) { - x = mm2->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarVolatile) { - mbar2 = x->as_MemBar(); - } - break; - } - } - // if we have two merge mems we must have two volatile membars - if (mbar == NULL || mbar2 == NULL) { - return NULL; - } - // return the trailing membar - if (is_card_mark_membar(mbar2)) { - return mbar; - } else { - if (is_card_mark_membar(mbar)) { - return mbar2; - } else { - return NULL; } + break; } } + + return mbar; } - // trailing_to_leading + // normal_to_leading // // graph traversal helper which detects the normal case Mem feed - // from a trailing membar to a preceding release membar (optionally - // its cpuorder child) i.e. it ensures that one or other of the - // following Mem flow subgraphs is present. + // from either a card mark or a trailing membar to a preceding + // release membar (optionally its cpuorder child) i.e. it ensures + // that one or other of the following Mem flow subgraphs is present. // - // MemBarRelease {leading} - // MemBarCPUOrder {optional} - // | Bot | \ . . . - // | | StoreN/P[mo_release] . . . - // | | / - // | MergeMem - // | | - // MemBarVolatile {not card mark} + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {card mark or trailing} // - // MemBarRelease {leading} - // MemBarCPUOrder {optional} + // MemBarRelease + // MemBarCPUOrder {leading} // | \ . . . // | CompareAndSwapX . . . // | // . . . SCMemProj // \ | // | MergeMem - // | | + // | / // MemBarCPUOrder // MemBarAcquire {trailing} // @@ -2227,20 +2085,15 @@ source %{ // if the configuration is present returns the cpuorder member for // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a MemBarVolatile or - // MemBarAcquire. if it is a MemBarVolatile it must *not* be a card - // mark membar. + // n.b. the input membar is expected to be a MemBarVolatile but + // need not be a card mark membar. - MemBarNode *trailing_to_leading(const MemBarNode *barrier) + MemBarNode *normal_to_leading(const MemBarNode *barrier) { // input must be a volatile membar assert((barrier->Opcode() == Op_MemBarVolatile || barrier->Opcode() == Op_MemBarAcquire), "expecting a volatile or an acquire membar"); - - assert((barrier->Opcode() != Op_MemBarVolatile) || - !is_card_mark_membar(barrier), - "not expecting a card mark membar"); Node *x; bool is_cas = barrier->Opcode() == Op_MemBarAcquire; @@ -2353,35 +2206,169 @@ source %{ return NULL; } - // card_mark_to_leading + // card_mark_to_trailing // - // graph traversal helper which traverses from a card mark volatile - // membar to a leading membar i.e. it ensures that the following Mem - // flow subgraph is present. + // graph traversal helper which detects extra, non-normal Mem feed + // from a card mark volatile membar to a trailing membar i.e. it + // ensures that one of the following three GC post-write Mem flow + // subgraphs is present. // - // MemBarRelease {leading} - // {MemBarCPUOrder} {optional} - // | . . . + // 1) + // . . . + // | + // MemBarVolatile (card mark) + // | | + // | StoreCM + // | | + // | . . . + // Bot | / + // MergeMem + // | + // | + // MemBarVolatile {trailing} + // + // 2) + // MemBarRelease/CPUOrder (leading) + // | + // | + // |\ . . . + // | \ | + // | \ MemBarVolatile (card mark) + // | \ | | + // \ \ | StoreCM . . . + // \ \ | + // \ Phi + // \ / + // Phi . . . // Bot | / - // MergeMem + // MergeMem // | - // MemBarVolatile (card mark) - // | \ - // . . . StoreCM + // MemBarVolatile {trailing} // - // if the configuration is present returns the cpuorder member for - // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a MemBarVolatile amd must - // be a card mark membar. + // 3) + // MemBarRelease/CPUOrder (leading) + // | + // |\ + // | \ + // | \ . . . + // | \ | + // |\ \ MemBarVolatile (card mark) + // | \ \ | | + // | \ \ | StoreCM . . . + // | \ \ | + // \ \ Phi + // \ \ / + // \ Phi + // \ / + // Phi . . . + // Bot | / + // MergeMem + // | + // | + // MemBarVolatile {trailing} + // + // configuration 1 is only valid if UseConcMarkSweepGC && + // UseCondCardMark + // + // configurations 2 and 3 are only valid if UseG1GC. + // + // if a valid configuration is present returns the trailing membar + // otherwise NULL. + // + // n.b. the supplied membar is expected to be a card mark + // MemBarVolatile i.e. the caller must ensure the input node has the + // correct operand and feeds Mem to a StoreCM node - MemBarNode *card_mark_to_leading(const MemBarNode *barrier) + MemBarNode *card_mark_to_trailing(const MemBarNode *barrier) { // input must be a card mark volatile membar assert(is_card_mark_membar(barrier), "expecting a card mark membar"); + Node *feed = barrier->proj_out(TypeFunc::Memory); + Node *x; + MergeMemNode *mm = NULL; + + const int MAX_PHIS = 3; // max phis we will search through + int phicount = 0; // current search count + + bool retry_feed = true; + while (retry_feed) { + // see if we have a direct MergeMem feed + for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { + x = feed->fast_out(i); + // the correct Phi will be merging a Bot memory slice + if (x->is_MergeMem()) { + mm = x->as_MergeMem(); + break; + } + } + if (mm) { + retry_feed = false; + } else if (UseG1GC & phicount++ < MAX_PHIS) { + // the barrier may feed indirectly via one or two Phi nodes + PhiNode *phi = NULL; + for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { + x = feed->fast_out(i); + // the correct Phi will be merging a Bot memory slice + if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) { + phi = x->as_Phi(); + break; + } + } + if (!phi) { + return NULL; + } + // look for another merge below this phi + feed = phi; + } else { + // couldn't find a merge + return NULL; + } + } + + // sanity check this feed turns up as the expected slice + assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge"); + + MemBarNode *trailing = NULL; + // be sure we have a trailing membar the merge + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { + trailing = x->as_MemBar(); + break; + } + } + + return trailing; + } + + // trailing_to_card_mark + // + // graph traversal helper which detects extra, non-normal Mem feed + // from a trailing volatile membar to a preceding card mark volatile + // membar i.e. it identifies whether one of the three possible extra + // GC post-write Mem flow subgraphs is present + // + // this predicate checks for the same flow as the previous predicate + // but starting from the bottom rather than the top. + // + // if the configuration is present returns the card mark membar + // otherwise NULL + // + // n.b. the supplied membar is expected to be a trailing + // MemBarVolatile i.e. the caller must ensure the input node has the + // correct opcode + + MemBarNode *trailing_to_card_mark(const MemBarNode *trailing) + { + assert(trailing->Opcode() == Op_MemBarVolatile, + "expecting a volatile membar"); + assert(!is_card_mark_membar(trailing), + "not expecting a card mark membar"); + // the Mem feed to the membar should be a merge - Node *x = barrier->in(TypeFunc::Memory); + Node *x = trailing->in(TypeFunc::Memory); if (!x->is_MergeMem()) { return NULL; } @@ -2389,20 +2376,118 @@ source %{ MergeMemNode *mm = x->as_MergeMem(); x = mm->in(Compile::AliasIdxBot); + // with G1 we may possibly see a Phi or two before we see a Memory + // Proj from the card mark membar + const int MAX_PHIS = 3; // max phis we will search through + int phicount = 0; // current search count + + bool retry_feed = !x->is_Proj(); + + while (retry_feed) { + if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) { + PhiNode *phi = x->as_Phi(); + ProjNode *proj = NULL; + PhiNode *nextphi = NULL; + bool found_leading = false; + for (uint i = 1; i < phi->req(); i++) { + x = phi->in(i); + if (x->is_Phi()) { + nextphi = x->as_Phi(); + } else if (x->is_Proj()) { + int opcode = x->in(0)->Opcode(); + if (opcode == Op_MemBarVolatile) { + proj = x->as_Proj(); + } else if (opcode == Op_MemBarRelease || + opcode == Op_MemBarCPUOrder) { + // probably a leading membar + found_leading = true; + } + } + } + // if we found a correct looking proj then retry from there + // otherwise we must see a leading and a phi or this the + // wrong config + if (proj != NULL) { + x = proj; + retry_feed = false; + } else if (found_leading && nextphi != NULL) { + // retry from this phi to check phi2 + x = nextphi; + } else { + // not what we were looking for + return NULL; + } + } else { + return NULL; + } + } + // the proj has to come from the card mark membar + x = x->in(0); if (!x->is_MemBar()) { return NULL; } - MemBarNode *leading = x->as_MemBar(); + MemBarNode *card_mark_membar = x->as_MemBar(); - if (leading_membar(leading)) { + if (!is_card_mark_membar(card_mark_membar)) { + return NULL; + } + + return card_mark_membar; + } + + // trailing_to_leading + // + // graph traversal helper which checks the Mem flow up the graph + // from a (non-card mark) trailing membar attempting to locate and + // return an associated leading membar. it first looks for a + // subgraph in the normal configuration (relying on helper + // normal_to_leading). failing that it then looks for one of the + // possible post-write card mark subgraphs linking the trailing node + // to a the card mark membar (relying on helper + // trailing_to_card_mark), and then checks that the card mark membar + // is fed by a leading membar (once again relying on auxiliary + // predicate normal_to_leading). + // + // if the configuration is valid returns the cpuorder member for + // preference or when absent the release membar otherwise NULL. + // + // n.b. the input membar is expected to be either a volatile or + // acquire membar but in the former case must *not* be a card mark + // membar. + + MemBarNode *trailing_to_leading(const MemBarNode *trailing) + { + assert((trailing->Opcode() == Op_MemBarAcquire || + trailing->Opcode() == Op_MemBarVolatile), + "expecting an acquire or volatile membar"); + assert((trailing->Opcode() != Op_MemBarVolatile || + !is_card_mark_membar(trailing)), + "not expecting a card mark membar"); + + MemBarNode *leading = normal_to_leading(trailing); + + if (leading) { return leading; } - return NULL; + // nothing more to do if this is an acquire + if (trailing->Opcode() == Op_MemBarAcquire) { + return NULL; + } + + MemBarNode *card_mark_membar = trailing_to_card_mark(trailing); + + if (!card_mark_membar) { + return NULL; + } + + return normal_to_leading(card_mark_membar); } + // predicates controlling emit of ldr/ldar and associated dmb + bool unnecessary_acquire(const Node *barrier) { assert(barrier->is_MemBar(), "expecting a membar"); @@ -2617,8 +2702,19 @@ bool unnecessary_release(const Node *n) } // must start with a normal feed - MemBarNode *trailing = leading_to_trailing(barrier); + MemBarNode *child_barrier = leading_to_normal(barrier); + if (!child_barrier) { + return false; + } + + if (!is_card_mark_membar(child_barrier)) { + // this is the trailing membar and we are done + return true; + } + + // must be sure this card mark feeds a trailing membar + MemBarNode *trailing = card_mark_to_trailing(child_barrier); return (trailing != NULL); } @@ -2640,7 +2736,7 @@ bool unnecessary_volatile(const Node *n) } // ok, if it's not a card mark then we still need to check if it is - // a trailing membar of a volatile put graph. + // a trailing membar of a volatile put hgraph. return (trailing_to_leading(mbvol) != NULL); } @@ -2690,9 +2786,20 @@ bool needs_releasing_store(const Node *n) } // does this lead a normal subgraph? - MemBarNode *trailing = leading_to_trailing(barrier); + MemBarNode *mbvol = leading_to_normal(barrier); - return (trailing != NULL); + if (!mbvol) { + return false; + } + + // all done unless this is a card mark + if (!is_card_mark_membar(mbvol)) { + return true; + } + + // we found a card mark -- just make sure we have a trailing barrier + + return (card_mark_to_trailing(mbvol) != NULL); } // predicate controlling translation of CAS @@ -2734,7 +2841,7 @@ bool needs_acquiring_load_exclusive(const Node *n) "CAS not fed by cpuorder+release membar pair!"); // does this lead a normal subgraph? - MemBarNode *mbar = leading_to_trailing(barrier); + MemBarNode *mbar = leading_to_normal(barrier); assert(mbar != NULL, "CAS not embedded in normal graph!"); @@ -2755,27 +2862,48 @@ bool unnecessary_storestore(const Node *storecm) // we only ever need to generate a dmb ishst between an object put // and the associated card mark when we are using CMS without - // conditional card marking. Any other occurence will happen when - // performing a card mark using CMS with conditional card marking or - // G1. In those cases the preceding MamBarVolatile will be - // translated to a dmb ish which guarantes visibility of the - // preceding StoreN/P before this StoreCM + // conditional card marking if (!UseConcMarkSweepGC || UseCondCardMark) { return true; } - // if we are implementing volatile puts using barriers then we must - // insert the dmb ishst + // if we are implementing volatile puts using barriers then the + // object put as an str so we must insert the dmb ishst if (UseBarriersForVolatile) { return false; } - // we must be using CMS with conditional card marking so we ahve to - // generate the StoreStore + // we can omit the dmb ishst if this StoreCM is part of a volatile + // put because in thta case the put will be implemented by stlr + // + // we need to check for a normal subgraph feeding this StoreCM. + // that means the StoreCM must be fed Memory from a leading membar, + // either a MemBarRelease or its dependent MemBarCPUOrder, and the + // leading membar must be part of a normal subgraph - return false; + Node *x = storecm->in(StoreNode::Memory); + + if (!x->is_Proj()) { + return false; + } + + x = x->in(0); + + if (!x->is_MemBar()) { + return false; + } + + MemBarNode *leading = x->as_MemBar(); + + // reject invalid candidates + if (!leading_membar(leading)) { + return false; + } + + // we can omit the StoreStore if it is the head of a normal subgraph + return (leading_to_normal(leading) != NULL); } @@ -3008,6 +3136,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ notify(Assembler::method_reentry); } + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + if (do_polling() && C->is_method_compilation()) { __ read_polling_page(rscratch1, os::get_polling_page(), relocInfo::poll_return_type); } @@ -9862,7 +9994,7 @@ instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne // END This section of the file is automatically generated. Do not edit -------------- // --------------------------------------------------------------------- -instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ +instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{ match(Set prev (GetAndSetI mem newv)); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} ins_encode %{ @@ -9871,7 +10003,7 @@ instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ ins_pipe(pipe_serial); %} -instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{ +instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{ match(Set prev (GetAndSetL mem newv)); format %{ "atomic_xchg $prev, $newv, [$mem]" %} ins_encode %{ @@ -9880,7 +10012,7 @@ instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{ ins_pipe(pipe_serial); %} -instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{ +instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ match(Set prev (GetAndSetN mem newv)); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} ins_encode %{ @@ -9889,7 +10021,7 @@ instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{ ins_pipe(pipe_serial); %} -instruct get_and_setP(indirect mem, iRegPNoSp newv, iRegP prev) %{ +instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{ match(Set prev (GetAndSetP mem newv)); format %{ "atomic_xchg $prev, $newv, [$mem]" %} ins_encode %{ diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 70c8f909337..b139a44f9a1 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -532,8 +532,14 @@ void LIR_Assembler::poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* void LIR_Assembler::return_op(LIR_Opr result) { assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,"); + // Pop the stack before the safepoint code __ remove_frame(initial_frame_size_in_bytes()); + + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + address polling_page(os::get_polling_page()); __ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type); __ ret(lr); diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp index 58ba9c0b613..8c83dc4125c 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1179,6 +1179,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ldrw(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(tmp, in_progress); + } + __ cbzw(tmp, done); + // Can we store original value in the thread's buffer? __ ldr(tmp, queue_index); __ cbz(tmp, runtime); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp index b74bce2d415..fe48df281b1 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp @@ -375,7 +375,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); } #endif @@ -629,6 +630,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); DESCRIBE_FP_OFFSET(interpreter_frame_method); DESCRIBE_FP_OFFSET(interpreter_frame_mdp); + DESCRIBE_FP_OFFSET(interpreter_frame_mirror); DESCRIBE_FP_OFFSET(interpreter_frame_cache); DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp index 5bcee325945..64a35bd3c30 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp @@ -46,6 +46,9 @@ // [pointer to locals ] = locals() locals_offset // [constant pool cache ] = cache() cache_offset +// [klass of method ] = mirror() mirror_offset +// [padding ] + // [methodData ] = mdp() mdx_offset // [methodOop ] = method() method_offset diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp index 7c410aaa74b..4f6d2bef7f5 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp @@ -82,7 +82,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod"); + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; diff --git a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp index 4c9d377ff09..0d78e2da1fe 100644 --- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp @@ -53,4 +53,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; // evidence that it's worth doing. #define DEOPTIMIZE_WHEN_PATCHING +#define SUPPORT_RESERVED_STACK_AREA + #endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp index 926e06004dc..06ec817cd9b 100644 --- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp @@ -50,7 +50,7 @@ define_pd_global(intx, InlineFrequencyCount, 100); // stack if compiled for unix and LP64. To pass stack overflow tests we need // 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5)) -#define DEFAULT_STACK_RESERVED_PAGES (0) +#define DEFAULT_STACK_RESERVED_PAGES (1) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index ed95d410e36..81636fb8ea1 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -619,6 +619,22 @@ void InterpreterMacroAssembler::remove_activation( // get sender esp ldr(esp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); + if (StackReservedPages > 0) { + // testing if reserved zone needs to be re-enabled + Label no_reserved_zone_enabling; + + ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); + cmp(esp, rscratch1); + br(Assembler::LS, no_reserved_zone_enabling); + + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_delayed_StackOverflowError)); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } // remove frame anchor leave(); // If we're returning to interpreted code we will shortly be diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index dc90886ab68..1c955d5afe3 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -402,6 +402,30 @@ void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) { } } +void MacroAssembler::reserved_stack_check() { + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; + + ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); + cmp(sp, rscratch1); + br(Assembler::LO, no_reserved_zone_enabling); + + enter(); // LR and FP are live. + lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)); + mov(c_rarg0, rthread); + blr(rscratch1); + leave(); + + // We have already removed our own frame. + // throw_delayed_StackOverflowError will think that it's been + // called by our caller. + lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + br(rscratch1); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); +} + int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 3418189f1b4..2f17699a262 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -957,6 +957,9 @@ public: // stack overflow + shadow pages. Also, clobbers tmp void bang_stack_size(Register size, Register tmp); + // Check for reserved stack access in method being exited (for JIT) + void reserved_stack_check(); + virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset); diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 681ecf34277..3143fe97d88 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -4676,8 +4676,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_StackOverflowError)); + SharedRuntime::throw_StackOverflowError)); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime::throw_delayed_StackOverflowError)); if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table; diff --git a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp index 937dfe91242..9f17c8fc810 100644 --- a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp +++ b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -551,6 +551,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register r_index_1 = R1; const Register r_buffer_2 = R2; + Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index())); Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + @@ -559,6 +561,11 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(R1, queue_active); + __ cbz(R1, done); + __ ldr(r_index_1, queue_index); __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize)); __ ldr(r_buffer_2, buffer); diff --git a/hotspot/src/cpu/arm/vm/frame_arm.cpp b/hotspot/src/cpu/arm/vm/frame_arm.cpp index 55f468fa74c..defe4a45a4a 100644 --- a/hotspot/src/cpu/arm/vm/frame_arm.cpp +++ b/hotspot/src/cpu/arm/vm/frame_arm.cpp @@ -364,7 +364,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); } #endif diff --git a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp index 589d75be640..4bde8e7be08 100644 --- a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp +++ b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp @@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(_cb->as_compiled_method()->insts_contains(_pc), "original PC must be in CompiledMethod"); + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; diff --git a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp index 1aa158b4a8f..3562a79825f 100644 --- a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -741,7 +741,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp = R14; Register tmp2 = R15; - Label refill, restart; + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -753,6 +756,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ std(tmp, -16, R1_SP); __ std(tmp2, -24, R1_SP); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwz(tmp, satb_q_active_byte_offset, R16_thread); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(tmp, satb_q_active_byte_offset, R16_thread); + } + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, marking_not_active); + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate. @@ -769,6 +782,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ std(tmp, satb_q_index_byte_offset, R16_thread); __ stdx(pre_val, tmp2, tmp); // [_buf + index] := + __ bind(marking_not_active); // Restore temp registers and return-from-leaf. __ ld(tmp2, -24, R1_SP); __ ld(tmp, -16, R1_SP); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 2d1f0c7230b..a5d5613a414 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -2569,7 +2569,7 @@ void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register } // Spin and retry if lock is busy. -// inputs: box_Reg (monitor address) +// inputs: owner_addr_Reg (monitor address) // : retry_count_Reg // output: retry_count_Reg decremented by 1 // CTR is killed @@ -2577,15 +2577,22 @@ void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register o Label SpinLoop, doneRetry; addic_(retry_count_Reg, retry_count_Reg, -1); blt(CCR0, doneRetry); - li(R0, RTMSpinLoopCount); - mtctr(R0); + + if (RTMSpinLoopCount > 1) { + li(R0, RTMSpinLoopCount); + mtctr(R0); + } bind(SpinLoop); smt_yield(); // Can't use waitrsv(). No permission (SIGILL). - bdz(retryLabel); - ld(R0, 0, owner_addr_Reg); - cmpdi(CCR0, R0, 0); - bne(CCR0, SpinLoop); + + if (RTMSpinLoopCount > 1) { + bdz(retryLabel); + ld(R0, 0, owner_addr_Reg); + cmpdi(CCR0, R0, 0); + bne(CCR0, SpinLoop); + } + b(retryLabel); bind(doneRetry); diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 6c6b83d257f..5e8be1425fa 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -327,7 +327,10 @@ void VM_Version::initialize() { warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50"); FLAG_SET_DEFAULT(RTMAbortRatio, 50); } - guarantee(RTMSpinLoopCount > 0, "unsupported"); + if (RTMSpinLoopCount < 0) { + warning("RTMSpinLoopCount must not be a negative value, resetting it to 0"); + FLAG_SET_DEFAULT(RTMSpinLoopCount, 0); + } #else // Only C2 does RTM locking optimization. // Can't continue because UseRTMLocking affects UseBiasedLocking flag diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp index 524a91fe07f..84fb4205099 100644 --- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp @@ -1105,16 +1105,16 @@ void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type, } case T_FLOAT : if (short_disp) { - __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); + __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); } else { - __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); + __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); } break; case T_DOUBLE: if (short_disp) { - __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); + __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); } else { - __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); + __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); } break; default: ShouldNotReachHere(); @@ -1148,6 +1148,10 @@ void LIR_Assembler::return_op(LIR_Opr result) { __ restore_return_pc(); } + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(Z_R14); + } + // We need to mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_return_type here. __ relocate(relocInfo::poll_return_type); diff --git a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp index c0fbee53da7..7b65476212f 100644 --- a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -784,7 +784,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val. Register tmp2 = Z_R7; - Label refill, restart; + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -796,6 +799,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); __ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } + __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently. + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate. @@ -810,6 +822,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := __ z_stg(tmp, satb_q_index_byte_offset, Z_thread); + __ bind(marking_not_active); // Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()). __ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); __ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); diff --git a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp index 83261cfdf47..63a9cb5abef 100644 --- a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp +++ b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp @@ -52,4 +52,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true; // The expected size in bytes of a cache line, used to pad data structures. #define DEFAULT_CACHE_LINE_SIZE 256 +#define SUPPORT_RESERVED_STACK_AREA + #endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP diff --git a/hotspot/src/cpu/s390/vm/globals_s390.hpp b/hotspot/src/cpu/s390/vm/globals_s390.hpp index fcd3ff45227..cb5adff3ef5 100644 --- a/hotspot/src/cpu/s390/vm/globals_s390.hpp +++ b/hotspot/src/cpu/s390/vm/globals_s390.hpp @@ -56,7 +56,7 @@ define_pd_global(intx, InlineSmallCode, 2000); // Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the // stack. To pass stack overflow tests we need 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2)) -#define DEFAULT_STACK_RESERVED_PAGES (0) +#define DEFAULT_STACK_RESERVED_PAGES (1) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES diff --git a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp index c53fa419a27..8cec2da25ac 100644 --- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp +++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp @@ -860,16 +860,39 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bool throw_monitor_exception, bool install_monitor_exception, bool notify_jvmti) { - + BLOCK_COMMENT("remove_activation {"); unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI); + if (StackReservedPages > 0) { + BLOCK_COMMENT("reserved_stack_check:"); + // Test if reserved zone needs to be enabled. + Label no_reserved_zone_enabling; + + // Compare frame pointers. There is no good stack pointer, as with stack + // frame compression we can get different SPs when we do calls. A subsequent + // call could have a smaller SP, so that this compare succeeds for an + // inner call of the method annotated with ReservedStack. + z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp))); + z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory. + z_brl(no_reserved_zone_enabling); + + // Enable reserved zone again, throw stack overflow exception. + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError)); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } + verify_oop(Z_tos, state); verify_thread(); pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3); + BLOCK_COMMENT("} remove_activation"); } // lock object diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp index a7cbd706255..0f78e5a6250 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp @@ -2666,6 +2666,32 @@ void MacroAssembler::bang_stack_with_offset(int offset) { } } +void MacroAssembler::reserved_stack_check(Register return_pc) { + // Test if reserved zone needs to be enabled. + Label no_reserved_zone_enabling; + assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub."); + BLOCK_COMMENT("reserved_stack_check {"); + + z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); + z_brl(no_reserved_zone_enabling); + + // Enable reserved zone again, throw stack overflow exception. + save_return_pc(); + push_frame_abi160(0); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread); + pop_frame(); + restore_return_pc(); + + load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry()); + // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc. + z_br(Z_R1); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + BLOCK_COMMENT("} reserved_stack_check"); +} + // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes. void MacroAssembler::tlab_allocate(Register obj, Register var_size_in_bytes, diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp index c9540860958..588bde6207e 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp @@ -627,6 +627,11 @@ class MacroAssembler: public Assembler { // Stack overflow checking void bang_stack_with_offset(int offset); + // Check for reserved stack access in method being exited. If the reserved + // stack area was accessed, protect it again and throw StackOverflowError. + // Uses Z_R1. + void reserved_stack_check(Register return_pc); + // Atomics // -- none? diff --git a/hotspot/src/cpu/s390/vm/s390.ad b/hotspot/src/cpu/s390/vm/s390.ad index 8ab6a5026d3..fd188525c46 100644 --- a/hotspot/src/cpu/s390/vm/s390.ad +++ b/hotspot/src/cpu/s390/vm/s390.ad @@ -909,15 +909,8 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // If this does safepoint polling, then do it here. bool need_polling = do_polling() && C->is_method_compilation(); - // Touch the polling page. - // Part 1: get the page's address. - if (need_polling) { - AddressLiteral pp(os::get_polling_page()); - __ load_const_optimized(Z_R1_scratch, pp); - } - // Pop frame, restore return_pc, and all stuff needed by interpreter. - // Pop frame by add insted of load (a penny saved is a penny got :-). + // Pop frame by add instead of load (a penny saved is a penny got :-). int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes); int retPC_offset = frame_size_in_bytes + _z_abi16(return_pc); if (Displacement::is_validDisp(retPC_offset)) { @@ -928,9 +921,14 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ restore_return_pc(); } - // Touch the polling page, - // part 2: touch the page now. + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(Z_R14); + } + + // Touch the polling page. if (need_polling) { + AddressLiteral pp(os::get_polling_page()); + __ load_const_optimized(Z_R1_scratch, pp); // We need to mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_return_type here. __ relocate(relocInfo::poll_return_type); @@ -939,7 +937,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { - // variable size. determine dynamically. + // Variable size. determine dynamically. return MachNode::size(ra_); } diff --git a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp index 8b872c5c922..be107222636 100644 --- a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp @@ -2433,13 +2433,12 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); //---------------------------------------------------------------------- // Entry points that are platform specific. - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); if (UseCRC32Intrinsics) { // We have no CRC32 table on z/Architecture. diff --git a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp index de266db04fc..2084f36006f 100644 --- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp @@ -1112,16 +1112,21 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state __ add2reg(top_frame_size, frame::z_top_ijava_frame_abi_size + - frame::z_ijava_state_size + - frame::interpreter_frame_monitor_size() * wordSize, + frame::z_ijava_state_size + + frame::interpreter_frame_monitor_size() * wordSize, max_stack); - // Check if there's room for the new frame... - Register frame_size = max_stack; // Reuse the regiser for max_stack. - __ z_lgr(frame_size, Z_SP); - __ z_sgr(frame_size, sp_after_resize); - __ z_agr(frame_size, top_frame_size); - generate_stack_overflow_check(frame_size, fp/*tmp1*/); + if (!native_call) { + // Stack overflow check. + // Native calls don't need the stack size check since they have no + // expression stack and the arguments are already on the stack and + // we only add a handful of words to the stack. + Register frame_size = max_stack; // Reuse the regiser for max_stack. + __ z_lgr(frame_size, Z_SP); + __ z_sgr(frame_size, sp_after_resize); + __ z_agr(frame_size, top_frame_size); + generate_stack_overflow_check(frame_size, fp/*tmp1*/); + } DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP)); __ asm_assert_eq("killed Z_R14", 0); diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 97fb2745a26..ae2942f19b5 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -694,6 +694,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) { int store_offset; if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) { + assert(base != O7, "destroying register"); assert(!unaligned, "can't handle this"); // for offsets larger than a simm13 we setup the offset in O7 __ set(offset, O7); @@ -712,9 +713,12 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType case T_LONG : #ifdef _LP64 if (unaligned || PatchALot) { - __ srax(from_reg->as_register_lo(), 32, O7); + // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem) + assert(G3_scratch != base, "can't handle this"); + assert(G3_scratch != from_reg->as_register_lo(), "can't handle this"); + __ srax(from_reg->as_register_lo(), 32, G3_scratch); __ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes); - __ stw(O7, base, offset + hi_word_offset_in_bytes); + __ stw(G3_scratch, base, offset + hi_word_offset_in_bytes); } else { __ stx(from_reg->as_register_lo(), base, offset); } @@ -821,7 +825,7 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break; case T_INT : __ ld(base, offset, to_reg->as_register()); break; case T_LONG : - if (!unaligned) { + if (!unaligned && !PatchALot) { #ifdef _LP64 __ ldx(base, offset, to_reg->as_register_lo()); #else @@ -1297,7 +1301,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, disp_reg = O7; } } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_register(), O7); + __ add(src, addr->index()->as_pointer_register(), O7); src = O7; } else { disp_reg = addr->index()->as_pointer_register(); @@ -1424,7 +1428,7 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, disp_reg = O7; } } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_register(), O7); + __ add(src, addr->index()->as_pointer_register(), O7); src = O7; } else { disp_reg = addr->index()->as_pointer_register(); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 5530a85cb4c..40e30551967 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -856,7 +856,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp2 = G3_scratch; Label refill, restart; - bool with_frame = false; // I don't know if we can do with-frame. + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -864,6 +866,17 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ld(G2_thread, satb_q_active_byte_offset, tmp); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldsb(G2_thread, satb_q_active_byte_offset, tmp); + } + __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart); + __ retl(); + __ delayed()->nop(); + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 5fe455600d1..58db92dcd32 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1623,6 +1623,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { NOT_LP64(__ get_thread(thread);) + Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + @@ -1631,6 +1633,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ cmpl(queue_active, 0); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ cmpb(queue_active, 0); + } + __ jcc(Assembler::equal, done); + // Can we store original value in the thread's buffer? __ movptr(tmp, queue_index); diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index 9cbc29af4c9..11f28bdb6ca 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -376,7 +376,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains(original_pc), "original PC must be in CompiledMethod"); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); } #endif diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index d7d8e47ea89..d0c72947e0f 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod"); + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { if (_cb->is_deoptimization_stub()) { diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 3d4dee751a5..b6d32631582 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -3499,12 +3499,12 @@ void MacroAssembler::movdqu(XMMRegister dst, XMMRegister src) { } } -void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) { +void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg) { if (reachable(src)) { movdqu(dst, as_Address(src)); } else { - lea(rscratch1, src); - movdqu(dst, Address(rscratch1, 0)); + lea(scratchReg, src); + movdqu(dst, Address(scratchReg, 0)); } } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 02fb401511e..a3e81e58dc5 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1085,7 +1085,7 @@ public: void movdqu(Address dst, XMMRegister src); void movdqu(XMMRegister dst, Address src); void movdqu(XMMRegister dst, XMMRegister src); - void movdqu(XMMRegister dst, AddressLiteral src); + void movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg = rscratch1); // AVX Unaligned forms void vmovdqu(Address dst, XMMRegister src); void vmovdqu(XMMRegister dst, Address src); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp index 37d93a48f21..10935345f70 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp @@ -817,7 +817,7 @@ enum { movl(d, Address(CTX, 4*3)); movl(e, Address(CTX, 4*4)); movl(f, Address(CTX, 4*5)); - movl(g, Address(CTX, 4*6)); + // load g - r10 after it is used as scratch movl(h, Address(CTX, 4*7)); pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask; @@ -825,6 +825,8 @@ enum { vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip] vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip] + movl(g, Address(CTX, 4*6)); + movq(Address(rsp, _CTX), CTX); // store bind(loop0); @@ -977,7 +979,7 @@ bind(only_one_block); movl(d, Address(CTX, 4*3)); // 0xa54ff53a movl(e, Address(CTX, 4*4)); // 0x510e527f movl(f, Address(CTX, 4*5)); // 0x9b05688c - movl(g, Address(CTX, 4*6)); // 0x1f83d9ab + // load g - r10 after use as scratch movl(h, Address(CTX, 4*7)); // 0x5be0cd19 @@ -986,6 +988,8 @@ bind(only_one_block); vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip] vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip] + movl(g, Address(CTX, 4*6)); // 0x1f83d9ab + movq(Address(rsp, _CTX), CTX); jmpb(do_last_block); @@ -1154,9 +1158,8 @@ void MacroAssembler::sha512_AVX2_one_round_and_schedule( // Move to appropriate lanes for calculating w[16] and w[17] vperm2f128(xmm4, xmm0, xmm0, 0); //xmm4 = W[-16] + W[-7] + s0{ BABA } - address MASK_YMM_LO = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512(); //Move to appropriate lanes for calculating w[18] and w[19] - vpand(xmm0, xmm0, ExternalAddress(MASK_YMM_LO + 32), AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 } + vpand(xmm0, xmm0, xmm10, AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 } //Calculate w[16] and w[17] in both 128 bit lanes //Calculate sigma1 for w[16] and w[17] on both 128 bit lanes vperm2f128(xmm2, xmm7, xmm7, 17); //xmm2 = W[-2] {BABA} @@ -1250,6 +1253,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste const XMMRegister& XFER = xmm0; // YTMP0 const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9 + const XMMRegister& YMM_MASK_LO = xmm10; // ymm10 #ifdef _WIN64 const Register& INP = rcx; //1st arg const Register& CTX = rdx; //2nd arg @@ -1368,11 +1372,14 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste movq(d, Address(CTX, 8 * 3)); movq(e, Address(CTX, 8 * 4)); movq(f, Address(CTX, 8 * 5)); - movq(g, Address(CTX, 8 * 6)); + // load g - r10 after it is used as scratch movq(h, Address(CTX, 8 * 7)); pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512; vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); //PSHUFFLE_BYTE_FLIP_MASK wrt rip + vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); + + movq(g, Address(CTX, 8 * 6)); bind(loop0); lea(TBL, ExternalAddress(K512_W)); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 1853cf9a42a..48be33ae526 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -3207,7 +3207,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) #else const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 - const Register len_reg = r10; // pick the first volatile windows register + const Register len_reg = r11; // pick the volatile windows register #endif const Register pos = rax; @@ -3404,7 +3404,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) #else const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 - const Register len_reg = r10; // pick the first volatile windows register + const Register len_reg = r11; // pick the volatile windows register #endif const Register pos = rax; @@ -3930,7 +3930,7 @@ class StubGenerator: public StubCodeGenerator { __ push(rbx); // Save RBX __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter - __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled __ movptr(pos, 0); @@ -3953,7 +3953,7 @@ class StubGenerator: public StubCodeGenerator { __ movl(Address(used_addr, 0), used); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} - __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); + __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); __ cmpl(rbx, 52); __ jcc(Assembler::equal, L_multiBlock_loopTop[1]); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index 7be7a80192e..6cd7a4ad8b0 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -37,6 +37,7 @@ import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; import jdk.tools.jaotc.binformat.elf.JELFRelocObject; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; /** * A format-agnostic container class that holds various components of a binary. @@ -257,9 +258,9 @@ public class BinaryContainer implements SymbolTable { * prefix {@code prefix}. It also initializes internal code container, symbol table and * relocation tables. */ - public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) { - this.codeSegmentSize = config.codeSegmentSize; - this.codeEntryAlignment = config.codeEntryAlignment; + public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) { + this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize; + this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment; // read only, code codeContainer = new CodeContainer(".text", this); @@ -289,30 +290,31 @@ public class BinaryContainer implements SymbolTable { addGlobalSymbols(); - recordConfiguration(config); + recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig); } - private void recordConfiguration(GraalHotSpotVMConfig config) { + private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) { // @formatter:off - boolean[] booleanFlags = { config.cAssertions, // Debug VM - config.useCompressedOops, - config.useCompressedClassPointers, - config.compactFields, - config.useG1GC, - config.useCMSGC, - config.useTLAB, - config.useBiasedLocking, + boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM + graalHotSpotVMConfig.useCompressedOops, + graalHotSpotVMConfig.useCompressedClassPointers, + graalHotSpotVMConfig.compactFields, + graalHotSpotVMConfig.useG1GC, + graalHotSpotVMConfig.useCMSGC, + graalHotSpotVMConfig.useTLAB, + graalHotSpotVMConfig.useBiasedLocking, TieredAOT.getValue(), - config.enableContended, - config.restrictContended, + graalHotSpotVMConfig.enableContended, + graalHotSpotVMConfig.restrictContended, + graphBuilderConfig.omitAssertions() }; - int[] intFlags = { config.narrowOopShift, - config.narrowKlassShift, - config.contendedPaddingWidth, - config.fieldsAllocationStyle, - config.objectAlignment, - config.codeSegmentSize, + int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift, + graalHotSpotVMConfig.getKlassEncoding().shift, + graalHotSpotVMConfig.contendedPaddingWidth, + graalHotSpotVMConfig.fieldsAllocationStyle, + 1 << graalHotSpotVMConfig.getOopEncoding().alignment, + graalHotSpotVMConfig.codeSegmentSize, }; // @formatter:on @@ -395,6 +397,10 @@ public class BinaryContainer implements SymbolTable { return "_aot_narrow_klass_base_address"; } + public String getNarrowOopBaseAddressSymbolName() { + return "_aot_narrow_oop_base_address"; + } + public String getLogOfHeapRegionGrainBytesSymbolName() { return "_aot_log_of_heap_region_grain_bytes"; } @@ -445,6 +451,7 @@ public class BinaryContainer implements SymbolTable { createGotSymbol(getHeapTopAddressSymbolName()); createGotSymbol(getHeapEndAddressSymbolName()); createGotSymbol(getNarrowKlassBaseAddressSymbolName()); + createGotSymbol(getNarrowOopBaseAddressSymbolName()); createGotSymbol(getPollingPageSymbolName()); createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName()); createGotSymbol(getInlineContiguousAllocationSupportedSymbolName()); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java index b5d081a51ca..3ba1067b959 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java @@ -77,10 +77,14 @@ public class AOTBackend { this.filters = filters; providers = backend.getProviders(); codeCache = providers.getCodeCache(); - graphBuilderSuite = initGraphBuilderSuite(backend); + graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions); highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL); } + public PhaseSuite getGraphBuilderSuite() { + return graphBuilderSuite; + } + private Suites getSuites() { // create suites every time, as we modify options for the compiler return backend.getSuites().getDefaultSuites(); @@ -146,14 +150,14 @@ public class AOTBackend { return backend.getRuntime().getVMConfig().cAssertions; } - private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend) { + private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) { PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); // Use all default plugins. Plugins plugins = baseConfig.getPlugins(); - GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions); iterator.next(); iterator.remove(); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java index cbf26294b0d..68fb146b8ce 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java @@ -293,12 +293,18 @@ public class AOTCompiledClass { // Record methods holder methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType); // Record inlinee classes - for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) { - methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); + ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods(); + if (inlinees != null) { + for (ResolvedJavaMethod m : inlinees) { + methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); + } } // Record classes of fields that were accessed - for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) { - methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); + ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields(); + if (fields != null) { + for (ResolvedJavaField f : fields) { + methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); + } } } } diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java new file mode 100644 index 00000000000..a0a01f7c1c9 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java @@ -0,0 +1,64 @@ +package jdk.tools.jaotc;/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class LoadedClass { + private final String name; + private final Class clz; + + public LoadedClass(String name, Class clz) { + this.name = name; + this.clz = clz; + } + + public String getName() { + return name; + } + + public Class getLoadedClass() { + return clz; + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LoadedClass)) return false; + + LoadedClass that = (LoadedClass) o; + + if (name != null ? !name.equals(that.name) : that.name != null) return false; + return clz != null ? clz.equals(that.clz) : that.clz == null; + + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (clz != null ? clz.hashCode() : 0); + return result; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index a1257b7a013..a98dc8d2d81 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,19 +43,31 @@ import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Set; import java.util.stream.Stream; import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; -import jdk.tools.jaotc.collect.ClassCollector; +import jdk.tools.jaotc.collect.*; +import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; +import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; +import jdk.tools.jaotc.collect.jar.JarSourceProvider; +import jdk.tools.jaotc.collect.module.ModuleSourceProvider; import jdk.tools.jaotc.utils.Timer; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.runtime.RuntimeProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -120,17 +132,7 @@ public class Main implements LogPrinter { abstract void process(Main task, String opt, String arg) throws BadArgs; } - static Option[] recognizedOptions = {new Option(" --module Module to compile", true, "--module") { - @Override - void process(Main task, String opt, String arg) { - task.options.module = arg; - } - }, new Option(" --module-path Specify where to find module to compile", true, "--module-path") { - @Override - void process(Main task, String opt, String arg) { - task.options.modulepath = arg; - } - }, new Option(" --output Output file name", true, "--output") { + static Option[] recognizedOptions = { new Option(" --output Output file name", true, "--output") { @Override void process(Main task, String opt, String arg) { String name = arg; @@ -139,22 +141,48 @@ public class Main implements LogPrinter { } task.options.outputName = name; } + }, new Option(" --class-name List of classes to compile", true, "--class-name", "--classname") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); + } + }, new Option(" --jar List of jar files to compile", true, "--jar") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); + } + }, new Option(" --module List of modules to compile", true, "--module") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); + } + }, new Option(" --directory List of directories where to search for files to compile", true, "--directory") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); + } + }, new Option(" --search-path List of directories where to search for specified files", true, "--search-path") { + @Override + void process(Main task, String opt, String arg) { + String[] elements = arg.split(":"); + task.options.searchPath.add(elements); + } }, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") { @Override void process(Main task, String opt, String arg) { task.options.methodList = arg; } - }, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") { + }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") { @Override void process(Main task, String opt, String arg) { TieredAOT.setValue(true); } - }, new Option(" --classpath Specify where to find user class files", true, "--classpath", "--class-path") { + }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") { @Override void process(Main task, String opt, String arg) { - task.options.classpath = arg; + task.options.compileWithAssertions = true; } - }, new Option(" --threads Number of compilation threads to be used", true, "--threads") { + }, new Option(" --compile-threads Number of compilation threads to be used", true, "--compile-threads", "--threads") { @Override void process(Main task, String opt, String arg) { int threads = Integer.parseInt(arg); @@ -213,27 +241,27 @@ public class Main implements LogPrinter { }}; public static class Options { - public List files = new LinkedList<>(); - public String module = null; - public String modulepath = "modules"; + public List files = new LinkedList<>(); public String outputName = "unnamed"; public String methodList; - public String classpath = "."; + public List sources = new ArrayList<>(); + public SearchPath searchPath = new SearchPath(); /** * We don't see scaling beyond 16 threads. */ private static final int COMPILER_THREADS = 16; - int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); + public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); public boolean ignoreClassLoadingErrors; public boolean exitOnError; - boolean info; - boolean verbose; - boolean debug; - boolean help; - boolean version; + public boolean info; + public boolean verbose; + public boolean debug; + public boolean help; + public boolean version; + public boolean compileWithAssertions; } /* package */final Options options = new Options(); @@ -275,7 +303,9 @@ public class Main implements LogPrinter { printlnInfo("Compiling " + options.outputName + "..."); final long start = System.currentTimeMillis(); - run(); + if (!run()) { + return EXIT_ABNORMAL; + } final long end = System.currentTimeMillis(); printlnInfo("Total time: " + (end - start) + " ms"); @@ -318,17 +348,34 @@ public class Main implements LogPrinter { } @SuppressWarnings("try") - private void run() throws Exception { + private boolean run() throws Exception { openLog(); try { CompilationSpec compilationRestrictions = collectSpecifiedMethods(); - Set> classesToCompile; + Set> classesToCompile = new HashSet<>(); try (Timer t = new Timer(this, "")) { - ClassCollector collector = new ClassCollector(this.options, this); - classesToCompile = collector.collectClassesToCompile(); + FileSupport fileSupport = new FileSupport(); + ClassSearch lookup = new ClassSearch(); + lookup.addProvider(new ModuleSourceProvider()); + lookup.addProvider(new ClassNameSourceProvider(fileSupport)); + lookup.addProvider(new JarSourceProvider()); + lookup.addProvider(new DirectorySourceProvider(fileSupport)); + + List found = null; + try { + found = lookup.search(options.files, options.searchPath); + } catch (InternalError e) { + reportError(e); + return false; + } + + for (LoadedClass loadedClass : found) { + classesToCompile.add(loadedClass.getLoadedClass()); + } + printInfo(classesToCompile.size() + " classes found"); } @@ -356,6 +403,11 @@ public class Main implements LogPrinter { AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads); classes = compiler.compileClasses(classes); + GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig(); + PhaseSuite graphBuilderSuite = aotBackend.getGraphBuilderSuite(); + ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); + GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); + // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { printMemoryUsage(); @@ -364,7 +416,7 @@ public class Main implements LogPrinter { System.gc(); } - BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION); + BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION); DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer); dataBuilder.prepareData(); @@ -446,6 +498,7 @@ public class Main implements LogPrinter { } finally { closeLog(); } + return true; } private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) { @@ -509,7 +562,7 @@ public class Main implements LogPrinter { break; } } else { - options.files.add(arg); + options.files.add(new SearchFor(arg)); } } } @@ -570,6 +623,12 @@ public class Main implements LogPrinter { log.flush(); } + private void reportError(Throwable e) { + log.println("Error: " + e.getMessage()); + e.printStackTrace(log); + log.flush(); + } + private void reportError(String key, Object... args) { printError(MessageFormat.format(key, args)); } @@ -580,17 +639,17 @@ public class Main implements LogPrinter { } private void showUsage() { - log.println("Usage: " + PROGNAME + " list..."); + log.println("Usage: " + PROGNAME + " list"); log.println("use --help for a list of possible options"); } private void showHelp() { - log.println("Usage: " + PROGNAME + " <--module name> | "); + log.println("Usage: " + PROGNAME + " list"); log.println(); - log.println(" list A list of class files, jar files or directories which"); - log.println(" contains class files."); + log.println(" list A : separated list of class names, modules, jar files"); + log.println(" or directories which contain class files."); log.println(); - log.println("where possible options include:"); + log.println("where options include:"); for (Option o : recognizedOptions) { String name = o.aliases[0].substring(1); // there must always be at least one name name = name.charAt(0) == '-' ? name.substring(1) : name; diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java index 4bbd4665434..eedeac3b720 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java @@ -48,6 +48,7 @@ enum MarkId { HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"), HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"), NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"), + NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"), CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"), LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"), INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED"); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java index 1e1944bc274..7a833c13914 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java @@ -57,6 +57,7 @@ class MarkProcessor { case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: case NARROW_KLASS_BASE_ADDRESS: + case NARROW_OOP_BASE_ADDRESS: case CRC_TABLE_ADDRESS: case LOG_OF_HEAP_REGION_GRAIN_BYTES: case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: @@ -78,6 +79,9 @@ class MarkProcessor { case NARROW_KLASS_BASE_ADDRESS: vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName(); break; + case NARROW_OOP_BASE_ADDRESS: + vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName(); + break; case CRC_TABLE_ADDRESS: vmSymbolName = binaryContainer.getCrcTableAddressSymbolName(); break; diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java deleted file mode 100644 index c46b3bfd062..00000000000 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.tools.jaotc.collect; - -import jdk.tools.jaotc.LogPrinter; -import jdk.tools.jaotc.Main; - -import java.io.File; -import java.io.IOException; -import java.net.*; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; - -import static java.nio.file.FileVisitResult.CONTINUE; - -public class ClassCollector { - private final Main.Options options; - private final LogPrinter log; - - public ClassCollector(Main.Options options, LogPrinter log) { - this.options = options; - this.log = log; - } - - /** - * Collect all class names passed by the user. - * - * @return array list of classes - */ - public Set> collectClassesToCompile() { - Set> classes = new HashSet<>(); - List filesToScan = new LinkedList<>(options.files); - - if (options.module != null) { - classes.addAll(scanModule(filesToScan)); - } - - classes.addAll(scanFiles(filesToScan)); - return classes; - } - - private Set> scanModule(List filesToScan) { - String module = options.module; - // Search module in standard JDK installation. - Path dir = getModuleDirectory(options.modulepath, module); - - if (Files.isDirectory(dir)) { - return loadFromModuleDirectory(dir); - } else { - findFilesToScan(filesToScan, module); - return new HashSet<>(); - } - } - - private Set> loadFromModuleDirectory(Path dir) { - log.printInfo("Scanning module: " + dir + " ..."); - log.printlnVerbose(" "); // Break line - - FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString())); - Set> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder); - log.printlnInfo(" " + cls.size() + " classes loaded."); - return cls; - } - - private void findFilesToScan(List filesToScan, String module) { - // Try to search regular directory, .jar or .class files - Path path = Paths.get(options.modulepath, module); - - if (Files.isDirectory(path)) { - filesToScan.add("."); - options.classpath = path.toString(); - } else if (path.endsWith(".jar") || path.endsWith(".class")) { - filesToScan.add(path.toString()); - } else { - path = Paths.get(options.modulepath, module + ".jar"); - if (Files.exists(path)) { - filesToScan.add(path.toString()); - } else { - path = Paths.get(options.modulepath, module + ".class"); - if (Files.exists(path)) { - filesToScan.add(path.toString()); - } else { - throw new InternalError("Expecting a .class, .jar or directory: " + path); - } - } - } - } - - private boolean entryIsClassFile(String entry) { - return entry.endsWith(".class") && !entry.endsWith("module-info.class"); - } - - private Set> scanFiles(List filesToScan) { - Set> classes = new HashSet<>(); - for (String fileName : filesToScan) { - Set> loaded = scanFile(fileName); - log.printlnInfo(" " + loaded.size() + " classes loaded."); - classes.addAll(loaded); - } - return classes; - } - - interface ClassLoaderFactory { - ClassLoader create() throws IOException; - } - - private Set> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) { - ClassLoader loader = null; - try { - loader = factory.create(); - return loadClassFiles(root, finder, loader); - } catch (IOException e) { - throw new InternalError(e); - } finally { - if (loader instanceof AutoCloseable) { - try { - ((AutoCloseable) loader).close(); - } catch (Exception e) { - throw new InternalError(e); - } - } - } - } - - private Set> scanFile(String fileName) { - log.printInfo("Scanning: " + fileName + " ..."); - log.printlnVerbose(" "); // Break line - - if (fileName.endsWith(".jar")) { - return loadFromJarFile(fileName); - } else if (fileName.endsWith(".class")) { - Set> classes = new HashSet<>(); - loadFromClassFile(fileName, classes); - return classes; - } else { - return scanClassPath(fileName); - } - } - - private Set> loadFromJarFile(String fileName) { - FileSystem fs = makeFileSystem(fileName); - FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString())); - return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder); - } - - private void loadFromClassFile(String fileName, Set> classes) { - Class result; - File file = new File(options.classpath); - try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { - result = loadClassFile(loader, fileName); - } catch (IOException e) { - throw new InternalError(e); - } - Class c = result; - addClass(classes, fileName, c); - } - - private Set> scanClassPath(String fileName) { - Path classPath = Paths.get(options.classpath); - if (!Files.exists(classPath)) { - throw new InternalError("Path does not exist: " + classPath); - } - if (!Files.isDirectory(classPath)) { - throw new InternalError("Path must be a directory: " + classPath); - } - - // Combine class path and file name and see what it is. - Path combinedPath = Paths.get(options.classpath + File.separator + fileName); - if (combinedPath.endsWith(".class")) { - throw new InternalError("unimplemented"); - } else if (Files.isDirectory(combinedPath)) { - return scanDirectory(classPath, combinedPath); - } else { - throw new InternalError("Expecting a .class, .jar or directory: " + fileName); - } - } - - private FileSystem makeFileSystem(String fileName) { - try { - return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>()); - } catch (IOException e) { - throw new InternalError(e); - } - } - - private URI makeJarFileURI(String fileName) { - try { - return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/"); - } catch (URISyntaxException e) { - throw new InternalError(e); - } - } - - private PathMatcher combine(PathMatcher m1, PathMatcher m2) { - return path -> m1.matches(path) && m2.matches(path); - } - - private Set> scanDirectory(Path classPath, Path combinedPath) { - String dir = options.classpath; - - FileSystem fileSystem = FileSystems.getDefault(); - PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class"); - FileSystemFinder finder = new FileSystemFinder(combinedPath, - combine(matcher, pathname -> entryIsClassFile(pathname.toString()))); - - File file = new File(dir); - try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { - return loadClassFiles(classPath, finder, loader); - } catch (IOException e) { - throw new InternalError(e); - } - } - - private Set> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) { - Set> classes = new HashSet<>(); - for (Path name : finder.done()) { - // Now relativize to the class path so we get the actual class names. - String entry = root.relativize(name).normalize().toString(); - Class c = loadClassFile(loader, entry); - addClass(classes, entry, c); - } - return classes; - } - - private void addClass(Set> classes, String name, Class c) { - if (c != null) { - classes.add(c); - log.printlnVerbose(" loaded " + name); - } - } - - private URL[] buildUrls(String fileName) throws MalformedURLException { - return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") }; - } - - private URL[] buildUrls(File file) throws MalformedURLException { - return new URL[] {file.toURI().toURL() }; - } - - private Path getModuleDirectory(String modulepath, String module) { - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - return fs.getPath(modulepath, module); - } - - /** - * Loads a class with the given file name from the specified {@link URLClassLoader}. - */ - private Class loadClassFile(final ClassLoader loader, final String fileName) { - int start = 0; - if (fileName.startsWith("/")) { - start = 1; - } - String className = fileName.substring(start, fileName.length() - ".class".length()); - className = className.replace('/', '.'); - try { - return loader.loadClass(className); - } catch (Throwable e) { - // If we are running in JCK mode we ignore all exceptions. - if (options.ignoreClassLoadingErrors) { - log.printError(className + ": " + e); - return null; - } - throw new InternalError(e); - } - } - - /** - * {@link FileVisitor} implementation to find class files recursively. - */ - private static class FileSystemFinder extends SimpleFileVisitor { - private final ArrayList fileNames = new ArrayList<>(); - private final PathMatcher filter; - - FileSystemFinder(Path combinedPath, PathMatcher filter) { - this.filter = filter; - try { - Files.walkFileTree(combinedPath, this); - } catch (IOException e) { - throw new InternalError(e); - } - } - - /** - * Compares the glob pattern against the file name. - */ - void find(Path file) { - Path name = file.getFileName(); - if (name != null && filter.matches(name)) { - fileNames.add(file); - } - } - - List done() { - return fileNames; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - find(file); - return CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - find(dir); - return CONTINUE; - } - - } -} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java new file mode 100644 index 00000000000..3fd63b2c0b8 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import jdk.tools.jaotc.LoadedClass; + +import java.util.ArrayList; +import java.util.List; + +public class ClassSearch { + private List providers = new ArrayList<>(); + + public void addProvider(SourceProvider provider) { + providers.add(provider); + } + + public List search(List search, SearchPath searchPath) { + List loaded = new ArrayList<>(); + + List sources = new ArrayList<>(); + + for (SearchFor entry : search) { + sources.add(findSource(entry, searchPath)); + } + + for (ClassSource source : sources) { + source.eachClass((name, loader) -> loaded.add(loadClass(name, loader))); + } + + return loaded; + } + + private LoadedClass loadClass(String name, ClassLoader loader) { + try { + Class clzz = loader.loadClass(name); + return new LoadedClass(name, clzz); + } catch (ClassNotFoundException e) { + throw new InternalError("Failed to load with: " + loader, e); + } + } + + private ClassSource findSource(SearchFor searchFor, SearchPath searchPath) { + ClassSource found = null; + + for (SourceProvider provider : providers) { + if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) { + continue; + } + + ClassSource source = provider.findSource(searchFor.getName(), searchPath); + if (source != null) { + if (found != null) { + throw new InternalError("Multiple possible sources: " + source + " and: " + found); + } + found = source; + } + } + + if (found == null) { + throw new InternalError("Failed to find: " + searchFor.toString()); + } + return found; + } + + public static List makeList(String type, String argument) { + List list = new ArrayList<>(); + String[] elements = argument.split(":"); + for (String element : elements) { + list.add(new SearchFor(element, type)); + } + return list; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java new file mode 100644 index 00000000000..8d9b8439760 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public interface ClassSource { + static boolean pathIsClassFile(Path entry) { + String fileName = entry.getFileName().toString(); + return fileName.endsWith(".class") && !fileName.endsWith("module-info.class"); + } + + static String makeClassName(Path path) { + String fileName = path.toString(); + + if (!fileName.endsWith(".class")) { + throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'"); + } + + int start = 0; + if (fileName.startsWith("/")) { + start = 1; + } + + String className = fileName.substring(start, fileName.length() - ".class".length()); + className = className.replace('/', '.'); + return className; + } + + void eachClass(BiConsumer consumer); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java new file mode 100644 index 00000000000..0761c0ae8e1 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.io.IOException; +import java.net.*; +import java.nio.file.*; +import java.util.HashMap; + +public class FileSupport { + public boolean exists(Path path) { + return Files.exists(path); + } + + public boolean isDirectory(Path path) { + return Files.isDirectory(path); + } + + private FileSystem makeJarFileSystem(Path path) { + try { + return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>()); + } catch (IOException e) { + throw new InternalError(e); + } + } + + private URI makeJarFileURI(Path path) { + try { + return new URI("jar:file:" + path.toAbsolutePath() + "!/"); + } catch (URISyntaxException e) { + throw new InternalError(e); + } + } + + public ClassLoader createClassLoader(Path path, ClassLoader parent) { + try { + return URLClassLoader.newInstance(buildUrls(path), parent); + } catch (MalformedURLException e) { + throw new InternalError(e); + } + } + + public ClassLoader createClassLoader(Path path) throws MalformedURLException { + return URLClassLoader.newInstance(buildUrls(path)); + } + + private URL[] buildUrls(Path path) throws MalformedURLException { + return new URL[] { path.toUri().toURL() }; + } + + public Path getJarFileSystemRoot(Path jarFile) { + FileSystem fileSystem = makeJarFileSystem(jarFile); + return fileSystem.getPath("/"); + } + + public boolean isAbsolute(Path entry) { + return entry.isAbsolute(); + } + + public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException { + DirectoryStream paths = fileSystem.provider().newDirectoryStream(root,null); + for (Path entry : paths) { + Path relative = root.relativize(entry); + if (relative.equals(path)) { + return entry; + } + } + return null; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java new file mode 100644 index 00000000000..7838104b89c --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Iterator; + +import static java.nio.file.FileVisitResult.CONTINUE; + +/** + * {@link FileVisitor} implementation to find class files recursively. + */ +public class FileSystemFinder extends SimpleFileVisitor implements Iterable { + private final ArrayList fileNames = new ArrayList<>(); + private final PathMatcher filter; + + public FileSystemFinder(Path combinedPath, PathMatcher filter) { + this.filter = filter; + try { + Files.walkFileTree(combinedPath, this); + } catch (IOException e) { + throw new InternalError(e); + } + } + + /** + * Compares the glob pattern against the file name. + */ + private void find(Path file) { + Path name = file.getFileName(); + if (name != null && filter.matches(name)) { + fileNames.add(file); + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + find(file); + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + find(dir); + return CONTINUE; + } + + + @Override + public Iterator iterator() { + return fileNames.iterator(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java new file mode 100644 index 00000000000..49e0cdd9945 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +public class SearchFor { + private final String name; + private final String type; + + public SearchFor(String name) { + this(name, "unknown"); + } + + public SearchFor(String name, String type) { + this.name = name; + this.type = type; + } + + public boolean isUnknown() { + return "unknown".equals(type); + } + + public String getType() { + return this.type; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return type + ":" + name; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java new file mode 100644 index 00000000000..19442069f16 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class SearchPath { + private final List searchPaths = new ArrayList<>(); + private final FileSupport fileSupport; + + public SearchPath() { + this(new FileSupport()); + } + + public SearchPath(FileSupport fileSupport) { + this.fileSupport = fileSupport; + } + + public Path find(FileSystem fileSystem, Path entry, String... defaults) { + if (isAbsolute(entry)) { + if (exists(entry)) { + return entry; + } + return null; + } + + if (exists(entry)) { + return entry; + } + + for (String searchPath : defaults) { + Path newPath = fileSystem.getPath(searchPath, entry.toString()); + if (exists(newPath)) { + return newPath; + } + } + + for (Path searchPath : searchPaths) { + Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString()); + if (exists(newPath)) { + return newPath; + } + } + + return null; + } + + private boolean isAbsolute(Path entry) { + return fileSupport.isAbsolute(entry); + } + + private boolean exists(Path entry) { + return fileSupport.exists(entry); + } + + public void add(String... paths) { + for (String name : paths) { + Path path = Paths.get(name); + searchPaths.add(path); + } + } +} + diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java new file mode 100644 index 00000000000..5effa83c8fa --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect; + +public interface SourceProvider { + ClassSource findSource(String name, SearchPath searchPath); + + boolean supports(String type); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java new file mode 100644 index 00000000000..22227d03882 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.classname; + +import jdk.tools.jaotc.collect.ClassSource; + +import java.util.function.BiConsumer; + +public class ClassNameSource implements ClassSource { + private final String name; + private final ClassLoader classLoader; + + public ClassNameSource(String name, ClassLoader classLoader) { + this.name = name; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + consumer.accept(name, classLoader); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java new file mode 100644 index 00000000000..b5bc2804ed4 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.classname; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ClassNameSourceProvider implements SourceProvider { + public final static String TYPE = "classname"; + private final ClassLoader classLoader; + + public ClassNameSourceProvider(FileSupport fileSupport) { + String classPath = System.getProperty("java.class.path"); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + if (classPath != null && !classPath.isEmpty()) { + classLoader = systemClassLoader; + } else { + Path path = Paths.get(".").toAbsolutePath(); + classLoader = fileSupport.createClassLoader(path, systemClassLoader); + } + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + try { + classLoader.loadClass(name); + return new ClassNameSource(name, classLoader); + } catch (ClassNotFoundException e) { + return null; + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java new file mode 100644 index 00000000000..8e5cdb5bc47 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class DirectorySource implements ClassSource { + private final Path directoryPath; + private final ClassLoader classLoader; + + public DirectorySource(Path directoryPath, ClassLoader classLoader) { + this.directoryPath = directoryPath; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader); + } + } + + @Override + public String toString() { + return "directory:" + directoryPath.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java new file mode 100644 index 00000000000..013e3858830 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.net.MalformedURLException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +public class DirectorySourceProvider implements SourceProvider { + private final FileSupport fileSupport; + private final FileSystem fileSystem; + public final static String TYPE = "directory"; + + public DirectorySourceProvider(FileSupport fileSupport) { + this.fileSupport = fileSupport; + fileSystem = FileSystems.getDefault(); + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path directoryPath = fileSystem.getPath(name); + + if (!fileSupport.exists(directoryPath)) { + return null; + } + if (!fileSupport.isDirectory(directoryPath)) { + return null; + } + + try { + ClassLoader classLoader = fileSupport.createClassLoader(directoryPath); + return new DirectorySource(directoryPath, classLoader); + } catch (MalformedURLException e) { + return null; + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java new file mode 100644 index 00000000000..af7330a53b8 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class JarFileSource implements ClassSource { + private final Path jarFile; + private final Path jarRootPath; + private final ClassLoader classLoader; + + + public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) { + this.jarFile = jarFile; + this.jarRootPath = jarRootPath; + this.classLoader = classLoader; + } + + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader); + } + } + + @Override + public String toString() { + return "jar:" + jarFile.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java new file mode 100644 index 00000000000..f876c740b74 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.net.MalformedURLException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; + +public class JarSourceProvider implements SourceProvider { + private final FileSystem fileSystem; + private final FileSupport fileSupport; + public final static String TYPE = "jar"; + + public JarSourceProvider() { + this(new FileSupport()); + } + + public JarSourceProvider(FileSupport fileSupport) { + this.fileSupport = fileSupport; + fileSystem = FileSystems.getDefault(); + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path fileName = fileSystem.getPath(name); + Path jarFile = searchPath.find(fileSystem, fileName); + + if (!validPath(jarFile)) { + return null; + } + + return createSource(jarFile); + } + + private ClassSource createSource(Path jarFile) { + try { + Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile); + if (jarRootPath == null) { + return null; + } + ClassLoader classLoader = fileSupport.createClassLoader(jarFile); + return new JarFileSource(jarFile, jarRootPath, classLoader); + } catch (ProviderNotFoundException | MalformedURLException e) { + } + return null; + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } + + private boolean validPath(Path jarFile) { + return jarFile != null && !fileSupport.isDirectory(jarFile); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java new file mode 100644 index 00000000000..bac5624ab6a --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.module; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class ModuleSource implements ClassSource { + private final Path modulePath; + private final ClassLoader classLoader; + + public ModuleSource(Path modulePath, ClassLoader classLoader) { + this.modulePath = modulePath; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader); + } + } + + public Path getModulePath() { + return modulePath; + } + + @Override + public String toString() { + return "module:" + modulePath.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java new file mode 100644 index 00000000000..cd1a464b6f9 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.tools.jaotc.collect.module; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +public class ModuleSourceProvider implements SourceProvider { + private final FileSystem fileSystem; + private final ClassLoader classLoader; + private final FileSupport fileSupport; + public final static String TYPE = "module"; + + public ModuleSourceProvider() { + this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport()); + } + + public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) { + this.fileSystem = fileSystem; + this.classLoader = classLoader; + this.fileSupport = fileSupport; + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path path = fileSystem.getPath(name); + Path dir = fileSystem.getPath("modules"); + + if (dir == null || !fileSupport.isDirectory(dir)) { + return null; + } + + Path found = findModuleDirectory(dir, path); + + if (found == null) { + return null; + } + + return new ModuleSource(found, classLoader); + } + + private Path findModuleDirectory(Path root, Path path) { + try { + return fileSupport.getSubDirectory(fileSystem, root, path); + } catch (IOException e) { + throw new InternalError(e); + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index f92f91b7c78..e0b5acb426f 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -100,15 +100,19 @@ final class CompilerToVM { native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method); /** - * Determines if {@code method} can be inlined. A method may not be inlinable for a number of - * reasons such as: - *
    - *
  • a CompileOracle directive may prevent inlining or compilation of methods
  • - *
  • the method may have a bytecode breakpoint set
  • - *
  • the method may have other bytecode features that require special handling by the VM
  • - *
+ * Determines whether {@code method} is currently compilable by the JVMCI compiler being used by + * the VM. This can return false if JVMCI compilation failed earlier for {@code method}, a + * breakpoint is currently set in {@code method} or {@code method} contains other bytecode + * features that require special handling by the VM. */ - native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method); + native boolean isCompilable(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} is targeted by a VM directive (e.g., + * {@code -XX:CompileCommand=dontinline,}) or annotation (e.g., + * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined. + */ + native boolean hasNeverInlineDirective(HotSpotResolvedJavaMethodImpl method); /** * Determines if {@code method} should be inlined at any cost. This could be because: diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java index dc56435038a..af75f81a2ff 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java @@ -49,13 +49,6 @@ public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { */ boolean isForceInline(); - /** - * Returns true if this method has a {@code DontInline} annotation. - * - * @return true if DontInline annotation present, false otherwise - */ - boolean isDontInline(); - /** * Returns true if this method has a {@code ReservedStackAccess} annotation. * diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index ad4c67d0275..393b740a71e 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -298,15 +298,6 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp return (getFlags() & config().methodFlagsForceInline) != 0; } - /** - * Returns true if this method has a {@code DontInline} annotation. - * - * @return true if DontInline annotation present, false otherwise - */ - public boolean isDontInline() { - return (getFlags() & config().methodFlagsDontInline) != 0; - } - /** * Returns true if this method has a {@code ReservedStackAccess} annotation. * @@ -582,10 +573,15 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp @Override public boolean canBeInlined() { - if (isDontInline()) { + if (hasNeverInlineDirective()) { return false; } - return compilerToVM().canInlineMethod(this); + return compilerToVM().isCompilable(this); + } + + @Override + public boolean hasNeverInlineDirective() { + return compilerToVM().hasNeverInlineDirective(this); } @Override diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java index 6d13d911398..dee43ffbc6a 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -346,6 +346,13 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP */ boolean canBeInlined(); + /** + * Determines if this method is targeted by a VM directive (e.g., + * {@code -XX:CompileCommand=dontinline,}) or VM recognized annotation (e.g., + * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined. + */ + boolean hasNeverInlineDirective(); + /** * Returns {@code true} if the inlining of this method should be forced. */ diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py index 402eae2dae5..dda989acedf 100644 --- a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py @@ -638,6 +638,7 @@ suite = { "annotationProcessors" : [ "GRAAL_NODEINFO_PROCESSOR", "GRAAL_REPLACEMENTS_VERIFIER", + "GRAAL_OPTIONS_PROCESSOR", ], "workingSets" : "Graal,Graph", }, diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java index f5a3758f066..cd5e7fca7ae 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java @@ -116,6 +116,7 @@ public class Debug { public static final int INFO_LOG_LEVEL = 2; public static final int VERBOSE_LOG_LEVEL = 3; public static final int DETAILED_LOG_LEVEL = 4; + public static final int VERY_DETAILED_LOG_LEVEL = 5; public static boolean isDumpEnabled(int dumpLevel) { return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel); diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 4ccc1bbc9ef..7cb4b03b27e 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -267,10 +267,15 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend { if (config.useCompressedClassPointers) { Register register = r10; - AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding()); - if (config.narrowKlassBase != 0) { - // The heap base register was destroyed above, so restore it - asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config); + if (GeneratePIC.getValue()) { + asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS); + } else { + if (config.narrowKlassBase != 0) { + // The heap base register was destroyed above, so restore it + asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + } } asm.cmpq(inlineCacheKlass, register); } else { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java index f7a5f205c26..168282ebcbf 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java @@ -265,14 +265,21 @@ public class AMD64HotSpotMove { } } - public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) { + public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) { + CompressEncoding encoding = config.getKlassEncoding(); masm.movl(register, address); if (encoding.shift != 0) { assert encoding.alignment == encoding.shift : "Decode algorithm is wrong"; masm.shlq(register, encoding.alignment); } - if (encoding.base != 0) { - masm.movq(scratch, encoding.base); + if (GeneratePIC.getValue() || encoding.base != 0) { + if (GeneratePIC.getValue()) { + masm.movq(scratch, masm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS); + } else { + assert encoding.base != 0; + masm.movq(scratch, encoding.base); + } masm.addq(register, scratch); } } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java new file mode 100644 index 00000000000..3a93d463936 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; + +public class AOTGraalHotSpotVMConfig extends GraalHotSpotVMConfig { + private final CompressEncoding aotOopEncoding; + private final CompressEncoding aotKlassEncoding; + + public AOTGraalHotSpotVMConfig(HotSpotVMConfigStore store) { + super(store); + // In AOT, force the shift to be always equal to alignment therefore avoiding zero-shift. + CompressEncoding vmOopEncoding = super.getOopEncoding(); + aotOopEncoding = new CompressEncoding(vmOopEncoding.base, vmOopEncoding.alignment, vmOopEncoding.alignment); + CompressEncoding vmKlassEncoding = super.getKlassEncoding(); + aotKlassEncoding = new CompressEncoding(vmKlassEncoding.base, vmKlassEncoding.alignment, vmKlassEncoding.alignment); + assert check(); + } + + @Override + public CompressEncoding getOopEncoding() { + return aotOopEncoding; + } + + @Override + public CompressEncoding getKlassEncoding() { + return aotKlassEncoding; + } +} diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index e7ce8f68cce..898d688747d 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -479,7 +479,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*"); - public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class); public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class); public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class); public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class); @@ -773,13 +772,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17); public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18); public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19); - public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20); - public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21); - public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22); + public final int MARKID_NARROW_OOP_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_OOP_BASE_ADDRESS", Integer.class, 20); + public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 21); + public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 22); + public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 23); // Checkstyle: resume - private boolean check() { + protected boolean check() { for (Field f : getClass().getDeclaredFields()) { int modifiers = f.getModifiers(); if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index 01401eafd4a..401169124f4 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.hotspot; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled; import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary; import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump; @@ -99,7 +100,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) { HotSpotVMConfigStore store = jvmciRuntime.getConfigStore(); - config = new GraalHotSpotVMConfig(store); + config = GeneratePIC.getValue() ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store); CompileTheWorldOptions.overrideWithNativeOptions(config); // Only set HotSpotPrintInlining if it still has its default value (false). diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java index 89729e7e3f4..10b2255a3dc 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode; @@ -112,11 +111,6 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin { return true; } } - if (GeneratePIC.getValue()) { - if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) { - return tryReadField(b, field, null); - } - } if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) { return true; } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index bba5c70cfe4..7ace642641e 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -1738,9 +1738,8 @@ public class BytecodeParser implements GraphBuilderContext { } else { // Intrinsic was not applied: remove intrinsic guard // and restore the original receiver node in the arguments array - for (Node node : graph.getNewNodes(intrinsicGuard.mark)) { - GraphUtil.killCFG(node); - } + intrinsicGuard.lastInstr.setNext(null); + GraphUtil.removeNewNodes(graph, intrinsicGuard.mark); lastInstr = intrinsicGuard.lastInstr; args[0] = intrinsicGuard.receiver; } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java index f26b3004799..f2f833d2a90 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java @@ -153,9 +153,7 @@ public class SimplifyingGraphDecoder extends GraphDecoder { } for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) { - if (!(node instanceof FixedNode) && node.hasNoUsages()) { - GraphUtil.killCFG(node); - } + GraphUtil.tryKillUnused(node); } } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java index af89e2711de..61603208b96 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java @@ -506,7 +506,7 @@ public class StructuredGraph extends Graph implements JavaMethodContext { for (Node successor : snapshot) { if (successor != null && successor.isAlive()) { if (successor != survivingSuccessor) { - GraphUtil.killCFG(successor, tool); + GraphUtil.killCFG((FixedNode) successor, tool); } } } @@ -566,6 +566,9 @@ public class StructuredGraph extends Graph implements JavaMethodContext { reduceTrivialMerge(begin); } else { // convert to merge AbstractMergeNode merge = this.add(new MergeNode()); + for (EndNode end : begin.forwardEnds()) { + merge.addForwardEnd(end); + } this.replaceFixedWithFixed(begin, merge); } } @@ -576,7 +579,14 @@ public class StructuredGraph extends Graph implements JavaMethodContext { for (PhiNode phi : merge.phis().snapshot()) { assert phi.valueCount() == 1; ValueNode singleValue = phi.valueAt(0); - phi.replaceAtUsagesAndDelete(singleValue); + if (phi.hasUsages()) { + phi.replaceAtUsagesAndDelete(singleValue); + } else { + phi.safeDelete(); + if (singleValue != null) { + GraphUtil.tryKillUnused(singleValue); + } + } } // remove loop exits if (merge instanceof LoopBeginNode) { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java index f942d8c2358..210c5f793da 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,18 +22,30 @@ */ package org.graalvm.compiler.nodes.util; +import static org.graalvm.compiler.graph.Graph.Options.VerifyGraalGraphEdges; +import static org.graalvm.compiler.nodes.util.GraphUtil.Options.VerifyKillCFGUnusedNodes; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; +import java.util.Set; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.code.SourceStackTraceBailoutException; +import org.graalvm.compiler.core.common.CollectionsFactory; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeWorkList; +import org.graalvm.compiler.graph.Position; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -48,11 +60,15 @@ import org.graalvm.compiler.nodes.ProxyNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; import org.graalvm.compiler.nodes.spi.LimitedValueProxy; import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.ValueProxy; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodePosition; @@ -64,22 +80,78 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public class GraphUtil { - public static void killCFG(Node node, SimplifierTool tool) { - NodeWorkList worklist = killCFG(node, tool, null); - if (worklist != null) { - for (Node successor : worklist) { - killCFG(successor, tool, worklist); + public static class Options { + @Option(help = "Verify that there are no new unused nodes when performing killCFG", type = OptionType.Debug)// + public static final OptionValue VerifyKillCFGUnusedNodes = new OptionValue<>(false); + } + + @SuppressWarnings("try") + public static void killCFG(FixedNode node, SimplifierTool tool) { + try (Debug.Scope scope = Debug.scope("KillCFG", node)) { + Set unusedNodes = null; + Set unsafeNodes = null; + Graph.NodeEventScope nodeEventScope = null; + if (VerifyGraalGraphEdges.getValue()) { + unsafeNodes = collectUnsafeNodes(node.graph()); + } + if (VerifyKillCFGUnusedNodes.getValue()) { + Set collectedUnusedNodes = unusedNodes = CollectionsFactory.newSet(); + nodeEventScope = node.graph().trackNodeEvents(new Graph.NodeEventListener() { + @Override + public void event(Graph.NodeEvent e, Node n) { + if (e == Graph.NodeEvent.ZERO_USAGES && isFloatingNode(n)) { + collectedUnusedNodes.add(n); + } + } + }); + } + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "Before killCFG %s", node); + NodeWorkList worklist = killCFG(node, tool, null); + if (worklist != null) { + for (Node n : worklist) { + killCFG(n, tool, worklist); + } + } + if (VerifyGraalGraphEdges.getValue()) { + Set newUnsafeNodes = collectUnsafeNodes(node.graph()); + newUnsafeNodes.removeAll(unsafeNodes); + assert newUnsafeNodes.isEmpty() : "New unsafe nodes: " + newUnsafeNodes; + } + if (VerifyKillCFGUnusedNodes.getValue()) { + nodeEventScope.close(); + unusedNodes.removeIf(n -> n.isDeleted()); + assert unusedNodes.isEmpty() : "New unused nodes: " + unusedNodes; + } + } catch (Throwable t) { + throw Debug.handle(t); + } + } + + /** + * Collects all node in the graph which have non-optional inputs that are null. + */ + private static Set collectUnsafeNodes(Graph graph) { + Set unsafeNodes = CollectionsFactory.newSet(); + for (Node n : graph.getNodes()) { + for (Position pos : n.inputPositions()) { + Node input = pos.get(n); + if (input == null) { + if (!pos.isInputOptional()) { + unsafeNodes.add(n); + } + } } } + return unsafeNodes; } private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) { NodeWorkList newWorklist = worklist; - // DebugScope.forceDump(node.graph(), "kill CFG %s", node); if (node instanceof FixedNode) { newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool); } else { - propagateKill(node); + newWorklist = propagateKill(node, newWorklist); + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "killCFG (Floating) %s", node); } return newWorklist; } @@ -93,19 +165,20 @@ public class GraphUtil { if (current instanceof AbstractEndNode) { // We reached a control flow end. AbstractEndNode end = (AbstractEndNode) current; - killEnd(end, tool); + newWorklist = killEnd(end, newWorklist, tool); } else if (current instanceof FixedWithNextNode) { - next = ((FixedWithNextNode) current).next(); + // Node guaranteed to have a single successor + FixedWithNextNode fixedWithNext = (FixedWithNextNode) current; + assert fixedWithNext.successors().count() == 1 || fixedWithNext.successors().count() == 0; + assert fixedWithNext.successors().first() == fixedWithNext.next(); + next = fixedWithNext.next(); } else { - // Normal control flow node. /* * We do not take a successor snapshot because this iterator supports concurrent * modifications as long as they do not change the size of the successor list. Not * taking a snapshot allows us to see modifications to other branches that may * happen while processing one branch. */ - // assert node.successors().count() > 1 || node.successors().count() == 0 : - // node.getClass(); Iterator successors = current.successors().iterator(); if (successors.hasNext()) { Node first = successors.next(); @@ -126,100 +199,158 @@ public class GraphUtil { } } current.replaceAtPredecessor(null); - propagateKill(current); + newWorklist = propagateKill(current, newWorklist); + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, current.graph(), "killCFGLinear %s", current); current = next; } + Debug.dump(Debug.DETAILED_LOG_LEVEL, in.graph(), "killCFGLinear %s", in); return newWorklist; } - public static void killCFG(Node node) { + public static void killCFG(FixedNode node) { killCFG(node, null); } - private static void killEnd(AbstractEndNode end, SimplifierTool tool) { + /** + * Node type used temporarily while deleting loops. + * + * It is used as replacement for the loop {@link PhiNode PhiNodes} in order to break data-flow + * cycles before deleting the loop. The control-flow of the whole loop is killed before killing + * the poison node if they are still alive. + */ + @NodeInfo(allowedUsageTypes = InputType.Unchecked) + private static final class PoisonNode extends FloatingNode { + public static final NodeClass TYPE = NodeClass.create(PoisonNode.class); + + protected PoisonNode() { + super(TYPE, StampFactory.forVoid()); + } + } + + private static NodeWorkList killEnd(AbstractEndNode end, NodeWorkList worklist, SimplifierTool tool) { + NodeWorkList newWorklist = worklist; AbstractMergeNode merge = end.merge(); if (merge != null) { merge.removeEnd(end); StructuredGraph graph = end.graph(); if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { // dead loop - for (PhiNode phi : merge.phis().snapshot()) { - propagateKill(phi); - } LoopBeginNode begin = (LoopBeginNode) merge; // disconnect and delete loop ends & loop exits for (LoopEndNode loopend : begin.loopEnds().snapshot()) { loopend.predecessor().replaceFirstSuccessor(loopend, null); loopend.safeDelete(); } - begin.removeExits(); - FixedNode loopBody = begin.next(); - if (loopBody != null) { // for small infinite loops, the body may be killed while - // killing the loop ends - killCFG(loopBody); + // clean unused proxies to avoid creating new unused nodes + for (LoopExitNode exit : begin.loopExits()) { + for (ProxyNode vpn : exit.proxies().snapshot()) { + tryKillUnused(vpn); + } } + begin.removeExits(); + PoisonNode poison = null; + if (merge.phis().isNotEmpty()) { + poison = graph.unique(new PoisonNode()); + for (PhiNode phi : merge.phis()) { + phi.replaceAtUsages(poison); + } + for (PhiNode phi : merge.phis().snapshot()) { + killWithUnusedFloatingInputs(phi); + } + } + FixedNode loopBody = begin.next(); + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, end.graph(), "killEnd (Loop) %s after initial loop cleanup", end); + if (loopBody != null) { + // for small infinite loops, the body may already be killed while killing the + // LoopEnds + newWorklist = killCFG(loopBody, tool, worklist); + } + FrameState frameState = begin.stateAfter(); begin.safeDelete(); + if (frameState != null) { + tryKillUnused(frameState); + } + if (poison != null && poison.isAlive()) { + if (newWorklist == null) { + newWorklist = graph.createNodeWorkList(); + } + // drain the worklist to finish the loop before adding the poison + for (Node n : newWorklist) { + killCFG(n, tool, newWorklist); + } + if (poison.isAlive()) { + newWorklist.add(poison); + } + } } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore if (tool != null) { - merge.phis().forEach(phi -> tool.addToWorkList(phi.usages())); + for (PhiNode phi : merge.phis()) { + tool.addToWorkList(phi.usages()); + } } graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore if (tool != null) { - merge.phis().forEach(phi -> tool.addToWorkList(phi.usages())); + for (PhiNode phi : merge.phis()) { + tool.addToWorkList(phi.usages()); + } } graph.reduceTrivialMerge(merge); } } + return newWorklist; } public static boolean isFloatingNode(Node n) { return !(n instanceof FixedNode); } - private static void propagateKill(Node node) { + private static NodeWorkList propagateKill(Node node, NodeWorkList workList) { + NodeWorkList newWorkList = workList; if (node != null && node.isAlive()) { - node.markDeleted(); - - for (Node in : node.inputs()) { - if (in.isAlive()) { - in.removeUsage(node); - if (in.hasNoUsages() && !(in instanceof FixedNode)) { - killWithUnusedFloatingInputs(in); - } - } - } - - ArrayList usageToKill = null; - for (Node usage : node.usages()) { - if (usage.isAlive() && !(usage instanceof FixedNode)) { - if (usageToKill == null) { - usageToKill = new ArrayList<>(); - } - usageToKill.add(usage); - } - } - if (usageToKill != null) { - for (Node usage : usageToKill) { - if (usage.isAlive()) { - if (usage instanceof PhiNode) { - PhiNode phiNode = (PhiNode) usage; - usage.replaceFirstInput(node, null); - if (phiNode.merge() == null || !phiNode.hasValidInput()) { - propagateKill(usage); - } + for (Node usage : node.usages().snapshot()) { + assert usage.isAlive(); + if (isFloatingNode(usage)) { + boolean addUsage = false; + if (usage instanceof PhiNode) { + PhiNode phi = (PhiNode) usage; + assert phi.merge() != null; + if (phi.merge() == node) { + // we reach the phi directly through he merge, queue it. + addUsage = true; } else { - propagateKill(usage); + // we reach it though a value + assert phi.values().contains(node); + // let that be handled when we reach the corresponding End node } + } else { + addUsage = true; + } + if (addUsage) { + if (newWorkList == null) { + newWorkList = node.graph().createNodeWorkList(); + } + newWorkList.add(usage); } } + usage.replaceFirstInput(node, null); } + killWithUnusedFloatingInputs(node); } + return newWorkList; + } + + private static boolean checkKill(Node node) { + node.assertTrue(node.isAlive(), "must be alive"); + node.assertTrue(node.hasNoUsages(), "cannot kill node %s because of usages: %s", node, node.usages()); + node.assertTrue(node.predecessor() == null, "cannot kill node %s because of predecessor: %s", node, node.predecessor()); + return true; } public static void killWithUnusedFloatingInputs(Node node) { + assert checkKill(node); node.markDeleted(); outer: for (Node in : node.inputs()) { if (in.isAlive()) { @@ -227,7 +358,7 @@ public class GraphUtil { if (in.hasNoUsages()) { node.maybeNotifyZeroUsages(in); } - if (!(in instanceof FixedNode)) { + if (isFloatingNode(in)) { if (in.hasNoUsages()) { killWithUnusedFloatingInputs(in); } else if (in instanceof PhiNode) { @@ -244,6 +375,35 @@ public class GraphUtil { } } + /** + * Removes all nodes created after the {@code mark}, assuming no "old" nodes point to "new" + * nodes. + */ + public static void removeNewNodes(Graph graph, Graph.Mark mark) { + assert checkNoOldToNewEdges(graph, mark); + for (Node n : graph.getNewNodes(mark)) { + n.markDeleted(); + for (Node in : n.inputs()) { + in.removeUsage(n); + } + } + } + + private static boolean checkNoOldToNewEdges(Graph graph, Graph.Mark mark) { + for (Node old : graph.getNodes()) { + if (graph.isNew(mark, old)) { + break; + } + for (Node n : old.successors()) { + assert !graph.isNew(mark, n) : old + " -> " + n; + } + for (Node n : old.inputs()) { + assert !graph.isNew(mark, n) : old + " -> " + n; + } + } + return true; + } + public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) { if (fixed instanceof StateSplit) { FrameState stateAfter = ((StateSplit) fixed).stateAfter(); @@ -688,8 +848,9 @@ public class GraphUtil { @Override public void deleteBranch(Node branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch, this); + FixedNode fixedBranch = (FixedNode) branch; + fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); + GraphUtil.killCFG(fixedBranch, this); } @Override diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java index 35c0a41a7fb..d57d0d45c7a 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java @@ -444,8 +444,9 @@ public class CanonicalizerPhase extends BasePhase { @Override public void deleteBranch(Node branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch, this); + FixedNode fixedBranch = (FixedNode) branch; + fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); + GraphUtil.killCFG(fixedBranch, this); } @Override diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index e900ce0af77..014d306e37f 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -632,7 +632,6 @@ void os::Aix::signal_sets_init() { sigaddset(&unblocked_sigs, SIGBUS); sigaddset(&unblocked_sigs, SIGFPE); sigaddset(&unblocked_sigs, SIGTRAP); - sigaddset(&unblocked_sigs, SIGDANGER); sigaddset(&unblocked_sigs, SR_signum); if (!ReduceSignalUsage) { @@ -1553,6 +1552,8 @@ void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) { print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen); print_signal_handler(st, BREAK_SIGNAL, buf, buflen); print_signal_handler(st, SIGTRAP, buf, buflen); + // We also want to know if someone else adds a SIGDANGER handler because + // that will interfere with OOM killling. print_signal_handler(st, SIGDANGER, buf, buflen); } @@ -3156,7 +3157,6 @@ void os::Aix::install_signal_handlers() { set_signal_handler(SIGFPE, true); set_signal_handler(SIGTRAP, true); set_signal_handler(SIGXFSZ, true); - set_signal_handler(SIGDANGER, true); if (libjsig_is_loaded) { // Tell libjsig jvm finishes setting signal handlers. @@ -3273,7 +3273,6 @@ void os::run_periodic_checks() { if (UseSIGTRAP) { DO_SIGNAL_CHECK(SIGTRAP); } - DO_SIGNAL_CHECK(SIGDANGER); // ReduceSignalUsage allows the user to override these handlers // see comments at the very top and jvm_solaris.h diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 5142cd37a25..23ad8e209cb 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -778,6 +778,11 @@ void os::set_native_thread_name(const char *name) { // is already attached to a debugger; debugger must observe // the exception below to show the correct name. + // If there is no debugger attached skip raising the exception + if (!IsDebuggerPresent()) { + return; + } + const DWORD MS_VC_EXCEPTION = 0x406D1388; struct { DWORD dwType; // must be 0x1000 diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp index 9bbb9387c54..721d99668b4 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,13 +258,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec } } - // Handle SIGDANGER right away. AIX would raise SIGDANGER whenever available swap - // space falls below 30%. This is only a chance for the process to gracefully abort. - // We can't hope to proceed after SIGDANGER since SIGKILL tailgates. - if (sig == SIGDANGER) { - goto report_and_die; - } - if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) { goto run_chained_handler; } diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp index 24c124a4e8d..7767cecf0e4 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp @@ -87,6 +87,7 @@ #define SPELL_REG_FP "rbp" #else #define REG_FP 29 +#define REG_LR 30 #define SPELL_REG_SP "sp" #define SPELL_REG_FP "x29" @@ -182,6 +183,46 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, fp, epc.pc()); } +bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Linux::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + // interpreter performs stack banging after the fixed frame header has + // been generated while the compilers perform it before. To maintain + // semantic consistency between interpreted and compiled frames, the + // method returns the Java sender of the current frame. + *fr = os::fetch_frame_from_context(uc); + if (!fr->is_first_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } else { + // more complex code with compiled code + assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { + // Not sure where the pc points to, fallback to default + // stack overflow handling + return false; + } else { + // In compiled code, the stack banging is performed before LR + // has been saved in the frame. LR is live, and SP and FP + // belong to the caller. + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + address pc = (address)(uc->uc_mcontext.regs[REG_LR] + - NativeInstruction::instruction_size); + *fr = frame(sp, fp, pc); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + assert(!fr->is_first_frame(), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + // By default, gcc always saves frame pointer rfp on this stack. This // may get turned off by -fomit-frame-pointer. frame os::get_sender_for_C_frame(frame* fr) { @@ -313,6 +354,24 @@ JVM_handle_linux_signal(int sig, if (thread->in_stack_yellow_reserved_zone(addr)) { thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be a Java frame"); + frame activation = + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + if (activation.sp() != NULL) { + thread->disable_stack_reserved_zone(); + if (activation.is_interpreted_frame()) { + thread->set_reserved_stack_activation((address)( + activation.fp() + frame::interpreter_frame_initial_sp_offset)); + } else { + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return 1; + } + } + } // Throw a stack overflow exception. Guard pages will be reenabled // while unwinding the stack. stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); diff --git a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp index 684853cfd34..e9120a8b696 100644 --- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp +++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp @@ -144,6 +144,42 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, epc.pc()); } +bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Linux::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + // Interpreter performs stack banging after the fixed frame header has + // been generated while the compilers perform it before. To maintain + // semantic consistency between interpreted and compiled frames, the + // method returns the Java sender of the current frame. + *fr = os::fetch_frame_from_context(uc); + if (!fr->is_first_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } else { + // More complex code with compiled code. + assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { + // Not sure where the pc points to, fallback to default + // stack overflow handling. In compiled code, we bang before + // the frame is complete. + return false; + } else { + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + *fr = frame(sp, (address)*sp); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + assert(!fr->is_first_frame(), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + frame os::get_sender_for_C_frame(frame* fr) { if (*fr->sp() == 0) { // fr is the last C frame. @@ -279,13 +315,31 @@ JVM_handle_linux_signal(int sig, if (thread->on_local_stack(addr)) { // stack overflow if (thread->in_stack_yellow_reserved_zone(addr)) { - thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be a Javac frame"); + frame activation = + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + if (activation.sp() != NULL) { + thread->disable_stack_reserved_zone(); + if (activation.is_interpreted_frame()) { + thread->set_reserved_stack_activation((address)activation.fp()); + } else { + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return 1; + } + } + } // Throw a stack overflow exception. // Guard pages will be reenabled while unwinding the stack. + thread->disable_stack_yellow_reserved_zone(); stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); } else { // Thread was in the vm or native code. Return and try to finish. + thread->disable_stack_yellow_reserved_zone(); return 1; } } else if (thread->in_stack_red_zone(addr)) { diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index f5c0ff370a0..5fcd2de83df 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -89,7 +89,10 @@ // Minimum usable stack sizes required to get to user code. Space for // HotSpot guard pages is added later. #ifdef _LP64 -size_t os::Posix::_compiler_thread_min_stack_allowed = 202 * K; +// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler +// threads requires a large stack with the Solaris Studio C++ compiler version 5.13 +// and product VM builds (debug builds require significantly less stack space). +size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K; size_t os::Posix::_java_thread_min_stack_allowed = 48 * K; size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K; #else diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index d9e8726bb58..3bc1fa6aec8 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -650,6 +650,7 @@ bool InstructForm::is_wide_memory_kill(FormDict &globals) const { if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true; + if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true; if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true; if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true; diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index 08283a92fbe..52e2c8d55b1 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -25,6 +25,7 @@ #include "aot/aotCodeHeap.hpp" #include "aot/aotLoader.hpp" +#include "classfile/javaAssertions.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/shared/gcLocker.hpp" #include "interpreter/abstractInterpreter.hpp" @@ -294,6 +295,8 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data // When the AOT compiler compiles something big we fail to generate metadata // in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end. // In all successful cases we always have 2 entries of scope pcs. + log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string()); + _code_to_aot[code_id]._state = invalid; return; } @@ -536,6 +539,7 @@ void AOTCodeHeap::link_global_lib_symbols() { SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL)); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page()); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base()); + SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base()); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc()); link_shared_runtime_symbols(); @@ -706,6 +710,12 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { return false; } + if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) { + log_trace(aot, class, load)("class %s in %s does not have java assertions in compiled code, but assertions are enabled for this execution.", kh->internal_name(), _lib->name()); + sweep_dependent_methods(klass_data); + return false; + } + NOT_PRODUCT( aot_klasses_found++; ) log_trace(aot, class, load)("found %s in %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread)); @@ -714,7 +724,7 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { // Set klass's Resolve (second) got cell. _metaspace_got[klass_data->_got_index] = kh(); - // Initialize global symbols of the DSO to the correspondingVM symbol values. + // Initialize global symbols of the DSO to the corresponding VM symbol values. link_global_lib_symbols(); int methods_offset = klass_data->_compiled_methods_offset; diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.hpp b/hotspot/src/share/vm/aot/aotCodeHeap.hpp index 21ce9a042f0..0e0d0038d10 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp @@ -88,7 +88,7 @@ typedef struct { } AOTHeader; typedef struct { - enum { CONFIG_SIZE = 11 + 7 * 4 }; + enum { CONFIG_SIZE = 12 + 7 * 4 }; int _config_size; int _narrowOopShift; int _narrowKlassShift; @@ -108,6 +108,7 @@ typedef struct { bool _tieredAOT; bool _enableContended; bool _restrictContended; + bool _omitAssertions; } AOTConfiguration; class AOTLib : public CHeapObj { diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 75a4f8aa3de..1a0a5f63687 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3298,7 +3298,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) // for osr compile, bailout if some requirements are not fulfilled if (osr_bci != -1) { BlockBegin* osr_block = blm.bci2block()->at(osr_bci); - assert(osr_block->is_set(BlockBegin::was_visited_flag),"osr entry must have been visited for osr compile"); + if (!osr_block->is_set(BlockBegin::was_visited_flag)) { + BAILOUT("osr entry must have been visited for osr compile"); + } // check if osr entry point has empty stack - we cannot handle non-empty stacks at osr entry points if (!osr_block->state()->stack_is_empty()) { diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp index f7916cb1dab..e960d142abe 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp @@ -895,8 +895,32 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl ciMethod* target = s.get_method(ignored_will_link, &declared_signature); ciKlass* holder = s.get_declared_method_holder(); assert(declared_signature != NULL, "cannot be null"); - // Push appendix argument, if one. - if (s.has_appendix()) { + // If the current bytecode has an attached appendix argument, + // push an unknown object to represent that argument. (Analysis + // of dynamic call sites, especially invokehandle calls, needs + // the appendix argument on the stack, in addition to "regular" arguments + // pushed onto the stack by bytecode instructions preceding the call.) + // + // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s) + // method to determine whether the current bytecode has an appendix argument. + // The has_appendix() method obtains the appendix from the + // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with + // resolution of dynamic call sites. Callees in the + // ciBytecodeStream::get_method() call above also access the _f1 field; + // interleaving the get_method() and has_appendix() calls in the current + // method with call site resolution can lead to an inconsistent view of + // the current method's argument count. In particular, some interleaving(s) + // can cause the method's argument count to not include the appendix, which + // then leads to stack over-/underflow in the escape analyzer. + // + // Instead of pushing the argument if has_appendix() is true, the escape analyzer + // pushes an appendix for all call sites targeted by invokedynamic and invokehandle + // instructions, except if the call site is the _invokeBasic intrinsic + // (that intrinsic is always targeted by an invokehandle instruction but does + // not have an appendix argument). + if (target->is_loaded() && + Bytecodes::has_optional_appendix(s.cur_bc_raw()) && + target->intrinsic_id() != vmIntrinsics::_invokeBasic) { state.apush(unknown_obj); } // Pass in raw bytecode because we need to see invokehandle instructions. diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 2580f40f3ea..f16948e71d7 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -136,15 +136,19 @@ class ciMethod : public ciMetadata { check_is_loaded(); return _signature->size() + (_flags.is_static() ? 0 : 1); } - // Report the number of elements on stack when invoking this method. - // This is different than the regular arg_size because invokedynamic - // has an implicit receiver. + // Report the number of elements on stack when invoking the current method. + // If the method is loaded, arg_size() gives precise information about the + // number of stack elements (using the method's signature and its flags). + // However, if the method is not loaded, the number of stack elements must + // be determined differently, as the method's flags are not yet available. + // The invoke_arg_size() method assumes in that case that all bytecodes except + // invokestatic and invokedynamic have a receiver that is also pushed onto the + // stack by the caller of the current method. int invoke_arg_size(Bytecodes::Code code) const { if (is_loaded()) { return arg_size(); } else { int arg_size = _signature->size(); - // Add a receiver argument, maybe: if (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic) { arg_size++; diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index e0b7c84e45b..0b036181d31 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -364,7 +364,12 @@ u1* ClassPathZipEntry::open_versioned_entry(const char* name, jint* filesize, TR if (verstr != NULL) { version = atoi(verstr); if (version < base_version || version > cur_ver) { - is_multi_ver = false; + // If the specified version is lower than the base version, the base + // entry will be used; if the version is higher than the current + // jdk version, the highest versioned entry will be used. + if (version < base_version) { + is_multi_ver = false; + } // print out warning, do not use assertion here since it will continue to look // for proper version. warning("JDK%d is not supported in multiple version jars", version); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index fbafa936950..d1e37d82761 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -94,7 +94,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen _metaspace(NULL), _unloading(false), _klasses(NULL), _modules(NULL), _packages(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), - _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1), + _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { TRACE_INIT_ID(this); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index b69c4e681d4..8c8df5187a7 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -204,9 +204,6 @@ class ClassLoaderData : public CHeapObj { // Support for walking class loader data objects ClassLoaderData* _next; /// Next loader_datas created - // CDS - int _shared_class_loader_id; - // ReadOnly and ReadWrite metaspaces (static because only on the null // class loader for now). static Metaspace* _ro_metaspace; @@ -338,15 +335,6 @@ class ClassLoaderData : public CHeapObj { Metaspace* rw_metaspace(); void initialize_shared_metaspaces(); - int shared_class_loader_id() const { - return _shared_class_loader_id; - } - void set_shared_class_loader_id(int id) { - assert(id >= 0, "sanity"); - assert(_shared_class_loader_id <0, "cannot be assigned more than once"); - _shared_class_loader_id = id; - } - TRACE_DEFINE_TRACE_ID_METHODS; }; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 91b51404489..b7fe590eee1 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -163,8 +163,8 @@ void java_lang_String::compute_offsets() { Klass* k = SystemDictionary::String_klass(); compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature()); - compute_optional_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature()); + compute_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature()); + compute_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature()); initialized = true; } @@ -3977,12 +3977,8 @@ void JavaClasses::check_offsets() { // java.lang.String CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B"); - if (java_lang_String::has_hash_field()) { - CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I"); - } - if (java_lang_String::has_coder_field()) { - CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B"); - } + CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I"); + CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B"); // java.lang.Class diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 0cf0090e851..f05db4c79b7 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -81,15 +81,6 @@ class java_lang_String : AllStatic { static Handle create_from_platform_dependent_str(const char* str, TRAPS); static Handle char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS); - static bool has_hash_field() { - assert(initialized, "Must be initialized"); - return (hash_offset > 0); - } - static bool has_coder_field() { - assert(initialized, "Must be initialized"); - return (coder_offset > 0); - } - static void set_compact_strings(bool value); static int value_offset_in_bytes() { diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index b1c4a3f9224..b388bb157d3 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -30,10 +30,8 @@ #include "oops/oopsHierarchy.hpp" void java_lang_String::set_coder(oop string, jbyte coder) { - assert(initialized, "Must be initialized"); - if (coder_offset > 0) { - string->byte_field_put(coder_offset, coder); - } + assert(initialized && (coder_offset > 0), "Must be initialized"); + string->byte_field_put(coder_offset, coder); } void java_lang_String::set_value_raw(oop string, typeArrayOop buffer) { @@ -61,15 +59,11 @@ unsigned int java_lang_String::hash(oop java_string) { return java_string->int_field(hash_offset); } bool java_lang_String::is_latin1(oop java_string) { - assert(initialized, "Must be initialized"); + assert(initialized && (coder_offset > 0), "Must be initialized"); assert(is_instance(java_string), "must be java_string"); - if (coder_offset > 0) { - jbyte coder = java_string->byte_field(coder_offset); - assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings"); - return coder == CODER_LATIN1; - } else { - return false; - } + jbyte coder = java_string->byte_field(coder_offset); + assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings"); + return coder == CODER_LATIN1; } int java_lang_String::length(oop java_string) { assert(initialized, "Must be initialized"); diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp index becda5363a6..afa3553af1c 100644 --- a/hotspot/src/share/vm/classfile/modules.cpp +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/objArrayOop.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" @@ -48,17 +46,17 @@ #include "utilities/stringUtils.hpp" #include "utilities/utf8.hpp" -static bool verify_module_name(char *module_name) { +static bool verify_module_name(const char *module_name) { if (module_name == NULL) return false; int len = (int)strlen(module_name); return (len > 0 && len <= Symbol::max_length()); } -bool Modules::verify_package_name(char *package_name) { +bool Modules::verify_package_name(const char* package_name) { if (package_name == NULL) return false; int len = (int)strlen(package_name); return (len > 0 && len <= Symbol::max_length() && - UTF8::is_legal_utf8((unsigned char *)package_name, len, false) && + UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) && ClassFileParser::verify_unqualified_name(package_name, len, ClassFileParser::LegalClass)); } @@ -107,10 +105,8 @@ static ModuleEntry* get_module_entry(jobject module, TRAPS) { return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL); } -static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) { +static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) { ResourceMark rm(THREAD); - if (package == NULL) return NULL; - const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); if (package_name == NULL) return NULL; TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL); PackageEntryTable* package_entry_table = module_entry->loader_data()->packages(); @@ -139,7 +135,8 @@ bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) { } static void define_javabase_module(jobject module, jstring version, - jstring location, jobjectArray packages, TRAPS) { + jstring location, const char* const* packages, + jsize num_packages, TRAPS) { ResourceMark rm(THREAD); Handle module_handle(THREAD, JNIHandles::resolve(module)); @@ -164,21 +161,12 @@ static void define_javabase_module(jobject module, jstring version, } } - objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages)); - objArrayHandle packages_h(THREAD, packages_oop); - int num_packages = (packages_h == NULL ? 0 : packages_h->length()); // Check that the list of packages has no duplicates and that the // packages are syntactically ok. GrowableArray* pkg_list = new GrowableArray(num_packages); for (int x = 0; x < num_packages; x++) { - oop string_obj = packages_h->obj_at(x); - - if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Bad package name for module: " JAVA_BASE_NAME); - } - char *package_name = java_lang_String::as_utf8_string(string_obj); + const char *package_name = packages[x]; if (!Modules::verify_package_name(package_name)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name)); @@ -239,7 +227,7 @@ static void define_javabase_module(jobject module, jstring version, } } if (duplicate_javabase) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + THROW_MSG(vmSymbols::java_lang_InternalError(), "Module " JAVA_BASE_NAME " is already defined"); } @@ -262,13 +250,39 @@ static void define_javabase_module(jobject module, jstring version, } } +// Caller needs ResourceMark. +void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) { + const char* package_name = package->name()->as_C_string(); + if (package->module()->is_named()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + err_msg("Package %s for module %s is already in another module, %s, defined to the class loader", + package_name, module_name, package->module()->name()->as_C_string())); + } else { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + err_msg("Package %s for module %s is already in the unnamed module defined to the class loader", + package_name, module_name)); + } +} + void Modules::define_module(jobject module, jstring version, - jstring location, jobjectArray packages, TRAPS) { + jstring location, const char* const* packages, + jsize num_packages, TRAPS) { ResourceMark rm(THREAD); if (module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); } + + if (num_packages < 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "num_packages must be >= 0"); + } + + if (packages == NULL && num_packages > 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "num_packages should be zero if packages is null"); + } + Handle module_handle(THREAD, JNIHandles::resolve(module)); if (!java_lang_reflect_Module::is_instance(module_handle())) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), @@ -283,7 +297,7 @@ void Modules::define_module(jobject module, jstring version, // Special handling of java.base definition if (strcmp(module_name, JAVA_BASE_NAME) == 0) { - define_javabase_module(module, version, location, packages, CHECK); + define_javabase_module(module, version, location, packages, num_packages, CHECK); return; } @@ -297,21 +311,11 @@ void Modules::define_module(jobject module, jstring version, } Handle h_loader = Handle(THREAD, loader); - objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages)); - objArrayHandle packages_h(THREAD, packages_oop); - int num_packages = (packages_h == NULL ? 0 : packages_h->length()); - // Check that the list of packages has no duplicates and that the // packages are syntactically ok. GrowableArray* pkg_list = new GrowableArray(num_packages); for (int x = 0; x < num_packages; x++) { - oop string_obj = packages_h->obj_at(x); - - if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Bad package name for module: %s", module_name)); - } - char *package_name = java_lang_String::as_utf8_string(string_obj); + const char* package_name = packages[x]; if (!verify_package_name(package_name)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid package name: %s for module: %s", @@ -323,12 +327,15 @@ void Modules::define_module(jobject module, jstring version, !SystemDictionary::is_platform_class_loader(h_loader) && strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) { const char* class_loader_name = SystemDictionary::loader_name(h_loader()); - StringUtils::replace_no_expand(package_name, "/", "."); + size_t pkg_len = strlen(package_name); + char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); + strncpy(pkg_name, package_name, pkg_len); + StringUtils::replace_no_expand(pkg_name, "/", "."); const char* msg_text1 = "Class loader (instance of): "; const char* msg_text2 = " tried to define prohibited package name: "; - size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1; + size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1; char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); - jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name); + jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message); } @@ -347,7 +354,6 @@ void Modules::define_module(jobject module, jstring version, // Create symbol* entry for module name. TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK); - int dupl_pkg_index = -1; bool dupl_modules = false; // Create symbol* entry for module version. @@ -373,6 +379,7 @@ void Modules::define_module(jobject module, jstring version, assert(loader_data != NULL, "class loader data shouldn't be null"); PackageEntryTable* package_table = NULL; + PackageEntry* existing_pkg = NULL; { MutexLocker ml(Module_lock, THREAD); @@ -382,13 +389,12 @@ void Modules::define_module(jobject module, jstring version, // Check that none of the packages exist in the class loader's package table. for (int x = 0; x < pkg_list->length(); x++) { - if (package_table->lookup_only(pkg_list->at(x)) != NULL) { + existing_pkg = package_table->lookup_only(pkg_list->at(x)); + if (existing_pkg != NULL) { // This could be because the module was already defined. If so, // report that error instead of the package error. if (module_table->lookup_only(module_symbol) != NULL) { dupl_modules = true; - } else { - dupl_pkg_index = x; } break; } @@ -396,9 +402,8 @@ void Modules::define_module(jobject module, jstring version, } // if (num_packages > 0)... // Add the module and its packages. - if (!dupl_modules && dupl_pkg_index == -1) { + if (!dupl_modules && existing_pkg == NULL) { // Create the entry for this module in the class loader's module entry table. - ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, module_symbol, version_symbol, location_symbol, loader_data); @@ -426,13 +431,10 @@ void Modules::define_module(jobject module, jstring version, // any errors ? if (dupl_modules) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), err_msg("Module %s is already defined", module_name)); - } - if (dupl_pkg_index != -1) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Package %s for module %s already exists for class loader", - pkg_list->at(dupl_pkg_index)->as_C_string(), module_name)); + } else if (existing_pkg != NULL) { + throw_dup_pkg_exception(module_name, existing_pkg, CHECK); } if (log_is_enabled(Debug, modules)) { @@ -497,8 +499,8 @@ void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) { java_lang_reflect_Module::set_module_entry(module_handle(), unnamed_module); } -void Modules::add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS) { - if (package == NULL) { +void Modules::add_module_exports(jobject from_module, const char* package_name, jobject to_module, TRAPS) { + if (package_name == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "package is null"); } @@ -526,10 +528,9 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t } } - PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK); + PackageEntry *package_entry = get_package_entry(from_module_entry, package_name, CHECK); ResourceMark rm(THREAD); if (package_entry == NULL) { - const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Package %s not found in from_module %s", package_name != NULL ? package_name : "", @@ -557,7 +558,7 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t } -void Modules::add_module_exports_qualified(jobject from_module, jstring package, +void Modules::add_module_exports_qualified(jobject from_module, const char* package, jobject to_module, TRAPS) { if (to_module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), @@ -649,21 +650,15 @@ jobject Modules::get_module(jclass clazz, TRAPS) { } -jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) { +jobject Modules::get_module_by_package_name(jobject loader, const char* package_name, TRAPS) { ResourceMark rm(THREAD); assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module_from_pkg before " JAVA_BASE_NAME " is defined"); - if (NULL == package) { + if (package_name == NULL) { THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "package is null", JNI_FALSE); } - const char* package_str = - java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); - if (NULL == package_str) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Invalid package", JNI_FALSE); - } Handle h_loader (THREAD, JNIHandles::resolve(loader)); // Check that loader is a subclass of java.lang.ClassLoader. @@ -672,7 +667,7 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA "Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE); } - if (strlen(package_str) == 0) { + if (strlen(package_name) == 0) { // Return the unnamed module ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL); if (NULL == module_table) return NULL; @@ -680,24 +675,24 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module())); } else { - TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL); + TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL); return get_module(package_sym, h_loader, CHECK_NULL); } return NULL; } -jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) { +jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRAPS) { assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_named_module before " JAVA_BASE_NAME " is defined"); assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()), "Class loader is not a subclass of java.lang.ClassLoader"); - assert(package_str != NULL, "the package_str should not be NULL"); + assert(package_name != NULL, "the package_name should not be NULL"); - if (strlen(package_str) == 0) { + if (strlen(package_name) == 0) { return NULL; } - TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL); + TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL); const PackageEntry* const pkg_entry = get_package_entry_by_name(package_sym, h_loader, THREAD); const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL); @@ -723,14 +718,14 @@ jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) { return NULL; } -void Modules::add_module_package(jobject module, jstring package, TRAPS) { +void Modules::add_module_package(jobject module, const char* package_name, TRAPS) { ResourceMark rm(THREAD); if (module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "module is null"); } - if (package == NULL) { + if (package_name == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "package is null"); } @@ -743,11 +738,6 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "module cannot be an unnamed module"); } - char *package_name = java_lang_String::as_utf8_string( - JNIHandles::resolve_non_null(package)); - if (package_name == NULL) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad package"); - } if (!verify_package_name(package_name)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid package name: %s", package_name)); @@ -760,12 +750,15 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { !loader_data->is_platform_class_loader_data() && strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) { const char* class_loader_name = SystemDictionary::loader_name(loader_data); - StringUtils::replace_no_expand(package_name, "/", "."); + size_t pkg_len = strlen(package_name); + char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); + strncpy(pkg_name, package_name, pkg_len); + StringUtils::replace_no_expand(pkg_name, "/", "."); const char* msg_text1 = "Class loader (instance of): "; const char* msg_text2 = " tried to define prohibited package name: "; - size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1; + size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1; char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); - jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name); + jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message); } @@ -776,31 +769,29 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { PackageEntryTable* package_table = loader_data->packages(); assert(package_table != NULL, "Missing package_table"); - bool pkg_exists = false; + PackageEntry* existing_pkg = NULL; { MutexLocker ml(Module_lock, THREAD); // Check that the package does not exist in the class loader's package table. - if (!package_table->lookup_only(pkg_symbol)) { + existing_pkg = package_table->lookup_only(pkg_symbol); + if (existing_pkg == NULL) { PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry); assert(pkg != NULL, "Unable to create a module's package entry"); - } else { - pkg_exists = true; } } - if (pkg_exists) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Package %s already exists for class loader", package_name)); + if (existing_pkg != NULL) { + throw_dup_pkg_exception(module_entry->name()->as_C_string(), existing_pkg, CHECK); } } // Export package in module to all unnamed modules. -void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) { +void Modules::add_module_exports_to_all_unnamed(jobject module, const char* package_name, TRAPS) { if (module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "module is null"); } - if (package == NULL) { + if (package_name == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "package is null"); } @@ -811,10 +802,9 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, } if (module_entry->is_named()) { // No-op for unnamed module. - PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK); + PackageEntry *package_entry = get_package_entry(module_entry, package_name, CHECK); ResourceMark rm(THREAD); if (package_entry == NULL) { - const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Package %s not found in module %s", package_name != NULL ? package_name : "", @@ -833,10 +823,7 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, package_entry->name()->as_C_string(), module_entry->name()->as_C_string()); - // Mark package as exported to all unnamed modules, unless already - // unqualifiedly exported. - if (!package_entry->is_unqual_exported()) { - package_entry->set_is_exported_allUnnamed(); - } + // Mark package as exported to all unnamed modules. + package_entry->set_is_exported_allUnnamed(); } } diff --git a/hotspot/src/share/vm/classfile/modules.hpp b/hotspot/src/share/vm/classfile/modules.hpp index 25d02bf845c..4f5e089a065 100644 --- a/hotspot/src/share/vm/classfile/modules.hpp +++ b/hotspot/src/share/vm/classfile/modules.hpp @@ -48,9 +48,12 @@ public: // * Packages contains a duplicate package name // * A package already exists in another module for this class loader // * Module is an unnamed module + // * num_packages is negative + // * num_packages is non-zero when packages is null // NullPointerExceptions are thrown if module is null. static void define_module(jobject module, jstring version, - jstring location, jobjectArray packages, TRAPS); + jstring location, const char* const* packages, + jsize num_packages, TRAPS); // Provides the java.lang.reflect.Module for the unnamed module defined // to the boot loader. @@ -72,7 +75,7 @@ public: // * Package is not syntactically correct // * Package is not defined for from_module's class loader // * Package is not in module from_module. - static void add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS); + static void add_module_exports(jobject from_module, const char* package, jobject to_module, TRAPS); // This does a qualified export of package in module from_module to module // to_module. The format for the package name must use "/' not ".". @@ -83,7 +86,7 @@ public: // * Package is not syntactically correct // * Package is not defined for from_module's class loader // * Package is not in module from_module. - static void add_module_exports_qualified(jobject from_module, jstring package, jobject to_module, TRAPS); + static void add_module_exports_qualified(jobject from_module, const char* package, jobject to_module, TRAPS); // add_reads_module adds module to_module to the list of modules that from_module // can read. If from_module is the same as to_module then this is a no-op. @@ -102,7 +105,7 @@ public: // NullPointerException is thrown if package is null. // IllegalArgumentException is thrown if loader is neither null nor a subtype of // java/lang/ClassLoader. - static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS); + static jobject get_module_by_package_name(jobject loader, const char* package, TRAPS); static jobject get_named_module(Handle h_loader, const char* package, TRAPS); // If package is defined by loader, return the @@ -116,16 +119,16 @@ public: // * Module is unnamed // * Package is not syntactically correct // * Package is already defined for module's class loader. - static void add_module_package(jobject module, jstring package, TRAPS); + static void add_module_package(jobject module, const char* package, TRAPS); // Marks the specified package as exported to all unnamed modules. // If either module or package is null then NullPointerException is thrown. // If module or package is bad, or module is unnamed, or package is not in // module then IllegalArgumentException is thrown. - static void add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS); + static void add_module_exports_to_all_unnamed(jobject module, const char* package, TRAPS); // Return TRUE if package_name is syntactically valid, false otherwise. - static bool verify_package_name(char *package_name); + static bool verify_package_name(const char *package_name); // Return TRUE iff package is defined by loader static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS); diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp index 7ee6c52dd4e..ab80fcb732b 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.cpp +++ b/hotspot/src/share/vm/classfile/packageEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,8 @@ // Returns true if this package specifies m as a qualified export, including through an unnamed export bool PackageEntry::is_qexported_to(ModuleEntry* m) const { + assert(Module_lock->owned_by_self(), "should have the Module_lock"); assert(m != NULL, "No module to lookup in this package's qualified exports list"); - MutexLocker m1(Module_lock); if (is_exported_allUnnamed() && !m->is_named()) { return true; } else if (!has_qual_exports_list()) { @@ -98,15 +98,8 @@ void PackageEntry::set_exported(ModuleEntry* m) { } if (m == NULL) { - // NULL indicates the package is being unqualifiedly exported - if (has_qual_exports_list()) { - // Legit to transition a package from being qualifiedly exported - // to unqualified. Clean up the qualified lists at the next - // safepoint. - _exported_pending_delete = _qualified_exports; - } - - // Mark package as unqualifiedly exported + // NULL indicates the package is being unqualifiedly exported. Clean up + // the qualified list at the next safepoint. set_unqual_exported(); } else { @@ -115,14 +108,19 @@ void PackageEntry::set_exported(ModuleEntry* m) { } } +// Set the package as exported to all unnamed modules unless the package is +// already unqualifiedly exported. void PackageEntry::set_is_exported_allUnnamed() { MutexLocker m1(Module_lock); if (!is_unqual_exported()) { - _is_exported_allUnnamed = true; + _export_flags = PKG_EXP_ALLUNNAMED; } } -// Remove dead module entries within the package's exported list. +// Remove dead module entries within the package's exported list. Note that +// if all of the modules on the _qualified_exports get purged the list does not +// get deleted. This prevents the package from illegally transitioning from +// exported to non-exported. void PackageEntry::purge_qualified_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (_must_walk_exports && @@ -160,18 +158,9 @@ void PackageEntry::purge_qualified_exports() { void PackageEntry::delete_qualified_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - if (_exported_pending_delete != NULL) { - // If a transition occurred from qualified to unqualified, the _qualified_exports - // field should have been NULL'ed out. - assert(_qualified_exports == NULL, "Package's exported pending delete, exported list should not be active"); - delete _exported_pending_delete; - } - if (_qualified_exports != NULL) { delete _qualified_exports; } - - _exported_pending_delete = NULL; _qualified_exports = NULL; } @@ -314,6 +303,11 @@ void PackageEntry::package_exports_do(ModuleClosure* const f) { } } +bool PackageEntry::exported_pending_delete() const { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + return (is_unqual_exported() && _qualified_exports != NULL); +} + // Remove dead entries from all packages' exported list void PackageEntryTable::purge_all_package_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); @@ -344,13 +338,17 @@ void PackageEntryTable::print(outputStream* st) { } } +// This function may be called from debuggers so access private fields directly +// to prevent triggering locking-related asserts that could result from calling +// getter methods. void PackageEntry::print(outputStream* st) { ResourceMark rm; st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index " INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next " PTR_FORMAT, p2i(this), name()->as_C_string(), (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE), - _classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next())); + _classpath_index, _export_flags == PKG_EXP_UNQUALIFIED, + _export_flags == PKG_EXP_ALLUNNAMED, p2i(next())); } void PackageEntryTable::verify() { diff --git a/hotspot/src/share/vm/classfile/packageEntry.hpp b/hotspot/src/share/vm/classfile/packageEntry.hpp index a379bf9de3b..aaafa54bb6d 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.hpp +++ b/hotspot/src/share/vm/classfile/packageEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,8 @@ // A PackageEntry basically represents a Java package. It contains: // - Symbol* containing the package's name. // - ModuleEntry* for this package's containing module. -// - a flag indicating if package is exported unqualifiedly -// - a flag indicating if this package is exported to all unnamed modules. +// - a field indicating if the package is exported unqualifiedly or to all +// unnamed modules. // - a growable array containing other module entries that this // package is exported to. // @@ -44,9 +44,9 @@ // - qualified exports: the package has been explicitly qualified to at least // one particular module or has been qualifiedly exported // to all unnamed modules. -// Note: _is_exported_allUnnamed is a form of a qualified -// export. It is equivalent to the package being -// explicitly exported to all current and future unnamed modules. +// Note: being exported to all unnamed is a form of a qualified +// export. It is equivalent to the package being explicitly +// exported to all current and future unnamed modules. // - unqualified exports: the package is exported to all modules. // // A package can transition from: @@ -56,21 +56,53 @@ // A package cannot transition from: // - being unqualifiedly exported, to exported qualifiedly to a specific module. // This transition attempt is silently ignored in set_exported. +// - being qualifiedly exported to not exported. +// Because transitions are only allowed from less exposure to greater exposure, +// the transition from qualifiedly exported to not exported would be considered +// a backward direction. Therefore the implementation considers a package as +// qualifiedly exported even if its export-list exists but is empty. // // The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either // data structure. + +// PKG_EXP_UNQUALIFIED and PKG_EXP_ALLUNNAMED indicate whether the package is +// exported unqualifiedly or exported to all unnamed modules. They are used to +// set the value of _export_flags. Field _export_flags and the _qualified_exports +// list are used to determine a package's export state. +// Valid states are: +// +// 1. Package is not exported +// _export_flags is zero and _qualified_exports is null +// 2. Package is unqualifiedly exported +// _export_flags is set to PKG_EXP_UNQUALIFIED +// _qualified_exports may or may not be null depending on whether the package +// transitioned from qualifiedly exported to unqualifiedly exported. +// 3. Package is qualifiedly exported +// _export_flags may be set to PKG_EXP_ALLUNNAMED if the package is also +// exported to all unnamed modules +// _qualified_exports will be non-null +// 4. Package is exported to all unnamed modules +// _export_flags is set to PKG_EXP_ALLUNNAMED +// _qualified_exports may or may not be null depending on whether the package +// is also qualifiedly exported to one or more named modules. +#define PKG_EXP_UNQUALIFIED 0x0001 +#define PKG_EXP_ALLUNNAMED 0x0002 +#define PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED (PKG_EXP_UNQUALIFIED | PKG_EXP_ALLUNNAMED) + class PackageEntry : public HashtableEntry { private: ModuleEntry* _module; + // Indicates if package is exported unqualifiedly or to all unnamed. Access to + // this field is protected by the Module_lock. + int _export_flags; // Used to indicate for packages with classes loaded by the boot loader that // a class in that package has been loaded. And, for packages with classes // loaded by the boot loader from -Xbootclasspath/a in an unnamed module, it // indicates from which class path entry. s2 _classpath_index; - bool _is_exported_unqualified; - bool _is_exported_allUnnamed; bool _must_walk_exports; - GrowableArray* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint + // Contains list of modules this package is qualifiedly exported to. Access + // to this list is protected by the Module_lock. GrowableArray* _qualified_exports; TRACE_DEFINE_TRACE_ID_FIELD; @@ -80,17 +112,14 @@ private: public: void init() { _module = NULL; + _export_flags = 0; _classpath_index = -1; - _is_exported_unqualified = false; - _is_exported_allUnnamed = false; _must_walk_exports = false; - _exported_pending_delete = NULL; _qualified_exports = NULL; } // package name Symbol* name() const { return literal(); } - void set_name(Symbol* n) { set_literal(n); } // the module containing the package definition ModuleEntry* module() const { return _module; } @@ -98,37 +127,39 @@ public: // package's export state bool is_exported() const { // qualifiedly or unqualifiedly exported - return (is_unqual_exported() || has_qual_exports_list() || is_exported_allUnnamed()); + assert_locked_or_safepoint(Module_lock); + return ((_export_flags & PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED) != 0) || has_qual_exports_list(); } // Returns true if the package has any explicit qualified exports or is exported to all unnamed bool is_qual_exported() const { + assert_locked_or_safepoint(Module_lock); return (has_qual_exports_list() || is_exported_allUnnamed()); } - // Returns true if there are any explicit qualified exports + // Returns true if there are any explicit qualified exports. Note that even + // if the _qualified_exports list is now empty (because the modules that were + // on the list got gc-ed and deleted from the list) this method may still + // return true. bool has_qual_exports_list() const { - assert(!(_qualified_exports != NULL && _is_exported_unqualified), - "_qualified_exports set at same time as _is_exported_unqualified"); - return (_qualified_exports != NULL); + assert_locked_or_safepoint(Module_lock); + return (!is_unqual_exported() && _qualified_exports != NULL); } bool is_exported_allUnnamed() const { - assert(!(_is_exported_allUnnamed && _is_exported_unqualified), - "_is_exported_allUnnamed set at same time as _is_exported_unqualified"); - return _is_exported_allUnnamed; + assert_locked_or_safepoint(Module_lock); + return (_export_flags == PKG_EXP_ALLUNNAMED); } bool is_unqual_exported() const { - assert(!(_qualified_exports != NULL && _is_exported_unqualified), - "_qualified_exports set at same time as _is_exported_unqualified"); - assert(!(_is_exported_allUnnamed && _is_exported_unqualified), - "_is_exported_allUnnamed set at same time as _is_exported_unqualified"); - return _is_exported_unqualified; + assert_locked_or_safepoint(Module_lock); + return (_export_flags == PKG_EXP_UNQUALIFIED); } + + // Explicitly set _export_flags to PKG_EXP_UNQUALIFIED and clear + // PKG_EXP_ALLUNNAMED, if it was set. void set_unqual_exported() { assert(Module_lock->owned_by_self(), "should have the Module_lock"); - _is_exported_unqualified = true; - _is_exported_allUnnamed = false; - _qualified_exports = NULL; + _export_flags = PKG_EXP_UNQUALIFIED; } - bool exported_pending_delete() const { return (_exported_pending_delete != NULL); } + + bool exported_pending_delete() const; void set_exported(ModuleEntry* m); diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp index 4da4869cef2..764e1eaa348 100644 --- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp @@ -29,7 +29,6 @@ #include "classfile/dictionary.hpp" class ClassFileStream; -class SerializeClosure; class SystemDictionaryShared: public SystemDictionary { public: @@ -79,8 +78,6 @@ public: return NULL; } - static void serialize(SerializeClosure* soc) {} - // The (non-application) CDS implementation supports only classes in the boot // class loader, which ensures that the verification constraints are the same // during archive creation time and runtime. Thus we can do the constraint checks diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 80ce54f847e..bfe643ab683 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -149,16 +149,17 @@ void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t total_size = non_nmethod_size + profiled_size + non_profiled_size; // Prepare error message const char* error = "Invalid code heap sizes"; - err_msg message("NonNMethodCodeHeapSize (%zuK) + ProfiledCodeHeapSize (%zuK) + NonProfiledCodeHeapSize (%zuK) = %zuK", + err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K) + ProfiledCodeHeapSize (" SIZE_FORMAT "K)" + " + NonProfiledCodeHeapSize (" SIZE_FORMAT "K) = " SIZE_FORMAT "K", non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K); if (total_size > cache_size) { // Some code heap sizes were explicitly set: total_size must be <= cache_size - message.append(" is greater than ReservedCodeCacheSize (%zuK).", cache_size/K); + message.append(" is greater than ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); vm_exit_during_initialization(error, message); } else if (all_set && total_size != cache_size) { // All code heap sizes were explicitly set: total_size must equal cache_size - message.append(" is not equal to ReservedCodeCacheSize (%zuK).", cache_size/K); + message.append(" is not equal to ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); vm_exit_during_initialization(error, message); } } @@ -267,7 +268,7 @@ void CodeCache::initialize_heaps() { uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); if (non_nmethod_size < (min_code_cache_size + code_buffers_size)) { vm_exit_during_initialization(err_msg( - "Not enough space in non-nmethod code heap to run VM: %zuK < %zuK", + "Not enough space in non-nmethod code heap to run VM: " SIZE_FORMAT "K < " SIZE_FORMAT "K", non_nmethod_size/K, (min_code_cache_size + code_buffers_size)/K)); } diff --git a/hotspot/src/share/vm/code/compiledMethod.hpp b/hotspot/src/share/vm/code/compiledMethod.hpp index 863e8cfa610..f260835384a 100644 --- a/hotspot/src/share/vm/code/compiledMethod.hpp +++ b/hotspot/src/share/vm/code/compiledMethod.hpp @@ -250,7 +250,11 @@ public: address insts_begin() const { return code_begin(); } address insts_end() const { return stub_begin(); } + // Returns true if a given address is in the 'insts' section. The method + // insts_contains_inclusive() is end-inclusive. bool insts_contains(address addr) const { return insts_begin() <= addr && addr < insts_end(); } + bool insts_contains_inclusive(address addr) const { return insts_begin() <= addr && addr <= insts_end(); } + int insts_size() const { return insts_end() - insts_begin(); } virtual address consts_begin() const = 0; diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp index a0d379773eb..00c2e64f851 100644 --- a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "compiler/compilerDefinitions.hpp" const char* compilertype2name_tab[compiler_number_of_types] = { @@ -32,3 +34,82 @@ const char* compilertype2name_tab[compiler_number_of_types] = { "jvmci", "shark" }; + +#if defined(COMPILER2) || defined(SHARK) +CompLevel CompLevel_highest_tier = CompLevel_full_optimization; // pure C2 and tiered or JVMCI and tiered +#elif defined(COMPILER1) +CompLevel CompLevel_highest_tier = CompLevel_simple; // pure C1 or JVMCI +#else +CompLevel CompLevel_highest_tier = CompLevel_none; +#endif + +#if defined(TIERED) +CompLevel CompLevel_initial_compile = CompLevel_full_profile; // tiered +#elif defined(COMPILER1) || INCLUDE_JVMCI +CompLevel CompLevel_initial_compile = CompLevel_simple; // pure C1 or JVMCI +#elif defined(COMPILER2) || defined(SHARK) +CompLevel CompLevel_initial_compile = CompLevel_full_optimization; // pure C2 +#else +CompLevel CompLevel_initial_compile = CompLevel_none; +#endif + +#if defined(COMPILER2) +CompMode Compilation_mode = CompMode_server; +#elif defined(COMPILER1) +CompMode Compilation_mode = CompMode_client; +#else +CompMode Compilation_mode = CompMode_none; +#endif + +#ifdef TIERED +void set_client_compilation_mode() { + Compilation_mode = CompMode_client; + CompLevel_highest_tier = CompLevel_simple; + CompLevel_initial_compile = CompLevel_simple; + FLAG_SET_ERGO(bool, TieredCompilation, false); + FLAG_SET_ERGO(bool, ProfileInterpreter, false); +#if INCLUDE_JVMCI + FLAG_SET_ERGO(bool, EnableJVMCI, false); + FLAG_SET_ERGO(bool, UseJVMCICompiler, false); +#endif +#if INCLUDE_AOT + FLAG_SET_ERGO(bool, UseAOT, false); +#endif + if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) { + FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true); + } + if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) { + FLAG_SET_ERGO(uintx, InitialCodeCacheSize, 160*K); + } + if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { + FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, 32*M); + } + if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) { + FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 27*M); + } + if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) { + FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0); + } + if (FLAG_IS_DEFAULT(NonNMethodCodeHeapSize)) { + FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 5*M); + } + if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) { + FLAG_SET_ERGO(uintx, CodeCacheExpansionSize, 32*K); + } + if (FLAG_IS_DEFAULT(MetaspaceSize)) { + FLAG_SET_ERGO(size_t, MetaspaceSize, 12*M); + } + if (FLAG_IS_DEFAULT(MaxRAM)) { + FLAG_SET_ERGO(uint64_t, MaxRAM, 1ULL*G); + } + if (FLAG_IS_DEFAULT(CompileThreshold)) { + FLAG_SET_ERGO(intx, CompileThreshold, 1500); + } + if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) { + FLAG_SET_ERGO(intx, OnStackReplacePercentage, 933); + } + if (FLAG_IS_DEFAULT(CICompilerCount)) { + FLAG_SET_ERGO(intx, CICompilerCount, 1); + } +} +#endif // TIERED diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp index 9a08a97b303..a2378ea1e92 100644 --- a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp @@ -54,27 +54,30 @@ enum CompLevel { CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4, // C2, Shark or JVMCI - -#if defined(COMPILER2) || defined(SHARK) - CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered -#elif defined(COMPILER1) - CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI -#else - CompLevel_highest_tier = CompLevel_none, -#endif - -#if defined(TIERED) - CompLevel_initial_compile = CompLevel_full_profile // tiered -#elif defined(COMPILER1) || INCLUDE_JVMCI - CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI -#elif defined(COMPILER2) || defined(SHARK) - CompLevel_initial_compile = CompLevel_full_optimization // pure C2 -#else - CompLevel_initial_compile = CompLevel_none -#endif + CompLevel_full_optimization = 4 // C2, Shark or JVMCI }; +extern CompLevel CompLevel_highest_tier; +extern CompLevel CompLevel_initial_compile; + +enum CompMode { + CompMode_none = 0, + CompMode_client = 1, + CompMode_server = 2 +}; + +extern CompMode Compilation_mode; + +inline bool is_server_compilation_mode_vm() { + return Compilation_mode == CompMode_server; +} + +inline bool is_client_compilation_mode_vm() { + return Compilation_mode == CompMode_client; +} + +extern void set_client_compilation_mode(); + inline bool is_c1_compile(int comp_level) { return comp_level > CompLevel_none && comp_level < CompLevel_full_optimization; } diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index ed224cea90f..4388f348e92 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -445,7 +445,9 @@ void DirectivesStack::init() { _default_directives->_c1_store->EnableOption = true; #endif #ifdef COMPILER2 - _default_directives->_c2_store->EnableOption = true; + if (is_server_compilation_mode_vm()) { + _default_directives->_c2_store->EnableOption = true; + } #endif assert(error_msg == NULL, "Must succeed."); push(_default_directives); diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index 283fd48127e..7c4efa650a5 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -60,13 +60,12 @@ cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \ cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \ cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \ - cflags(TraceOptoPipelining, bool, false, TraceOptoPipelining) \ - cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \ +NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipelining)) \ +NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ - cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \ cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #else diff --git a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp index 42069703b27..93b07b21e2d 100644 --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,12 +69,12 @@ protected: void initialize(HeapWord* bottom, HeapWord* end, size_t target_elem_size_in_bytes, size_t mapping_granularity_in_bytes) { assert(mapping_granularity_in_bytes > 0, "just checking"); assert(is_power_of_2(mapping_granularity_in_bytes), - "mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes); + "mapping granularity must be power of 2, is " SIZE_FORMAT, mapping_granularity_in_bytes); assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0, - "bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + "bottom mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(bottom)); assert((uintptr_t)end % mapping_granularity_in_bytes == 0, - "end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + "end mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(end)); size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes); idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes; diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 4f2c46913db..737c57c117d 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -233,7 +233,7 @@ void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. #if defined(COMPILER2) || INCLUDE_JVMCI - _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() + _defer_initial_card_mark = is_server_compilation_mode_vm() && ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store()); #else assert(_defer_initial_card_mark == false, "Who would set it?"); diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 5248654f2f7..0119e115104 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -1209,7 +1209,7 @@ void GenCollectedHeap::gc_epilogue(bool full) { #if defined(COMPILER2) || INCLUDE_JVMCI assert(DerivedPointerTable::is_empty(), "derived pointer present"); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); - guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); + guarantee(is_client_compilation_mode_vm() || actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); #endif /* COMPILER2 || INCLUDE_JVMCI */ resize_all_tlabs(); diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp index 38df96ddd4c..5d6d160a4ee 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp @@ -57,11 +57,11 @@ void ReferenceProcessor::init_statics() { java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); -#if defined(COMPILER2) || INCLUDE_JVMCI - _default_soft_ref_policy = new LRUMaxHeapPolicy(); -#else - _default_soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif + if (is_server_compilation_mode_vm()) { + _default_soft_ref_policy = new LRUMaxHeapPolicy(); + } else { + _default_soft_ref_policy = new LRUCurrentHeapPolicy(); + } if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp index 0df1ba020a2..b004ba58c89 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp @@ -233,9 +233,11 @@ void ThreadLocalAllocBuffer::startup_initialization() { // If the C2 compiler is not present, no space is reserved. // +1 for rounding up to next cache line, +1 to be safe - int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; - _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / - (int)HeapWordSize; + if (is_server_compilation_mode_vm()) { + int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; + _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / + (int)HeapWordSize; + } #endif // During jvm startup, the main (primordial) thread is initialized diff --git a/hotspot/src/share/vm/interpreter/bytecode.cpp b/hotspot/src/share/vm/interpreter/bytecode.cpp index 80b95d627b5..6cc38a5a0cd 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.cpp +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,7 +112,7 @@ void Bytecode::assert_native_index(Bytecodes::Code bc, bool is_wide) { // Implementation of Bytecode_tableupswitch int Bytecode_tableswitch::dest_offset_at(int i) const { - return get_Java_u4_at(aligned_offset(1 + (3 + i)*jintSize)); + return get_aligned_Java_u4_at(1 + (3 + i)*jintSize); } diff --git a/hotspot/src/share/vm/interpreter/bytecode.hpp b/hotspot/src/share/vm/interpreter/bytecode.hpp index f3fc9ea9d6a..5c53ab4121f 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.hpp +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,11 +45,11 @@ class Bytecode: public StackObj { address addr_at (int offset) const { return (address)_bcp + offset; } u_char byte_at(int offset) const { return *addr_at(offset); } address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); } - int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); } // Word access: int get_Java_u2_at (int offset) const { return Bytes::get_Java_u2(addr_at(offset)); } int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); } + int get_aligned_Java_u4_at(int offset) const { return Bytes::get_Java_u4(aligned_addr_at(offset)); } int get_native_u2_at (int offset) const { return Bytes::get_native_u2(addr_at(offset)); } int get_native_u4_at (int offset) const { return Bytes::get_native_u4(addr_at(offset)); } @@ -150,8 +150,8 @@ class Bytecode_lookupswitch: public Bytecode { void verify() const PRODUCT_RETURN; // Attributes - int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } - int number_of_pairs() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } + int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); } + int number_of_pairs() const { return get_aligned_Java_u4_at(1 + 1*jintSize); } LookupswitchPair pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); return LookupswitchPair(aligned_addr_at(1 + (1 + i)*2*jintSize)); @@ -166,9 +166,9 @@ class Bytecode_tableswitch: public Bytecode { void verify() const PRODUCT_RETURN; // Attributes - int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } - int low_key() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } - int high_key() const { return get_Java_u4_at(aligned_offset(1 + 2*jintSize)); } + int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); } + int low_key() const { return get_aligned_Java_u4_at(1 + 1*jintSize); } + int high_key() const { return get_aligned_Java_u4_at(1 + 2*jintSize); } int dest_offset_at(int i) const; int length() { return high_key()-low_key()+1; } }; diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index 745fb5199ec..cca40f1aeb2 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -554,7 +554,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle _constants = buffer.consts(); initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, false, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -587,7 +587,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand _constants = buffer.consts(); initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, true, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -726,7 +726,7 @@ int CodeInstaller::estimate_stubs_size(TRAPS) { } // perform data and call relocation on the CodeBuffer -JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, TRAPS) { +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS) { HandleMark hm; objArrayHandle sites = this->sites(); int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); @@ -738,7 +738,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, int stubs_size = estimate_stubs_size(CHECK_OK); int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); - if (total_size > JVMCINMethodSizeLimit) { + if (check_size && total_size > JVMCINMethodSizeLimit) { return JVMCIEnv::code_too_large; } @@ -1258,6 +1258,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, T case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: case NARROW_KLASS_BASE_ADDRESS: + case NARROW_OOP_BASE_ADDRESS: case CRC_TABLE_ADDRESS: case LOG_OF_HEAP_REGION_GRAIN_BYTES: case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 775a8c19f40..a700174de1d 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -133,9 +133,10 @@ private: HEAP_TOP_ADDRESS = 17, HEAP_END_ADDRESS = 18, NARROW_KLASS_BASE_ADDRESS = 19, - CRC_TABLE_ADDRESS = 20, - LOG_OF_HEAP_REGION_GRAIN_BYTES = 21, - INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 22, + NARROW_OOP_BASE_ADDRESS = 20, + CRC_TABLE_ADDRESS = 21, + LOG_OF_HEAP_REGION_GRAIN_BYTES = 22, + INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 23, INVOKE_INVALID = -1 }; @@ -227,7 +228,7 @@ protected: int estimate_stubs_size(TRAPS); // perform data and call relocation on the CodeBuffer - JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, TRAPS); + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS); void assumption_NoFinalizableSubclass(Handle assumption); void assumption_ConcreteSubtype(Handle assumption); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index f7eb56ff404..2fe6b45b79e 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -591,12 +591,16 @@ C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, job return method->is_ignored_by_security_stack_walk(); C2V_END -C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) +C2V_VMENTRY(jboolean, isCompilable,(JNIEnv *, jobject, jobject jvmci_method)) methodHandle method = CompilerToVM::asMethod(jvmci_method); - // In hosted mode ignore the not_compilable flags since they are never set by + // Ignore the not_compilable flags in hosted mode since they are never set by // the JVMCI compiler. - bool is_compilable = UseJVMCICompiler ? !method->is_not_compilable(CompLevel_full_optimization) : true; - return is_compilable && !CompilerOracle::should_not_inline(method) && !method->dont_inline(); + return UseJVMCICompiler || !method->is_not_compilable(CompLevel_full_optimization); +C2V_END + +C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return CompilerOracle::should_not_inline(method) || method->dont_inline(); C2V_END C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) @@ -1591,7 +1595,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getStackTraceElement", CC "(" HS_RESOLVED_METHOD "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, {CC "doNotInlineOrCompile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(doNotInlineOrCompile)}, - {CC "canInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(canInlineMethod)}, + {CC "isCompilable", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(isCompilable)}, + {CC "hasNeverInlineDirective", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(hasNeverInlineDirective)}, {CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)}, {CC "lookupType", CC "(" STRING CLASS "Z)" HS_RESOLVED_KLASS, FN_PTR(lookupType)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)}, diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 2dad27fdfd9..a01651f55aa 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -429,6 +429,7 @@ declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_OOP_BASE_ADDRESS) \ declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ declare_constant(CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES) \ declare_constant(CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED) \ @@ -534,7 +535,6 @@ \ declare_constant(markOopDesc::no_hash) \ \ - declare_constant(Method::_jfr_towrite) \ declare_constant(Method::_caller_sensitive) \ declare_constant(Method::_force_inline) \ declare_constant(Method::_dont_inline) \ diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index b8a5932ba0e..9b77b220e70 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -478,7 +478,7 @@ void LogConfiguration::describe(outputStream* out) { void LogConfiguration::print_command_line_help(FILE* out) { jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n" - "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n" + "\t where 'what' is a combination of tags and levels of the form tag1[+tag2...][*][=level][,...]\n" "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n"); jio_fprintf(out, "Available log levels:\n"); @@ -514,6 +514,14 @@ void LogConfiguration::print_command_line_help(FILE* out) { " -Xlog:gc\n" "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n" + " -Xlog:gc,safepoint\n" + "\t Log messages tagged either with 'gc' or 'safepoint' tags, both using 'info' level, to stdout, with default decorations.\n" + "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n" + + " -Xlog:gc+ref=debug\n" + "\t Log messages tagged with both 'gc' and 'ref' tags, using 'debug' level, to stdout, with default decorations.\n" + "\t (Messages tagged only with one of the two tags will not be logged.)\n\n" + " -Xlog:gc=debug:file=gc.txt:none\n" "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n" diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 61d6fa37b41..446517fd426 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -145,10 +145,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc, GrowableArray StringTable::serialize(soc, string_space, space_size); soc->do_tag(--tag); - // Dump/restore the misc information for system dictionary - SystemDictionaryShared::serialize(soc); - soc->do_tag(--tag); - soc->do_tag(666); } diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 5b2180f945c..41f5fd143a8 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2139,8 +2139,6 @@ void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) { } void InstanceKlass::release_C_heap_structures() { - assert(!this->is_shared(), "should not be called for a shared class"); - // Can't release the constant pool here because the constant pool can be // deallocated separately from the InstanceKlass for default methods and // redefine classes. @@ -2191,7 +2189,7 @@ void InstanceKlass::release_C_heap_structures() { } // deallocate the cached class file - if (_cached_class_file != NULL) { + if (_cached_class_file != NULL && !MetaspaceShared::is_in_shared_space(_cached_class_file)) { os::free(_cached_class_file); _cached_class_file = NULL; } diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 4e3dcf03bd8..f37278edd13 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -85,7 +85,6 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags) { set_constMethod(xconst); set_access_flags(access_flags); set_intrinsic_id(vmIntrinsics::_none); - set_jfr_towrite(false); set_force_inline(false); set_hidden(false); set_dont_inline(false); diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 1c6e72df0fc..ebd5f0feef2 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -75,18 +75,19 @@ class Method : public Metadata { // Flags enum Flags { - _jfr_towrite = 1 << 0, - _caller_sensitive = 1 << 1, - _force_inline = 1 << 2, - _dont_inline = 1 << 3, - _hidden = 1 << 4, - _has_injected_profile = 1 << 5, - _running_emcp = 1 << 6, - _intrinsic_candidate = 1 << 7, - _reserved_stack_access = 1 << 8 + _caller_sensitive = 1 << 0, + _force_inline = 1 << 1, + _dont_inline = 1 << 2, + _hidden = 1 << 3, + _has_injected_profile = 1 << 4, + _running_emcp = 1 << 5, + _intrinsic_candidate = 1 << 6, + _reserved_stack_access = 1 << 7 }; mutable u2 _flags; + TRACE_DEFINE_FLAG; + #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) #endif @@ -833,13 +834,6 @@ class Method : public Metadata { void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(const Klass* holder); - bool jfr_towrite() const { - return (_flags & _jfr_towrite) != 0; - } - void set_jfr_towrite(bool x) const { - _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite); - } - bool caller_sensitive() { return (_flags & _caller_sensitive) != 0; } @@ -890,6 +884,8 @@ class Method : public Metadata { _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access); } + TRACE_DEFINE_FLAG_ACCESSOR; + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 85f7c9b6098..a99000aabcf 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -717,9 +717,9 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, const methodHandl } int MethodData::bytecode_cell_count(Bytecodes::Code code) { -#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) - return no_profile_data; -#else + if (is_client_compilation_mode_vm()) { + return no_profile_data; + } switch (code) { case Bytecodes::_checkcast: case Bytecodes::_instanceof: @@ -778,7 +778,6 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) { return variable_cell_count; } return no_profile_data; -#endif } // Compute the size of the profiling information corresponding to @@ -840,7 +839,9 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) { case Bytecodes::_ifnonnull: case Bytecodes::_invokestatic: #ifdef COMPILER2 - return UseTypeSpeculation; + if (is_server_compilation_mode_vm()) { + return UseTypeSpeculation; + } #endif default: return false; @@ -942,9 +943,9 @@ int MethodData::compute_allocation_size_in_words(const methodHandle& method) { // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { -#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) - return 0; -#else + if (is_client_compilation_mode_vm()) { + return 0; + } int cell_count = -1; int tag = DataLayout::no_tag; DataLayout* data_layout = data_layout_at(data_index); @@ -1061,7 +1062,6 @@ int MethodData::initialize_data(BytecodeStream* stream, assert(!bytecode_has_profile(c), "agree w/ !BHP"); return 0; } -#endif } // Get the data at an arbitrary (sort of) data index. diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index a85b64e8801..627fba527e2 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -2183,7 +2183,7 @@ private: uint _nof_overflow_traps; // trap count, excluding _trap_hist union { intptr_t _align; - u1 _array[_trap_hist_limit]; + u1 _array[JVMCI_ONLY(2 *) _trap_hist_limit]; } _trap_hist; // Support for interprocedural escape analysis, from Thomas Kotzmann. diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index 47606b6a599..de85b1cb155 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -2097,6 +2097,7 @@ const RegMask &PhiNode::out_RegMask() const { uint ideal_reg = _type->ideal_reg(); assert( ideal_reg != Node::NotAMachineReg, "invalid type at Phi" ); if( ideal_reg == 0 ) return RegMask::Empty; + assert(ideal_reg != Op_RegFlags, "flags register is not spillable"); return *(Compile::current()->matcher()->idealreg2spillmask[ideal_reg]); } diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp index 1e8af4e27ee..fb45d92df42 100644 --- a/hotspot/src/share/vm/opto/coalesce.cpp +++ b/hotspot/src/share/vm/opto/coalesce.cpp @@ -292,7 +292,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { // Copy any flags as well _phc.clone_projs(pred, pred->end_idx(), m, copy, _phc._lrg_map); } else { - const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; + int ireg = m->ideal_reg(); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s", + m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::PhiInput)); + C->record_method_not_compilable("attempted to spill a non-spillable item"); + return; + } + const RegMask *rm = C->matcher()->idealreg2spillmask[ireg]; copy = new MachSpillCopyNode(MachSpillCopyNode::PhiInput, m, *rm, *rm); // Find a good place to insert. Kinda tricky, use a subroutine insert_copy_with_overlap(pred,copy,phi_name,src_name); @@ -326,7 +333,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { b->insert_node(copy, l++); l += _phc.clone_projs(b, l, m, copy, _phc._lrg_map); } else { - const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; + int ireg = m->ideal_reg(); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s", + m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::TwoAddress)); + C->record_method_not_compilable("attempted to spill a non-spillable item"); + return; + } + const RegMask *rm = C->matcher()->idealreg2spillmask[ireg]; copy = new MachSpillCopyNode(MachSpillCopyNode::TwoAddress, m, *rm, *rm); // Insert the copy in the basic block, just before us b->insert_node(copy, l++); @@ -373,7 +387,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { if( k < b->_num_succs ) continue; // Live out; do not pre-split // Split the lrg at this use - const RegMask *rm = C->matcher()->idealreg2spillmask[inp->ideal_reg()]; + int ireg = inp->ideal_reg(); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s", + inp->_idx, inp->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::DebugUse)); + C->record_method_not_compilable("attempted to spill a non-spillable item"); + return; + } + const RegMask *rm = C->matcher()->idealreg2spillmask[ireg]; Node* copy = new MachSpillCopyNode(MachSpillCopyNode::DebugUse, inp, *rm, *rm); // Insert the copy in the use-def chain n->set_req(inpidx, copy ); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 77e20b264cb..4c84b0339ec 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -971,7 +971,7 @@ Compile::Compile( ciEnv* ci_env, _java_calls(0), _inner_loops(0), #ifndef PRODUCT - _trace_opto_output(TraceOptoOutput), + _trace_opto_output(directive->TraceOptoOutputOption), _in_dump_cnt(0), _printer(NULL), #endif diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index c879137d882..1c328b7bb75 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3152,19 +3152,6 @@ Node* GraphKit::insert_mem_bar_volatile(int opcode, int alias_idx, Node* precede return membar; } -void GraphKit::insert_store_load_for_barrier() { - Node* mem = reset_memory(); - MemBarNode* mb = MemBarNode::make(C, Op_MemBarVolatile, Compile::AliasIdxBot); - mb->init_req(TypeFunc::Control, control()); - mb->init_req(TypeFunc::Memory, mem); - Node* membar = _gvn.transform(mb); - set_control(_gvn.transform(new ProjNode(membar, TypeFunc::Control))); - Node* newmem = _gvn.transform(new ProjNode(membar, TypeFunc::Memory)); - set_all_memory(mem); - set_memory(newmem, Compile::AliasIdxRaw); -} - - //------------------------------shared_lock------------------------------------ // Emit locking code. FastLockNode* GraphKit::shared_lock(Node* obj) { @@ -3854,7 +3841,7 @@ void GraphKit::write_barrier_post(Node* oop_store, BasicType bt = T_BYTE; if (UseConcMarkSweepGC && UseCondCardMark) { - insert_store_load_for_barrier(); + insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier __ sync_kit(this); } @@ -4294,7 +4281,8 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, __ if_then(card_val, BoolTest::ne, young_card); { sync_kit(ideal); - insert_store_load_for_barrier(); + // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. + insert_mem_bar(Op_MemBarVolatile, oop_store); __ sync_kit(this); Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); @@ -4348,20 +4336,16 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) { } Node* GraphKit::load_String_coder(Node* ctrl, Node* str) { - if (java_lang_String::has_coder_field()) { - if (!CompactStrings) { - return intcon(java_lang_String::CODER_UTF16); - } - int coder_offset = java_lang_String::coder_offset_in_bytes(); - const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), - false, NULL, 0); - const TypePtr* coder_field_type = string_type->add_offset(coder_offset); - int coder_field_idx = C->get_alias_index(coder_field_type); - return make_load(ctrl, basic_plus_adr(str, str, coder_offset), - TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered); - } else { - return intcon(0); // false + if (!CompactStrings) { + return intcon(java_lang_String::CODER_UTF16); } + int coder_offset = java_lang_String::coder_offset_in_bytes(); + const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), + false, NULL, 0); + const TypePtr* coder_field_type = string_type->add_offset(coder_offset); + int coder_field_idx = C->get_alias_index(coder_field_type); + return make_load(ctrl, basic_plus_adr(str, str, coder_offset), + TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered); } void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) { diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 6d60539b527..cbae7ce3761 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -837,7 +837,6 @@ class GraphKit : public Phase { int next_monitor(); Node* insert_mem_bar(int opcode, Node* precedent = NULL); Node* insert_mem_bar_volatile(int opcode, int alias_idx, Node* precedent = NULL); - void insert_store_load_for_barrier(); // Optional 'precedent' is appended as an extra edge, to force ordering. FastLockNode* shared_lock(Node* obj); void shared_unlock(Node* box, Node* obj); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index c298e318ab5..5d837d6ecb0 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -6335,7 +6335,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { -#ifdef PPC64 +#if defined(PPC64) || defined(S390) // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. // Intel's extention is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index cd0839c3294..07f791d05d1 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -643,6 +643,7 @@ const RegMask &MachSafePointNode::in_RegMask( uint idx ) const { } // Values outside the domain represent debug info + assert(in(idx)->ideal_reg() != Op_RegFlags, "flags register is not spillable"); return *Compile::current()->matcher()->idealreg2spillmask[in(idx)->ideal_reg()]; } diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 9bae43a4e28..bd0a1b75c9a 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -426,7 +426,7 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me // Generate loads from source of the arraycopy for fields of // destination needed at a deoptimization point -Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc) { +Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc) { BasicType bt = ft; const Type *type = ftype; if (ft == T_NARROWOOP) { @@ -438,8 +438,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* base = ac->in(ArrayCopyNode::Src)->in(AddPNode::Base); Node* adr = _igvn.transform(new AddPNode(base, base, MakeConX(offset))); const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset); - Node* m = ac->in(TypeFunc::Memory); - res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); + res = LoadNode::make(_igvn, ctl, mem, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); } else { if (ac->modifies(offset, offset, &_igvn, true)) { assert(ac->in(ArrayCopyNode::Dest) == alloc->result_cast(), "arraycopy destination should be allocation's result"); @@ -454,8 +453,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* base = ac->in(ArrayCopyNode::Src); Node* adr = _igvn.transform(new AddPNode(base, base, off)); const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset); - Node* m = ac->in(TypeFunc::Memory); - res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); + res = LoadNode::make(_igvn, ctl, mem, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); } } if (res != NULL) { @@ -544,7 +542,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type * assert(false, "Object is not scalar replaceable if a LoadStore node accesses its field"); return NULL; } else if (val->is_ArrayCopy()) { - Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), ft, phi_type, alloc); + Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), val->in(TypeFunc::Memory), ft, phi_type, alloc); if (res == NULL) { return NULL; } @@ -657,11 +655,13 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType } } else if (mem->is_ArrayCopy()) { Node* ctl = mem->in(0); + Node* m = mem->in(TypeFunc::Memory); if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) { // pin the loads in the uncommon trap path ctl = sfpt_ctl; + m = sfpt_mem; } - return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, ft, ftype, alloc); + return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, m, ft, ftype, alloc); } } // Something go wrong. diff --git a/hotspot/src/share/vm/opto/macro.hpp b/hotspot/src/share/vm/opto/macro.hpp index ba8e9eac8e4..5482a1d8282 100644 --- a/hotspot/src/share/vm/opto/macro.hpp +++ b/hotspot/src/share/vm/opto/macro.hpp @@ -200,7 +200,7 @@ private: Node* old_eden_top, Node* new_eden_top, Node* length); - Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc); + Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc); public: PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) { diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 7c7ed8dd493..698b0bae068 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -85,6 +85,7 @@ Matcher::Matcher() idealreg2spillmask [Op_VecX] = NULL; idealreg2spillmask [Op_VecY] = NULL; idealreg2spillmask [Op_VecZ] = NULL; + idealreg2spillmask [Op_RegFlags] = NULL; idealreg2debugmask [Op_RegI] = NULL; idealreg2debugmask [Op_RegN] = NULL; @@ -97,6 +98,7 @@ Matcher::Matcher() idealreg2debugmask [Op_VecX] = NULL; idealreg2debugmask [Op_VecY] = NULL; idealreg2debugmask [Op_VecZ] = NULL; + idealreg2debugmask [Op_RegFlags] = NULL; idealreg2mhdebugmask[Op_RegI] = NULL; idealreg2mhdebugmask[Op_RegN] = NULL; @@ -109,6 +111,7 @@ Matcher::Matcher() idealreg2mhdebugmask[Op_VecX] = NULL; idealreg2mhdebugmask[Op_VecY] = NULL; idealreg2mhdebugmask[Op_VecZ] = NULL; + idealreg2mhdebugmask[Op_RegFlags] = NULL; debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node } diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp index ea80b5b8110..9ba9e1ad419 100644 --- a/hotspot/src/share/vm/prims/jniCheck.cpp +++ b/hotspot/src/share/vm/prims/jniCheck.cpp @@ -238,8 +238,8 @@ functionExit(JavaThread* thr) size_t live_handles = handles->get_number_of_live_handles(); if (live_handles > planned_capacity) { IN_VM( - tty->print_cr("WARNING: JNI local refs: %zu, exceeds capacity: %zu", - live_handles, planned_capacity); + tty->print_cr("WARNING: JNI local refs: " SIZE_FORMAT ", exceeds capacity: " SIZE_FORMAT, + live_handles, planned_capacity); thr->print_stack(); ) // Complain just the once, reset to current + warn threshold diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 6a1b4dda087..2955463852e 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1009,9 +1009,9 @@ JVM_END // Module support ////////////////////////////////////////////////////////////////////////////// JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version, - jstring location, jobjectArray packages)) + jstring location, const char* const* packages, jsize num_packages)) JVMWrapper("JVM_DefineModule"); - Modules::define_module(module, version, location, packages, CHECK); + Modules::define_module(module, version, location, packages, num_packages, CHECK); JVM_END JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)) @@ -1019,17 +1019,17 @@ JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)) Modules::set_bootloader_unnamed_module(module, CHECK); JVM_END -JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module)) +JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module)) JVMWrapper("JVM_AddModuleExports"); Modules::add_module_exports_qualified(from_module, package, to_module, CHECK); JVM_END -JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package)) +JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package)) JVMWrapper("JVM_AddModuleExportsToAllUnnamed"); Modules::add_module_exports_to_all_unnamed(from_module, package, CHECK); JVM_END -JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package)) +JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package)) JVMWrapper("JVM_AddModuleExportsToAll"); Modules::add_module_exports(from_module, package, NULL, CHECK); JVM_END @@ -1039,16 +1039,11 @@ JVM_ENTRY (void, JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject so Modules::add_reads_module(from_module, source_module, CHECK); JVM_END -JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, jstring package)) +JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, const char* package)) JVMWrapper("JVM_AddModulePackage"); Modules::add_module_package(module, package, CHECK); JVM_END -JVM_ENTRY (jobject, JVM_GetModuleByPackageName(JNIEnv *env, jobject loader, jstring package)) - JVMWrapper("JVM_GetModuleByPackageName"); - return Modules::get_module_by_package_name(loader, package, THREAD); -JVM_END - // Reflection support ////////////////////////////////////////////////////////////////////////////// JVM_ENTRY(jstring, JVM_GetClassName(JNIEnv *env, jclass cls)) diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index c713645024e..e105c97766d 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -412,30 +412,67 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, * Module support funcions */ +/* + * Define a module with the specified packages and bind the module to the + * given class loader. + * module: module to define + * is_open: specifies if module is open (currently ignored) + * version: the module version + * location: the module location + * packages: list of packages in the module + * num_packages: number of packages in the module + */ JNIEXPORT void JNICALL JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version, - jstring location, jobjectArray packages); + jstring location, const char* const* packages, jsize num_packages); +/* + * Set the boot loader's unnamed module. + * module: boot loader's unnamed module + */ JNIEXPORT void JNICALL JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); +/* + * Do a qualified export of a package. + * from_module: module containing the package to export + * package: name of the package to export + * to_module: module to export the package to + */ JNIEXPORT void JNICALL -JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); +JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module); +/* + * Do an export of a package to all unnamed modules. + * from_module: module containing the package to export + * package: name of the package to export to all unnamed modules + */ JNIEXPORT void JNICALL -JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); +JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package); +/* + * Do an unqualified export of a package. + * from_module: module containing the package to export + * package: name of the package to export + */ JNIEXPORT void JNICALL -JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); +JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package); +/* + * Add a module to the list of modules that a given module can read. + * from_module: module requesting read access + * source_module: module that from_module wants to read + */ JNIEXPORT void JNICALL JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module); +/* + * Add a package to a module. + * module: module that will contain the package + * package: package to add to the module + */ JNIEXPORT void JNICALL -JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); - -JNIEXPORT jobject JNICALL -JVM_GetModuleByPackageName(JNIEnv* env, jobject loader, jstring package); +JVM_AddModulePackage(JNIEnv* env, jobject module, const char* package); /* * Reflection support functions diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index 0f390214eb2..7a0515c2bc4 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@ defines first_mod --> no packages +// defines second_mod --> packages p2 +// +// first_mod can read second_mod +// package p2 in second_mod is exported to first_mod +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in second_mod +// Access is not allowed, even after p2 is exported to all unnamed modules. + +public class AccessExportTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base, second_mod + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.module("first_mod") + .requires("java.base") + .requires("second_mod") + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.module("second_mod") + .requires("java.base") + .exports("p2", Set.of("first_mod")) + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod); + + // Resolves "first_mod" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod")); + + // Map each module to the same class loader + Map map = new HashMap<>(); + map.put("first_mod", MySameClassLoader.loader1); + map.put("second_mod", MySameClassLoader.loader1); + + // Create Layer that contains first_mod & second_mod + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("first_mod") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("second_mod") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = MySameClassLoader.loader1.loadClass("p2.c2"); + // Use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + // First access check for p1.c1 + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, the unnamed module should not have access to public type p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module second_mod does not export p2 to unnamed module"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Export second_mod/p2 to all unnamed modules. + Module second_mod = p2_c2_class.getModule(); + jdk.internal.module.Modules.addExportsToAllUnnamed(second_mod, "p2"); + + // Second access check for p1.c1, should have same result as first + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module second_mod does not export p2 to unnamed module"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + } + + public static void main(String args[]) throws Throwable { + AccessExportTwice test = new AccessExportTwice(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java new file mode 100644 index 00000000000..5d1a690a740 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @summary Class p1.c1 in module first_mod cannot read p2.c2 in module second_mod, + * even after a read edge is added between first_mod and second_mod. + * Ensures constant access check answers when not accessible due to readability. + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.module + * @compile p2/c2.java + * @compile p1/c1.java + * @compile p4/c4.java + * @run main/othervm AccessReadTwice + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +// +// ClassLoader1 --> defines first_mod --> packages p1, p4 +// defines second_mod --> package p2 +// +// package p2 in second_mod is exported to first_mod +// +// class p1.c1 defined in first_mod tries to access p2.c2 defined in second_mod +// Access is not allowed, even after a read edge is added between first_mod and second_mod. + +public class AccessReadTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base + // Packages: p1, p4 + // Packages exported: none + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.module("first_mod") + .requires("java.base") + .contains(Set.of("p1", "p4")) + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.module("second_mod") + .requires("java.base") + .exports("p2", Set.of("first_mod")) + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod); + + // Resolves "first_mod" and "second_mod" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod", "second_mod")); + + // Map each module to this class loader + Map map = new HashMap<>(); + ClassLoader loader = AccessReadTwice.class.getClassLoader(); + map.put("first_mod", loader); + map.put("second_mod", loader); + + // Create Layer that contains first_mod & second_mod + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("first_mod") == loader); + assertTrue(layer.findLoader("second_mod") == loader); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = loader.loadClass("p2.c2"); + Class p1_c1_class = loader.loadClass("p1.c1"); + Class p4_c4_class = loader.loadClass("p4.c4"); + + Module first_mod = p1_c1_class.getModule(); + Module second_mod = p2_c2_class.getModule(); + + // Export first_mod/p1 and first_mod/p4 to all unnamed modules so that + // this test can use them + jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p1"); + jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p4"); + + // First access check for p1.c1 + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, module first_mod should not have access to p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Add a read edge from p4/c4's module (first_mod) to second_mod + p4.c4 c4_obj = new p4.c4(); + c4_obj.addReads(second_mod); + + // Second access check for p1.c1, should have same result as first + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + } + + public static void main(String args[]) throws Throwable { + AccessReadTwice test = new AccessReadTwice(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/p4/c4.java b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java new file mode 100644 index 00000000000..d0098674672 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests. + +package p4; + +import java.lang.reflect.Module; + +public class c4 { + // Add a read edge from c4's module to given module m + public void addReads(Module m) { + c4.class.getModule().addReads(m); + } +} diff --git a/hotspot/test/runtime/modules/JVMAddModulePackage.java b/hotspot/test/runtime/modules/JVMAddModulePackage.java index 62106f8597f..3f7f2fd29a0 100644 --- a/hotspot/test/runtime/modules/JVMAddModulePackage.java +++ b/hotspot/test/runtime/modules/JVMAddModulePackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,11 +84,11 @@ public class JVMAddModulePackage { // Expected } - // Existing package, expect an IAE + // Existing package, expect an ISE try { ModuleHelper.AddModulePackage(module1, "yourpackage"); - throw new RuntimeException("Failed to get the expected IAE"); - } catch(IllegalArgumentException e) { + throw new RuntimeException("Failed to get the expected ISE"); + } catch(IllegalStateException e) { // Expected } diff --git a/hotspot/test/runtime/modules/JVMDefineModule.java b/hotspot/test/runtime/modules/JVMDefineModule.java index dd19770ee98..9e44878490d 100644 --- a/hotspot/test/runtime/modules/JVMDefineModule.java +++ b/hotspot/test/runtime/modules/JVMDefineModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,27 +127,27 @@ public class JVMDefineModule { } } - // Duplicate module name, expect an IAE - m = ModuleHelper.ModuleObject("module.name", cl, new String[] { "mypackage6" }); + // Duplicate module name, expect an ISE + m = ModuleHelper.ModuleObject("Module_A", cl, new String[] { "mypackage6" }); assertNotNull(m, "Module should not be null"); ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" }); try { ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6a" }); - throw new RuntimeException("Failed to get IAE for duplicate module"); - } catch(IllegalArgumentException e) { - if (!e.getMessage().contains("Module module.name is already defined")) { - throw new RuntimeException("Failed to get expected IAE message for duplicate module: " + e.getMessage()); + throw new RuntimeException("Failed to get ISE for duplicate module"); + } catch(IllegalStateException e) { + if (!e.getMessage().contains("Module Module_A is already defined")) { + throw new RuntimeException("Failed to get expected ISE message for duplicate module: " + e.getMessage()); } } - // Package is already defined for class loader, expect an IAE + // Package is already defined for class loader, expect an ISE m = ModuleHelper.ModuleObject("dupl.pkg.module", cl, new String[] { "mypackage6b" }); try { ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" }); - throw new RuntimeException("Failed to get IAE for existing package"); - } catch(IllegalArgumentException e) { - if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module already exists for class loader")) { - throw new RuntimeException("Failed to get expected IAE message for duplicate package: " + e.getMessage()); + throw new RuntimeException("Failed to get ISE for existing package"); + } catch(IllegalStateException e) { + if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module is already in another module, Module_A, defined to the class loader")) { + throw new RuntimeException("Failed to get expected ISE message for duplicate package: " + e.getMessage()); } } diff --git a/hotspot/test/serviceability/attach/AttachSetGetFlag.java b/hotspot/test/serviceability/attach/AttachSetGetFlag.java index 3b48759cc23..2d6a28cfce3 100644 --- a/hotspot/test/serviceability/attach/AttachSetGetFlag.java +++ b/hotspot/test/serviceability/attach/AttachSetGetFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * java.compiler * java.management * jdk.attach/sun.tools.attach - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run main AttachSetGetFlag */ diff --git a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java index c22be26f951..8b3a8d8a47d 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+SegmentedCodeCache CodeCacheTest * @run testng/othervm -XX:-SegmentedCodeCache CodeCacheTest * @run testng/othervm -Xint -XX:+SegmentedCodeCache CodeCacheTest diff --git a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java index e0bdd408012..11a28ec9a85 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java index c43dfafa56f..8d40423b5e8 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java @@ -49,7 +49,7 @@ public class CompilerDirectivesDCMDTest { public void run(CommandExecutor executor) { - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { filename = System.getProperty("test.src", ".") + File.separator + "control2.txt"; } else { filename = System.getProperty("test.src", ".") + File.separator + "control1.txt"; diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java index 3640bbcebbb..a1b79533a3a 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @summary Test of diagnostic command Compiler.queue * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/serviceability/dcmd/framework/HelpTest.java b/hotspot/test/serviceability/dcmd/framework/HelpTest.java index b172db8e7ca..d88ddffce71 100644 --- a/hotspot/test/serviceability/dcmd/framework/HelpTest.java +++ b/hotspot/test/serviceability/dcmd/framework/HelpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+UsePerfData HelpTest */ public class HelpTest { diff --git a/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java index be8a4d8560d..2536b4125aa 100644 --- a/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java +++ b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+UsePerfData InvalidCommandTest */ public class InvalidCommandTest { diff --git a/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java index dadaf3113b2..d39f0de5263 100644 --- a/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java +++ b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+UsePerfData VMVersionTest */ public class VMVersionTest { diff --git a/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java index bc2f3e2eb15..a3d244cef4e 100644 --- a/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java +++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassHistogramAllTest */ public class ClassHistogramAllTest extends ClassHistogramTest { diff --git a/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java index 5b4f017ec40..fec990e5a10 100644 --- a/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java +++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassHistogramTest */ public class ClassHistogramTest { diff --git a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java index 257acea6b10..d811493c1d3 100644 --- a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java +++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng HeapDumpAllTest */ public class HeapDumpAllTest extends HeapDumpTest { diff --git a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java index 257a30f899c..60444ae358c 100644 --- a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java +++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import jdk.test.lib.dcmd.PidJcmdExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng HeapDumpTest */ public class HeapDumpTest { diff --git a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java index 22af05f0523..f49e4165688 100644 --- a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java +++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.test.lib.process.ProcessTools; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build FinalizationRunner * @run main RunFinalizationTest */ diff --git a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java index 44bd09a6268..267e91381a5 100644 --- a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java +++ b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -Xlog:gc=debug:RunGC.gclog -XX:-ExplicitGCInvokesConcurrent RunGCTest */ public class RunGCTest { diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java index 373edf07857..c190353803f 100644 --- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java +++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java @@ -41,7 +41,7 @@ import org.testng.annotations.Test; * java.compiler * java.instrument * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build SimpleJvmtiAgent * @run main ClassFileInstaller SimpleJvmtiAgent * @run testng LoadAgentDcmdTest diff --git a/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java index b931c42019e..c1ca3a35442 100644 --- a/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java +++ b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng PrintConcurrentLocksTest */ public class PrintConcurrentLocksTest extends PrintTest { diff --git a/hotspot/test/serviceability/dcmd/thread/PrintTest.java b/hotspot/test/serviceability/dcmd/thread/PrintTest.java index 77e22e1d8c5..e4af11c3261 100644 --- a/hotspot/test/serviceability/dcmd/thread/PrintTest.java +++ b/hotspot/test/serviceability/dcmd/thread/PrintTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import java.util.regex.Pattern; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng PrintTest */ public class PrintTest { diff --git a/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java b/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java index aee55b5cc31..7c77a2d2a82 100644 --- a/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java +++ b/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassHierarchyTest */ diff --git a/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java index d2230e33d8b..60f94069986 100644 --- a/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassLoaderStatsTest */ diff --git a/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java index ac04d02b382..72f009d75e4 100644 --- a/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java +++ b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis CommandLineTest */ public class CommandLineTest { diff --git a/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java index 3b4cfce1b60..4bda8a8f4c6 100644 --- a/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng DynLibsTest */ diff --git a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java index f83ab760a49..3554a696119 100644 --- a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -Xmx129m -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right -XX:-TieredCompilation FlagsTest */ public class FlagsTest { diff --git a/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java index 71ec4e17139..8325dc85f39 100644 --- a/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java +++ b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng SystemPropertiesTest */ public class SystemPropertiesTest { diff --git a/hotspot/test/serviceability/dcmd/vm/UptimeTest.java b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java index a907421d5da..77ff300ee2f 100644 --- a/hotspot/test/serviceability/dcmd/vm/UptimeTest.java +++ b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import java.text.ParseException; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng UptimeTest */ public class UptimeTest { diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java b/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java index 1030675d8f3..0b30a67dd52 100644 --- a/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java +++ b/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java @@ -35,7 +35,7 @@ import jdk.test.lib.process.ProcessTools; * java.compiler * java.instrument * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build GetObjectSizeClassAgent * @run main ClassFileInstaller GetObjectSizeClassAgent * @run main GetObjectSizeClass diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java index e2a801aaef8..57eabb72e8a 100644 --- a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java +++ b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.process.ProcessTools; * java.compiler * java.instrument * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build GetObjectSizeOverflowAgent * @run main ClassFileInstaller GetObjectSizeOverflowAgent * @run main GetObjectSizeOverflow diff --git a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java index 4a9bb2606fe..c6a203e86bc 100644 --- a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java +++ b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * java.instrument * java.management * jdk.jartool/sun.tools.jar - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build UnresolvedClassAgent * @run main TestRedefineWithUnresolvedClass */ diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java index c3dced229db..855fbad95c6 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java @@ -21,12 +21,9 @@ * questions. */ -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import jdk.test.lib.process.ProcessTools; import sun.management.VMManagement; @@ -38,7 +35,7 @@ public class JMapHProfLargeHeapProc { buildLargeHeap(args); // Print our pid on stdout - System.out.println("PID[" + getProcessId() + "]"); + System.out.println("PID[" + ProcessTools.getProcessId() + "]"); // Wait for input before termination System.in.read(); @@ -50,22 +47,4 @@ public class JMapHProfLargeHeapProc { } } - public static int getProcessId() throws Exception { - - // Get the current process id using a reflection hack - RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); - Field jvm = runtime.getClass().getDeclaredField("jvm"); - - jvm.setAccessible(true); - VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); - - Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); - - pid_method.setAccessible(true); - - int pid = (Integer) pid_method.invoke(mgmt); - - return pid; - } - } diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java index d2e64f75d34..2a46621d118 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ import jdk.test.lib.process.ProcessTools; * @modules java.base/jdk.internal.misc * java.compiler * java.management/sun.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build JMapHProfLargeHeapProc * @run main JMapHProfLargeHeapTest */ @@ -90,6 +90,9 @@ public class JMapHProfLargeHeapTest { try (Scanner largeHeapScanner = new Scanner( largeHeapProc.getInputStream());) { String pidstring = null; + if (!largeHeapScanner.hasNext()) { + throw new RuntimeException ("Test failed: could not open largeHeapScanner."); + } while ((pidstring = largeHeapScanner.findInLine("PID\\[[0-9].*\\]")) == null) { Thread.sleep(500); } diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java index 88a94f66cdf..98a3d29bfa4 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java @@ -59,6 +59,8 @@ public class CompileTheWorld { OUT = os; } + boolean passed = false; + try { try { if (ManagementFactory.getCompilationMXBean() == null) { @@ -84,10 +86,10 @@ public class CompileTheWorld { PathHandler.getClassCount(), Compiler.getMethodCount(), System.currentTimeMillis() - start); + passed = true; } finally { - if (os != null) { - os.close(); - } + // might have started new threads + System.exit(passed ? 0 : 1); } } diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java index 4159c483408..75d82dd1ebd 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java @@ -101,10 +101,12 @@ public class Utils { INITIAL_COMP_LEVEL = 1; } else { String vmName = System.getProperty("java.vm.name"); - if (Utils.endsWithIgnoreCase(vmName, " Server VM")) { + String vmInfo = System.getProperty("java.vm.info"); + boolean isEmulatedClient = (vmInfo != null) && vmInfo.contains("emulated-client"); + if (Utils.endsWithIgnoreCase(vmName, " Server VM") && !isEmulatedClient) { INITIAL_COMP_LEVEL = 4; } else if (Utils.endsWithIgnoreCase(vmName, " Client VM") - || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) { + || Utils.endsWithIgnoreCase(vmName, " Minimal VM") || isEmulatedClient) { INITIAL_COMP_LEVEL = 1; } else { throw new RuntimeException("Unknown VM: " + vmName); diff --git a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java index 43c9715a95e..5e56d66bd4a 100644 --- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java +++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java @@ -50,7 +50,7 @@ public class TestMutuallyExclusivePlatformPredicates { OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"), VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero", "isEmbedded"), MODE("isInt", "isMixed", "isComp"), - IGNORED("isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", + IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", "shouldSAAttach", "canPtraceAttachLinux", "canAttachOSX", "isTieredSupported"); diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java index 31f24081fa1..e24461cdac9 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java @@ -30,11 +30,11 @@ * java.base/jdk.internal.reflect * java.management * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassesDirTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes - * @run main ClassesDirTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver ClassesDirTest prepare + * @run driver ClassesDirTest compile classes + * @run driver ClassesDirTest check * @summary testing of CompileTheWorld :: classes in directory * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java index c2823de598c..5ffe27ba0c6 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java @@ -30,11 +30,11 @@ * java.base/jdk.internal.reflect * java.management * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassesListTest prepare - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst - * @run main ClassesListTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver ClassesListTest prepare + * @run driver/timeout=600 ClassesListTest compile classes.lst + * @run driver ClassesListTest check * @summary testing of CompileTheWorld :: list of classes in file * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/CtwTest.java b/hotspot/test/testlibrary_tests/ctw/CtwTest.java index 06b16b631b9..eb6aedc1fbe 100644 --- a/hotspot/test/testlibrary_tests/ctw/CtwTest.java +++ b/hotspot/test/testlibrary_tests/ctw/CtwTest.java @@ -21,6 +21,7 @@ * questions. */ +import java.util.Arrays; import java.util.List; import java.util.Collections; import java.util.ArrayList; @@ -38,8 +39,20 @@ import java.nio.charset.Charset; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; public abstract class CtwTest { + private static final String LOG_FILE = "ctw.log"; + private static final String[] CTW_COMMAND = { + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Dsun.hotspot.tools.ctw.logfile=" + LOG_FILE, + "--add-exports", "java.base/jdk.internal.jimage=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED", + sun.hotspot.tools.ctw.CompileTheWorld.class.getName(), + }; protected final String[] shouldContain; protected CtwTest(String[] shouldContain) { this.shouldContain = shouldContain; @@ -54,7 +67,10 @@ public abstract class CtwTest { prepare(); break; case "check": - check(args); + check(); + break; + case "compile": + compile(args); break; default: throw new Error("unregonized action -- " + args[0]); @@ -63,20 +79,27 @@ public abstract class CtwTest { protected void prepare() throws Exception { } - protected void check(String[] args) throws Exception { - if (args.length < 2) { - throw new Error("logfile isn't specified"); - } - String logfile = args[1]; - try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile), + protected void check() throws Exception { + try (BufferedReader r = Files.newBufferedReader(Paths.get(LOG_FILE), Charset.defaultCharset())) { OutputAnalyzer output = readOutput(r); - for (String test : shouldContain) { + for (String test : shouldContain) { output.shouldContain(test); } } } + protected void compile(String[] args) throws Exception { + // concat CTW_COMMAND and args w/o 0th element + String[] cmd = Arrays.copyOf(CTW_COMMAND, CTW_COMMAND.length + args.length - 1); + System.arraycopy(args, 1, cmd, CTW_COMMAND.length, args.length - 1); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmd); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + dump(output, "compile"); + output.shouldHaveExitValue(0); + } + private static OutputAnalyzer readOutput(BufferedReader reader) throws IOException { StringBuilder builder = new StringBuilder(); diff --git a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java index a784bda84ad..18ce6347b81 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,13 +30,13 @@ * java.base/jdk.internal.reflect * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main JarDirTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/* - * @run main JarDirTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver JarDirTest prepare + * @run driver JarDirTest compile jars/* + * @run driver JarDirTest check * @summary testing of CompileTheWorld :: jars in directory * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/JarsTest.java b/hotspot/test/testlibrary_tests/ctw/JarsTest.java index 16af1639854..cae3f7b7193 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarsTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,13 +30,13 @@ * java.base/jdk.internal.reflect * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main JarsTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar - * @run main JarsTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver JarsTest prepare + * @run driver JarsTest compile foo.jar bar.jar + * @run driver JarsTest check * @summary testing of CompileTheWorld :: jars * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java index 302f77c3d31..79830375479 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management/sun.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission