Recognize unsafe Wasm intrinsics
Summary: This Diff we provide a way to define and recognize unsafe compiler intrinsics used in Asm.js/Wasm. For now during the pass it only checks if an intrinsic is defined and is called with correct number of arguments. Reviewed By: tmikov Differential Revision: D29637395 fbshipit-source-id: 663bb77ee3beff277b66fb459c5b57be4d735c60
This commit is contained in:
Родитель
92e16809eb
Коммит
32d4b941e8
|
@ -227,6 +227,9 @@ set(HERMESVM_EXCEPTION_ON_OOM OFF CACHE BOOL
|
|||
set(HERMESVM_PLATFORM_LOGGING OFF CACHE BOOL
|
||||
"hermesLog(...) is enabled, using the platform's logging mechanism")
|
||||
|
||||
set(HERMES_RUN_WASM ON CACHE BOOL
|
||||
"Emit Asm.js/Wasm unsafe compiler intrinsics")
|
||||
|
||||
set(HERMES_USE_FLOWPARSER OFF CACHE BOOL
|
||||
"Use libflowparser for parsing es6")
|
||||
|
||||
|
@ -403,6 +406,9 @@ endif()
|
|||
if(HERMESVM_PLATFORM_LOGGING)
|
||||
add_definitions(-DHERMESVM_PLATFORM_LOGGING)
|
||||
endif()
|
||||
if(HERMES_RUN_WASM)
|
||||
add_definitions(-DHERMES_RUN_WASM)
|
||||
endif()
|
||||
if (NOT (ANDROID_LINUX_PERF_PATH STREQUAL ""))
|
||||
add_definitions(-DANDROID_LINUX_PERF_PATH="${ANDROID_LINUX_PERF_PATH}")
|
||||
endif()
|
||||
|
|
|
@ -19,6 +19,10 @@ namespace hbc {
|
|||
class BackendContext;
|
||||
}
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
class EmitWasmIntrinsicsContext;
|
||||
#endif // HERMES_RUN_WASM
|
||||
|
||||
struct CodeGenerationSettings {
|
||||
/// Whether we should emit TDZ checks.
|
||||
bool enableTDZ{true};
|
||||
|
@ -60,6 +64,9 @@ struct OptimizationSettings {
|
|||
|
||||
/// Attempt to resolve CommonJS require() calls at compile time.
|
||||
bool staticRequire{false};
|
||||
|
||||
/// Recognize and emit Asm.js/Wasm unsafe compiler intrinsics.
|
||||
bool useUnsafeIntrinsics{false};
|
||||
};
|
||||
|
||||
enum class DebugInfoSetting {
|
||||
|
@ -213,6 +220,10 @@ class Context {
|
|||
/// on its destructor.
|
||||
std::shared_ptr<hbc::BackendContext> hbcBackendContext_{};
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
std::shared_ptr<EmitWasmIntrinsicsContext> wasmIntrinsicsContext_{};
|
||||
#endif // HERMES_RUN_WASM
|
||||
|
||||
public:
|
||||
explicit Context(
|
||||
SourceErrorManager &sm,
|
||||
|
@ -392,6 +403,10 @@ class Context {
|
|||
return optimizationSettings_.staticBuiltins;
|
||||
}
|
||||
|
||||
bool getUseUnsafeIntrinsics() const {
|
||||
return optimizationSettings_.useUnsafeIntrinsics;
|
||||
}
|
||||
|
||||
const CodeGenerationSettings &getCodeGenerationSettings() const {
|
||||
return codeGenerationSettings_;
|
||||
}
|
||||
|
@ -418,6 +433,17 @@ class Context {
|
|||
std::shared_ptr<hbc::BackendContext> hbcBackendContext) {
|
||||
hbcBackendContext_ = std::move(hbcBackendContext);
|
||||
}
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
EmitWasmIntrinsicsContext *getWasmIntrinsicsContext() {
|
||||
return wasmIntrinsicsContext_.get();
|
||||
}
|
||||
|
||||
void setWasmIntrinsicsContext(
|
||||
std::shared_ptr<EmitWasmIntrinsicsContext> wasmIntrinsicsContext) {
|
||||
wasmIntrinsicsContext_ = std::move(wasmIntrinsicsContext);
|
||||
}
|
||||
#endif // HERMES_RUN_WASM
|
||||
};
|
||||
|
||||
} // namespace hermes
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
#ifndef HERMES_BCGEN_HBC_PASSES_WASMINTRINSICSPASS_H
|
||||
#define HERMES_BCGEN_HBC_PASSES_WASMINTRINSICSPASS_H
|
||||
|
||||
#include "hermes/Optimizer/PassManager/Pass.h"
|
||||
|
||||
namespace hermes {
|
||||
|
||||
/// Detect calls to unsafe intrinsics like `__uasm.add32()` and replace them
|
||||
/// with CallIntrinsicsInst.
|
||||
class EmitWasmIntrinsics : public FunctionPass {
|
||||
public:
|
||||
explicit EmitWasmIntrinsics() : FunctionPass("EmitWasmIntrinsics") {}
|
||||
|
||||
bool runOnFunction(Function *F) override;
|
||||
};
|
||||
|
||||
} // namespace hermes
|
||||
|
||||
#endif // HERMES_BCGEN_HBC_PASSES_WASMINTRINSICSPASS_H
|
||||
#endif // HERMES_RUN_WASM
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef WASM_INTRINSICS
|
||||
#define WASM_INTRINSICS(name, numArgs)
|
||||
#endif
|
||||
|
||||
// Arithmetic
|
||||
WASM_INTRINSICS(add32, 2)
|
||||
WASM_INTRINSICS(sub32, 2)
|
||||
WASM_INTRINSICS(mul32, 2)
|
||||
WASM_INTRINSICS(divi32, 2)
|
||||
WASM_INTRINSICS(divu32, 2)
|
||||
WASM_INTRINSICS(modi32, 2)
|
||||
WASM_INTRINSICS(modu32, 2)
|
||||
WASM_INTRINSICS(shl32, 2)
|
||||
WASM_INTRINSICS(shri32, 2)
|
||||
WASM_INTRINSICS(shru32, 2)
|
||||
|
||||
// Comparison
|
||||
WASM_INTRINSICS(eq32, 2)
|
||||
WASM_INTRINSICS(ne32, 2)
|
||||
WASM_INTRINSICS(lti32, 2)
|
||||
WASM_INTRINSICS(ltu32, 2)
|
||||
|
||||
// Memory
|
||||
WASM_INTRINSICS(loadi8, 2)
|
||||
WASM_INTRINSICS(loadu8, 2)
|
||||
WASM_INTRINSICS(loadi16, 2)
|
||||
WASM_INTRINSICS(loadu16, 2)
|
||||
WASM_INTRINSICS(load32, 2)
|
||||
WASM_INTRINSICS(loadf32, 2)
|
||||
WASM_INTRINSICS(loadf64, 2)
|
||||
|
||||
WASM_INTRINSICS(store8, 3)
|
||||
WASM_INTRINSICS(store16, 3)
|
||||
WASM_INTRINSICS(store32, 3)
|
||||
WASM_INTRINSICS(storef32, 3)
|
||||
WASM_INTRINSICS(storef64, 3)
|
||||
|
||||
#undef WASM_INTRINSICS
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
#ifndef HERMES_INST_WASM_INTRINSICS_H
|
||||
#define HERMES_INST_WASM_INTRINSICS_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace hermes {
|
||||
|
||||
namespace WasmIntrinsics {
|
||||
enum Enum : unsigned char {
|
||||
#define WASM_INTRINSICS(name, numArgs) __uasm##_##name,
|
||||
#include "WasmIntrinsics.def"
|
||||
_count,
|
||||
};
|
||||
|
||||
} // namespace WasmIntrinsics
|
||||
|
||||
/// Return a string representation of the Wasm intrinsics.
|
||||
const char *getWasmIntrinsicsName(unsigned intrinsics);
|
||||
|
||||
} // namespace hermes
|
||||
|
||||
#endif // HERMES_INST_WASM_INTRINSICS_H
|
||||
#endif // HERMES_RUN_WASM
|
|
@ -26,6 +26,8 @@ add_hermes_library(hermesOptimizer
|
|||
Optimizer/Scalar/HoistStartGenerator.cpp
|
||||
Optimizer/Scalar/InstructionEscapeAnalysis.cpp
|
||||
Optimizer/Scalar/TDZDedup.cpp
|
||||
Optimizer/Wasm/WasmIntrinsics.cpp
|
||||
Optimizer/Wasm/EmitWasmIntrinsics.cpp
|
||||
IR/Analysis.cpp
|
||||
IR/IREval.cpp
|
||||
)
|
||||
|
|
|
@ -553,6 +553,13 @@ static opt<bool> InstrumentIR(
|
|||
init(false),
|
||||
Hidden,
|
||||
cat(CompilerCategory));
|
||||
|
||||
static CLFlag UseUnsafeIntrinsics(
|
||||
'f',
|
||||
"unsafe-intrinsics",
|
||||
false,
|
||||
"Recognize and lower Asm.js/Wasm unsafe compiler intrinsics.",
|
||||
CompilerCategory);
|
||||
} // namespace cl
|
||||
|
||||
namespace {
|
||||
|
@ -1054,6 +1061,8 @@ std::shared_ptr<Context> createContext(
|
|||
cl::StaticBuiltins == cl::StaticBuiltinSetting::ForceOn;
|
||||
optimizationOpts.staticRequire = cl::StaticRequire;
|
||||
|
||||
optimizationOpts.useUnsafeIntrinsics = cl::UseUnsafeIntrinsics;
|
||||
|
||||
auto context = std::make_shared<Context>(
|
||||
codeGenOpts,
|
||||
optimizationOpts,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "hermes/Optimizer/Scalar/SimplifyCFG.h"
|
||||
#include "hermes/Optimizer/Scalar/StackPromotion.h"
|
||||
#include "hermes/Optimizer/Scalar/TypeInference.h"
|
||||
#include "hermes/Optimizer/Wasm/EmitWasmIntrinsics.h"
|
||||
|
||||
#include "llvh/Support/Debug.h"
|
||||
#include "llvh/Support/raw_ostream.h"
|
||||
|
@ -81,6 +82,13 @@ void hermes::runFullOptimizationPasses(Module &M) {
|
|||
// Move StartGenerator instructions to the start of functions.
|
||||
PM.addHoistStartGenerator();
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
// Emit Asm.js/Wasm unsafe compiler intrinsics, if enabled.
|
||||
if (M.getContext().getUseUnsafeIntrinsics()) {
|
||||
PM.addPass(new EmitWasmIntrinsics());
|
||||
}
|
||||
#endif // HERMES_RUN_WASM
|
||||
|
||||
// Run the optimizations.
|
||||
PM.run(&M);
|
||||
}
|
||||
|
@ -95,12 +103,32 @@ void hermes::runDebugOptimizationPasses(Module &M) {
|
|||
// Move StartGenerator instructions to the start of functions.
|
||||
PM.addHoistStartGenerator();
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
// Emit Asm.js/Wasm unsafe compiler intrinsics, if enabled.
|
||||
if (M.getContext().getUseUnsafeIntrinsics()) {
|
||||
PM.addPass(new EmitWasmIntrinsics());
|
||||
}
|
||||
#endif // HERMES_RUN_WASM
|
||||
|
||||
// Run the optimizations.
|
||||
PM.run(&M);
|
||||
}
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
void hermes::runNoOptimizationPasses(Module &M) {
|
||||
LLVM_DEBUG(dbgs() << "Running -O0 optimizations...\n");
|
||||
|
||||
// Emit Asm.js/Wasm unsafe compiler intrinsics, if enabled.
|
||||
if (M.getContext().getUseUnsafeIntrinsics()) {
|
||||
PassManager PM;
|
||||
PM.addPass(new EmitWasmIntrinsics());
|
||||
PM.run(&M);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void hermes::runNoOptimizationPasses(Module &) {
|
||||
LLVM_DEBUG(dbgs() << "Running -O0 optimizations...\n");
|
||||
}
|
||||
#endif // HERMES_RUN_WASM
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
#define DEBUG_TYPE "EmitWasmIntrinsics"
|
||||
#include "hermes/Optimizer/Wasm/EmitWasmIntrinsics.h"
|
||||
|
||||
#include "hermes/IR/IRBuilder.h"
|
||||
#include "hermes/Optimizer/Wasm/WasmIntrinsics.h"
|
||||
#include "hermes/Support/Statistic.h"
|
||||
#include "hermes/Support/StringTable.h"
|
||||
|
||||
#include "llvh/ADT/DenseMap.h"
|
||||
#include "llvh/Support/Debug.h"
|
||||
|
||||
STATISTIC(NumWasmIntrinsics, "Number of Wasm intrinsics recognized");
|
||||
|
||||
namespace hermes {
|
||||
|
||||
class EmitWasmIntrinsicsContext {
|
||||
public:
|
||||
explicit EmitWasmIntrinsicsContext(StringTable &strTab);
|
||||
|
||||
static EmitWasmIntrinsicsContext &get(Context &ctx) {
|
||||
if (!ctx.getWasmIntrinsicsContext()) {
|
||||
auto wasmIntrinsicsContext =
|
||||
std::make_shared<EmitWasmIntrinsicsContext>(ctx.getStringTable());
|
||||
ctx.setWasmIntrinsicsContext(wasmIntrinsicsContext);
|
||||
}
|
||||
|
||||
return *ctx.getWasmIntrinsicsContext();
|
||||
}
|
||||
|
||||
/// Look for unsafe compiler intrinsics.
|
||||
hermes::OptValue<WasmIntrinsics::Enum> findWasmIntrinsics(
|
||||
Identifier intrinsicsName);
|
||||
|
||||
/// Lookup the expected number of arguments for a specific intrinsic.
|
||||
unsigned getWasmIntrinsicsNumArgs(WasmIntrinsics::Enum index) {
|
||||
return intrinsicsNumArgs_[index];
|
||||
}
|
||||
|
||||
private:
|
||||
/// Map from an intrinisc name to an integer "intrinsic index".
|
||||
llvh::DenseMap<Identifier, WasmIntrinsics::Enum> intrinsics_;
|
||||
|
||||
/// Map from an integer "intrinsic index" to its expected number of
|
||||
/// arguments.
|
||||
unsigned intrinsicsNumArgs_[WasmIntrinsics::_count];
|
||||
};
|
||||
|
||||
EmitWasmIntrinsicsContext::EmitWasmIntrinsicsContext(StringTable &strTab) {
|
||||
// Insert all intrinsics.
|
||||
int intrinsicsIndex = 0;
|
||||
#define WASM_INTRINSICS(name, numArgs) \
|
||||
intrinsics_[strTab.getIdentifier(#name)] = \
|
||||
(WasmIntrinsics::Enum)(intrinsicsIndex++);
|
||||
#include "hermes/Optimizer/Wasm/WasmIntrinsics.def"
|
||||
|
||||
// Insert number of arguments.
|
||||
intrinsicsIndex = 0;
|
||||
#define WASM_INTRINSICS(name, numArgs) \
|
||||
intrinsicsNumArgs_[intrinsicsIndex++] = numArgs;
|
||||
#include "hermes/Optimizer/Wasm/WasmIntrinsics.def"
|
||||
}
|
||||
|
||||
hermes::OptValue<WasmIntrinsics::Enum>
|
||||
EmitWasmIntrinsicsContext::findWasmIntrinsics(Identifier intrinsicsName) {
|
||||
auto intrinsicsIt = intrinsics_.find(intrinsicsName);
|
||||
if (intrinsicsIt == intrinsics_.end()) {
|
||||
return llvh::None;
|
||||
}
|
||||
|
||||
return intrinsicsIt->second;
|
||||
}
|
||||
|
||||
bool EmitWasmIntrinsics::runOnFunction(Function *F) {
|
||||
NumWasmIntrinsics = 0;
|
||||
|
||||
IRBuilder builder{F};
|
||||
bool changed = false;
|
||||
|
||||
auto &wasmIntrinsics = EmitWasmIntrinsicsContext::get(F->getContext());
|
||||
|
||||
for (auto &BB : *F) {
|
||||
for (auto it = BB.begin(), e = BB.end(); it != e;) {
|
||||
auto *inst = &*it++;
|
||||
// Look for an instruction sequence of the kind:
|
||||
// (Call
|
||||
// (LoadProperty
|
||||
// (LoadProperty globalObject, "__uasm")
|
||||
// Prop)
|
||||
// ...)
|
||||
if (inst->getKind() != ValueKind::CallInstKind)
|
||||
continue;
|
||||
auto *callInst = cast<CallInst>(inst);
|
||||
auto *loadProp = llvh::dyn_cast<LoadPropertyInst>(callInst->getCallee());
|
||||
if (!loadProp)
|
||||
continue;
|
||||
auto propLit = llvh::dyn_cast<LiteralString>(loadProp->getProperty());
|
||||
if (!propLit)
|
||||
continue;
|
||||
auto *loadGlobalProp =
|
||||
llvh::dyn_cast<LoadPropertyInst>(loadProp->getObject());
|
||||
if (!loadGlobalProp)
|
||||
continue;
|
||||
if (!llvh::isa<GlobalObject>(loadGlobalProp->getObject()))
|
||||
continue;
|
||||
LiteralString *objLit =
|
||||
llvh::dyn_cast<LiteralString>(loadGlobalProp->getProperty());
|
||||
if (!objLit || (objLit->getValue().str() != "__uasm"))
|
||||
continue;
|
||||
|
||||
// Check if the intrinsic is defined.
|
||||
auto wasmIntrinsicsIndex =
|
||||
wasmIntrinsics.findWasmIntrinsics(propLit->getValue());
|
||||
if (!wasmIntrinsicsIndex) {
|
||||
// Undefined intrinsics in __uasm namesapce.
|
||||
F->getContext().getSourceErrorManager().error(
|
||||
F->getSourceRange(),
|
||||
Twine("the intrinsic \"") + propLit->getValue().str() +
|
||||
"\" is undefined.");
|
||||
continue;
|
||||
}
|
||||
|
||||
LLVM_DEBUG(
|
||||
llvh::dbgs() << "__uasm call: " << objLit->getValue() << "."
|
||||
<< propLit->getValue() << "\n");
|
||||
LLVM_DEBUG(
|
||||
llvh::dbgs() << "Wasm intriniscs found [" << (int)*wasmIntrinsicsIndex
|
||||
<< "] " << getWasmIntrinsicsName(*wasmIntrinsicsIndex)
|
||||
<< "()\n");
|
||||
|
||||
// Check if the intrinsic call has the correct number of arguments.
|
||||
unsigned numArgsExcludingThis = callInst->getNumArguments() - 1;
|
||||
unsigned numExpectedArgs =
|
||||
wasmIntrinsics.getWasmIntrinsicsNumArgs(*wasmIntrinsicsIndex);
|
||||
if (numArgsExcludingThis != numExpectedArgs) {
|
||||
F->getContext().getSourceErrorManager().error(
|
||||
F->getSourceRange(),
|
||||
Twine("the intrinsic \"") + propLit->getValue().str() +
|
||||
"\" is called with incorrect number of arguments. Expecting " +
|
||||
llvh::Twine(numExpectedArgs) + " but got " +
|
||||
llvh::Twine(numArgsExcludingThis) + ".");
|
||||
continue;
|
||||
}
|
||||
|
||||
NumWasmIntrinsics++;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace hermes
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
#endif // HERMES_RUN_WASM
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifdef HERMES_RUN_WASM
|
||||
#include "hermes/Optimizer/Wasm/WasmIntrinsics.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace hermes {
|
||||
|
||||
static const char *wasmIntrinsicsName[] = {
|
||||
#define WASM_INTRINSICS(name, numArgs) "__uasm." #name "_" #numArgs,
|
||||
#include "hermes/Optimizer/Wasm/WasmIntrinsics.def"
|
||||
};
|
||||
|
||||
const char *getWasmIntrinsicsName(unsigned intrinsics) {
|
||||
assert(
|
||||
intrinsics < WasmIntrinsics::_count && "invalid Wasm intrinsics index");
|
||||
return wasmIntrinsicsName[intrinsics];
|
||||
}
|
||||
|
||||
} // namespace hermes
|
||||
#endif // HERMES_RUN_WASM
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 -dump-lir %s | %FileCheck --match-full-lines %s
|
||||
|
||||
// LowerIntrinsics pass is only enabled if -funsafe-intrinsics is set.
|
||||
function undefinedIntrinsic(func) {
|
||||
return __uasm.foo(42, 3);
|
||||
}
|
||||
//CHECK-LABEL:function undefinedIntrinsic(func)
|
||||
//CHECK-NEXT:frame = []
|
||||
//CHECK-NEXT:%BB0:
|
||||
//CHECK-NEXT: %0 = HBCGetGlobalObjectInst
|
||||
//CHECK-NEXT: %1 = TryLoadGlobalPropertyInst %0 : object, "__uasm" : string
|
||||
//CHECK-NEXT: %2 = LoadPropertyInst %1, "foo" : string
|
||||
//CHECK-NEXT: %3 = HBCLoadConstInst 42 : number
|
||||
//CHECK-NEXT: %4 = HBCLoadConstInst 3 : number
|
||||
//CHECK-NEXT: %5 = HBCCallNInst %2, %1, %3 : number, %4 : number
|
||||
//CHECK-NEXT: %6 = ReturnInst %5
|
||||
//CHECK-NEXT:function_end
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 -funsafe-intrinsics -dump-lir -Werror %s 2>&1 ) | %FileCheck %s --match-full-lines
|
||||
|
||||
function undefinedIntrinsic(func) {
|
||||
return __uasm.foo(42, 3);
|
||||
}
|
||||
//CHECK: {{.*}}unsafe-intrinsics-undefined.js:10:1: error: the intrinsic "foo" is undefined.
|
||||
//CHECK-NEXT: function undefinedIntrinsic(func) {
|
||||
//CHECK-NEXT: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//CHECK-NEXT: Emitted 1 errors. exiting.
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 -funsafe-intrinsics -dump-lir -Werror %s 2>&1 ) | %FileCheck %s --match-full-lines
|
||||
|
||||
function wrongNumArgs(func) {
|
||||
return __uasm.add32(1, 2, 3);
|
||||
}
|
||||
//CHECK: {{.*}}unsafe-intrinsics-wrong-num-args.js:10:1: error: the intrinsic "add32" is called with incorrect number of arguments. Expecting 2 but got 3.
|
||||
//CHECK-NEXT: function wrongNumArgs(func) {
|
||||
//CHECK-NEXT: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//CHECK-NEXT: Emitted 1 errors. exiting.
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its 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 -funsafe-intrinsics -dump-lir %s | %FileCheck --match-full-lines %s
|
||||
|
||||
// Instrinsics that are defined should not cause any error. But
|
||||
// we also do not do anything, yet.
|
||||
function unsafeIntrinsics(func) {
|
||||
t0 = __uasm.add32(1, 2);
|
||||
t1 = __uasm.modu32(42, 7);
|
||||
return t0 + t1;
|
||||
}
|
||||
//CHECK-LABEL:function unsafeIntrinsics(func) : string|number
|
||||
//CHECK-NEXT:frame = []
|
||||
//CHECK-NEXT:%BB0:
|
||||
//CHECK-NEXT: %0 = HBCGetGlobalObjectInst
|
||||
//CHECK-NEXT: %1 = TryLoadGlobalPropertyInst %0 : object, "__uasm" : string
|
||||
//CHECK-NEXT: %2 = LoadPropertyInst %1, "add32" : string
|
||||
//CHECK-NEXT: %3 = HBCLoadConstInst 1 : number
|
||||
//CHECK-NEXT: %4 = HBCLoadConstInst 2 : number
|
||||
//CHECK-NEXT: %5 = HBCCallNInst %2, %1, %3 : number, %4 : number
|
||||
//CHECK-NEXT: %6 = StorePropertyInst %5, %0 : object, "t0" : string
|
||||
//CHECK-NEXT: %7 = TryLoadGlobalPropertyInst %0 : object, "__uasm" : string
|
||||
//CHECK-NEXT: %8 = LoadPropertyInst %7, "modu32" : string
|
||||
//CHECK-NEXT: %9 = HBCLoadConstInst 42 : number
|
||||
//CHECK-NEXT: %10 = HBCLoadConstInst 7 : number
|
||||
//CHECK-NEXT: %11 = HBCCallNInst %8, %7, %9 : number, %10 : number
|
||||
//CHECK-NEXT: %12 = StorePropertyInst %11, %0 : object, "t1" : string
|
||||
//CHECK-NEXT: %13 = TryLoadGlobalPropertyInst %0 : object, "t0" : string
|
||||
//CHECK-NEXT: %14 = TryLoadGlobalPropertyInst %0 : object, "t1" : string
|
||||
//CHECK-NEXT: %15 = BinaryOperatorInst '+', %13, %14
|
||||
//CHECK-NEXT: %16 = ReturnInst %15 : string|number
|
||||
//CHECK-NEXT:function_end
|
Загрузка…
Ссылка в новой задаче