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