jdk

Форк
0
/
directivesParser.cpp 
614 строк · 18.6 Кб
1
/*
2
 * Copyright (c) 2015, 2024, 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 "opto/phasetype.hpp"
31
#include "opto/traceAutoVectorizationTag.hpp"
32
#include "runtime/os.hpp"
33
#include <string.h>
34

35
void DirectivesParser::push_tmp(CompilerDirectives* dir) {
36
  _tmp_depth++;
37
  dir->set_next(_tmp_top);
38
  _tmp_top = dir;
39
}
40

41
CompilerDirectives* DirectivesParser::pop_tmp() {
42
  if (_tmp_top == nullptr) {
43
    return nullptr;
44
  }
45
  CompilerDirectives* tmp = _tmp_top;
46
  _tmp_top = _tmp_top->next();
47
  tmp->set_next(nullptr);
48
  _tmp_depth--;
49
  return tmp;
50
}
51

52
void DirectivesParser::clean_tmp() {
53
  CompilerDirectives* tmp = pop_tmp();
54
  while (tmp != nullptr) {
55
    delete tmp;
56
    tmp = pop_tmp();
57
  }
58
  assert(_tmp_depth == 0, "Consistency");
59
}
60

61
int DirectivesParser::parse_string(const char* text, outputStream* st, bool silent) {
62
  DirectivesParser cd(text, st, silent);
63
  if (cd.valid()) {
64
    return cd.install_directives();
65
  } else {
66
    cd.clean_tmp();
67
    st->flush();
68
    st->print_cr("Parsing of compiler directives failed");
69
    return -1;
70
  }
71
}
72

73
bool DirectivesParser::has_file() {
74
  return CompilerDirectivesFile != nullptr;
75
}
76

77
bool DirectivesParser::parse_from_flag() {
78
  return parse_from_file(CompilerDirectivesFile, tty);
79
}
80

81
bool DirectivesParser::parse_from_file(const char* filename, outputStream* st, bool silent) {
82
  assert(filename != nullptr, "Test before calling this");
83
  if (!parse_from_file_inner(filename, st, silent)) {
84
    st->print_cr("Could not load file: %s", filename);
85
    return false;
86
  }
87
  return true;
88
}
89

90
bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* stream, bool silent) {
91
  struct stat st;
92
  ResourceMark rm;
93
  if (os::stat(filename, &st) == 0) {
94
    // found file, open it
95
    int file_handle = os::open(filename, 0, 0);
96
    if (file_handle != -1) {
97
      // read contents into resource array
98
      char* buffer = NEW_RESOURCE_ARRAY(char, st.st_size+1);
99
      ssize_t num_read = ::read(file_handle, (char*) buffer, st.st_size);
100
      ::close(file_handle);
101
      if (num_read >= 0) {
102
        buffer[num_read] = '\0';
103
        return parse_string(buffer, stream, silent) > 0;
104
      }
105
    }
106
  }
107
  return false;
108
}
109

110
int DirectivesParser::install_directives() {
111
  // Check limit
112
  if (!DirectivesStack::check_capacity(_tmp_depth, _st)) {
113
    clean_tmp();
114
    return 0;
115
  }
116

117
  // Pop from internal temporary stack and push to compileBroker.
118
  CompilerDirectives* tmp = pop_tmp();
119
  int i = 0;
120
  while (tmp != nullptr) {
121
    i++;
122
    DirectivesStack::push(tmp);
123
    tmp = pop_tmp();
124
  }
125
  if (i == 0) {
126
    _st->print_cr("No directives in file");
127
    return 0;
128
  } else {
129
    _st->print_cr("%i compiler directives added", i);
130
    if (CompilerDirectivesPrint) {
131
      // Print entire directives stack after new has been pushed.
132
      DirectivesStack::print(_st);
133
    }
134
    return i;
135
  }
136
}
137

138
DirectivesParser::DirectivesParser(const char* text, outputStream* st, bool silent)
139
: JSON(text, silent, st), depth(0), current_directive(nullptr), current_directiveset(nullptr), _tmp_top(nullptr), _tmp_depth(0) {
140
#ifndef PRODUCT
141
  memset(stack, 0, MAX_DEPTH * sizeof(stack[0]));
142
#endif
143
  parse();
144
}
145

146
DirectivesParser::~DirectivesParser() {
147
  assert(_tmp_top == nullptr, "Consistency");
148
  assert(_tmp_depth == 0, "Consistency");
149
}
150

151
const DirectivesParser::key DirectivesParser::keys[] = {
152
    // name, keytype, allow_array, allowed_mask, set_function
153
    { "c1",     type_c1,     0, mask(type_directives), nullptr, UnknownFlagType },
154
    { "c2",     type_c2,     0, mask(type_directives), nullptr, UnknownFlagType },
155
    { "match",  type_match,  1, mask(type_directives), nullptr, UnknownFlagType },
156
    { "inline", type_inline, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), nullptr, UnknownFlagType },
157

158
    // Global flags
159
    #define common_flag_key(name, type, dvalue, compiler) \
160
    { #name, type_flag, 0, mask(type_directives) | mask(type_c1) | mask(type_c2), &DirectiveSet::set_##name, type##Flag},
161
    compilerdirectives_common_flags(common_flag_key)
162
    compilerdirectives_c2_flags(common_flag_key)
163
    compilerdirectives_c1_flags(common_flag_key)
164
    #undef common_flag_key
165
};
166

167
const DirectivesParser::key DirectivesParser::dir_array_key = {
168
     "top level directives array", type_dir_array, 0, 1 // Lowest bit means allow at top level
169
};
170
const DirectivesParser::key DirectivesParser::dir_key = {
171
   "top level directive", type_directives, 0, mask(type_dir_array) | 1 // Lowest bit means allow at top level
172
};
173
const DirectivesParser::key DirectivesParser::value_array_key = {
174
   "value array", type_value_array, 0, UINT_MAX // Allow all, checked by allow_array on other keys, not by allowed_mask from this key
175
};
176

177
const DirectivesParser::key* DirectivesParser::lookup_key(const char* str, size_t len) {
178
  for (size_t i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {
179
    if (strncasecmp(keys[i].name, str, len) == 0) {
180
      return &keys[i];
181
    }
182
  }
183
  return nullptr;
184
}
185

186
uint DirectivesParser::mask(keytype kt) {
187
  return 1 << (kt + 1);
188
}
189

190
bool DirectivesParser::push_key(const char* str, size_t len) {
191
  bool result = true;
192
  const key* k = lookup_key(str, len);
193

194
  if (k == nullptr) {
195
    // os::strdup
196
    char* s = NEW_C_HEAP_ARRAY(char, len + 1, mtCompiler);
197
    strncpy(s, str, len);
198
    s[len] = '\0';
199
    error(KEY_ERROR, "No such key: '%s'.", s);
200
    FREE_C_HEAP_ARRAY(char, s);
201
    return false;
202
  }
203

204
  return push_key(k);
205
}
206

207
bool DirectivesParser::push_key(const key* k) {
208
  assert(k->allowedmask != 0, "not allowed anywhere?");
209

210
  // Exceeding the stack should not be possible with a valid compiler directive,
211
  // and an invalid should abort before this happens
212
  assert(depth < MAX_DEPTH, "exceeded stack depth");
213
  if (depth >= MAX_DEPTH) {
214
    error(INTERNAL_ERROR, "Stack depth exceeded.");
215
    return false;
216
  }
217

218
  assert(stack[depth] == nullptr, "element not nulled, something is wrong");
219

220
  if (depth == 0 && !(k->allowedmask & 1)) {
221
    error(KEY_ERROR, "Key '%s' not allowed at top level.", k->name);
222
    return false;
223
  }
224

225
  if (depth > 0) {
226
    const key* prev = stack[depth - 1];
227
    if (!(k->allowedmask & mask(prev->type))) {
228
      error(KEY_ERROR, "Key '%s' not allowed after '%s' key.", k->name, prev->name);
229
      return false;
230
    }
231
  }
232

233
  stack[depth] = k;
234
  depth++;
235
  return true;
236
}
237

238
const DirectivesParser::key* DirectivesParser::current_key() {
239
  assert(depth > 0, "getting key from empty stack");
240
  if (depth == 0) {
241
    return nullptr;
242
  }
243
  return stack[depth - 1];
244
}
245

246
const DirectivesParser::key* DirectivesParser::pop_key() {
247
  assert(depth > 0, "popping empty stack");
248
  if (depth == 0) {
249
    error(INTERNAL_ERROR, "Popping empty stack.");
250
    return nullptr;
251
  }
252
  depth--;
253

254
  const key* k = stack[depth];
255
#ifndef PRODUCT
256
  stack[depth] = nullptr;
257
#endif
258

259
  return k;
260
}
261

262
bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set) {
263

264
  void (DirectiveSet::*test)(void *args);
265
  test = option_key->set;
266

267
  switch (t) {
268
    case JSON_TRUE:
269
      if (option_key->flag_type != boolFlag) {
270
        error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);
271
        return false;
272
      } else {
273
        bool val = true;
274
        (set->*test)((void *)&val);
275
      }
276
      break;
277

278
    case JSON_FALSE:
279
      if (option_key->flag_type != boolFlag) {
280
        error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);
281
        return false;
282
      } else {
283
        bool val = false;
284
        (set->*test)((void *)&val);
285
      }
286
      break;
287

288
    case JSON_NUMBER_INT:
289
      if (option_key->flag_type == intxFlag) {
290
        intx ival = v->int_value;
291
        (set->*test)((void *)&ival);
292
      } else if (option_key->flag_type == uintxFlag) {
293
        uintx ival = v->uint_value;
294
        (set->*test)((void *)&ival);
295
      } else if (option_key->flag_type == doubleFlag) {
296
        double dval = (double)v->int_value;
297
        (set->*test)((void *)&dval);
298
      } else {
299
        error(VALUE_ERROR, "Cannot use int value for an %s flag", flag_type_names[option_key->flag_type]);
300
        return false;
301
      }
302
      break;
303

304
    case JSON_NUMBER_FLOAT:
305
      if (option_key->flag_type != doubleFlag) {
306
        error(VALUE_ERROR, "Cannot use double value for an %s flag", flag_type_names[option_key->flag_type]);
307
        return false;
308
      } else {
309
        double dval = v->double_value;
310
        (set->*test)((void *)&dval);
311
      }
312
      break;
313

314
    case JSON_STRING:
315
      if (option_key->flag_type != ccstrFlag && option_key->flag_type != ccstrlistFlag) {
316
        error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]);
317
        return false;
318
      } else {
319
        char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
320
        strncpy(s, v->str.start, v->str.length + 1);
321
        s[v->str.length] = '\0';
322

323
        bool valid = true;
324

325
        if (strncmp(option_key->name, "ControlIntrinsic", 16) == 0) {
326
          ControlIntrinsicValidator validator(s, false/*disabled_all*/);
