2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/autoload-handler.h"
18 #include "hphp/runtime/base/runtime-option.h"
19 #include "hphp/runtime/vm/decl-provider.h"
23 TRACE_SET_MOD(unit_parse
);
27 // Helper to return DeclProviderResult::Missing
28 DeclProviderResult
missing() {
29 return DeclProviderResult
{DeclProviderResult::Tag::Missing
, {}};
32 // Helper to return DeclProviderResult::Decls
33 DeclProviderResult
decls(const Decls
* decls
) {
35 r
.tag
= DeclProviderResult::Tag::Decls
;
36 r
.decl_provider_decls_result
._0
= decls
;
42 std::unique_ptr
<HhvmDeclProvider
>
43 HhvmDeclProvider::create(const RepoOptionsFlags
& options
) {
44 if (!RuntimeOption::EvalEnableDecl
) {
47 if (!AutoloadHandler::s_instance
) {
48 // It is not safe to autoinit AutoloadHandler outside a normal request.
51 auto map
= AutoloadHandler::s_instance
->getAutoloadMap();
52 if (!map
|| !map
->isNative()) {
53 // Either compiling systemlib.php with no autoload map initialized yet,
54 // or AutoloadHandler was not configured with a native AutoloadMap.
58 // Create the DeclProvider.
59 // This will only cache entries it sees during this invocation of
60 // the compiler. Hackc should have a per-session cache indexed by symbol,
61 // and this file-to-decls cache should span sessions.
62 auto decl_flags
= options
.getDeclFlags();
63 auto aliased_namespaces
= options
.getAliasedNamespacesConfig();
64 return std::make_unique
<HhvmDeclProvider
>(
65 decl_flags
, aliased_namespaces
, map
69 HhvmDeclProvider::HhvmDeclProvider(
71 std::string
const& aliased_namespaces
,
74 : m_opts
{hackc_create_direct_decl_parse_options(flags
, aliased_namespaces
)}
78 // Called by hackc, potentially on a different thread.
79 DeclProviderResult
HhvmDeclProvider::getDecl(
80 AutoloadMap::KindOf kind
,
81 std::string_view symbol
83 // TODO(T110866581): symbol should be normalized by hackc
84 std::string_view
sym(normalizeNS(symbol
));
85 ITRACE(3, "DP lookup {}\n", sym
);
87 // Lookup the file where sym is defined in the autoload map.
88 auto filename_opt
= m_map
->getFile(kind
, sym
);
90 auto filename
= filename_opt
->native();
91 auto result
= m_cache
.find(filename
);
93 if (result
!= m_cache
.end()) {
94 ITRACE(3, "DP found cached decls for {} in {}\n", sym
, filename
);
95 return decls(&(*result
->second
.decls
));
98 // Nothing cached: Load file, parse decls.
99 std::ifstream
s(filename
);
101 std::istreambuf_iterator
<char>(s
), std::istreambuf_iterator
<char>()
104 DeclResult decl_result
= hackc_direct_decl_parse(*m_opts
, filename
, text
);
105 ITRACE(3, "DP parsed {} in {}\n", sym
, filename
);
107 // Insert decl_result into the cache, return DeclResult::decls,
108 // a pointer to rust decls in m_cache.
109 auto [it
, _
] = m_cache
.insert({filename
, std::move(decl_result
)});
110 return decls(&(*it
->second
.decls
));
112 ITRACE(4, "DP {}: getFile() returned None\n", sym
);
118 DeclProviderResult
hhvm_decl_provider_get_decl(
119 void* provider
, int symbol_kind
, char const* symbol
, size_t len
122 // Unsafe: if `symbol_kind` is out of range the result of this cast is UB.
123 HPHP::AutoloadMap::KindOf kind
{
124 static_cast<HPHP::AutoloadMap::KindOf
>(symbol_kind
)
126 return ((HhvmDeclProvider
*)provider
)->getDecl(
127 kind
, std::string_view(symbol
, len
)