This file is indexed.

/usr/include/hphp/hhbbc/index.h is in hhvm-dev 3.11.1+dfsg-1ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
/*
   +----------------------------------------------------------------------+
   | HipHop for PHP                                                       |
   +----------------------------------------------------------------------+
   | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com)     |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_01.txt                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
*/
#ifndef incl_HHBBC_INDEX_H_
#define incl_HHBBC_INDEX_H_

#include <memory>
#include <mutex>
#include <tuple>
#include <vector>
#include <map>

#include <boost/variant.hpp>
#include <tbb/concurrent_hash_map.h>

#include <folly/Optional.h>
#include <folly/Hash.h>

#include "hphp/util/either.h"
#include "hphp/runtime/base/repo-auth-type-array.h"
#include "hphp/runtime/vm/type-constraint.h"

#include "hphp/hhbbc/hhbbc.h"
#include "hphp/hhbbc/misc.h"

namespace HPHP { namespace HHBBC {

//////////////////////////////////////////////////////////////////////

struct Type;
struct Index;
struct PublicSPropIndexer;

namespace php {
struct Class;
struct Func;
struct Unit;
struct Program;
}

//////////////////////////////////////////////////////////////////////

/*
 * This module contains functions for building and querying an Index
 * of data relating to "resolved" versions of the names in of a
 * php::Program.  It also records dependencies so it is possible to
 * tell which parts of the program may be interested in new inferred
 * information about other parts of the program.
 *
 * The main entry point here is the Index class.  The Index is built
 * after parse time, and then analysis can query it for information.
 */

//////////////////////////////////////////////////////////////////////

/*
 * A Context is a (unit, func, class) triple, where cls and func
 * fields may be null in some situations.  Most queries to the Index
 * need a "context", to allow recording dependencies.
 */
struct Context { borrowed_ptr<php::Unit> unit;
                 borrowed_ptr<php::Func> func;
                 borrowed_ptr<php::Class> cls; };

inline bool operator==(Context a, Context b) {
  return a.unit == b.unit && a.func == b.func && a.cls == b.cls;
}

inline bool operator<(Context a, Context b) {
  return std::make_tuple(a.unit, a.func, a.cls) <
         std::make_tuple(b.unit, b.func, b.cls);
}

std::string show(Context);

/*
 * Context for a call to a function.  This means the types and number
 * of arguments, and where it is being called from.
 *
 * TODO(#3788877): add type of $this if it is going to be an object
 * method, and the LSB class type if static.
 */
struct CallContext {
  Context caller;
  std::vector<Type> args;
};

inline bool operator==(const CallContext& a, const CallContext& b) {
  return a.caller == b.caller &&
         a.args == b.args;
}

/*
 * State of properties on a class.  Map from property name to its
 * Type.
 */
using PropState = std::map<SString,Type>;

//////////////////////////////////////////////////////////////////////

// private types
struct IndexData;
struct FuncFamily;
struct FuncInfo;
struct ClassInfo;

//////////////////////////////////////////////////////////////////////

/*
 * References to "resolved" entities with information in the index are
 * in the res:: namespace.
 *
 * These represent handles to program entities that may have variable
 * amounts of information.  For example, we may know the name of a
 * class in a res::Class, but do not know for sure which php::Class
 * struct is actually associated with it.
 */
namespace res {

/*
 * A resolved runtime Class, for a particular php::Class.
 *
 * Provides various lookup tables that allow querying the Class'
 * information.
 */
struct Class {
  /*
   * Returns whether two classes are definitely same at runtime.  If
   * this function returns false, they still *may* be the same at
   * runtime.
   */
  bool same(const Class&) const;

  /*
   * Returns true if this class is definitely going to be a subtype
   * of `o' at runtime.  If this function returns false, this may
   * still be a subtype of `o' at runtime, it just may not be known.
   * A typical example is with "non unique" classes.
   */
  bool subtypeOf(const Class& o) const;