327

328
          valid = validator.is_valid();
329
          if (!valid) {
330
            error(VALUE_ERROR, "Unrecognized intrinsic detected in ControlIntrinsic: %s", validator.what());
331
          }
332
        } else if (strncmp(option_key->name, "DisableIntrinsic", 16) == 0) {
333
          ControlIntrinsicValidator validator(s, true/*disabled_all*/);
334

335
          valid = validator.is_valid();
336
          if (!valid) {
337
            error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what());
338
          }
339
        }
340
#if !defined(PRODUCT) && defined(COMPILER2)
341
        else if (strncmp(option_key->name, "TraceAutoVectorization", 22) == 0) {
342
          TraceAutoVectorizationTagValidator validator(s, false);
343

344
          valid = validator.is_valid();
345
          if (valid) {
346
            set->set_trace_auto_vectorization_tags(validator.tags());
347
          } else {
348
            error(VALUE_ERROR, "Unrecognized tag name detected in TraceAutoVectorization: %s", validator.what());
349
          }
350
        } else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) {
351
          PhaseNameValidator validator(s);
352

353
          valid = validator.is_valid();
354
          if (valid) {
355
            set->set_ideal_phase_name_set(validator.phase_name_set());
356
          } else {
357
            error(VALUE_ERROR, "Unrecognized phase name detected in PrintIdealPhase: %s", validator.what());
358
          }
359
        }
