lib/VM/JSLib/eval.cpp (110 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "JSLibInternal.h"
#include "hermes/BCGen/HBC/HBC.h"
#include "hermes/Parser/JSParser.h"
#include "hermes/Support/MemoryBuffer.h"
#include "hermes/Support/ScopeChain.h"
#include "hermes/VM/JSLib.h"
#include "hermes/VM/Runtime.h"
#include "hermes/VM/StringPrimitive.h"
#include "hermes/VM/StringView.h"
#include "llvh/Support/ConvertUTF.h"
#include "llvh/Support/raw_ostream.h"
#ifdef HERMESVM_ENABLE_OPTIMIZATION_AT_RUNTIME
#include "hermes/Optimizer/PassManager/Pipeline.h"
#endif
namespace hermes {
namespace vm {
CallResult<HermesValue> evalInEnvironment(
Runtime &runtime,
llvh::StringRef utf8code,
Handle<Environment> environment,
const ScopeChain &scopeChain,
Handle<> thisArg,
bool singleFunction) {
#ifdef HERMESVM_LEAN
return runtime.raiseEvalUnsupported(utf8code);
#else
if (!runtime.enableEval) {
return runtime.raiseEvalUnsupported(utf8code);
}
hbc::CompileFlags compileFlags;
compileFlags.strict = false;
compileFlags.includeLibHermes = false;
compileFlags.verifyIR = runtime.verifyEvalIR;
compileFlags.emitAsyncBreakCheck = runtime.asyncBreakCheckInEval;
compileFlags.lazy =
utf8code.size() >= compileFlags.preemptiveFileCompilationThreshold;
#ifdef HERMES_ENABLE_DEBUGGER
// Required to allow stepping and examining local variables in eval'd code
compileFlags.debug = true;
#endif
std::function<void(Module &)> runOptimizationPasses;
#ifdef HERMESVM_ENABLE_OPTIMIZATION_AT_RUNTIME
if (runtime.optimizedEval)
runOptimizationPasses = runFullOptimizationPasses;
#endif
std::unique_ptr<hbc::BCProviderFromSrc> bytecode;
{
std::unique_ptr<hermes::Buffer> buffer;
if (compileFlags.lazy) {
buffer.reset(new hermes::OwnedMemoryBuffer(
llvh::MemoryBuffer::getMemBufferCopy(utf8code)));
} else {
buffer.reset(new hermes::OwnedMemoryBuffer(
llvh::MemoryBuffer::getMemBuffer(utf8code)));
}
auto bytecode_err = hbc::BCProviderFromSrc::createBCProviderFromSrc(
std::move(buffer),
"JavaScript",
nullptr,
compileFlags,
scopeChain,
{},
nullptr,
runOptimizationPasses);
if (!bytecode_err.first) {
return runtime.raiseSyntaxError(TwineChar16(bytecode_err.second));
}
if (singleFunction && !bytecode_err.first->isSingleFunction()) {
return runtime.raiseSyntaxError("Invalid function expression");
}
bytecode = std::move(bytecode_err.first);
}
// TODO: pass a sourceURL derived from a '//# sourceURL' comment.
llvh::StringRef sourceURL{};
return runtime.runBytecode(
std::move(bytecode),
RuntimeModuleFlags{},
sourceURL,
environment,
thisArg);
#endif
}
CallResult<HermesValue> directEval(
Runtime &runtime,
Handle<StringPrimitive> str,
const ScopeChain &scopeChain,
bool singleFunction) {
// Convert the code into UTF8.
std::string code;
auto view = StringPrimitive::createStringView(runtime, str);
if (view.isASCII()) {
code = std::string(view.begin(), view.end());
} else {
SmallU16String<4> allocator;
convertUTF16ToUTF8WithReplacements(code, view.getUTF16Ref(allocator));
}
return evalInEnvironment(
runtime,
code,
Runtime::makeNullHandle<Environment>(),
scopeChain,
runtime.getGlobal(),
singleFunction);
}
CallResult<HermesValue> eval(void *, Runtime &runtime, NativeArgs args) {
GCScope gcScope(runtime);
if (!args.getArg(0).isString()) {
return args.getArg(0);
}
return directEval(runtime, args.dyncastArg<StringPrimitive>(0), {}, false);
}
} // namespace vm
} // namespace hermes