  /*
   * If this function return false, it is known that this class
   * is in no subtype relationship with the argument Class 'o'.
   * Returns true if this class could be a subtype of `o' at runtime.
   * When true is returned the two classes may still be unrelated but it is
   * not possible to tell. A typical example is with "non unique" classes.
   */
  bool couldBe(const Class& o) const;

  /*
   * Returns the name of this class.  Non-null guarantee.
   */
  SString name() const;

  /*
   * Whether this class could possibly be an interface or a trait.
   *
   * When returning false, it is known that this class is not an interface
   * or a trait. When returning true, it's possible that this class is not
   * an interface or trait but the system cannot tell.
   */
  bool couldBeInterfaceOrTrait() const;

  /*
   * Returns whether this type has the no override attribute, that is, if it
   * is a final class (explicitly marked by the user or known by the static
   * analysis).
   *
   * When returning false the class is guaranteed to be final.  When returning
   * true the system cannot tell though the class may still be final.
   */
  bool couldBeOverriden() const;

  /*
   * Whether this class (or its subtypes) could possibly have have
   * certain magic methods.
   */
  bool couldHaveMagicGet() const;

  /*
   * Returns the Class that is the first common ancestor between 'this' and 'o'.
   * If there is no common ancestor folly::none is returned
   */
  folly::Optional<Class> commonAncestor(const Class& o) const;

private:
  Class(borrowed_ptr<const Index>, Either<SString,borrowed_ptr<ClassInfo>>);

private:
  friend std::string show(const Class&);
  friend struct ::HPHP::HHBBC::Index;
  friend struct ::HPHP::HHBBC::PublicSPropIndexer;
  borrowed_ptr<const Index> index;
  Either<SString,borrowed_ptr<ClassInfo>> val;
};

/*
 * This is an abstraction layer to represent possible runtime function
 * resolutions.
 *
 * Internally, this may only know the name of the function (or method), or we
 * may know exactly which source-code-level function it refers to, or we may
 * only have ruled it down to one of a few functions in a class hierarchy.  The
 * interpreter can treat all these cases the same way using this.
 */
struct Func {
  /*
   * Returns whether two res::Funcs definitely mean the func at
   * runtime.
   *
   * Note: this is potentially pessimistic for its use in ActRec state
   * merging right now, but not incorrect.
   */
  bool same(const Func&) const;

  /*
   * Returns the name of this function.  Non-null guarantee.
   */
  SString name() const;

  /*
   * Returns whether this resolved function could possibly be going through a
   * magic call, in the magic way.
   *
   * That is, if was resolved as part of a direct call to an __call method,
   * this will say true.  If it was resolved as part as some normal method
   * call, and we haven't proven that there's no way an __call dispatch could
   * be involved, this will say false.
   */
  bool cantBeMagicCall() const;

private:
  friend struct ::HPHP::HHBBC::Index;
  struct FuncName {
    bool operator==(FuncName o) const { return name == o.name; }
    SString name;
  };
  struct MethodName {
    bool operator==(MethodName o) const { return name == o.name; }
    SString name;
  };
  using Rep = boost::variant< FuncName
                            , MethodName
                            , borrowed_ptr<FuncInfo>
                            , borrowed_ptr<FuncFamily>
                            >;

private:
  Func(borrowed_ptr<const Index>, Rep);
  friend std::string show(const Func&);

private:
  borrowed_ptr<const Index> index;
  Rep val;
};

/*
 * Produce a trace-able string for a res::Func or res::Class.
 */
std::string show(const Func&);
std::string show(const Class&);

}

//////////////////////////////////////////////////////////////////////

/*
 * This class encapsulates the known facts about the program, with a
 * whole-program view.
 *
 * This structure contains unowned pointers into the php::Program it
 * was created for.  It should not out-live the Program.
 *
 * The const member functions of this class are thread safe for
 * concurrent reads and writes.  The non-const functions should be
 * called in a single threaded context only (they are used during the
 * "update" step in between whole program analysis rounds).
 */
struct Index {
  /*
   * Create an Index for a php::Program.  Performs some initial
   * analysis of the program.
   */
  explicit Index(borrowed_ptr<php::Program>);