360
#endif
361

362
        if (!valid) {
363
          FREE_C_HEAP_ARRAY(char, s);
364
          return false;
365
        }
366
        (set->*test)((void *)&s);  // Takes ownership.
367
      }
368
      break;
369

370
    default:
371
      assert(0, "Should not reach here.");
372
    }
373
  return true;
374
}
375

376
bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) {
377

378
  const key* option_key = pop_key();
379
  const key* enclosing_key = current_key();
380

381
  if (option_key->type == value_array_key.type) {
382
    // Multi value array, we are really setting the value
383
    // for the key one step further up.
384
    option_key = pop_key();
385
    enclosing_key = current_key();
386

387
    // Repush option_key and multi value marker, since
388
    // we need to keep them until all multi values are set.
389
    push_key(option_key);
390
    push_key(&value_array_key);
391
  }
392

393
  switch (option_key->type) {
394
  case type_flag:
395
  {
396
    if (current_directiveset == nullptr) {
397
      assert(depth == 2, "Must not have active directive set");
398

399
      if (!set_option_flag(t, v, option_key, current_directive->_c1_store)) {
400
        return false;
401
      }
402
      if (!set_option_flag(t, v, option_key, current_directive->_c2_store)) {
403
        return false;
404
      }
405
    } else {
406
      assert(depth > 2, "Must have active current directive set");
407
      if (!set_option_flag(t, v, option_key, current_directiveset)) {
408
        return false;
409
      }
410
    }
411
    break;
412
  }
413

414
  case type_match:
415
    if (t != JSON_STRING) {
416
      error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);
417
      return false;
418
    }
419
    if (enclosing_key->type != type_directives) {
420
      error(SYNTAX_ERROR, "Match keyword can only exist inside a directive");
421
      return false;
422
    }
423
    {
424
      char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
425
      strncpy(s, v->str.start, v->str.length);
426
      s[v->str.length] = '\0';
427

428
      const char* error_msg = nullptr;
429
      if (!current_directive->add_match(s, error_msg)) {
430
        assert (error_msg != nullptr, "Must have valid error message");
431
        error(VALUE_ERROR, "Method pattern error: %s", error_msg);
432
      }
433
      FREE_C_HEAP_ARRAY(char, s);
434
    }
435
    break;
436

437
  case type_inline:
438
    if (t != JSON_STRING) {
439
      error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);
440
      return false;
441
    }
