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