  /*
   * This class must not be destructed after its associated
   * php::Program.
   */
  ~Index();

  /*
   * The index operates in two modes: frozen, and unfrozen.
   *
   * Conceptually, the index is mutable and may acquire new
   * information until it has been frozen, and once frozen, it retains
   * the information it had at the point it was frozen.
   *
   * The reason this exists is because certain functions on the index
   * may cause it to need to consult information in the bodies of
   * functions other than the Context passed in.  Specifically, if the
   * interpreter tries to look up the return type for a callee in a
   * given CallContext, the index may choose to recursively invoke
   * type inference on that callee's function body to see if more
   * precise information can be determined, unless it is frozen.
   *
   * This is fine until the final pass, because all bytecode is
   * read-only at that stage.  However, in the final pass, other
   * threads might be optimizing a callee's bytecode and changing it,
   * so we should not be reading from it to perform type inference
   * concurrently.  Freezing the index tells it it can't do that
   * anymore.
   *
   * These are the functions to query and transition to frozen state.
   */
  bool frozen() const;
  void freeze();

  /*
   * The Index contains a Builder for an ArrayTypeTable.
   *
   * If we're creating assert types with options.InsertAssertions, we
   * need to keep track of which array types exist in the whole
   * program in order to include it in the repo.
   */
  std::unique_ptr<ArrayTypeTable::Builder>& array_table_builder() const;

  /*
   * Find all the closures created inside the context of a given
   * php::Class.
   */
  std::vector<borrowed_ptr<php::Class>>
    lookup_closures(borrowed_ptr<const php::Class>) const;

  /*
   * Try to resolve which class will be the class named `name' from a
   * given context, if we can resolve it to a single class.
   *
   * Note, the returned class may or may not be *defined* at the
   * program point you care about (it could be non-hoistable, even
   * though it's unique, for example).
   *
   * Returns folly::none if we can't prove the supplied name must be a
   * object type.  (E.g. if there are type aliases.)
   */
  folly::Optional<res::Class> resolve_class(Context, SString name) const;

  /*
   * Resolve a closure class.
   *
   * Returns both a resolved Class, and the actual php::Class for the
   * closure.  This function should only be used with class names are
   * guaranteed to be closures (for example, the name supplied to a
   * CreateCl opcode).
   */
  std::pair<res::Class,borrowed_ptr<php::Class>>
    resolve_closure_class(Context ctx, SString name) const;

  /*
   * Return a resolved class for a builtin class.
   *
   * Pre: `name' must be the name of a class defined in a systemlib.
   */
  res::Class builtin_class(SString name) const;

  /*
   * Try to resolve a function named `name' from a given context.
   *
   * Note, the returned function may or may not be defined at the
   * program point (it could require a function autoload that might
   * fail).
   */
  res::Func resolve_func(Context, SString name) const;

  /*
   * Try to resolve a function using namespace-style fallback lookup.
   *
   * The name `name' is tried first, and `fallback' is used if this
   * isn't found.  Both names must already be namespace-normalized.
   * Resolution can fail because there are possible situations where
   * we don't know which will be called at runtime.
   *
   * Note: the returned function may or may not be defined at the
   * program point (it could require a function autoload that might
   * fail).
   */
  folly::Optional<res::Func> resolve_func_fallback(Context,
                                                   SString name,
                                                   SString fallback) const;

  /*
   * Try to resolve a class method named `name' with a given Context
   * and class type.
   *
   * Pre: clsType.subtypeOf(TCls)
   */
  res::Func resolve_method(Context, Type clsType, SString name) const;

  /*
   * Try to resolve a class constructor for the supplied class.
   *
   * Returns: folly::none if we can't figure out which constructor
   * this would call.
   */
  folly::Optional<res::Func> resolve_ctor(Context, res::Class) const;