442
    {
443
      //char* s = strndup(v->str.start, v->str.length);
444
      char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
445
      strncpy(s, v->str.start, v->str.length);
446
      s[v->str.length] = '\0';
447

448
      const char* error_msg = nullptr;
449
      if (current_directiveset == nullptr) {
450
        if (current_directive->_c1_store->parse_and_add_inline(s, error_msg)) {
451
          if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) {
452
            assert (error_msg != nullptr, "Must have valid error message");
453
            error(VALUE_ERROR, "Method pattern error: %s", error_msg);
454
          }
455
        } else {
456
          assert (error_msg != nullptr, "Must have valid error message");
457
          error(VALUE_ERROR, "Method pattern error: %s", error_msg);
458
        }
459
      } else {
460
        if (!current_directiveset->parse_and_add_inline(s, error_msg)) {
461
          assert (error_msg != nullptr, "Must have valid error message");
462
          error(VALUE_ERROR, "Method pattern error: %s", error_msg);
463
        }
464
      }
465
      FREE_C_HEAP_ARRAY(char, s);
466
    }
467
    break;
468

469
  case type_c1:
470
    current_directiveset = current_directive->_c1_store;
471
    if (t != JSON_TRUE && t != JSON_FALSE) {
472
      error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);
473
      return false;
