Skip to content

Commit 4af630f

Browse files
neildharfacebook-github-bot
authored andcommitted
Parse source map in BCProviderFromSrc::create
Summary: We currently fail to link `hermesvmlean` because we take a dependency on the `SourceMapParser` which in turn requires the `JSONParser`. We currently only use it to pass a parsed `SourceMap` to `createBCProviderFromSrc`, so instead pass the actual source map and perform the parsing there. This allows us to compile out the `SourceMapParser` in lean builds. While we're changing the signatures, clarify and enforce the null termination requirement for the source map. Reviewed By: avp Differential Revision: D68936292 fbshipit-source-id: c1d00630c85c7cdb4a461100abd62cc7aa41f3bf
1 parent fa8a149 commit 4af630f

File tree

11 files changed

+51
-50
lines changed

11 files changed

+51
-50
lines changed

API/hermes/CompileJS.cpp

+10-8
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@ bool compileJS(
5454
flags.emitAsyncBreakCheck = compileJSOptions.emitAsyncBreakCheck;
5555
flags.inlineMaxSize = compileJSOptions.inlineMaxSize;
5656

57-
std::unique_ptr<hermes::SourceMap> sourceMap{};
58-
// parse the source map if one was provided
57+
// If there is a source map, ensure that it is null terminated, copying it if
58+
// needed.
59+
std::string smCopy;
60+
llvh::StringRef smRef;
5961
if (sourceMapBuf.has_value()) {
60-
hermes::SourceErrorManager sm;
61-
sourceMap = hermes::SourceMapParser::parse(
62-
llvh::StringRef{sourceMapBuf->data(), sourceMapBuf->size()}, {}, sm);
63-
if (!sourceMap) {
64-
return false;
62+
if (sourceMapBuf->back() != '\0') {
63+
smCopy = *sourceMapBuf;
64+
smRef = {smCopy.data(), smCopy.size() + 1};
65+
} else {
66+
smRef = {sourceMapBuf->data(), sourceMapBuf->size()};
6567
}
6668
}
6769

@@ -70,7 +72,7 @@ bool compileJS(
7072
auto res = hbc::createBCProviderFromSrc(
7173
std::make_unique<hermes::Buffer>((const uint8_t *)str.data(), str.size()),
7274
sourceURL,
73-
std::move(sourceMap),
75+
smRef,
7476
flags,
7577
"global",
7678
diagHandler ? diagHandlerAdapter : nullptr,

API/hermes/hermes.cpp

+6-18
Original file line numberDiff line numberDiff line change
@@ -1536,27 +1536,15 @@ HermesRuntimeImpl::prepareJavaScriptWithSourceMap(
15361536
std::make_unique<BufferAdapter>(jsiBuffer));
15371537
runtimeFlags.persistent = true;
15381538
} else {
1539-
std::unique_ptr<::hermes::SourceMap> sourceMap{};
1539+
llvh::StringRef sourceMap;
1540+
std::unique_ptr<BufferAdapter> buf0;
15401541
if (sourceMapBuf) {
1541-
auto buf0 = ensureZeroTerminated(sourceMapBuf);
1542-
// Convert the buffer into a form the parser needs.
1543-
llvh::MemoryBufferRef mbref(
1544-
llvh::StringRef((const char *)buf0->data(), buf0->size()), "");
1545-
::hermes::SimpleDiagHandler diag;
1546-
::hermes::SourceErrorManager sm;
1547-
diag.installInto(sm);
1548-
sourceMap = ::hermes::SourceMapParser::parse(mbref, {}, sm);
1549-
if (!sourceMap) {
1550-
auto errorStr = diag.getErrorString();
1551-
LOG_EXCEPTION_CAUSE("Error parsing source map: %s", errorStr.c_str());
1552-
throw std::runtime_error("Error parsing source map:" + errorStr);
1553-
}
1542+
buf0 = ensureZeroTerminated(sourceMapBuf);
1543+
// The source map StringRef must include the null terminator.
1544+
sourceMap = llvh::StringRef((const char *)buf0->data(), buf0->size() + 1);
15541545
}
15551546
bcErr = hbc::createBCProviderFromSrc(
1556-
ensureZeroTerminated(jsiBuffer),
1557-
sourceURL,
1558-
std::move(sourceMap),
1559-
compileFlags_);
1547+
ensureZeroTerminated(jsiBuffer), sourceURL, sourceMap, compileFlags_);
15601548
if (bcErr.first) {
15611549
runtimeFlags.persistent = bcErr.first->allowPersistent();
15621550
}

include/hermes/BCGen/HBC/BCProviderFromSrc.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ class BCProviderFromSrc final : public BCProviderBase {
8787
/// "eval" for eval, "global" for ordinary scripts.
8888
/// \param sourceURL this will be used as the "file name" of the buffer for
8989
/// errors, stack traces, etc.
90-
/// \param sourceMap optional input source map for \p buffer.
90+
/// \param sourceMap optional input source map for \p buffer. It may be empty
91+
/// if no source map is provided. If it is non-empty, the last byte must
92+
/// be a null terminator.
9193
/// \param compileFlags self explanatory
9294
/// \param diagHandler handler for errors/warnings/notes.
9395
/// \param diagContext opaque data that will be passed to diagHandler.
@@ -104,7 +106,7 @@ class BCProviderFromSrc final : public BCProviderBase {
104106
static std::pair<std::unique_ptr<BCProviderFromSrc>, std::string> create(
105107
std::unique_ptr<Buffer> buffer,
106108
llvh::StringRef sourceURL,
107-
std::unique_ptr<SourceMap> sourceMap,
109+
llvh::StringRef sourceMap,
108110
const CompileFlags &compileFlags,
109111
llvh::StringRef topLevelFunctionName = "global",
110112
SourceErrorManager::DiagHandlerTy diagHandler = {},

include/hermes/BCGen/HBC/HBC.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ void fullOptimizationPipeline(Module &M);
8787
/// "eval" for eval, "global" for ordinary scripts.
8888
/// \param sourceURL this will be used as the "file name" of the buffer for
8989
/// errors, stack traces, etc.
90-
/// \param sourceMap optional input source map for \p buffer.
90+
/// \param sourceMap optional input source map for \p buffer. It may be empty
91+
/// if no source map is provided. If it is non-empty, the last byte must
92+
/// be a null terminator.
9193
/// \param compileFlags self explanatory
9294
/// \param diagHandler handler for errors/warnings/notes.
9395
/// \param diagContext opaque data that will be passed to diagHandler.
@@ -104,7 +106,7 @@ void fullOptimizationPipeline(Module &M);
104106
std::pair<std::unique_ptr<BCProvider>, std::string> createBCProviderFromSrc(
105107
std::unique_ptr<Buffer> buffer,
106108
llvh::StringRef sourceURL,
107-
std::unique_ptr<SourceMap> sourceMap,
109+
llvh::StringRef sourceMap,
108110
const CompileFlags &compileFlags,
109111
llvh::StringRef topLevelFunctionName = "global",
110112
SourceErrorManager::DiagHandlerTy diagHandler = {},

lib/BCGen/HBC/BCProviderFromSrc.cpp

+19-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "hermes/Runtime/Libhermes.h"
1515
#include "hermes/Sema/SemContext.h"
1616
#include "hermes/Sema/SemResolve.h"
17+
#include "hermes/SourceMap/SourceMapParser.h"
1718
#include "hermes/SourceMap/SourceMapTranslator.h"
1819
#include "hermes/Support/MemoryBuffer.h"
1920
#include "hermes/Support/SimpleDiagHandler.h"
@@ -87,7 +88,7 @@ std::pair<std::unique_ptr<BCProviderFromSrc>, std::string>
8788
BCProviderFromSrc::create(
8889
std::unique_ptr<Buffer> buffer,
8990
llvh::StringRef sourceURL,
90-
std::unique_ptr<SourceMap> sourceMap,
91+
llvh::StringRef sourceMap,
9192
const CompileFlags &compileFlags,
9293
llvh::StringRef topLevelFunctionName,
9394
SourceErrorManager::DiagHandlerTy diagHandler,
@@ -161,11 +162,26 @@ BCProviderFromSrc::create(
161162
buffer->size() >= context->getPreemptiveFileCompilationThreshold();
162163
int fileBufId = context->getSourceErrorManager().addNewSourceBuffer(
163164
std::make_unique<HermesLLVMMemoryBuffer>(std::move(buffer), sourceURL));
164-
if (sourceMap != nullptr) {
165+
166+
if (!sourceMap.empty()) {
167+
assert(sourceMap.back() == '\0' && "Must be null terminated");
168+
// Convert the buffer into a form the parser needs. Note that the incoming
169+
// buffer has the null terminator embedded at the end, whereas for the
170+
// MemoryBuffer we want it past-the-end, so we shrink it by one.
171+
llvh::MemoryBufferRef mbref(
172+
llvh::StringRef{sourceMap.data(), sourceMap.size() - 1}, "");
173+
SimpleDiagHandler diag;
174+
SourceErrorManager sm;
175+
diag.installInto(sm);
176+
std::unique_ptr<SourceMap> parsedSM = SourceMapParser::parse(mbref, {}, sm);
177+
if (!parsedSM) {
178+
auto errorStr = diag.getErrorString();
179+
return std::make_pair(nullptr, "Error parsing source map: " + errorStr);
180+
}
165181
auto sourceMapTranslator =
166182
std::make_shared<SourceMapTranslator>(context->getSourceErrorManager());
167183
context->getSourceErrorManager().setTranslator(sourceMapTranslator);
168-
sourceMapTranslator->addSourceMap(fileBufId, std::move(sourceMap));
184+
sourceMapTranslator->addSourceMap(fileBufId, std::move(parsedSM));
169185
}
170186

171187
auto parserMode = parser::FullParse;

lib/BCGen/HBC/HBC.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void fullOptimizationPipeline(Module &M) {
3131
std::pair<std::unique_ptr<BCProvider>, std::string> createBCProviderFromSrc(
3232
std::unique_ptr<Buffer> buffer,
3333
llvh::StringRef sourceURL,
34-
std::unique_ptr<SourceMap> sourceMap,
34+
llvh::StringRef sourceMap,
3535
const CompileFlags &compileFlags,
3636
llvh::StringRef topLevelFunctionName,
3737
SourceErrorManager::DiagHandlerTy diagHandler,
@@ -41,7 +41,7 @@ std::pair<std::unique_ptr<BCProvider>, std::string> createBCProviderFromSrc(
4141
return BCProviderFromSrc::create(
4242
std::move(buffer),
4343
sourceURL,
44-
std::move(sourceMap),
44+
sourceMap,
4545
compileFlags,
4646
topLevelFunctionName,
4747
diagHandler,

lib/BCGen/HBC/HBCStub.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void fullOptimizationPipeline(Module &M) {
2323
std::pair<std::unique_ptr<BCProvider>, std::string> createBCProviderFromSrc(
2424
std::unique_ptr<Buffer> buffer,
2525
llvh::StringRef sourceURL,
26-
std::unique_ptr<SourceMap> sourceMap,
26+
llvh::StringRef sourceMap,
2727
const CompileFlags &compileFlags,
2828
llvh::StringRef topLevelFunctionName,
2929
SourceErrorManager::DiagHandlerTy diagHandler,

lib/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ target_link_libraries(hermesvmlean_a PUBLIC
166166
hermesPublic_obj
167167
hermesRegex_obj
168168
hermesSupport_obj
169-
hermesSourceMap_obj
170169
hermesVMRuntime_obj
171170
zip_obj
172171
)

lib/VM/JSLib/eval.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ CallResult<HermesValue> evalInEnvironment(
9696
bytecode_err = hbc::createBCProviderFromSrc(
9797
std::move(buffer),
9898
"",
99-
nullptr,
99+
{},
100100
compileFlags,
101101
"eval",
102102
{},

lib/VM/Runtime.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ CallResult<HermesValue> Runtime::run(
10191019
PerfSection loading("Loading new JavaScript code");
10201020
loading.addArg("url", sourceURL);
10211021
auto bytecode_err = hbc::createBCProviderFromSrc(
1022-
std::move(code), sourceURL, /* sourceMap */ nullptr, compileFlags);
1022+
std::move(code), sourceURL, /* sourceMap */ {}, compileFlags);
10231023
if (!bytecode_err.first) {
10241024
return raiseSyntaxError(TwineChar16(bytecode_err.second));
10251025
}

tools/emhermesc/emhermesc.cpp

+3-11
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ extern "C" CompileResult *hermesCompileToBytecode(
116116
const char *sourceMapData,
117117
size_t sourceMapSize) {
118118
auto compileRes = std::make_unique<CompileResult>();
119-
std::unique_ptr<SourceMap> sourceMap;
119+
llvh::StringRef smRef;
120120

121121
if (source[sourceSize - 1] != 0) {
122122
compileRes->error_ = "Input source must be zero-terminated";
@@ -129,15 +129,7 @@ extern "C" CompileResult *hermesCompileToBytecode(
129129
return compileRes.release();
130130
}
131131

132-
SourceErrorManager sm;
133-
SimpleDiagHandlerRAII diagHandler(sm);
134-
sourceMap =
135-
SourceMapParser::parse({sourceMapData, sourceMapSize - 1}, {}, sm);
136-
if (!sourceMap) {
137-
compileRes->error_ =
138-
"Failed to parse source map:" + diagHandler.getErrorString();
139-
return compileRes.release();
140-
}
132+
smRef = {sourceMapData, sourceMapSize};
141133
}
142134

143135
hbc::CompileFlags flags{};
@@ -148,7 +140,7 @@ extern "C" CompileResult *hermesCompileToBytecode(
148140
auto res = hbc::createBCProviderFromSrc(
149141
std::make_unique<hermes::Buffer>((const uint8_t *)source, sourceSize - 1),
150142
sourceURL ? sourceURL : "",
151-
std::move(sourceMap),
143+
smRef,
152144
flags);
153145
if (!res.first) {
154146
if (!res.second.empty())

0 commit comments

Comments
 (0)