  /*
   * Give the Type in our type system that matches an hhvm
   * TypeConstraint, subject to the information in this Index.
   *
   * This function returns a subtype of Cell, although TypeConstraints
   * at runtime can match reference parameters.  The caller should
   * make sure to handle that case.
   *
   * For soft constraints (@), this function returns Cell.
   *
   * For some non-soft constraints (such as "Stringish"), this
   * function may return a Type that is a strict supertype of the
   * constraint's type.
   */
  Type lookup_constraint(Context, const TypeConstraint&) const;

  /*
   * If this function returns true, it is safe to assume that Type t
   * will always satisfy TypeConstraint tc at run time.
   */
  bool satisfies_constraint(Context, Type t, const TypeConstraint& tc) const;

  /*
   * Lookup what the best known Type for a class constant would be,
   * using a given Index and Context, if a class of that name were
   * loaded.
   */
  Type lookup_class_constant(Context, res::Class, SString cns) const;

  /*
   * Return the best known return type for a resolved function, in a
   * context insensitive way.  Returns TInitGen at worst.
   */
  Type lookup_return_type(Context, res::Func) const;

  /*
   * Return the best known return type for a resolved function, given
   * the supplied calling context.  Returns TInitGen at worst.
   *
   * During analyze phases, this function may re-enter analyze in
   * order to interpret the callee with these argument types.
   */
  Type lookup_return_type(CallContext, res::Func) const;

  /*
   * Look up the return type for an unresolved function.  The
   * interpreter should not use this routine---it's for stats or debug
   * dumps.
   *
   * Nothing may be writing to the index when this function is used,
   * but concurrent readers are allowed.
   */
  Type lookup_return_type_raw(borrowed_ptr<const php::Func>) const;

  /*
   * Return the best known types of a closure's used variables (on
   * entry to the closure).  The function is the closure body.
   */
  std::vector<Type>
    lookup_closure_use_vars(borrowed_ptr<const php::Func>) const;

  /*
   * Return the availability of $this on entry to the provided method.
   * If the Func provided is not a method of a class false is
   * returned.
   */
  bool lookup_this_available(borrowed_ptr<const php::Func>) const;

  /*
   * Returns the parameter preparation kind (if known) for parameter
   * `paramId' on the given resolved Func.
   */
  PrepKind lookup_param_prep(Context, res::Func, uint32_t paramId) const;

  /*
   * Returns the control-flow insensitive inferred private instance
   * property types for a Class.  The Class doesn't need to be
   * resolved, because private properties don't depend on the
   * inheritance hierarchy.
   *
   * The Index tracks the largest types for private properties that
   * are guaranteed to hold at any program point.
   */
  PropState lookup_private_props(borrowed_ptr<const php::Class>) const;

  /*
   * Returns the control-flow insensitive inferred private static
   * property types for a Class.  The class doesn't need to be
   * resolved for the same reasons as for instance properties.
   *
   * The Index tracks the largest types for private static properties
   * that are guaranteed to hold at any program point.
   */
  PropState lookup_private_statics(borrowed_ptr<const php::Class>) const;

  /*
   * Lookup the best known type for a public static property, with a given
   * class and name.
   *
   * This function will always return TInitGen before refine_public_statics has
   * been called, or if the AnalyzePublicStatics option is off.
   */
  Type lookup_public_static(Type cls, Type name) const;
  Type lookup_public_static(borrowed_ptr<const php::Class>, SString name) const;

  /*
   * Returns whether a public static property is known to be immutable.  This
   * is used to add AttrPersistent flags to static properties, and relies on
   * AnalyzePublicStatics (without this flag it will always return false).
   */
  bool lookup_public_static_immutable(borrowed_ptr<const php::Class>,
                                      SString name) const;