474
    }
475
    break;
476

477
  case type_c2:
478
    current_directiveset = current_directive->_c2_store;
479
    if (t != JSON_TRUE && t != JSON_FALSE) {
480
      error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);
481
      return false;
482
    }
483
    break;
484

485
  default:
486
    break;
487
  }
488

489
  return true;
490
}
491

492
bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) {
493
  const key* k;
494

495
  if (depth == 0) {
496
    switch (t) {
497
      case JSON_ARRAY_BEGIN:
498
        return push_key(&dir_array_key);
499

500
      case JSON_OBJECT_BEGIN:
501
        // push synthetic dir_array
502
        push_key(&dir_array_key);
503
        assert(depth == 1, "Make sure the stack are aligned with the directives");
504
        break;
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
  }
511
  if (depth == 1) {
512
    switch (t) {
513
      case JSON_OBJECT_BEGIN:
514
        // Parsing a new directive.
515
        current_directive = new CompilerDirectives();
516
        return push_key(&dir_key);
517

518
      case JSON_ARRAY_END:
519
        k = pop_key();
520

521
        if (k->type != type_dir_array) {
522
          error(SYNTAX_ERROR, "Expected end of directives array");
523
          return false;
524
        }
525
        return true;
526

527
    default:
528
      error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");
529
      return false;
530
    }
531
  } else {
532
    switch (t) {
533
    case JSON_OBJECT_BEGIN:
534
      k = current_key();
535
      switch (k->type) {
536
      case type_c1:
537
        current_directiveset = current_directive->_c1_store;
538
        return true;
539
      case type_c2:
540
        current_directiveset = current_directive->_c2_store;
541
        return true;
542

543
      case type_dir_array:
544
        return push_key(&dir_key);
545

546
      default:
547
        error(SYNTAX_ERROR, "The key '%s' does not allow an object to follow.", k->name);
548
        return false;
549
      }
550
      return false;
551

552
    case JSON_OBJECT_END:
553
      k = pop_key();
554
      switch (k->type) {
555
      case type_c1:
556
      case type_c2:
557
        // This is how we now if options apply to a single or both directive sets
558
        current_directiveset = nullptr;
559
        break;
560

561
      case type_directives:
562
        // Check, finish and push to stack!
563
        if (current_directive->match() == nullptr) {
564
          error(INTERNAL_ERROR, "Directive missing required match.");
565
          return false;
566
        }
567
        current_directive->finalize(_st);
568
        push_tmp(current_directive);
569
        current_directive = nullptr;
570
        break;
571

572
      default:
573
        error(INTERNAL_ERROR, "Object end with wrong key type on stack: %s.", k->name);
574
        ShouldNotReachHere();
575
        return false;
576
      }
577
      return true;
578

579
    case JSON_ARRAY_BEGIN:
580
      k = current_key();
581
      if (!(k->allow_array_value)) {
582
        if (k->type == type_dir_array) {
583
          error(SYNTAX_ERROR, "Array not allowed inside top level array, expected directive object.");
584
        } else {
585
          error(VALUE_ERROR, "The key '%s' does not allow an array of values.", k->name);
586
        }
587
        return false;
588
      }
589
      return push_key(&value_array_key);
590

591
    case JSON_ARRAY_END:
592
      k = pop_key(); // Pop multi value marker
593
      assert(k->type == value_array_key.type, "array end for level != 0 should terminate multi value");
594
      k = pop_key(); // Pop key for option that was set
595
      return true;
596

597
    case JSON_KEY:
598
      return push_key(v->str.start, v->str.length);
599

600
    case JSON_STRING:
601
    case JSON_NUMBER_INT:
602
    case JSON_NUMBER_FLOAT:
603
    case JSON_TRUE:
604
    case JSON_FALSE:
605
    case JSON_NULL:
606
      return set_option(t, v);
607

608
    default:
609
      error(INTERNAL_ERROR, "Unknown JSON type: %d.", t);
610
      ShouldNotReachHere();
611
      return false;
612
    }
613
  }
614
}
615

616

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.