1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "compiler/compileBroker.hpp"
  27 #include "compiler/directivesparser.hpp"
  28 #include "memory/allocation.inline.hpp"
  29 #include "runtime/os.hpp"
  30 #include <string.h>
  31 
  32 void DirectivesParser::push_tmp(CompilerDirectives* dir) {
  33   dir->set_next(_tmp_top);
  34   _tmp_top = dir;
  35 }
  36 
  37 CompilerDirectives* DirectivesParser::pop_tmp() {
  38   if (_tmp_top == NULL) {
  39     return NULL;
  40   }
  41   CompilerDirectives* tmp = _tmp_top;
  42   _tmp_top = _tmp_top->next();
  43   tmp->set_next(NULL);
  44   return tmp;
  45 }
  46 
  47 bool DirectivesParser::parse_string(const char* text) {
  48   ResourceMark rm;
  49   DirectivesParser cd(text);
  50   if (cd.valid()) {
  51     cd.install_directives();
  52     return true;
  53   }
  54   tty->print_cr("Parsing of compiler directives failed");
  55   return false;;
  56 }
  57 
  58 bool DirectivesParser::has_file() {
  59   return CompilerDirectivesFile != NULL;
  60 }
  61 
  62 bool DirectivesParser::parse_from_flag() {
  63   return parse_from_file(CompilerDirectivesFile);
  64 }
  65 
  66 bool DirectivesParser::parse_from_file(const char* filename) {
  67   assert(filename != NULL, "Test before calling this");
  68 
  69   // Open in binary mode to get a correct size
  70   FILE* file1 = fopen(filename, "rb");
  71   fseek(file1, 0L, SEEK_END);
  72   long size = ftell(file1);
  73   fseek(file1, 0L, SEEK_SET);
  74   fclose(file1);
  75 
  76   // Open in textmode for parsing
  77   FILE* file = fopen(filename, "rb");
  78   if (file == NULL) {
  79     tty->print("Could not open compiler directives file: %s", filename);
  80     return false;
  81   }
  82 
  83   // Copy to buffer for parsing - The parser must be able to work on strings too.
  84   char* token = NEW_C_HEAP_ARRAY(char, size + 1, mtCompiler);
  85   int  pos = 0;
  86   int  c = getc(file);
  87   while(c != EOF && pos < size) {
  88     token[pos++] = c;
  89     c = getc(file);
  90   }
  91   token[pos++] = '\0';
  92 
  93   fclose(file);
  94 
  95   bool result = parse_string(token);
  96   FREE_C_HEAP_ARRAY(char, token);
  97   return result;
  98 }
  99 
 100 void DirectivesParser::install_directives() {
 101   // Pop from internal temporary stack and push to compileBroker.
 102   CompilerDirectives* tmp = pop_tmp();
 103   int i = 0;
 104   while (tmp != NULL) {
 105     i++;
 106     CompileBroker::dirstack()->push(tmp);
 107     tmp = pop_tmp();
 108   }
 109   tty->print_cr("%i compiler directives added", i);
 110 }
 111 
 112 DirectivesParser::DirectivesParser(const char* text)
 113 : JSON(text, false), depth(0), current_dir(NULL), current_dirset(NULL), _tmp_top(NULL) {
 114 #ifndef PRODUCT
 115   memset(stack, 0, MAX_DEPTH * sizeof(stack[0]));
 116 #endif
 117   parse();
 118 }
 119 
 120 DirectivesParser::~DirectivesParser() {
 121 }
 122 
 123 const DirectivesParser::key DirectivesParser::keys[] = {
 124     // name, keytype, allow_array, allowed_mask, set_function
 125     { "c1",     type_c1,     0, mask(type_directives), NULL, UnknownFlagType },
 126     { "c2",     type_c2,     0, mask(type_directives), NULL, UnknownFlagType },
 127     { "match",  type_match,  1, mask(type_directives), NULL, UnknownFlagType },
 128     { "inline", type_inline, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },
 129     { "enable", type_enable, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },
 130     { "preset", type_preset, 0, mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },
 131 
 132     // Global flags
 133     #define common_flag_key(name, type, dvalue, compiler) \
 134     { #name, type_flag, 0, mask(type_directives) | mask(type_c1) | mask(type_c2), &DirectiveSet::set_##name, type##Flag},
 135     compilerdirectives_common_flags(common_flag_key)
 136     compilerdirectives_c2_flags(common_flag_key)
 137     compilerdirectives_c1_flags(common_flag_key)
 138     #undef common_flag_key
 139 };
 140 
 141 const DirectivesParser::key DirectivesParser::dir_array_key = {
 142      "top level directives array", type_dir_array, 0, 1 // Lowest bit means allow at top level
 143 };
 144 const DirectivesParser::key DirectivesParser::dir_key = {
 145    "top level directive", type_directives, 0, mask(type_dir_array) | 1 // Lowest bit means allow at top level
 146 };
 147 const DirectivesParser::key DirectivesParser::value_array_key = {
 148    "value array", type_value_array, 0, UINT_MAX // Allow all, checked by allow_array on other keys, not by allowed_mask from this key
 149 };
 150 
 151 // CMH - hash or binary search for more efficient lookup on many keys
 152 const DirectivesParser::key* DirectivesParser::lookup_key(const char* str, size_t len) {
 153   for (size_t i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {
 154     if (strncasecmp(keys[i].name, str, len) == 0) {
 155       return &keys[i];
 156     }
 157   }
 158   return NULL;
 159 }
 160 
 161 uint DirectivesParser::mask(keytype kt) {
 162   return 1 << (kt + 1);
 163 }
 164 
 165 bool DirectivesParser::push_key(const char* str, size_t len) {
 166   bool result = true;
 167   const key* k = lookup_key(str, len);
 168 
 169   if (k == NULL) {
 170     // os::strdup
 171     char* s = NEW_C_HEAP_ARRAY(char, len + 1, mtCompiler);
 172     strncpy(s, str, len);
 173     s[len] = '\0';
 174     error(KEY_ERROR, "No such key: '%s'.", s);
 175     FREE_C_HEAP_ARRAY(char, s);
 176     return false;
 177   }
 178 
 179   return push_key(k);
 180 }
 181 
 182 bool DirectivesParser::push_key(const key* k) {
 183   assert(k->allowedmask != 0, "not allowed anywhere?");
 184 
 185   // Exceeding the stack should not be possible with a valid compiler directive,
 186   // and an invalid should abort before this happens
 187   assert(depth < MAX_DEPTH, "exceeded stack depth");
 188   if (depth >= MAX_DEPTH) {
 189     error(INTERNAL_ERROR, "Stack depth exceeded.");
 190     return false;
 191   }
 192 
 193   assert(stack[depth] == NULL, "element not nulled, something is wrong");
 194 
 195   if (depth == 0 && !(k->allowedmask & 1)) {
 196     error(KEY_ERROR, "Key '%s' not allowed at top level.", k->name);
 197     return false;
 198   }
 199 
 200   if (depth > 0) {
 201     const key* prev = stack[depth - 1];
 202     if (!(k->allowedmask & mask(prev->type))) {
 203       error(KEY_ERROR, "Key '%s' not allowed after '%s' key.", k->name, prev->name);
 204       return false;
 205     }
 206   }
 207 
 208   stack[depth] = k;
 209   depth++;
 210   return true;
 211 }
 212 
 213 const DirectivesParser::key* DirectivesParser::current_key() {
 214   assert(depth > 0, "getting key from empty stack");
 215   if (depth == 0) {
 216     return NULL;
 217   }
 218   return stack[depth - 1];
 219 }
 220 
 221 const DirectivesParser::key* DirectivesParser::pop_key() {
 222   assert(depth > 0, "popping empty stack");
 223   if (depth == 0) {
 224     error(INTERNAL_ERROR, "Popping empty stack.");
 225     return NULL;
 226   }
 227   depth--;
 228 
 229   const key* k = stack[depth];
 230 #ifndef PRODUCT
 231   stack[depth] = NULL;
 232 #endif
 233 
 234   return k;
 235 }
 236 
 237 bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set) {
 238 
 239   void (DirectiveSet::*test)(void *args);
 240   test = option_key->set;
 241 
 242   switch (t) {
 243     case JSON_TRUE:
 244       if (option_key->flag_type != boolFlag) {
 245         error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);
 246         return false;
 247       } else {
 248         int val = 1;
 249         (set->*test)((void *)&val);
 250       }
 251       break;
 252 
 253     case JSON_FALSE:
 254       if (option_key->flag_type != boolFlag) {
 255         error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);
 256         return false;
 257       } else {
 258         int val = 0;
 259         (set->*test)((void *)&val);
 260       }
 261       break;
 262 
 263     case JSON_NUMBER_INT:
 264       if (option_key->flag_type != intxFlag) {
 265         if (option_key->flag_type == doubleFlag) {
 266           double dval = (double)v->int_value;
 267           (set->*test)((void *)&dval);
 268           break;
 269         }
 270         error(VALUE_ERROR, "Cannot use int value for an %s flag", flag_type_names[option_key->flag_type]);
 271         return false;
 272       } else {
 273         intx ival = v->int_value;
 274         (set->*test)((void *)&ival);
 275       }
 276       break;
 277 
 278     case JSON_NUMBER_FLOAT:
 279       if (option_key->flag_type != doubleFlag) {
 280         error(VALUE_ERROR, "Cannot use double value for an %s flag", flag_type_names[option_key->flag_type]);
 281         return false;
 282       } else {
 283         double dval = v->double_value;
 284         (set->*test)((void *)&dval);
 285       }
 286       break;
 287 
 288     case JSON_STRING:
 289       if (option_key->flag_type != ccstrFlag) {
 290         error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]);
 291         return false;
 292       } else {
 293         //char* s = strndup(v->str.start, v->str.length);
 294         char* s = NEW_C_HEAP_ARRAY(char, v->str.length, mtCompiler);
 295         strncpy(s, v->str.start, v->str.length + 1);
 296         s[v->str.length] = '\0';
 297         (set->*test)((void *)&s);
 298       }
 299       break;
 300 
 301     default:
 302       assert(0, "Should not reach here.");
 303     }
 304   return true;
 305 }
 306 
 307 bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) {
 308 
 309   const key* option_key = pop_key();
 310   const key* enclosing_key = current_key();
 311 
 312   if (option_key->type == value_array_key.type) {
 313     // Multi value array, we are really setting the value
 314     // for the key one step further up.
 315     option_key = pop_key();
 316     enclosing_key = current_key();
 317 
 318     // Repush option_key and multi value marker, since
 319     // we need to keep them until all multi values are set.
 320     push_key(option_key);
 321     push_key(&value_array_key);
 322   }
 323 
 324   switch (option_key->type) {
 325   case type_flag:
 326   {
 327     if (current_dirset == NULL) {
 328       assert(depth == 2, "Must not have active dirset");
 329 
 330       if (!set_option_flag(t, v, option_key, current_dir->_c1_store)) {
 331         return false;
 332       }
 333       if(!set_option_flag(t, v, option_key, current_dir->_c2_store)) {
 334         return false;
 335       }
 336     } else {
 337       assert(depth > 2, "Must have active current dirset");
 338       if (!set_option_flag(t, v, option_key, current_dirset)) {
 339         return false;
 340       }
 341     }
 342     break;
 343   }
 344 
 345   case type_match:
 346     if (t != JSON_STRING) {
 347       error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);
 348       return false;
 349     }
 350     if (enclosing_key->type != type_directives) {
 351       error(SYNTAX_ERROR, "Match keyword can only exist inside a directive");
 352       return false;
 353     }
 354     {
 355       //char* s = strndup(v->str.start, v->str.length);
 356       char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
 357       strncpy(s, v->str.start, v->str.length);
 358       s[v->str.length] = '\0';
 359 
 360       const char* error_msg = NULL;
 361       if (!current_dir->add_match(s, error_msg)) {
 362         assert (error_msg != NULL, "Must have valid error message");
 363         error(VALUE_ERROR, "Method pattern error: %s", error_msg);
 364       }
 365       FREE_C_HEAP_ARRAY(char, s);
 366     }
 367     break;
 368 
 369   case type_inline:
 370     if (t != JSON_STRING) {
 371       error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);
 372       return false;
 373     }
 374     {
 375       //char* s = strndup(v->str.start, v->str.length);
 376       char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
 377       strncpy(s, v->str.start, v->str.length);
 378       s[v->str.length] = '\0';
 379 
 380       const char* error_msg = NULL;
 381       //CMH Make a cleaner impl of when adding options to both sets
 382       if (current_dirset == NULL) {
 383         if (!current_dir->_c1_store->parse_and_add_inline(s, error_msg)) {
 384           assert (error_msg != NULL, "Must have valid error message");
 385           error(VALUE_ERROR, "Method pattern error: %s", error_msg);
 386         }
 387         if (!current_dir->_c2_store->parse_and_add_inline(s, error_msg)) {
 388           assert (error_msg != NULL, "Must have valid error message");
 389           error(VALUE_ERROR, "Method pattern error: %s", error_msg);
 390         }
 391       } else {
 392         if (!current_dirset->parse_and_add_inline(s, error_msg)) {
 393           assert (error_msg != NULL, "Must have valid error message");
 394           error(VALUE_ERROR, "Method pattern error: %s", error_msg);
 395         }
 396       }
 397       FREE_C_HEAP_ARRAY(char, s);
 398     }
 399     break;
 400 
 401   case type_c1:
 402     current_dirset = current_dir->_c1_store;
 403     if (t != JSON_TRUE && t != JSON_FALSE) {
 404       error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);
 405       return false;
 406     }
 407     break;
 408 
 409   case type_c2:
 410     current_dirset = current_dir->_c2_store;
 411     if (t != JSON_TRUE && t != JSON_FALSE) {
 412       error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);
 413       return false;
 414     }
 415     break;
 416 
 417   case type_enable:
 418     switch (enclosing_key->type) {
 419     case type_c1:
 420     case type_c2:
 421     {
 422       if (t != JSON_TRUE && t != JSON_FALSE) {
 423         error(VALUE_ERROR, "Key of type %s enclosed in a %s key needs a true or false value", option_key->name, enclosing_key->name);
 424         return false;
 425       }
 426       int val = (t == JSON_TRUE);
 427       current_dirset->set_Enabled(&val);
 428       break;
 429     }
 430 
 431     case type_directives:
 432       error(VALUE_ERROR, "Enable keyword not available for generic directive");
 433       return false;
 434       /*if (t == JSON_STRING) {
 435         if (strncasecmp("c1", v->str.start, v->str.length) == 0) {
 436           if (strncasecmp("c2", v->str.start, v->str.length) != 0) {
 437             char* s = strndup(v->str.start, v->str.length);
 438             error(VALUE_ERROR, "Key %s can only enable or disable specific compilers (c1 or c2), not \"%s\".", option_key->name, s);
 439             free(s);
 440             return false;
 441           }
 442         }
 443       }
 444       if (t == JSON_ARRAY_BEGIN) {
 445         error(VALUE_ERROR, "Key of type %s needs a value of type string or array", option_key->name);
 446         return false;
 447       }*/
 448 
 449     default:
 450       error(INTERNAL_ERROR, "Unexpected enclosing type for key %s: %s", option_key->name, enclosing_key->name);
 451       ShouldNotReachHere();
 452       return false;
 453     }
 454     break;
 455 
 456   default:
 457     break;
 458   }
 459 
 460   return true;
 461 }
 462 
 463 bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) {
 464   const key* k;
 465 
 466   if (depth == 0) {
 467     switch (t) {
 468       case JSON_ARRAY_BEGIN:
 469         return push_key(&dir_array_key);
 470 
 471       case JSON_OBJECT_BEGIN:
 472         // push synthetic dir_array
 473         push_key(&dir_array_key);
 474         assert(depth == 1, "Make sure the stack are aligned with the directives");
 475         break;
 476 
 477       default:
 478         error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");
 479         return false;
 480       }
 481   }
 482   if (depth == 1) {
 483     switch (t) {
 484       case JSON_OBJECT_BEGIN:
 485         // Parsing a new directive.
 486         current_dir = new CompilerDirectives();
 487         return push_key(&dir_key);
 488 
 489       case JSON_ARRAY_END:
 490         k = pop_key();
 491 
 492         if (k->type != type_dir_array) {
 493           error(SYNTAX_ERROR, "Expected end of directives array");
 494           return false;
 495         }
 496         return true;
 497 
 498     default:
 499       error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");
 500       return false;
 501     }
 502   } else {
 503     switch (t) {
 504     case JSON_OBJECT_BEGIN:
 505       k = current_key();
 506       switch (k->type) {
 507       case type_c1:
 508         current_dirset = current_dir->_c1_store;
 509         return true;
 510       case type_c2:
 511         current_dirset = current_dir->_c2_store;
 512         return true;
 513 
 514       case type_dir_array:
 515         return push_key(&dir_key);
 516 
 517       default:
 518         error(SYNTAX_ERROR, "The key '%s' does not allow an object to follow.", k->name);
 519         return false;
 520       }
 521       return false;
 522 
 523     case JSON_OBJECT_END:
 524       k = pop_key();
 525       switch (k->type) {
 526       case type_c1:
 527       case type_c2:
 528         // This is how we now if options apply to a single or both dirsets
 529         current_dirset = NULL;
 530         break;
 531 
 532       case type_directives:
 533         // Finish directive and push to stack!
 534         push_tmp(current_dir);
 535 
 536         current_dir = NULL;
 537         break;
 538 
 539       default:
 540         error(INTERNAL_ERROR, "Object end with wrong key type on stack: %s.", k->name);
 541         ShouldNotReachHere();
 542         return false;
 543       }
 544       return true;
 545 
 546     case JSON_ARRAY_BEGIN:
 547       k = current_key();
 548       if (!(k->allow_array_value)) {
 549         if (k->type == type_dir_array) {
 550           error(SYNTAX_ERROR, "Array not allowed inside top level array, expected directive object.");
 551         } else {
 552           error(VALUE_ERROR, "The key '%s' does not allow an array of values.", k->name);
 553         }
 554         return false;
 555       }
 556       return push_key(&value_array_key);
 557 
 558     case JSON_ARRAY_END:
 559       k = pop_key(); // Pop multi value marker
 560       assert(k->type == value_array_key.type, "array end for level != 0 should terminate multi value");
 561       k = pop_key(); // Pop key for option that was set
 562       return true;
 563 
 564     case JSON_KEY:
 565       return push_key(v->str.start, v->str.length);
 566 
 567     case JSON_STRING:
 568     case JSON_NUMBER_INT:
 569     case JSON_NUMBER_FLOAT:
 570     case JSON_TRUE:
 571     case JSON_FALSE:
 572     case JSON_NULL:
 573       return set_option(t, v);
 574 
 575     default:
 576       error(INTERNAL_ERROR, "Unknown JSON type: %d.", t);
 577       ShouldNotReachHere();
 578       return false;
 579     }
 580   }
 581 }
 582 
 583 #ifndef PRODUCT
 584 void DirectivesParser::test(const char* text, bool should_pass) {
 585   DirectivesParser cd(text);
 586   if (should_pass) {
 587     assert(cd.valid() == true, "failed on a valid DirectivesParser string");
 588     if (VerboseInternalVMTests) {
 589       tty->print("-- DirectivesParser test passed as expected --\n");
 590     }
 591   } else {
 592     assert(cd.valid() == false, "succeeded on an invalid DirectivesParser string");
 593     if (VerboseInternalVMTests) {
 594       tty->print("-- DirectivesParser test failed as expected --\n");
 595     }
 596   }
 597 }
 598 
 599 bool DirectivesParser::test() {
 600   DirectivesParser::test("{}", true);
 601   DirectivesParser::test("[]", true);
 602   DirectivesParser::test("[{}]", true);
 603   DirectivesParser::test("[{},{}]", true);
 604   DirectivesParser::test("{},{}", false);
 605 
 606   DirectivesParser::test(
 607     "[" "\n"
 608     "  {" "\n"
 609     "    match: \"foo.bar.*\"," "\n"
 610     "    inline : \"+java.util.*\"," "\n"
 611     "    print_assembly: true," "\n"
 612     "    verify_oopmaps: true," "\n"
 613     "    max_loop_unrolling: 5" "\n"
 614     "  }" "\n"
 615     "]" "\n", true);
 616 
 617   DirectivesParser::test(
 618     "[" "\n"
 619     "  [" "\n"
 620     "    {" "\n"
 621     "      match: \"foo.bar.*\"," "\n"
 622     "      inline : \"+java.util.*\"," "\n"
 623     "      print_assembly: true," "\n"
 624     "      verify_oopmaps: true," "\n"
 625     "      max_loop_unrolling: 5" "\n"
 626     "    }" "\n"
 627     "  ]" "\n"
 628     "]" "\n", false);
 629 
 630   DirectivesParser::test(
 631     "[" "\n"
 632     "  {" "\n"
 633     "    match: \"foo.bar.*\"," "\n"
 634     "    c1: {"
 635     "      array_bounds_check_removal: false," "\n"
 636     "    }" "\n"
 637     "  }" "\n"
 638     "]" "\n", true);
 639 
 640   DirectivesParser::test(
 641     "[" "\n"
 642     "  {" "\n"
 643     "    match: \"foo.bar.*\"," "\n"
 644     "    c2: {" "\n"
 645     "      array_bounds_check_removal: false," "\n"
 646     "    }" "\n"
 647     "  }" "\n"
 648     "]" "\n", false);
 649 
 650   DirectivesParser::test(
 651     "[" "\n"
 652     "  {" "\n"
 653     "    match: \"foo.bar.*\"," "\n"
 654     "    array_bounds_check_removal: [" "\n"
 655     "      true," "\n"
 656     "      false" "\n"
 657     "    ]," "\n"
 658     "  }" "\n"
 659     "]" "\n", false);
 660 
 661   DirectivesParser::test(
 662     "[" "\n"
 663     "  {"
 664     "    // pattern to match against class+method+signature" "\n"
 665     "    // leading and trailing wildcard (*) allowed" "\n"
 666     "    match: \"foo.bar.*\"," "\n"
 667     "" "\n"
 668     "    // override defaults for specified compiler" "\n"
 669     "    // we may differentiate between levels too. TBD." "\n"
 670     "    c1:  {" "\n"
 671     "      //override c1 presets " "\n"
 672     "      array_bounds_check_removal: false," "\n"
 673     "      blocking_compile: true," "\n"
 674     "    }," "\n"
 675     "" "\n"
 676     "    c2: {" "\n"
 677     "        // control inlining of method" "\n"
 678     "        // + force inline, - dont inline" "\n"
 679     "        inline : \"+java.util.*\"," "\n"
 680     "        print_inlining: true," "\n"
 681     "    }," "\n"
 682     "" "\n"
 683     "    // directives outside a specific preset applies to all compilers" "\n"
 684     "    inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
 685     "    print_assembly: true," "\n"
 686     "    verify_oopmaps: true," "\n"
 687     "    max_loop_unrolling: 5" "\n"
 688     "  }," "\n"
 689     "  {" "\n"
 690     "    // matching several patterns require an array" "\n"
 691     "    match: [\"baz.*\",\"frob*\"]," "\n"
 692     "" "\n"
 693     "    // only enable c1 for this directive" "\n"
 694     "    // all enabled by default. Command disables all not listed" "\n"
 695     "    enable: \"c1\"," "\n"
 696     "" "\n"
 697     "    // applies to all compilers" "\n"
 698     "    // + force inline, - dont inline" "\n"
 699     "    inline : [ \"+java.util.*\", \"-com.sun.*\" ]," "\n"
 700     "    print_inlining: true," "\n"
 701     "" "\n"
 702     "    // force matching compiles to be blocking/syncronous" "\n"
 703     "    blocking_compile: true" "\n"
 704     "  }," "\n"
 705     "]" "\n", true);
 706 
 707   // Test max stack depth
 708     DirectivesParser::test(
 709       "[" "\n"             // depth 1: type_dir_array
 710       "  {" "\n"           // depth 2: type_directives
 711       "    c1:" "\n"       // depth 3: type_c1
 712       "    {" "\n"
 713       "      inline:" "\n" // depth 4: type_inline
 714       "      [" "\n"       // depth 5: type_value_array
 715       "        \"foo\"," "\n"
 716       "        \"bar\"," "\n"
 717       "      ]" "\n"       // depth 3: pop type_value_array and type_inline keys
 718       "    }" "\n"         // depth 2: pop type_c1 key
 719       "  }" "\n"           // depth 1: pop type_directives key
 720       "]" "\n", true);     // depth 0: pop type_dir_array key
 721 
 722     // Test max stack depth
 723     DirectivesParser::test(
 724       "[{c1:{c1:{c1:{c1:{c1:{c1:{c1:{}}}}}}}}]", false);
 725 
 726   DirectivesParser::test(
 727     "[" "\n"
 728     "  {" "\n"
 729     "    c1: true," "\n"
 730     "    c2: true," "\n"
 731     "    match: true," "\n"
 732     "    inline: true," "\n"
 733     "    enable: true," "\n"
 734     "    c1: {" "\n"
 735     "      preset: true," "\n"
 736     "    }" "\n"
 737     "  }" "\n"
 738     "]" "\n", false);
 739 
 740   return true;
 741 }
 742 
 743 #endif