  /*
   * Returns the computed vtable slot for the given class, if it's an interface
   * that was given a vtable slot. No two interfaces implemented by the same
   * class will share the same vtable slot. May return kInvalidSlot, if the
   * given class isn't an interface or if it wasn't assigned a slot.
   */
  Slot lookup_iface_vtable_slot(borrowed_ptr<const php::Class>) const;

  /*
   * Refine the return type for a function, based on a round of
   * analysis.
   *
   * No other threads should be calling functions on this Index when
   * this function is called.
   *
   * Returns: the set of Contexts that depended on the return type of
   * this php::Func.
   */
  std::vector<Context> refine_return_type(borrowed_ptr<const php::Func>, Type);

  /*
   * Refine the used var types for a closure, based on a round of
   * analysis.
   *
   * No other threads should be calling functions on this Index when
   * this function is called.
   *
   * Returns: true if the types have changed.
   */
  bool refine_closure_use_vars(borrowed_ptr<const php::Class>,
                               const std::vector<Type>&);

  /*
   * Refine the private property types for a class, based on a round
   * of analysis.
   *
   * No other threads should be calling functions on this Index when
   * this function is called.
   */
  void refine_private_props(borrowed_ptr<const php::Class> cls,
                            const PropState&);

  /*
   * Refine the static private property types for a class, based on a
   * round of analysis.
   *
   * No other threads should be calling functions on this Index when
   * this function is called.
   */
  void refine_private_statics(borrowed_ptr<const php::Class> cls,
                              const PropState&);

  /*
   * After a whole program pass using PublicSPropIndexer, the types can be
   * reflected into the index for use during another type inference pass.
   *
   * No other threads should be calling functions on this Index or on the
   * provided PublicSPropIndexer when this function is called.
   */
  void refine_public_statics(const PublicSPropIndexer&);

private:
  Index(const Index&) = delete;
  Index& operator=(Index&&) = delete;

private:
  template<class FuncRange>
  res::Func resolve_func_helper(const FuncRange&, SString) const;
  res::Func do_resolve(borrowed_ptr<const php::Func>) const;
  bool must_be_derived_from(borrowed_ptr<const php::Class>,
                            borrowed_ptr<const php::Class>) const;
  bool could_be_related(borrowed_ptr<const php::Class>,
                        borrowed_ptr<const php::Class>) const;
  Type satisfies_constraint_helper(Context, const TypeConstraint&) const;

private:
  std::unique_ptr<IndexData> const m_data;
};

//////////////////////////////////////////////////////////////////////

/*
 * Indexer object used for collecting information about public static property
 * types.  See analyze_public_statics in whole-program.cpp for details about
 * how it is used.
 */
struct PublicSPropIndexer {
  explicit PublicSPropIndexer(borrowed_ptr<const Index> index)
    : m_index(index)
  {}

  /*
   * Called by the interpreter during analyze_func_collect when a
   * PublicSPropIndexer is active.  This function must be called anywhere the
   * interpreter does something that could change the type of public static
   * properties named `name' on classes of type `cls' to `val'.
   *
   * Note that if cls and name are both too generic this object will have to
   * give up all information it knows about any public static properties.
   *
   * This routine may be safely called concurrently by multiple analysis
   * threads.
   */
  void merge(Context ctx, Type cls, Type name, Type val);

private:
  friend struct Index;

  struct KnownKey {
    bool operator==(KnownKey o) const {
      return cinfo == o.cinfo && prop == o.prop;
    }

    friend size_t tbb_hasher(KnownKey k) {
      return folly::hash::hash_combine(k.cinfo, k.prop);
    }

    borrowed_ptr<ClassInfo> cinfo;
    SString prop;
  };

  using UnknownMap = tbb::concurrent_hash_map<SString,Type>;
  using KnownMap = tbb::concurrent_hash_map<KnownKey,Type>;

private:
  borrowed_ptr<const Index> m_index;
  std::atomic<bool> m_everything_bad{false};
  UnknownMap m_unknown;
  KnownMap m_known;
};

//////////////////////////////////////////////////////////////////////

}}

#endif