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