Skip to content

Commit

Permalink
Re-sync with internal repository (#822)
Browse files Browse the repository at this point in the history
Co-authored-by: Facebook Community Bot <[email protected]>
  • Loading branch information
facebook-github-bot and facebook-github-bot authored Sep 27, 2022
1 parent 628f29f commit 6aa825e
Show file tree
Hide file tree
Showing 15 changed files with 165 additions and 22 deletions.
21 changes: 14 additions & 7 deletions include/hermes/BCGen/HBC/BytecodeInstructionGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ class BytecodeInstructionGenerator {
/// A list of opcodes.
std::vector<opcode_atom_t> opcodes_{};

/// A flag indicating that an encoding error happened, in which case the
/// bytecode is wrong and shouldn't be executed.
bool encodingError_{};

public:
/// Returns whether an encoding error happened during bytecode emission.
bool hasEncodingError() const {
return encodingError_;
}

/// Returns the current location of the bytecode stream.
offset_t getCurrentLocation() {
return opcodes_.size();
Expand Down Expand Up @@ -76,13 +85,11 @@ class BytecodeInstructionGenerator {
// We also assert that the value can fit into ctype.
// For integer values, ((param_t)(ctype)value) == value will do the job;
// We also want doubles to pass the check unconditionally.
#define DEFINE_OPERAND_TYPE(name, ctype) \
void emit##name(param_t value) { \
assert( \
(((param_t)(ctype)value) == value || \
std::is_floating_point<ctype>::value) && \
"Value does not fit in " #ctype); \
emitOperand(value, sizeof(ctype)); \
#define DEFINE_OPERAND_TYPE(name, ctype) \
void emit##name(param_t value) { \
encodingError_ |= ((param_t)(ctype)value) != value && \
!std::is_floating_point<ctype>::value; \
emitOperand(value, sizeof(ctype)); \
}
#include "hermes/BCGen/HBC/BytecodeList.def"

Expand Down
2 changes: 2 additions & 0 deletions include/hermes/CompilerDriver/CompilerDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ enum CompileStatus {
OutputFileError,
/// An error occured during optimization.
OptimizationFailed,
/// An error occured in the backend during/after IR lowering.
BackendError,
};

/// Information about a bytecode file that is loaded into a buffer.
Expand Down
11 changes: 7 additions & 4 deletions include/hermes/VM/CodeBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class CodeBlock final

#ifndef HERMESVM_LEAN
/// Compiles a lazy CodeBlock. Intended to be called from lazyCompile.
void lazyCompileImpl(Runtime &runtime);
ExecutionStatus lazyCompileImpl(Runtime &runtime);
#endif

/// Helper function for getting start and end locations.
Expand Down Expand Up @@ -237,17 +237,20 @@ class CodeBlock final
}

/// Compiles this CodeBlock, if it's lazy and not already compiled.
void lazyCompile(Runtime &runtime) {
ExecutionStatus lazyCompile(Runtime &runtime) {
if (LLVM_UNLIKELY(isLazy())) {
lazyCompileImpl(runtime);
return lazyCompileImpl(runtime);
}
return ExecutionStatus::RETURNED;
}
#else
/// Checks whether this function is lazily compiled.
bool isLazy() const {
return false;
}
void lazyCompile(Runtime &) {}
ExecutionStatus lazyCompile(Runtime &) {
return ExecutionStatus::RETURNED;
}
#endif

/// Get the start location of this function, if it's lazy.
Expand Down
2 changes: 2 additions & 0 deletions lib/BCGen/HBC/BytecodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ void BytecodeModuleGenerator::setFunctionGenerator(
assert(
functionGenerators_.find(F) == functionGenerators_.end() &&
"Adding same function twice.");
assert(
!BFG->hasEncodingError() && "Error should have been reported already.");
functionGenerators_[F] = std::move(BFG);
}

Expand Down
7 changes: 5 additions & 2 deletions lib/BCGen/HBC/BytecodeProviderFromSrc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,11 @@ BCProviderFromSrc::createBCProviderFromSrcImpl(
opts.staticBuiltinsEnabled =
context->getOptimizationSettings().staticBuiltins;
opts.verifyIR = compileFlags.verifyIR;
auto bytecode = createBCProviderFromSrc(
hbc::generateBytecodeModule(&M, M.getTopLevelFunction(), opts));
auto BM = hbc::generateBytecodeModule(&M, M.getTopLevelFunction(), opts);
if (context->getSourceErrorManager().getErrorCount() > 0) {
return {nullptr, getErrorString()};
}
auto bytecode = createBCProviderFromSrc(std::move(BM));
bytecode->singleFunction_ = isSingleFunctionExpression(parsed.getValue());
return {std::move(bytecode), std::string{}};
}
Expand Down
9 changes: 9 additions & 0 deletions lib/BCGen/HBC/HBC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ std::unique_ptr<BytecodeModule> hbc::generateBytecodeModule(
debugCache = hbciSel.getDebugCache();
}

if (funcGen->hasEncodingError()) {
M->getContext().getSourceErrorManager().error(
F.getSourceRange().Start, "Error encoding bytecode");
return nullptr;
}
BMGen.setFunctionGenerator(&F, std::move(funcGen));
}

Expand All @@ -335,6 +340,10 @@ std::unique_ptr<BytecodeModule> hbc::generateBytecode(
sourceMapGen,
std::move(baseBCProvider));

if (!BM) {
return {};
}

if (options.format == OutputFormatKind::EmitBundle) {
assert(BM != nullptr);
BytecodeSerializer BS{OS, options};
Expand Down
4 changes: 4 additions & 0 deletions lib/BCGen/HBC/ISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,10 @@ void HBCISel::generateHBCResolveEnvironment(
"Cannot access variables in inner scopes");
int32_t delta = curScopeDepth.getValue() - instScopeDepth.getValue();
assert(delta > 0 && "HBCResolveEnvironment for current scope");
if (std::numeric_limits<uint8_t>::max() < delta) {
F_->getContext().getSourceErrorManager().error(
Inst->getLocation(), "Variable environment is out-of-reach");
}
BCFGen_->emitGetEnvironment(encodeValue(Inst), delta - 1);
}
void HBCISel::generateHBCStoreToEnvironmentInst(
Expand Down
15 changes: 13 additions & 2 deletions lib/CompilerDriver/CompilerDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1694,9 +1694,15 @@ CompileResult generateBytecodeForExecution(
std::shared_ptr<Context> context = M.shareContext();
CompileResult result{Success};
if (cl::BytecodeFormat == cl::BytecodeFormatKind::HBC) {
result.bytecodeProvider = hbc::BCProviderFromSrc::createBCProviderFromSrc(
hbc::generateBytecodeModule(&M, M.getTopLevelFunction(), genOptions));
auto BM =
hbc::generateBytecodeModule(&M, M.getTopLevelFunction(), genOptions);
if (auto N = context->getSourceErrorManager().getErrorCount()) {
llvh::errs() << "Emitted " << N << " errors in the backend. exiting.\n";
return BackendError;
}

result.bytecodeProvider =
hbc::BCProviderFromSrc::createBCProviderFromSrc(std::move(BM));
} else {
llvm_unreachable("Invalid bytecode kind for execution");
result = InvalidFlags;
Expand Down Expand Up @@ -1735,6 +1741,11 @@ CompileResult generateBytecodeForSerialization(
sourceMapGenOrNull,
std::move(baseBCProvider));

if (auto N = M.getContext().getSourceErrorManager().getErrorCount()) {
llvh::errs() << "Emitted " << N << " errors in the backend. exiting.\n";
return BackendError;
}

if (cl::DumpTarget == DumpBytecode) {
disassembleBytecode(hbc::BCProviderFromSrc::createBCProviderFromSrc(
std::move(bytecodeModule)));
Expand Down
6 changes: 5 additions & 1 deletion lib/VM/Callable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1395,7 +1395,11 @@ CallResult<PseudoHandle<>> GeneratorInnerFunction::callInnerFunction(
// Note that this will do nothing after the very first time a lazy function
// is called, so we only resize before we save any registers at all.
if (LLVM_UNLIKELY(selfHandle->getCodeBlock(runtime)->isLazy())) {
selfHandle->getCodeBlock(runtime)->lazyCompile(runtime);
if (LLVM_UNLIKELY(
selfHandle->getCodeBlock(runtime)->lazyCompile(runtime) ==
ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
if (LLVM_UNLIKELY(
ArrayStorage::resize(
ctx,
Expand Down
15 changes: 14 additions & 1 deletion lib/VM/CodeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "hermes/IRGen/IRGen.h"
#include "hermes/Support/Conversions.h"
#include "hermes/Support/PerfSection.h"
#include "hermes/Support/SimpleDiagHandler.h"
#include "hermes/VM/GCPointer-inline.h"
#include "hermes/VM/Runtime.h"
#include "hermes/VM/RuntimeModule.h"
Expand Down Expand Up @@ -330,14 +331,24 @@ std::unique_ptr<hbc::BytecodeModule> compileLazyFunction(
}
} // namespace

void CodeBlock::lazyCompileImpl(Runtime &runtime) {
ExecutionStatus CodeBlock::lazyCompileImpl(Runtime &runtime) {
assert(isLazy() && "Laziness has not been checked");
PerfSection perf("Lazy function compilation");
auto *provider = (hbc::BCProviderLazy *)runtimeModule_->getBytecode();
auto *func = provider->getBytecodeFunction();
auto *lazyData = func->getLazyCompilationData();
SourceErrorManager &manager = lazyData->context->getSourceErrorManager();
SimpleDiagHandlerRAII outputManager{manager};
auto bcModule = compileLazyFunction(lazyData);

if (manager.getErrorCount()) {
// Raise a SyntaxError to be consistent with eval().
return runtime.raiseSyntaxError(
llvh::StringRef{outputManager.getErrorString()});
}

assert(bcModule && "No errors, yet no bcModule");

runtimeModule_->initializeLazyMayAllocate(
hbc::BCProviderFromSrc::createBCProviderFromSrc(std::move(bcModule)));
// Reset all meta lazyData of the CodeBlock to point to the newly
Expand All @@ -346,6 +357,8 @@ void CodeBlock::lazyCompileImpl(Runtime &runtime) {
functionHeader_ =
runtimeModule_->getBytecode()->getFunctionHeader(functionID_);
bytecode_ = runtimeModule_->getBytecode()->getBytecode(functionID_);

return ExecutionStatus::RETURNED;
}
#endif // HERMESVM_LEAN

Expand Down
7 changes: 6 additions & 1 deletion lib/VM/Debugger/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1147,7 +1147,12 @@ bool Debugger::resolveBreakpointLocation(Breakpoint &breakpoint) const {
(start.col <= request.column && request.column <= end.col))) {
// The code block probably contains the breakpoint we want to set.
// First, we compile it.
codeBlock->lazyCompile(runtime_);
if (LLVM_UNLIKELY(
codeBlock->lazyCompile(runtime_) ==
ExecutionStatus::EXCEPTION)) {
// TODO: how to better handle this?
runtime_.clearThrownValue();
}

// We've found the codeBlock at this level and expanded it,
// so there's no point continuing the search.
Expand Down
15 changes: 12 additions & 3 deletions lib/VM/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,10 @@ static inline const Inst *nextInstCall(const Inst *ip) {

CallResult<HermesValue> Runtime::interpretFunctionImpl(
CodeBlock *newCodeBlock) {
newCodeBlock->lazyCompile(*this);
if (LLVM_UNLIKELY(
newCodeBlock->lazyCompile(*this) == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}

#if defined(HERMES_MEMORY_INSTRUMENTATION) || !defined(NDEBUG)
// We always call getCurrentIP() in a debug build as this has the effect
Expand Down Expand Up @@ -1584,7 +1587,10 @@ CallResult<HermesValue> Interpreter::interpretFunction(
#endif

CodeBlock *calleeBlock = func->getCodeBlock(runtime);
CAPTURE_IP(calleeBlock->lazyCompile(runtime));
CAPTURE_IP_ASSIGN(auto res, calleeBlock->lazyCompile(runtime));
if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
goto exception;
}
curCodeBlock = calleeBlock;
CAPTURE_IP_SET();
goto tailCall;
Expand Down Expand Up @@ -1637,7 +1643,10 @@ CallResult<HermesValue> Interpreter::interpretFunction(

assert(!SingleStep && "can't single-step a call");

CAPTURE_IP(calleeBlock->lazyCompile(runtime));
CAPTURE_IP_ASSIGN(auto res, calleeBlock->lazyCompile(runtime));
if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
goto exception;
}
curCodeBlock = calleeBlock;
CAPTURE_IP_SET();
goto tailCall;
Expand Down
4 changes: 3 additions & 1 deletion lib/VM/Operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1679,7 +1679,9 @@ CallResult<bool> isConstructor(Runtime &runtime, Callable *callable) {
auto *cb = func->getCodeBlock(runtime);
// Even though it doesn't make sense logically, we need to compile the
// function in order to access it flags.
cb->lazyCompile(runtime);
if (LLVM_UNLIKELY(cb->lazyCompile(runtime) == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
return !func->getCodeBlock(runtime)->getHeaderFlags().isCallProhibited(
true);
}
Expand Down
33 changes: 33 additions & 0 deletions test/hermes/far-environment-access-eval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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.
*/

// RUN: %hermes -O -target=HBC %s 2>&1 | %FileCheck --match-full-lines %s
// RUN: %hermes -O -target=HBC %s -lazy 2>&1 | %FileCheck --match-full-lines %s
// XFAIL: windows
// UNSUPPORTED: ubsan

// Hermes has a 256 limit on the number of scopes nesting. This test ensures
// that the compiler will handle applications that require more scopes
// gracefully -- i.e., it won't crash, nor emit bad bytecode.

try {
eval('"use strict";\n' +
'\n' +
'function sink(x) { return x; }\n' +
'function foo(){\n' +
' var var0 = sink("1");\n' +
' var var1 = sink("2");\n' +
' var var2 = sink("3");\n' +
' return ()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=> [var0, var1, var2];\n' +
'}\n' +
'\n' +
'print(foo()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()());\n')
} catch (e) {
print(e);
}

// CHECK: SyntaxError: {{[0-9]+}}:{{[0-9]+}}:Variable environment is out-of-reach
36 changes: 36 additions & 0 deletions test/hermes/far-environment-access.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* 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.
*/

// RUN: (%hermesc -O -target=HBC %s --dump-bytecode 2>&1 || true) | %FileCheck --match-full-lines %s
// RUN: (%hermes -O -target=HBC %s 2>&1 || true) | %FileCheck --match-full-lines %s
// RUN: %hermes -O -target=HBC %s -lazy 2>&1 | %FileCheck --match-full-lines %s --check-prefix=LAZY
// XFAIL: windows
// UNSUPPORTED: ubsan

// Hermes has a 256 limit on the number of scopes nesting. This test ensures
// that the compiler will handle applications that require more scopes
// gracefully -- i.e., it won't crash, nor emit bad bytecode.

"use strict";

function sink(x) { return x; }
function foo(){
var var0 = sink("1");
var var1 = sink("2");
var var2 = sink("3");
return ()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=>()=> [var0, var1, var2];
}

try {
print(foo()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()());
} catch (e) {
print(e);
}


// CHECK: {{.*}}far-environment-access.js:{{[0-9]+}}:{{[0-9]+}}: error: Variable environment is out-of-reach
// LAZY: SyntaxError: {{[0-9]+}}:{{[0-9]+}}:Variable environment is out-of-reach

0 comments on commit 6aa825e

Please sign in to comment.