Commit 691b8d69 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #433 from undingen/objectcache

Add a cache for JITed object code
parents 59d38882 729a81c5
......@@ -10,3 +10,6 @@
[submodule "test/integration/virtualenv"]
path = test/integration/virtualenv
url = https://github.com/dropbox/virtualenv
[submodule "lz4"]
path = lz4
url = git://github.com/Cyan4973/lz4.git
......@@ -116,6 +116,10 @@ ExternalProject_Add(libunwind
add_subdirectory(libpypa)
add_dependencies(pypa gitsubmodules)
# lz4
add_subdirectory(lz4/cmake_unofficial)
add_dependencies(lz4 gitsubmodules)
# valgrind
if(ENABLE_VALGRIND)
find_package(Valgrind REQUIRED)
......@@ -182,7 +186,7 @@ add_subdirectory(tools)
add_executable(pyston $<TARGET_OBJECTS:PYSTON_MAIN_OBJECT> $<TARGET_OBJECTS:PYSTON_OBJECTS> $<TARGET_OBJECTS:FROM_CPYTHON>)
# Wrap the stdlib in --whole-archive to force all the symbols to be included and eventually exported
target_link_libraries(pyston -Wl,--whole-archive stdlib -Wl,--no-whole-archive pthread m readline sqlite3 gmp ssl crypto unwind pypa double-conversion ${LLVM_LIBS} ${LIBLZMA_LIBRARIES} ${OPTIONAL_LIBRARIES})
target_link_libraries(pyston -Wl,--whole-archive stdlib -Wl,--no-whole-archive pthread m readline sqlite3 gmp ssl crypto unwind pypa liblz4 double-conversion ${LLVM_LIBS} ${LIBLZMA_LIBRARIES} ${OPTIONAL_LIBRARIES})
# copy src/codegen/parse_ast.py to the build directory
add_custom_command(TARGET pyston POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/src/codegen/parse_ast.py ${CMAKE_BINARY_DIR}/src/codegen/parse_ast.py)
......
......@@ -88,3 +88,32 @@ products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
------
LZ4 Library
Copyright (c) 2011-2014, Yann Collet
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------
......@@ -155,6 +155,7 @@ COMMON_CXXFLAGS += -fexceptions -fno-rtti
COMMON_CXXFLAGS += -Wno-invalid-offsetof # allow the use of "offsetof", and we'll just have to make sure to only use it legally.
COMMON_CXXFLAGS += -DENABLE_INTEL_JIT_EVENTS=$(ENABLE_INTEL_JIT_EVENTS)
COMMON_CXXFLAGS += -I$(DEPS_DIR)/pypa-install/include
COMMON_CXXFLAGS += -I$(DEPS_DIR)/lz4-install/include
ifeq ($(ENABLE_VALGRIND),0)
COMMON_CXXFLAGS += -DNVALGRIND
......@@ -170,6 +171,7 @@ COMMON_CXXFLAGS += -DDEFAULT_PYTHON_MAJOR_VERSION=$(PYTHON_MAJOR_VERSION) -DDEFA
# Use our "custom linker" that calls gold if available
COMMON_LDFLAGS := -B$(TOOLS_DIR)/build_system -L/usr/local/lib -lpthread -lm -lunwind -llzma -L$(DEPS_DIR)/gcc-4.8.2-install/lib64 -lreadline -lgmp -lssl -lcrypto -lsqlite3
COMMON_LDFLAGS += $(DEPS_DIR)/pypa-install/lib/libpypa.a
COMMON_LDFLAGS += $(DEPS_DIR)/lz4-install/lib/liblz4.a
# Conditionally add libtinfo if available - otherwise nothing will be added
COMMON_LDFLAGS += `pkg-config tinfo 2>/dev/null && pkg-config tinfo --libs || echo ""`
......
......@@ -140,6 +140,15 @@ cd gtest-1.7.0
make -j4
```
### LZ4
```
cd ~/pyston_deps
git clone git://github.com/Cyan4973/lz4.git
mkdir lz4-install
cd lz4/lib
DESTDIR="$HOME/pyston_deps/lz4-install" PREFIX="/" make install
```
---
At this point you should be able to run `make check` (in the `~/pyston` directory) and pass the tests. See the main README for more information about available targets and options.
......
From a27e2f111d85c2e55c5a9672b9ef39494b4d7fd8 Mon Sep 17 00:00:00 2001
From: Marius Wachtler <undingen@gmail.com>
Date: Wed, 15 Apr 2015 09:40:51 +0200
Subject: [PATCH] Add support for symbolic entries in the stackmap constant
table
---
include/llvm/CodeGen/StackMaps.h | 18 ++++++++++--
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 9 ++++++
lib/CodeGen/StackMaps.cpp | 36 +++++++++++++++++++++---
test/CodeGen/X86/stackmap.ll | 26 +++++++++++++++--
4 files changed, 79 insertions(+), 10 deletions(-)
diff --git a/include/llvm/CodeGen/StackMaps.h b/include/llvm/CodeGen/StackMaps.h
index 4e48afe..30cae3b 100644
--- a/include/llvm/CodeGen/StackMaps.h
+++ b/include/llvm/CodeGen/StackMaps.h
@@ -136,9 +136,13 @@ public:
unsigned Size;
unsigned Reg;
int64_t Offset;
- Location() : LocType(Unprocessed), Size(0), Reg(0), Offset(0) {}
+ const MCSymbol *Sym;
+ Location() : LocType(Unprocessed), Size(0), Reg(0), Offset(0), Sym(0) {}
Location(LocationType LocType, unsigned Size, unsigned Reg, int64_t Offset)
- : LocType(LocType), Size(Size), Reg(Reg), Offset(Offset) {}
+ : LocType(LocType), Size(Size), Reg(Reg), Offset(Offset), Sym(0) {}
+ Location(const MCSymbol *Sym)
+ : LocType(LocationType::Constant), Size(sizeof(int64_t)), Reg(0),
+ Offset(0), Sym(Sym) {}
};
struct LiveOutReg {
@@ -160,13 +164,19 @@ public:
// OpTypes are used to encode information about the following logical
// operand (which may consist of several MachineOperands) for the
// OpParser.
- typedef enum { DirectMemRefOp, IndirectMemRefOp, ConstantOp } OpType;
+ typedef enum {
+ DirectMemRefOp,
+ IndirectMemRefOp,
+ ConstantOp,
+ ConstantGVOp
+ } OpType;
StackMaps(AsmPrinter &AP);
void reset() {
CSInfos.clear();
ConstPool.clear();
+ ConstSymPool.clear();
FnStackSize.clear();
}
@@ -191,6 +201,7 @@ private:
typedef SmallVector<Location, 8> LocationVec;
typedef SmallVector<LiveOutReg, 8> LiveOutVec;
typedef MapVector<uint64_t, uint64_t> ConstantPool;
+ typedef MapVector<const MCSymbol *, const MCSymbol *> ConstantSymMap;
typedef MapVector<const MCSymbol *, uint64_t> FnStackSizeMap;
struct CallsiteInfo {
@@ -210,6 +221,7 @@ private:
AsmPrinter &AP;
CallsiteInfoList CSInfos;
ConstantPool ConstPool;
+ ConstantSymMap ConstSymPool;
FnStackSizeMap FnStackSize;
MachineInstr::const_mop_iterator
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index c0a8299..98cc692 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -7122,6 +7122,15 @@ static void addStackMapLiveVars(ImmutableCallSite CS, unsigned StartIdx,
const TargetLowering &TLI = Builder.DAG.getTargetLoweringInfo();
Ops.push_back(
Builder.DAG.getTargetFrameIndex(FI->getIndex(), TLI.getPointerTy()));
+ } else if (auto *GA = dyn_cast<GlobalAddressSDNode>(OpVal)) {
+ if (GA->getValueType(0) != MVT::i64)
+ Ops.push_back(OpVal);
+ else {
+ Ops.push_back(
+ Builder.DAG.getTargetConstant(StackMaps::ConstantGVOp, MVT::i64));
+ Ops.push_back(Builder.DAG.getTargetGlobalAddress(GA->getGlobal(),
+ SDLoc(GA), MVT::i64));
+ }
} else
Ops.push_back(OpVal);
}
diff --git a/lib/CodeGen/StackMaps.cpp b/lib/CodeGen/StackMaps.cpp
index 0797d56..7151166 100644
--- a/lib/CodeGen/StackMaps.cpp
+++ b/lib/CodeGen/StackMaps.cpp
@@ -107,6 +107,16 @@ StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
Locs.push_back(Location(Location::Constant, sizeof(int64_t), 0, Imm));
break;
}
+ case StackMaps::ConstantGVOp: {
+ ++MOI;
+ assert(MOI->isGlobal() && "Expected a global value operand.");
+ const GlobalValue *GV = MOI->getGlobal();
+ assert(GV);
+ MCSymbol *Sym = AP.TM.getSymbol(GV, *AP.Mang);
+ assert(Sym);
+ Locs.push_back(Location(Sym));
+ break;
+ }
}
return ++MOI;
}
@@ -226,7 +236,7 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
I != E; ++I) {
// Constants are encoded as sign-extended integers.
// -1 is directly encoded as .long 0xFFFFFFFF with no constant pool.
- if (I->LocType == Location::Constant && !isInt<32>(I->Offset)) {
+ if (I->LocType == Location::Constant && !isInt<32>(I->Offset) && !I->Sym) {
I->LocType = Location::ConstantIndex;
// ConstPool is intentionally a MapVector of 'uint64_t's (as
// opposed to 'int64_t's). We should never be in a situation
@@ -243,6 +253,17 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID,
}
}
+ // Convert constant symbols to ConstantIndex entries.
+ for (LocationVec::iterator I = Locations.begin(), E = Locations.end(); I != E;
+ ++I) {
+ if (I->LocType == Location::Constant && I->Sym) {
+ I->LocType = Location::ConstantIndex;
+ auto Result = ConstSymPool.insert(std::make_pair(I->Sym, I->Sym));
+ // The symbolic entries will be emitted after the ConstPool entries.
+ I->Offset = ConstPool.size() + Result.first - ConstSymPool.begin();
+ }
+ }
+
// Create an expression to calculate the offset of the callsite from function
// entry.
const MCExpr *CSOffsetExpr = MCBinaryExpr::CreateSub(
@@ -325,8 +346,9 @@ void StackMaps::emitStackmapHeader(MCStreamer &OS) {
DEBUG(dbgs() << WSMP << "#functions = " << FnStackSize.size() << '\n');
OS.EmitIntValue(FnStackSize.size(), 4);
// Num constants.
- DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n');
- OS.EmitIntValue(ConstPool.size(), 4);
+ auto NumConst = ConstPool.size() + ConstSymPool.size();
+ DEBUG(dbgs() << WSMP << "#constants = " << NumConst << '\n');
+ OS.EmitIntValue(NumConst, 4);
// Num callsites.
DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n');
OS.EmitIntValue(CSInfos.size(), 4);
@@ -359,6 +381,10 @@ void StackMaps::emitConstantPoolEntries(MCStreamer &OS) {
DEBUG(dbgs() << WSMP << ConstEntry.second << '\n');
OS.EmitIntValue(ConstEntry.second, 8);
}
+ for (auto ConstEntry : ConstSymPool) {
+ DEBUG(dbgs() << WSMP << ConstEntry.second << '\n');
+ OS.EmitSymbolValue(ConstEntry.second, 8);
+ }
}
/// Emit the callsite info for each callsite.
@@ -511,7 +537,8 @@ void StackMaps::emitCallsiteEntries(MCStreamer &OS,
void StackMaps::serializeToStackMapSection() {
(void) WSMP;
// Bail out if there's no stack map data.
- assert((!CSInfos.empty() || (CSInfos.empty() && ConstPool.empty())) &&
+ assert((!CSInfos.empty() ||
+ (CSInfos.empty() && ConstPool.empty() && ConstSymPool.empty())) &&
"Expected empty constant pool too!");
assert((!CSInfos.empty() || (CSInfos.empty() && FnStackSize.empty())) &&
"Expected empty function record too!");
@@ -541,4 +568,5 @@ void StackMaps::serializeToStackMapSection() {
// Clean up.
CSInfos.clear();
ConstPool.clear();
+ ConstSymPool.clear();
}
diff --git a/test/CodeGen/X86/stackmap.ll b/test/CodeGen/X86/stackmap.ll
index 5e356f3..59fa50f 100644
--- a/test/CodeGen/X86/stackmap.ll
+++ b/test/CodeGen/X86/stackmap.ll
@@ -11,7 +11,7 @@
; Num Functions
; CHECK-NEXT: .long 16
; Num LargeConstants
-; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 5
; Num Callsites
; CHECK-NEXT: .long 20
@@ -53,6 +53,8 @@
; CHECK-NEXT: .quad 2147483648
; CHECK-NEXT: .quad 4294967295
; CHECK-NEXT: .quad 4294967296
+; CHECK-NEXT: .quad _constSym1
+; CHECK-NEXT: .quad _constSym2
; Callsites
; Constant arguments
@@ -60,7 +62,7 @@
; CHECK-NEXT: .quad 1
; CHECK-NEXT: .long L{{.*}}-_constantargs
; CHECK-NEXT: .short 0
-; CHECK-NEXT: .short 12
+; CHECK-NEXT: .short 15
; SmallConstant
; CHECK-NEXT: .byte 4
; CHECK-NEXT: .byte 8
@@ -116,16 +118,34 @@
; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
; CHECK-NEXT: .long 2
+; LargeConstant at index 3
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 8
+; CHECK-NEXT: .short 0
+; CHECK-NEXT: .long 3
+; LargeConstant at index 3
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 8
+; CHECK-NEXT: .short 0
+; CHECK-NEXT: .long 3
+; LargeConstant at index 4
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 8
+; CHECK-NEXT: .short 0
+; CHECK-NEXT: .long 4
; SmallConstant
; CHECK-NEXT: .byte 4
; CHECK-NEXT: .byte 8
; CHECK-NEXT: .short 0
; CHECK-NEXT: .long -1
+
+@constSym1 = external constant i64
+@constSym2 = external constant i64
define void @constantargs() {
entry:
%0 = inttoptr i64 12345 to i8*
- tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 1, i32 15, i8* %0, i32 0, i16 65535, i16 -1, i32 65536, i32 2000000000, i32 2147483647, i32 -1, i32 4294967295, i32 4294967296, i64 2147483648, i64 4294967295, i64 4294967296, i64 -1)
+ tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 1, i32 15, i8* %0, i32 0, i16 65535, i16 -1, i32 65536, i32 2000000000, i32 2147483647, i32 -1, i32 4294967295, i32 4294967296, i64 2147483648, i64 4294967295, i64 4294967296, i64* @constSym1, i64* @constSym1, i64* @constSym2, i64 -1)
ret void
}
--
2.1.0
Subproject commit 160661c7a4cbf805f4af74d2e3932a17a66e6ce7
......@@ -8,6 +8,7 @@ set_source_files_properties(jit.cpp PROPERTIES COMPILE_DEFINITIONS "GITREV=${GIT
include_directories(${CMAKE_BINARY_DIR})
include_directories(${CMAKE_BINARY_DIR}/libunwind/include)
include_directories(${CMAKE_SOURCE_DIR}/libpypa/src)
include_directories(${CMAKE_SOURCE_DIR}/lz4/lib)
if(ENABLE_GPERFTOOLS)
set(OPTIONAL_SRCS ${OPTIONAL_SRCS} codegen/profiling/pprof.cpp)
......@@ -109,7 +110,7 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS}
add_dependencies(PYSTON_OBJECTS libunwind pypa ${LLVM_LIBS})
add_library(PYSTON_MAIN_OBJECT OBJECT jit.cpp)
add_dependencies(PYSTON_MAIN_OBJECT libunwind pypa ${LLVM_LIBS})
add_dependencies(PYSTON_MAIN_OBJECT libunwind pypa liblz4 ${LLVM_LIBS})
# build stdlib
add_subdirectory(runtime/inline)
......
......@@ -283,8 +283,12 @@ public:
assert(usage);
assert(ast);
// Sort the entries by name to make the order deterministic.
std::vector<InternedString> referenced_from_nested_sorted(usage->referenced_from_nested.begin(),
usage->referenced_from_nested.end());
std::sort(referenced_from_nested_sorted.begin(), referenced_from_nested_sorted.end());
int i = 0;
for (auto& p : usage->referenced_from_nested) {
for (auto& p : referenced_from_nested_sorted) {
closure_offsets[p] = i;
i++;
}
......
......@@ -1555,6 +1555,27 @@ void* extractSlowpathFunc(uint8_t* pp_addr) {
return call_addr;
}
void setSlowpathFunc(uint8_t* pp_addr, void* func) {
#ifndef NDEBUG
// mov $imm, %r11:
ASSERT(pp_addr[0] == 0x49, "%x", pp_addr[0]);
assert(pp_addr[1] == 0xbb);
// 8 bytes of the addr
// callq *%r11:
assert(pp_addr[10] == 0x41);
assert(pp_addr[11] == 0xff);
assert(pp_addr[12] == 0xd3);
int i = INITIAL_CALL_SIZE;
while (*(pp_addr + i) == 0x66 || *(pp_addr + i) == 0x0f || *(pp_addr + i) == 0x2e)
i++;
assert(*(pp_addr + i) == 0x90 || *(pp_addr + i) == 0x1f);
#endif
*(void**)&pp_addr[2] = func;
}
std::pair<uint8_t*, uint8_t*> initializePatchpoint3(void* slowpath_func, uint8_t* start_addr, uint8_t* end_addr,
int scratch_offset, int scratch_size,
const std::unordered_set<int>& live_outs, SpillMap& remapped) {
......
......@@ -476,6 +476,7 @@ public:
};
void* extractSlowpathFunc(uint8_t* pp_addr);
void setSlowpathFunc(uint8_t* pp_addr, void* func);
struct GRCompare {
bool operator()(assembler::GenericRegister gr1, assembler::GenericRegister gr2) const {
......
......@@ -293,7 +293,8 @@ public:
llvm::Value* cls_value = emitter.getBuilder()->CreateLoad(cls_ptr);
assert(cls_value->getType() == g.llvm_class_type_ptr);
llvm::Value* rtn = emitter.getBuilder()->CreateICmpEQ(cls_value, embedConstantPtr(cls, g.llvm_class_type_ptr));
llvm::Value* rtn
= emitter.getBuilder()->CreateICmpEQ(cls_value, embedRelocatablePtr(cls, g.llvm_class_type_ptr));
return rtn;
}
......@@ -367,8 +368,8 @@ public:
}
// We don't know the type so we have to check at runtime if __iter__ is implemented
llvm::Value* cmp = emitter.getBuilder()->CreateICmpNE(converted_iter_call->getValue(),
embedConstantPtr(0, g.llvm_value_type_ptr));
llvm::Value* cmp
= emitter.getBuilder()->CreateICmpNE(converted_iter_call->getValue(), getNullPtr(g.llvm_value_type_ptr));
llvm::BasicBlock* bb_has_iter = emitter.createBasicBlock("has_iter");
bb_has_iter->moveAfter(emitter.currentBasicBlock());
......@@ -529,19 +530,19 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
if (args.size() >= 1) {
llvm_args.push_back(converted_args[0]->getValue());
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
llvm_args.push_back(getNullPtr(g.llvm_value_type_ptr));
}
if (args.size() >= 2) {
llvm_args.push_back(converted_args[1]->getValue());
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
llvm_args.push_back(getNullPtr(g.llvm_value_type_ptr));
}
if (args.size() >= 3) {
llvm_args.push_back(converted_args[2]->getValue());
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
llvm_args.push_back(getNullPtr(g.llvm_value_type_ptr));
}
llvm::Value* mallocsave = NULL;
......@@ -569,10 +570,10 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
llvm_args.push_back(arg_array);
if (pass_keyword_names)
llvm_args.push_back(embedConstantPtr(keyword_names, g.vector_ptr));
llvm_args.push_back(embedRelocatablePtr(keyword_names, g.vector_ptr));
} else if (pass_keyword_names) {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr->getPointerTo()));
llvm_args.push_back(embedConstantPtr(keyword_names, g.vector_ptr));
llvm_args.push_back(getNullPtr(g.llvm_value_type_ptr->getPointerTo()));
llvm_args.push_back(embedRelocatablePtr(keyword_names, g.vector_ptr));
}
// f->dump();
......@@ -683,7 +684,7 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info,
std::vector<llvm::Value*> other_args;
other_args.push_back(var->getValue());
other_args.push_back(embedConstantPtr(attr, g.llvm_str_type_ptr));
other_args.push_back(embedRelocatablePtr(attr, g.llvm_str_type_ptr));
other_args.push_back(getConstantInt(flags_to_int.value, g.i8));
llvm::Value* llvm_argspec = llvm::ConstantInt::get(g.i32, argspec.asInt(), false);
......@@ -737,7 +738,7 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
convertedClosure = closure->makeConverted(emitter, closure->getConcreteType());
closure_v = convertedClosure->getValue();
} else {
closure_v = embedConstantPtr(nullptr, g.llvm_closure_type_ptr);
closure_v = getNullPtr(g.llvm_closure_type_ptr);
}
llvm::Value* scratch;
......@@ -752,20 +753,20 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
i++;
}
} else {
scratch = embedConstantPtr(nullptr, g.llvm_value_type_ptr_ptr);
scratch = getNullPtr(g.llvm_value_type_ptr_ptr);
}
llvm::Value* isGenerator_v = llvm::ConstantInt::get(g.i1, isGenerator, false);
assert(globals == NULL);
llvm::Value* globals_v = embedConstantPtr(nullptr, g.llvm_dict_type_ptr);
llvm::Value* globals_v = getNullPtr(g.llvm_dict_type_ptr);
// We know this function call can't throw, so it's safe to use emitter.getBuilder()->CreateCall() rather than
// emitter.createCall().
llvm::Value* boxed = emitter.getBuilder()->CreateCall(
g.funcs.boxCLFunction,
std::vector<llvm::Value*>{ embedConstantPtr(f, g.llvm_clfunction_type_ptr), closure_v, isGenerator_v, globals_v,
scratch, getConstantInt(defaults.size(), g.i64) });
std::vector<llvm::Value*>{ embedRelocatablePtr(f, g.llvm_clfunction_type_ptr), closure_v, isGenerator_v,
globals_v, scratch, getConstantInt(defaults.size(), g.i64) });
if (convertedClosure)
convertedClosure->decvref(emitter);
......@@ -1339,7 +1340,7 @@ ConcreteCompilerVariable* makeFloat(double d) {
ConcreteCompilerVariable* makeLong(IREmitter& emitter, std::string& n_long) {
llvm::Value* v
= emitter.getBuilder()->CreateCall(g.funcs.createLong, embedConstantPtr(&n_long, g.llvm_str_type_ptr));
= emitter.getBuilder()->CreateCall(g.funcs.createLong, embedRelocatablePtr(&n_long, g.llvm_str_type_ptr));
return new ConcreteCompilerVariable(LONG, v, true);
}
......@@ -1481,7 +1482,7 @@ public:
ASSERT(rtattr, "%s.%s", debugName().c_str(), attr->c_str());
if (rtattr->cls == function_cls) {
CompilerVariable* clattr = new ConcreteCompilerVariable(
typeFromClass(function_cls), embedConstantPtr(rtattr, g.llvm_value_type_ptr), false);
typeFromClass(function_cls), embedRelocatablePtr(rtattr, g.llvm_value_type_ptr), false);
return InstanceMethodType::makeIM(var, clattr);
}
}
......@@ -1587,7 +1588,11 @@ public:
}
llvm::FunctionType* ft = llvm::FunctionType::get(cf->spec->rtn_type->llvmType(), arg_types, false);
llvm::Value* linked_function = embedConstantPtr(cf->code, ft->getPointerTo());
llvm::Value* linked_function;
if (cf->func) // for JITed functions we need to make the desination address relocatable.
linked_function = embedRelocatablePtr(cf->code, ft->getPointerTo());
else
linked_function = embedConstantPtr(cf->code, ft->getPointerTo());
std::vector<CompilerVariable*> new_args;
new_args.push_back(var);
......@@ -1595,10 +1600,14 @@ public:
for (int i = args.size() + 1; i < cl->num_args; i++) {
// TODO should _call() be able to take llvm::Value's directly?
new_args.push_back(new ConcreteCompilerVariable(
UNKNOWN, embedConstantPtr(rtattr_func->defaults->elts[i - cl->num_args + cl->num_defaults],
g.llvm_value_type_ptr),
true));
auto value = rtattr_func->defaults->elts[i - cl->num_args + cl->num_defaults];
llvm::Value* llvm_value;
if (value)
llvm_value = embedRelocatablePtr(value, g.llvm_value_type_ptr);
else
llvm_value = getNullPtr(g.llvm_value_type_ptr);
new_args.push_back(new ConcreteCompilerVariable(UNKNOWN, llvm_value, true));
}
std::vector<llvm::Value*> other_args;
......@@ -1873,8 +1882,8 @@ public:
ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* var, ConcreteCompilerType* other_type) override {
assert(other_type == STR || other_type == UNKNOWN);
llvm::Value* boxed = emitter.getBuilder()->CreateCall(g.funcs.boxStringPtr,
embedConstantPtr(var->getValue(), g.llvm_str_type_ptr));
llvm::Value* boxed = emitter.getBuilder()->CreateCall(
g.funcs.boxStringPtr, embedRelocatablePtr(var->getValue(), g.llvm_str_type_ptr));
return new ConcreteCompilerVariable(other_type, boxed, true);
}
......@@ -1928,7 +1937,7 @@ public:
}
void serializeToFrame(VAR* var, std::vector<llvm::Value*>& stackmap_args) override {
stackmap_args.push_back(embedConstantPtr(var->getValue(), g.i8_ptr));
stackmap_args.push_back(embedRelocatablePtr(var->getValue(), g.i8_ptr));
}
Box* deserializeFromFrame(const FrameVals& vals) override {
......@@ -1947,7 +1956,7 @@ CompilerVariable* makeStr(const std::string* s) {
CompilerVariable* makeUnicode(IREmitter& emitter, const std::string* s) {
llvm::Value* boxed
= emitter.getBuilder()->CreateCall(g.funcs.decodeUTF8StringPtr, embedConstantPtr(s, g.llvm_str_type_ptr));
= emitter.getBuilder()->CreateCall(g.funcs.decodeUTF8StringPtr, embedRelocatablePtr(s, g.llvm_str_type_ptr));
return new ConcreteCompilerVariable(typeFromClass(unicode_cls), boxed, true);
}
......
......@@ -16,6 +16,8 @@
#include <cstdio>
#include <iostream>
#include <lz4frame.h>
#include <openssl/evp.h>
#include <unordered_map>
#include "llvm/Analysis/Passes.h"
......@@ -31,6 +33,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Cloning.h"
......@@ -118,54 +121,215 @@ static llvm::Module* loadStdlib() {
return m;
}
class MyObjectCache : public llvm::ObjectCache {
class CompressedFile {
public:
static bool writeFile(llvm::StringRef file_name, llvm::StringRef data) {
std::error_code error_code;
llvm::raw_fd_ostream file(file_name, error_code, llvm::sys::fs::F_RW);
if (error_code)
return false;
LZ4F_preferences_t preferences;
memset(&preferences, 0, sizeof(preferences));
preferences.frameInfo.contentChecksumFlag = contentChecksumEnabled;
preferences.frameInfo.contentSize = data.size();
std::vector<char> compressed;
size_t max_size = LZ4F_compressFrameBound(data.size(), &preferences);
compressed.resize(max_size);
size_t compressed_size = LZ4F_compressFrame(&compressed[0], max_size, data.data(), data.size(), &preferences);
if (LZ4F_isError(compressed_size))
return false;
file.write(compressed.data(), compressed_size);
return true;
}
static std::unique_ptr<llvm::MemoryBuffer> getFile(llvm::StringRef file_name) {
auto compressed_content = llvm::MemoryBuffer::getFile(file_name, -1, false);
if (!compressed_content)
return std::unique_ptr<llvm::MemoryBuffer>();
LZ4F_decompressionContext_t context;
LZ4F_createDecompressionContext(&context, LZ4F_VERSION);
LZ4F_frameInfo_t frame_info;
memset(&frame_info, 0, sizeof(frame_info));
const char* start = (*compressed_content)->getBufferStart();
size_t pos = 0;
size_t compressed_size = (*compressed_content)->getBufferSize();
size_t remaining = compressed_size - pos;
LZ4F_getFrameInfo(context, &frame_info, start, &remaining);
pos += remaining;
std::vector<char> uncompressed;
uncompressed.reserve(frame_info.contentSize);
while (pos < compressed_size) {
unsigned char buff[4096];
size_t buff_size = sizeof(buff);
remaining = compressed_size - pos;
size_t error_code = LZ4F_decompress(context, buff, &buff_size, start + pos, &remaining, NULL);
if (LZ4F_isError(error_code)) {
LZ4F_freeDecompressionContext(context);
return std::unique_ptr<llvm::MemoryBuffer>();
}
pos += remaining;
if (buff_size != 0)
uncompressed.insert(uncompressed.end(), buff, buff + buff_size);
}
LZ4F_freeDecompressionContext(context);
if (uncompressed.size() != frame_info.contentSize)
return std::unique_ptr<llvm::MemoryBuffer>();
return llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(uncompressed.data(), uncompressed.size()));
}
};
class PystonObjectCache : public llvm::ObjectCache {
private:
bool loaded;
// Stream which calculates the SHA256 hash of the data writen to.
class HashOStream : public llvm::raw_ostream {
EVP_MD_CTX* md_ctx;
void write_impl(const char* ptr, size_t size) override { EVP_DigestUpdate(md_ctx, ptr, size); }
uint64_t current_pos() const override { return 0; }
public:
HashOStream() {
md_ctx = EVP_MD_CTX_create();
RELEASE_ASSERT(md_ctx, "");
int ret = EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL);
RELEASE_ASSERT(ret == 1, "");
}
~HashOStream() { EVP_MD_CTX_destroy(md_ctx); }
std::string getHash() {
flush();
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len = 0;
int ret = EVP_DigestFinal_ex(md_ctx, md_value, &md_len);
RELEASE_ASSERT(ret == 1, "");
std::string str;
str.reserve(md_len * 2 + 1);
llvm::raw_string_ostream stream(str);
for (int i = 0; i < md_len; ++i)
stream.write_hex(md_value[i]);
return stream.str();
}
};
llvm::SmallString<128> cache_dir;
std::string module_identifier;
std::string hash_before_codegen;
public:
MyObjectCache() : loaded(false) {}
PystonObjectCache() {
llvm::sys::path::home_directory(cache_dir);
llvm::sys::path::append(cache_dir, ".cache");
llvm::sys::path::append(cache_dir, "pyston");
llvm::sys::path::append(cache_dir, "object_cache");
cleanupCacheDirectory();
}
#if LLVMREV < 216002
virtual void notifyObjectCompiled(const llvm::Module* M, const llvm::MemoryBuffer* Obj) {}
virtual void notifyObjectCompiled(const llvm::Module* M, const llvm::MemoryBuffer* Obj)
#else
virtual void notifyObjectCompiled(const llvm::Module* M, llvm::MemoryBufferRef Obj) {}
virtual void notifyObjectCompiled(const llvm::Module* M, llvm::MemoryBufferRef Obj)
#endif
{
RELEASE_ASSERT(module_identifier == M->getModuleIdentifier(), "");
RELEASE_ASSERT(!hash_before_codegen.empty(), "");
llvm::SmallString<128> cache_file = cache_dir;
llvm::sys::path::append(cache_file, hash_before_codegen);
if (!llvm::sys::fs::exists(cache_dir.str()) && llvm::sys::fs::create_directories(cache_dir.str()))
return;
CompressedFile::writeFile(cache_file, Obj.getBuffer());
}
#if LLVMREV < 215566
virtual llvm::MemoryBuffer* getObject(const llvm::Module* M){
virtual llvm::MemoryBuffer* getObject(const llvm::Module* M)
#else
virtual std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* M) {
virtual std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* M)
#endif
assert(!loaded);
loaded = true;
g.engine->setObjectCache(NULL);
std::unique_ptr<MyObjectCache> del_at_end(this);
{
static StatCounter jit_objectcache_hits("num_jit_objectcache_hits");
static StatCounter jit_objectcache_misses("num_jit_objectcache_misses");
module_identifier = M->getModuleIdentifier();
// Generate a hash for the module
HashOStream hash_stream;
M->print(hash_stream, 0);
hash_before_codegen = hash_stream.getHash();
llvm::SmallString<128> cache_file = cache_dir;
llvm::sys::path::append(cache_file, hash_before_codegen);
if (!llvm::sys::fs::exists(cache_file.str())) {
#if 0
if (!USE_STRIPPED_STDLIB) {
stajt = STDLIB_CACHE_START;
size = (intptr_t)&STDLIB_CACHE_SIZE;
} else {
start = STRIPPED_STDLIB_CACHE_START;
size = (intptr_t)&STRIPPED_STDLIB_CACHE_SIZE;
}
#else
RELEASE_ASSERT(0, "");
char* start = NULL;
intptr_t size = 0;
// This code helps with identifying why we got a cache miss for a file.
// - clear the cache directory
// - run pyston
// - run pyston a second time
// - Now look for "*_second.ll" files in the cache directory and compare them to the "*_first.ll" IR dump
std::string llvm_ir;
llvm::raw_string_ostream sstr(llvm_ir);
M->print(sstr, 0);
sstr.flush();
std::string filename = cache_dir.str().str() + "/" + module_identifier + "_first.ll";
if (llvm::sys::fs::exists(filename))
filename = cache_dir.str().str() + "/" + module_identifier + "_second.ll";
FILE* f = fopen(filename.c_str(), "wt");
fwrite(llvm_ir.c_str(), 1, llvm_ir.size(), f);
fclose(f);
#endif
// Make sure the stdlib got linked in correctly; check the magic number at the beginning:
assert(start[0] == 0x7f);
assert(start[1] == 'E');
assert(start[2] == 'L');
assert(start[3] == 'F');
// This file isn't in our cache
jit_objectcache_misses.log();
return NULL;
}
assert(size > 0 && size < 1 << 30); // make sure the size is being loaded correctly
std::unique_ptr<llvm::MemoryBuffer> mem_buff = CompressedFile::getFile(cache_file);
if (!mem_buff) {
jit_objectcache_misses.log();
return NULL;
}
llvm::StringRef data(start, size);
return llvm::MemoryBuffer::getMemBufferCopy(data, "");
}
jit_objectcache_hits.log();
return mem_buff;
}
void cleanupCacheDirectory() {
// Find all files inside the cache directory, if the number of files is larger than
// MAX_OBJECT_CACHE_ENTRIES,
// sort them by last modification time and remove the oldest excessive ones.
typedef std::pair<std::string, llvm::sys::TimeValue> CacheFileEntry;
std::vector<CacheFileEntry> cache_files;
std::error_code ec;
for (llvm::sys::fs::directory_iterator file(cache_dir.str(), ec), end; !ec && file != end; file.increment(ec)) {
llvm::sys::fs::file_status status;
if (file->status(status))
continue; // ignore files where we can't retrieve the file status.
cache_files.emplace_back(std::make_pair(file->path(), status.getLastModificationTime()));
}
int num_expired = cache_files.size() - MAX_OBJECT_CACHE_ENTRIES;
if (num_expired <= 0)
return;
std::stable_sort(cache_files.begin(), cache_files.end(),
[](const CacheFileEntry& lhs, const CacheFileEntry& rhs) { return lhs.second < rhs.second; });
for (int i = 0; i < num_expired; ++i)
llvm::sys::fs::remove(cache_files[i].first);
}
};
static void handle_sigusr1(int signum) {
......@@ -223,7 +387,8 @@ void initCodegen() {
g.engine = eb.create(g.tm);
assert(g.engine && "engine creation failed?");
// g.engine->setObjectCache(new MyObjectCache());
if (ENABLE_JIT_OBJECT_CACHE)
g.engine->setObjectCache(new PystonObjectCache());
g.i1 = llvm::Type::getInt1Ty(g.context);
g.i8 = llvm::Type::getInt8Ty(g.context);
......
......@@ -16,6 +16,7 @@
#include <cstdio>
#include <iostream>
#include <set>
#include <sstream>
#include <stdint.h>
......@@ -541,7 +542,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction());
emitter->getBuilder()->SetInsertPoint(preentry_bb);
llvm::Value* call_count_ptr = embedConstantPtr(&cf->times_called, g.i64->getPointerTo());
llvm::Value* call_count_ptr = embedRelocatablePtr(&cf->times_called, g.i64->getPointerTo());
llvm::Value* cur_call_count = emitter->getBuilder()->CreateLoad(call_count_ptr);
llvm::Value* new_call_count
= emitter->getBuilder()->CreateAdd(cur_call_count, getConstantInt(1, g.i64));
......@@ -569,7 +570,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
emitter->getBuilder()->SetInsertPoint(reopt_bb);
// emitter->getBuilder()->CreateCall(g.funcs.my_assert, getConstantInt(0, g.i1));
llvm::Value* r = emitter->getBuilder()->CreateCall(g.funcs.reoptCompiledFunc,
embedConstantPtr(cf, g.i8->getPointerTo()));
embedRelocatablePtr(cf, g.i8->getPointerTo()));
assert(r);
assert(r->getType() == g.i8->getPointerTo());
......@@ -632,7 +633,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
std::unordered_set<InternedString> names;
std::set<InternedString> names;
for (const auto& s : source->phis->getAllRequiredFor(block)) {
names.insert(s);
if (source->phis->isPotentiallyUndefinedAfter(s, block->predecessors[0])) {
......@@ -739,9 +740,17 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// NB. This is where most `typical' phi nodes get added.
// And go through and add phi nodes:
ConcreteSymbolTable* pred_st = phi_ending_symbol_tables[pred];
for (auto it = pred_st->begin(); it != pred_st->end(); ++it) {
InternedString name = it->first;
ConcreteCompilerVariable* cv = it->second; // incoming CCV from predecessor block
// We have to sort the phi table by name in order to a get a deterministic ordering for the JIT object
// cache.
typedef std::pair<InternedString, ConcreteCompilerVariable*> Entry;
std::vector<Entry> sorted_pred_st(pred_st->begin(), pred_st->end());
std::sort(sorted_pred_st.begin(), sorted_pred_st.end(),
[](const Entry& lhs, const Entry& rhs) { return lhs.first < rhs.first; });
for (auto& entry : sorted_pred_st) {
InternedString name = entry.first;
ConcreteCompilerVariable* cv = entry.second; // incoming CCV from predecessor block
// printf("block %d: adding phi for %s from pred %d\n", block->idx, name.c_str(), pred->idx);
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(cv->getType()->llvmType(),
block->predecessors.size(), name.str());
......@@ -749,7 +758,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(cv->getType(), phi, true);
generator->giveLocalSymbol(name, var);
(*phis)[it->first] = std::make_pair(it->second->getType(), phi);
(*phis)[name] = std::make_pair(cv->getType(), phi);
}
}
}
......@@ -959,6 +968,9 @@ CompiledFunction* doCompile(SourceInfo* source, ParamNames* param_names, const O
source->cfg->print();
assert(g.cur_module == NULL);
clearRelocatableSymsMap();
std::string name = getUniqueFunctionName(nameprefix, effort, entry_descriptor);
g.cur_module = new llvm::Module(name, g.context);
#if LLVMREV < 217070 // not sure if this is the right rev
......@@ -1010,7 +1022,7 @@ CompiledFunction* doCompile(SourceInfo* source, ParamNames* param_names, const O
CompiledFunction* cf
= new CompiledFunction(NULL, spec, (effort == EffortLevel::INTERPRETED), NULL, NULL, effort, entry_descriptor);
= new CompiledFunction(NULL, spec, (effort == EffortLevel::INTERPRETED), NULL, effort, entry_descriptor);
llvm::FunctionType* ft = llvm::FunctionType::get(cf->getReturnType()->llvmType(), llvm_arg_types, false /*vararg*/);
......
......@@ -156,8 +156,6 @@ static void compileIR(CompiledFunction* cf, EffortLevel effort) {
assert(compiled);
ASSERT(compiled == cf->code, "cf->code should have gotten filled in");
cf->llvm_code = embedConstantPtr(compiled, cf->func->getType());
long us = _t.end();
static StatCounter us_jitting("us_compiling_jitting");
us_jitting.log(us);
......@@ -243,7 +241,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
CompiledFunction* cf = 0;
if (effort == EffortLevel::INTERPRETED) {
assert(!entry_descriptor);
cf = new CompiledFunction(0, spec, true, NULL, NULL, effort, 0);
cf = new CompiledFunction(0, spec, true, NULL, effort, 0);
} else {
cf = doCompile(source, &f->param_names, entry_descriptor, effort, spec, name);
compileIR(cf, effort);
......@@ -651,21 +649,6 @@ void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type,
#endif
FunctionSpecialization* spec = new FunctionSpecialization(processType(rtn_type), arg_types);
std::vector<llvm::Type*> llvm_arg_types;
int npassed_args = arg_types.size();
assert(npassed_args == cl_f->numReceivedArgs());
for (int i = 0; i < npassed_args; i++) {
if (i == 3) {
llvm_arg_types.push_back(g.i8_ptr->getPointerTo());
break;
}
llvm_arg_types.push_back(arg_types[i]->llvmType());
}
llvm::FunctionType* ft = llvm::FunctionType::get(g.llvm_value_type_ptr, llvm_arg_types, false);
cl_f->addVersion(new CompiledFunction(NULL, spec, false, f, embedConstantPtr(f, ft->getPointerTo()),
EffortLevel::MAXIMAL, NULL));
cl_f->addVersion(new CompiledFunction(NULL, spec, false, f, EffortLevel::MAXIMAL, NULL));
}
}
......@@ -159,11 +159,11 @@ llvm::Value* IRGenState::getFrameInfoVar() {
// The "normal" case
// frame_info.exc.type = NULL
builder.CreateStore(embedConstantPtr(NULL, g.llvm_value_type_ptr), getExcinfoGep(builder, al));
builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), getExcinfoGep(builder, al));
// frame_info.boxedLocals = NULL
llvm::Value* boxed_locals_gep = getBoxedLocalsGep(builder, al);
builder.CreateStore(embedConstantPtr(NULL, g.llvm_value_type_ptr), boxed_locals_gep);
builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), boxed_locals_gep);
if (getScopeInfo()->usesNameLookup()) {
// frame_info.boxedLocals = createDict()
......@@ -175,7 +175,7 @@ llvm::Value* IRGenState::getFrameInfoVar() {
// frame_info.frame_obj = NULL
static llvm::Type* llvm_frame_obj_type_ptr
= llvm::cast<llvm::StructType>(g.llvm_frame_info_type)->getElementType(2);
builder.CreateStore(embedConstantPtr(NULL, llvm_frame_obj_type_ptr), getFrameObjGep(builder, al));
builder.CreateStore(getNullPtr(llvm_frame_obj_type_ptr), getFrameObjGep(builder, al));
this->frame_info = al;
}
......@@ -229,14 +229,33 @@ private:
if (pp == NULL)
assert(ic_stackmap_args.size() == 0);
PatchpointInfo* info = PatchpointInfo::create(currentFunction(), pp, ic_stackmap_args.size());
int64_t pp_id = reinterpret_cast<int64_t>(info);
// Retrieve address of called function, currently handles the IR
// embedConstantPtr() and embedRelocatablePtr() create.
void* func_addr = nullptr;
if (llvm::isa<llvm::ConstantExpr>(func)) {
llvm::ConstantExpr* cast = llvm::cast<llvm::ConstantExpr>(func);
auto opcode = cast->getOpcode();
if (opcode == llvm::Instruction::IntToPtr) {
auto operand = cast->getOperand(0);
if (llvm::isa<llvm::ConstantInt>(operand))
func_addr = (void*)llvm::cast<llvm::ConstantInt>(operand)->getZExtValue();
}
}
assert(func_addr);
PatchpointInfo* info = PatchpointInfo::create(currentFunction(), pp, ic_stackmap_args.size(), func_addr);
int64_t pp_id = info->getId();
int pp_size = pp ? pp->totalSize() : CALL_ONLY_SIZE;
std::vector<llvm::Value*> pp_args;
pp_args.push_back(getConstantInt(pp_id, g.i64)); // pp_id: will fill this in later
pp_args.push_back(getConstantInt(pp_size, g.i32));
pp_args.push_back(func);
if (ENABLE_JIT_OBJECT_CACHE)
// add fixed dummy dest pointer, we will replace it with the correct address during stackmap processing
pp_args.push_back(embedConstantPtr((void*)-1L, g.i8_ptr));
else
pp_args.push_back(func);
pp_args.push_back(getConstantInt(args.size(), g.i32));
pp_args.insert(pp_args.end(), args.begin(), args.end());
......@@ -452,7 +471,7 @@ private:
curblock = deopt_bb;
emitter.getBuilder()->SetInsertPoint(curblock);
llvm::Value* v = emitter.createCall2(UnwindInfo(current_statement, NULL), g.funcs.deopt,
embedConstantPtr(node, g.i8->getPointerTo()), node_value);
embedRelocatablePtr(node, g.i8->getPointerTo()), node_value);
emitter.getBuilder()->CreateRet(v);
curblock = success_bb;
......@@ -509,13 +528,17 @@ private:
assert(personality_func);
llvm::LandingPadInst* landing_pad = emitter.getBuilder()->CreateLandingPad(
llvm::StructType::create(std::vector<llvm::Type*>{ g.i8_ptr, g.i64 }), personality_func, 1);
landing_pad->addClause(embedConstantPtr(NULL, g.i8_ptr));
landing_pad->addClause(getNullPtr(g.i8_ptr));
llvm::Value* cxaexc_pointer = emitter.getBuilder()->CreateExtractValue(landing_pad, { 0 });
if (irstate->getEffortLevel() != EffortLevel::INTERPRETED) {
llvm::Value* excinfo_pointer
= emitter.getBuilder()->CreateCall(g.funcs.__cxa_begin_catch, cxaexc_pointer);
llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch");
auto begin_catch_func = g.cur_module->getOrInsertFunction(std_module_catch->getName(),
std_module_catch->getFunctionType());
assert(begin_catch_func);
llvm::Value* excinfo_pointer = emitter.getBuilder()->CreateCall(begin_catch_func, cxaexc_pointer);
llvm::Value* excinfo_pointer_casted
= emitter.getBuilder()->CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo());
......@@ -567,7 +590,7 @@ private:
assert(name.size());
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.importFrom, converted_module->getValue(),
embedConstantPtr(&name, g.llvm_str_type_ptr));
embedRelocatablePtr(&name, g.llvm_str_type_ptr));
CompilerVariable* v = new ConcreteCompilerVariable(UNKNOWN, r, true);
......@@ -585,9 +608,8 @@ private:
ConcreteCompilerVariable* converted_module = module->makeConverted(emitter, module->getBoxType());
module->decvref(emitter);
llvm::Value* r = emitter.createCall2(
unw_info, g.funcs.importStar, converted_module->getValue(),
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr));
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.importStar, converted_module->getValue(),
embedParentModulePtr());
CompilerVariable* v = new ConcreteCompilerVariable(UNKNOWN, r, true);
converted_module->decvref(emitter);
......@@ -612,7 +634,7 @@ private:
llvm::Value* imported = emitter.createCall3(unw_info, g.funcs.import, getConstantInt(level, g.i32),
converted_froms->getValue(),
embedConstantPtr(&module_name, g.llvm_str_type_ptr));
embedRelocatablePtr(&module_name, g.llvm_str_type_ptr));
ConcreteCompilerVariable* v = new ConcreteCompilerVariable(UNKNOWN, imported, true);
converted_froms->decvref(emitter);
......@@ -671,7 +693,7 @@ private:
llvm::Value* exc_info = builder->CreateConstInBoundsGEP2_32(frame_info, 0, 0);
assert(exc_info->getType() == g.llvm_excinfo_type->getPointerTo());
llvm::Constant* v = embedConstantPtr(0, g.llvm_value_type_ptr);
llvm::Constant* v = getNullPtr(g.llvm_value_type_ptr);
builder->CreateStore(v, builder->CreateConstInBoundsGEP2_32(exc_info, 0, 0));
builder->CreateStore(v, builder->CreateConstInBoundsGEP2_32(exc_info, 0, 1));
builder->CreateStore(v, builder->CreateConstInBoundsGEP2_32(exc_info, 0, 2));
......@@ -889,10 +911,15 @@ private:
ConcreteCompilerVariable* getNone() {
ConcreteCompilerVariable* v = new ConcreteCompilerVariable(
typeFromClass(none_cls), embedConstantPtr(None, g.llvm_value_type_ptr), false);
typeFromClass(none_cls), embedRelocatablePtr(None, g.llvm_value_type_ptr), false);
return v;
}
llvm::Constant* embedParentModulePtr() {
// TODO: We could reuse the name to reduce the number of relocatable pointers.
return embedRelocatablePtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr);
}
ConcreteCompilerVariable* _getGlobal(AST_Name* node, UnwindInfo unw_info) {
if (node->id.str() == "None")
return getNone();
......@@ -902,17 +929,15 @@ private:
ICSetupInfo* pp = createGetGlobalIC(getOpInfoForNode(node, unw_info).getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr));
llvm_args.push_back(embedConstantPtr(&node->id.str(), g.llvm_str_type_ptr));
llvm_args.push_back(embedParentModulePtr());
llvm_args.push_back(embedRelocatablePtr(&node->id.str(), g.llvm_str_type_ptr));
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::getGlobal, llvm_args, unw_info);
llvm::Value* r = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
return new ConcreteCompilerVariable(UNKNOWN, r, true);
} else {
llvm::Value* r
= emitter.createCall2(unw_info, g.funcs.getGlobal,
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr),
embedConstantPtr(&node->id.str(), g.llvm_str_type_ptr));
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.getGlobal, embedParentModulePtr(),
embedRelocatablePtr(&node->id.str(), g.llvm_str_type_ptr));
return new ConcreteCompilerVariable(UNKNOWN, r, true);
}
}
......@@ -959,7 +984,7 @@ private:
= llvm::BasicBlock::Create(g.context, "deref_undefined", irstate->getLLVMFunction());
llvm::Value* check_val
= emitter.getBuilder()->CreateICmpEQ(lookupResult, embedConstantPtr(NULL, g.llvm_value_type_ptr));
= emitter.getBuilder()->CreateICmpEQ(lookupResult, getNullPtr(g.llvm_value_type_ptr));
llvm::BranchInst* non_null_check = emitter.getBuilder()->CreateCondBr(check_val, fail_bb, success_bb);
// Case that it is undefined: call the assert fail function.
......@@ -979,7 +1004,7 @@ private:
} else if (vst == ScopeInfo::VarScopeType::NAME) {
llvm::Value* boxedLocals = irstate->getBoxedLocalsVar();
llvm::Value* attr = getStringConstantPtr(node->id.str() + '\0');
llvm::Value* module = embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr);
llvm::Value* module = embedParentModulePtr();
llvm::Value* r = emitter.createCall3(unw_info, g.funcs.boxedLocalsGet, boxedLocals, attr, module);
return new ConcreteCompilerVariable(UNKNOWN, r, true);
} else {
......@@ -990,7 +1015,7 @@ private:
llvm::CallSite call = emitter.createCall(
unw_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(node->id.str() + '\0'),
embedConstantPtr(UnboundLocalError, g.llvm_class_type_ptr), getConstantInt(true, g.i1) });
embedRelocatablePtr(UnboundLocalError, g.llvm_class_type_ptr), getConstantInt(true, g.i1) });
call.setDoesNotReturn();
return undefVariable();
}
......@@ -1002,7 +1027,7 @@ private:
if (is_defined_var) {
emitter.createCall(unw_info, g.funcs.assertNameDefined,
{ i1FromBool(emitter, is_defined_var), getStringConstantPtr(node->id.str() + '\0'),
embedConstantPtr(UnboundLocalError, g.llvm_class_type_ptr),
embedRelocatablePtr(UnboundLocalError, g.llvm_class_type_ptr),
getConstantInt(true, g.i1) });
// At this point we know the name must be defined (otherwise the assert would have fired):
......@@ -1108,7 +1133,7 @@ private:
CompilerVariable* evalStr(AST_Str* node, UnwindInfo unw_info) {
if (node->str_type == AST_Str::STR) {
llvm::Value* rtn = embedConstantPtr(
llvm::Value* rtn = embedRelocatablePtr(
irstate->getSourceInfo()->parent_module->getStringConstant(node->str_data), g.llvm_value_type_ptr);
return new ConcreteCompilerVariable(STR, rtn, true);
......@@ -1239,7 +1264,7 @@ private:
attr_dict->decvref(emitter);
llvm::Value* classobj = emitter.createCall3(unw_info, g.funcs.createUserClass,
embedConstantPtr(&node->name.str(), g.llvm_str_type_ptr),
embedRelocatablePtr(&node->name.str(), g.llvm_str_type_ptr),
bases_tuple->getValue(), converted_attr_dict->getValue());
// Note: createuserClass is free to manufacture non-class objects
......@@ -1502,8 +1527,8 @@ private:
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
// TODO do something special here so that it knows to only emit a monomorphic inline cache?
ConcreteCompilerVariable* module = new ConcreteCompilerVariable(
MODULE, embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_value_type_ptr), false);
auto parent_module = llvm::ConstantExpr::getPointerCast(embedParentModulePtr(), g.llvm_value_type_ptr);
ConcreteCompilerVariable* module = new ConcreteCompilerVariable(MODULE, parent_module, false);
module->setattr(emitter, getEmptyOpInfo(unw_info), &name.str(), val);
module->decvref(emitter);
} else if (vst == ScopeInfo::VarScopeType::NAME) {
......@@ -1627,7 +1652,7 @@ private:
assert(num->n_int == 0);
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr));
llvm_args.push_back(embedParentModulePtr());
ConcreteCompilerVariable* converted_msg = NULL;
if (node->msg) {
......@@ -1636,7 +1661,7 @@ private:
msg->decvref(emitter);
llvm_args.push_back(converted_msg->getValue());
} else {
llvm_args.push_back(embedConstantPtr(NULL, g.llvm_value_type_ptr));
llvm_args.push_back(getNullPtr(g.llvm_value_type_ptr));
}
llvm::CallSite call = emitter.createCall(unw_info, g.funcs.assertFail, llvm_args);
call.setDoesNotReturn();
......@@ -1707,9 +1732,8 @@ private:
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(target->id);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
// Can't use delattr since the errors are different:
emitter.createCall2(unw_info, g.funcs.delGlobal,
embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr),
embedConstantPtr(&target->id.str(), g.llvm_str_type_ptr));
emitter.createCall2(unw_info, g.funcs.delGlobal, embedParentModulePtr(),
embedRelocatablePtr(&target->id.str(), g.llvm_str_type_ptr));
return;
}
......@@ -1725,10 +1749,11 @@ private:
assert(vst == ScopeInfo::VarScopeType::FAST);
if (symbol_table.count(target->id) == 0) {
llvm::CallSite call = emitter.createCall(
unw_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(target->id.str() + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr), getConstantInt(true /*local_error_msg*/, g.i1) });
llvm::CallSite call
= emitter.createCall(unw_info, g.funcs.assertNameDefined,
{ getConstantInt(0, g.i1), getStringConstantPtr(target->id.str() + '\0'),
embedRelocatablePtr(NameError, g.llvm_class_type_ptr),
getConstantInt(true /*local_error_msg*/, g.i1) });
call.setDoesNotReturn();
return;
}
......@@ -1739,7 +1764,7 @@ private:
if (is_defined_var) {
emitter.createCall(unw_info, g.funcs.assertNameDefined,
{ i1FromBool(emitter, is_defined_var), getStringConstantPtr(target->id.str() + '\0'),
embedConstantPtr(NameError, g.llvm_class_type_ptr),
embedRelocatablePtr(NameError, g.llvm_class_type_ptr),
getConstantInt(true /*local_error_msg*/, g.i1) });
_popFake(defined_name);
}
......@@ -1758,7 +1783,7 @@ private:
vglobals = globals->makeConverted(emitter, globals->getBoxType())->getValue();
globals->decvref(emitter);
} else {
vglobals = embedConstantPtr(NULL, g.llvm_value_type_ptr);
vglobals = getNullPtr(g.llvm_value_type_ptr);
}
llvm::Value* vlocals;
......@@ -1767,7 +1792,7 @@ private:
vlocals = locals->makeConverted(emitter, locals->getBoxType())->getValue();
locals->decvref(emitter);
} else {
vlocals = embedConstantPtr(NULL, g.llvm_value_type_ptr);
vlocals = getNullPtr(g.llvm_value_type_ptr);
}
emitter.createCall3(unw_info, g.funcs.exec, vbody, vglobals, vlocals);
......@@ -1855,7 +1880,7 @@ private:
return;
}
val = new ConcreteCompilerVariable(NONE, embedConstantPtr(None, g.llvm_value_type_ptr), false);
val = getNone();
} else {
val = evalExpr(node->value, unw_info);
}
......@@ -1950,7 +1975,7 @@ private:
OSREntryDescriptor* entry = OSREntryDescriptor::create(irstate->getCurFunction(), osr_key);
OSRExit* exit = new OSRExit(irstate->getCurFunction(), entry);
llvm::Value* partial_func = emitter.getBuilder()->CreateCall(g.funcs.compilePartialFunc,
embedConstantPtr(exit, g.i8->getPointerTo()));
embedRelocatablePtr(exit, g.i8->getPointerTo()));
std::vector<llvm::Value*> llvm_args;
std::vector<llvm::Type*> llvm_arg_types;
......@@ -2125,7 +2150,7 @@ private:
v->decvref(emitter);
args.push_back(converted->getValue());
} else {
args.push_back(embedConstantPtr(None, g.llvm_value_type_ptr));
args.push_back(embedRelocatablePtr(None, g.llvm_value_type_ptr));
}
}
......@@ -2332,7 +2357,17 @@ public:
stackmap_args.push_back(irstate->getFrameInfoVar());
assert(INT->llvmType() == g.i64);
stackmap_args.push_back(getConstantInt((uint64_t)current_stmt, g.i64));
if (ENABLE_JIT_OBJECT_CACHE) {
llvm::Value* v;
if (current_stmt)
v = emitter.getBuilder()->CreatePtrToInt(embedRelocatablePtr(current_stmt, g.i8_ptr), g.i64);
else
v = getConstantInt(0, g.i64);
stackmap_args.push_back(v);
} else {
stackmap_args.push_back(getConstantInt((uint64_t)current_stmt, g.i64));
}
pp->addFrameVar("!current_stmt", INT);
if (ENABLE_FRAME_INTROSPECTION) {
......@@ -2469,7 +2504,7 @@ public:
if (scope_info->createsClosure()) {
if (!passed_closure)
passed_closure = embedConstantPtr(nullptr, g.llvm_closure_type_ptr);
passed_closure = getNullPtr(g.llvm_closure_type_ptr);
llvm::Value* new_closure = emitter.getBuilder()->CreateCall2(
g.funcs.createClosure, passed_closure, getConstantInt(scope_info->getClosureSize(), g.i64));
......
......@@ -80,7 +80,7 @@ llvm::Constant* getStringConstantPtr(const std::string& str) {
strings[str] = buf;
c = buf;
}
return embedConstantPtr(c, g.i8->getPointerTo());
return embedRelocatablePtr(c, g.i8->getPointerTo());
}
// Returns a llvm::Constant char* to a global string constant
......@@ -92,6 +92,33 @@ llvm::Constant* getStringConstantPtr(const char* str) {
// to some associated compiler-level data structure.
// It's slightly easier to emit them as integers (there are primitive integer constants but not pointer constants),
// but doing it this way makes it clearer what's going on.
static llvm::StringMap<const void*> relocatable_syms;
void clearRelocatableSymsMap() {
relocatable_syms.clear();
}
const void* getValueOfRelocatableSym(const std::string& str) {
auto it = relocatable_syms.find(str);
if (it != relocatable_syms.end())
return it->second;
return NULL;
}
llvm::Constant* embedRelocatablePtr(const void* addr, llvm::Type* type) {
assert(addr);
if (!ENABLE_JIT_OBJECT_CACHE)
return embedConstantPtr(addr, type);
std::string name = (llvm::Twine("c") + llvm::Twine(relocatable_syms.size())).str();
relocatable_syms[name] = addr;
llvm::Type* var_type = type->getPointerElementType();
return new llvm::GlobalVariable(*g.cur_module, var_type, true, llvm::GlobalVariable::ExternalLinkage, 0, name);
}
llvm::Constant* embedConstantPtr(const void* addr, llvm::Type* type) {
assert(type);
llvm::Constant* int_val = llvm::ConstantInt::get(g.i64, reinterpret_cast<uintptr_t>(addr), false);
......@@ -99,6 +126,11 @@ llvm::Constant* embedConstantPtr(const void* addr, llvm::Type* type) {
return ptr_val;
}
llvm::Constant* getNullPtr(llvm::Type* t) {
assert(llvm::isa<llvm::PointerType>(t));
return llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(t));
}
llvm::Constant* getConstantInt(int64_t n, llvm::Type* t) {
return llvm::ConstantInt::get(t, n);
}
......
......@@ -27,10 +27,15 @@ namespace pyston {
llvm::Constant* getStringConstantPtr(const std::string& str);
llvm::Constant* getStringConstantPtr(const char* str);
llvm::Constant* embedRelocatablePtr(const void* addr, llvm::Type*);
llvm::Constant* embedConstantPtr(const void* addr, llvm::Type*);
llvm::Constant* getConstantInt(int64_t val);
llvm::Constant* getConstantDouble(double val);
llvm::Constant* getConstantInt(int64_t val, llvm::Type*);
llvm::Constant* getNullPtr(llvm::Type* t);
void clearRelocatableSymsMap();
const void* getValueOfRelocatableSym(const std::string& str);
void dumpPrettyIR(llvm::Function* f);
}
......
......@@ -20,6 +20,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include "codegen/irgen/util.h"
#include "core/common.h"
#include "core/stats.h"
#include "core/util.h"
......@@ -206,7 +207,11 @@ void PystonMemoryManager::invalidateInstructionCache() {
}
uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
uint64_t base = RTDyldMemoryManager::getSymbolAddress(name);
uint64_t base = (uint64_t)getValueOfRelocatableSym(name);
if (base)
return base;
base = RTDyldMemoryManager::getSymbolAddress(name);
if (base)
return base;
......@@ -214,7 +219,7 @@ uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
return getSymbolAddress(".L" + name);
}
printf("getSymbolAddress(%s); %lx\n", name.c_str(), base);
RELEASE_ASSERT(0, "Could not find sym: %s", name.c_str());
return 0;
}
......
......@@ -20,6 +20,7 @@
#include "asm_writing/icinfo.h"
#include "asm_writing/rewriter.h"
#include "codegen/compvars.h"
#include "codegen/irgen/util.h"
#include "codegen/stackmaps.h"
#include "core/common.h"
#include "core/options.h"
......@@ -41,7 +42,7 @@ int ICSetupInfo::totalSize() const {
return num_slots * slot_size + call_size;
}
static std::vector<PatchpointInfo*> new_patchpoints;
static std::vector<std::pair<PatchpointInfo*, void* /* addr of func to call */>> new_patchpoints;
ICSetupInfo* ICSetupInfo::initialize(bool has_return_value, int num_slots, int slot_size, ICType type,
TypeRecorder* type_recorder) {
......@@ -165,9 +166,12 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
const StackMap::StackSizeRecord& stack_size_record = stackmap->stack_size_records[0];
int stack_size = stack_size_record.stack_size;
PatchpointInfo* pp = reinterpret_cast<PatchpointInfo*>(r->id);
RELEASE_ASSERT(new_patchpoints.size() > r->id, "");
PatchpointInfo* pp = new_patchpoints[r->id].first;
assert(pp);
void* dst_func = new_patchpoints[r->id].second;
if (VERBOSITY() >= 2) {
printf("Processing pp %ld; [%d, %d)\n", reinterpret_cast<int64_t>(pp), r->offset,
r->offset + pp->patchpointSize());
......@@ -183,6 +187,9 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
uint8_t* start_addr = (uint8_t*)pp->parentFunction()->code + r->offset;
uint8_t* end_addr = start_addr + pp->patchpointSize();
if (ENABLE_JIT_OBJECT_CACHE)
setSlowpathFunc(start_addr, dst_func);
// TODO shouldn't have to do it this way
void* slowpath_func = extractSlowpathFunc(start_addr);
......@@ -270,7 +277,8 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
cf->ics.push_back(icinfo.release());
}
for (PatchpointInfo* pp : new_patchpoints) {
for (auto& e : new_patchpoints) {
PatchpointInfo* pp = e.first;
const ICSetupInfo* ic = pp->getICInfo();
if (ic)
delete ic;
......@@ -279,13 +287,14 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
new_patchpoints.clear();
}
PatchpointInfo* PatchpointInfo::create(CompiledFunction* parent_cf, const ICSetupInfo* icinfo,
int num_ic_stackmap_args) {
PatchpointInfo* PatchpointInfo::create(CompiledFunction* parent_cf, const ICSetupInfo* icinfo, int num_ic_stackmap_args,
void* func_addr) {
if (icinfo == NULL)
assert(num_ic_stackmap_args == 0);
auto* r = new PatchpointInfo(parent_cf, icinfo, num_ic_stackmap_args);
new_patchpoints.push_back(r);
r->id = new_patchpoints.size();
new_patchpoints.push_back(std::make_pair(r, func_addr));
return r;
}
......
......@@ -53,10 +53,12 @@ private:
int num_frame_stackmap_args;
std::vector<FrameVarInfo> frame_vars;
unsigned int id;
PatchpointInfo(CompiledFunction* parent_cf, const ICSetupInfo* icinfo, int num_ic_stackmap_args)
: parent_cf(parent_cf), icinfo(icinfo), num_ic_stackmap_args(num_ic_stackmap_args),
num_frame_stackmap_args(-1) {}
: parent_cf(parent_cf), icinfo(icinfo), num_ic_stackmap_args(num_ic_stackmap_args), num_frame_stackmap_args(-1),
id(0) {}
public:
const ICSetupInfo* getICInfo() { return icinfo; }
......@@ -84,11 +86,14 @@ public:
return num_frame_stackmap_args;
}
unsigned int getId() const { return id; }
void parseLocationMap(StackMap::Record* r, LocationMap* map);
int totalStackmapArgs() { return frameStackmapArgsStart() + numFrameStackmapArgs(); }
static PatchpointInfo* create(CompiledFunction* parent_cf, const ICSetupInfo* icinfo, int num_ic_stackmap_args);
static PatchpointInfo* create(CompiledFunction* parent_cf, const ICSetupInfo* icinfo, int num_ic_stackmap_args,
void* func_addr);
};
class ICSetupInfo {
......
......@@ -261,7 +261,6 @@ void initGlobalFuncs(GlobalState& g) {
g.funcs.reoptCompiledFunc = addFunc((void*)reoptCompiledFunc, g.i8_ptr, g.i8_ptr);
g.funcs.compilePartialFunc = addFunc((void*)compilePartialFunc, g.i8_ptr, g.i8_ptr);
GET(__cxa_begin_catch);
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
GET(raise0);
GET(raise3);
......
......@@ -49,7 +49,7 @@ struct GlobalFuncs {
llvm::Value* exec;
llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel;
llvm::Value* __cxa_begin_catch, *__cxa_end_catch;
llvm::Value* __cxa_end_catch;
llvm::Value* raise0, *raise3;
llvm::Value* deopt;
......
......@@ -32,11 +32,113 @@
namespace pyston {
// TODO shouldn't be recording this in a global variable
static StackMap* cur_map = NULL;
static uint64_t stackmap_address = 0;
StackMap* parseStackMap() {
StackMap* rtn = cur_map;
cur_map = NULL;
return rtn;
if (!stackmap_address)
return NULL;
if (VERBOSITY() >= 3)
printf("Found the stackmaps at stackmap_address 0x%lx\n", stackmap_address);
StackMap* cur_map = new StackMap();
union {
const int8_t* i8;
const int16_t* i16;
const int32_t* i32;
const int64_t* i64;
const uint8_t* u8;
const uint16_t* u16;
const uint32_t* u32;
const uint64_t* u64;
const StackMap::Record::Location* record_loc;
const StackMap::Record::LiveOut* record_liveout;
const StackMap::StackSizeRecord* size_record;
} ptr;
const int8_t* start_ptr = ptr.i8 = (const int8_t*)stackmap_address;
cur_map->header = *ptr.u32++; // header
#if LLVMREV < 200481
int nfunctions = 0;
#else
int nfunctions = *ptr.u32++;
#endif
int nconstants = *ptr.u32++;
int nrecords = *ptr.u32++;
if (VERBOSITY() >= 3)
printf("%d functions\n", nfunctions);
for (int i = 0; i < nfunctions; i++) {
const StackMap::StackSizeRecord& size_record = *ptr.size_record++;
cur_map->stack_size_records.push_back(size_record);
if (VERBOSITY() >= 3)
printf("function %d: offset 0x%lx, stack size 0x%lx\n", i, size_record.offset, size_record.stack_size);
}
if (VERBOSITY() >= 3)
printf("%d constants\n", nconstants);
for (int i = 0; i < nconstants; i++) {
uint64_t constant = *ptr.u64++;
if (VERBOSITY() >= 3)
printf("Constant %d: %ld\n", i, constant);
cur_map->constants.push_back(constant);
}
if (VERBOSITY() >= 3)
printf("%d records\n", nrecords);
for (int i = 0; i < nrecords; i++) {
StackMap::Record* record = new StackMap::Record();
cur_map->records.push_back(record);
record->id = *ptr.u64++;
record->offset = *ptr.u32++;
record->flags = *ptr.u16++; // reserved (record flags)
int numlocations = *ptr.u16++;
if (VERBOSITY() >= 3)
printf("Stackmap record %ld at 0x%x has %d locations:\n", record->id, record->offset, numlocations);
for (int j = 0; j < numlocations; j++) {
assert(sizeof(StackMap::Record::Location) == sizeof(*ptr.u64));
const StackMap::Record::Location& r = *ptr.record_loc++;
record->locations.push_back(r);
// from http://lxr.free-electrons.com/source/tools/perf/arch/x86/util/dwarf-regs.c
// TODO this probably can be fetched more portably from the llvm target files
const char* dwarf_reg_names[] = {
"%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
};
if (VERBOSITY() >= 3) {
if (r.type == 1) {
printf("Location %d: type %d (reg), reg %d (%s), offset %d\n", j, r.type, r.regnum,
dwarf_reg_names[r.regnum], r.offset);
} else {
printf("Location %d: type %d, reg %d, offset %d\n", j, r.type, r.regnum, r.offset);
}
}
}
ptr.u16++; // padding
int num_live_outs = *ptr.u16++;
for (int i = 0; i < num_live_outs; i++) {
const StackMap::Record::LiveOut& r = *ptr.record_liveout++;
record->live_outs.push_back(r);
if (VERBOSITY() >= 3) {
printf("Live out %d: reg #%d (?), size %d\n", i, r.regnum, r.size);
}
}
if (num_live_outs % 2 == 0)
ptr.u32++; // pad to 8-byte boundary
}
stackmap_address = 0;
return cur_map;
}
class StackmapJITEventListener : public llvm::JITEventListener {
......@@ -68,112 +170,9 @@ void StackmapJITEventListener::NotifyObjectEmitted(const llvm::object::ObjectFil
assert(!code);
if (name == ".llvm_stackmaps") {
uint64_t stackmap_address = L.getSectionLoadAddress(name);
assert(stackmap_address == 0);
stackmap_address = L.getSectionLoadAddress(name);
assert(stackmap_address > 0);
if (VERBOSITY() >= 3)
printf("Found the stackmaps at stackmap_address 0x%lx\n", stackmap_address);
assert(cur_map == NULL);
cur_map = new StackMap();
union {
const int8_t* i8;
const int16_t* i16;
const int32_t* i32;
const int64_t* i64;
const uint8_t* u8;
const uint16_t* u16;
const uint32_t* u32;
const uint64_t* u64;
const StackMap::Record::Location* record_loc;
const StackMap::Record::LiveOut* record_liveout;
const StackMap::StackSizeRecord* size_record;
} ptr;
const int8_t* start_ptr = ptr.i8 = (const int8_t*)stackmap_address;
cur_map->header = *ptr.u32++; // header
#if LLVMREV < 200481
int nfunctions = 0;
#else
int nfunctions = *ptr.u32++;
#endif
int nconstants = *ptr.u32++;
int nrecords = *ptr.u32++;
if (VERBOSITY() >= 3)
printf("%d functions\n", nfunctions);
for (int i = 0; i < nfunctions; i++) {
const StackMap::StackSizeRecord& size_record = *ptr.size_record++;
cur_map->stack_size_records.push_back(size_record);
if (VERBOSITY() >= 3)
printf("function %d: offset 0x%lx, stack size 0x%lx\n", i, size_record.offset,
size_record.stack_size);
}
if (VERBOSITY() >= 3)
printf("%d constants\n", nconstants);
for (int i = 0; i < nconstants; i++) {
uint64_t constant = *ptr.u64++;
if (VERBOSITY() >= 3)
printf("Constant %d: %ld\n", i, constant);
cur_map->constants.push_back(constant);
}
if (VERBOSITY() >= 3)
printf("%d records\n", nrecords);
for (int i = 0; i < nrecords; i++) {
StackMap::Record* record = new StackMap::Record();
cur_map->records.push_back(record);
record->id = *ptr.u64++;
record->offset = *ptr.u32++;
record->flags = *ptr.u16++; // reserved (record flags)
int numlocations = *ptr.u16++;
if (VERBOSITY() >= 3)
printf("Stackmap record %ld at 0x%x has %d locations:\n", record->id, record->offset, numlocations);
for (int j = 0; j < numlocations; j++) {
assert(sizeof(StackMap::Record::Location) == sizeof(*ptr.u64));
const StackMap::Record::Location& r = *ptr.record_loc++;
record->locations.push_back(r);
// from http://lxr.free-electrons.com/source/tools/perf/arch/x86/util/dwarf-regs.c
// TODO this probably can be fetched more portably from the llvm target files
const char* dwarf_reg_names[] = {
"%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
};
if (VERBOSITY() >= 3) {
if (r.type == 1) {
printf("Location %d: type %d (reg), reg %d (%s), offset %d\n", j, r.type, r.regnum,
dwarf_reg_names[r.regnum], r.offset);
} else {
printf("Location %d: type %d, reg %d, offset %d\n", j, r.type, r.regnum, r.offset);
}
}
}
ptr.u16++; // padding
int num_live_outs = *ptr.u16++;
for (int i = 0; i < num_live_outs; i++) {
const StackMap::Record::LiveOut& r = *ptr.record_liveout++;
record->live_outs.push_back(r);
if (VERBOSITY() >= 3) {
printf("Live out %d: reg #%d (?), size %d\n", i, r.regnum, r.size);
}
}
if (num_live_outs % 2 == 0)
ptr.u32++; // pad to 8-byte boundary
}
uint64_t stackmap_size = sec.getSize();
ASSERT(ptr.i8 - start_ptr == stackmap_size, "%ld %ld", ptr.i8 - start_ptr, stackmap_size);
}
}
}
......
......@@ -24,7 +24,7 @@
namespace pyston {
#ifndef NDEBUG
#ifdef DEBUG_LINE_NUMBERS
int AST::next_lineno = 100000;
AST::AST(AST_TYPE::AST_TYPE type) : type(type), lineno(++next_lineno) {
......@@ -1655,7 +1655,12 @@ bool PrintVisitor::visit_return(AST_Return* node) {
}
bool PrintVisitor::visit_set(AST_Set* node) {
assert(node->elts.size());
// An empty set literal is not writeable in Python (it's a dictionary),
// but we sometimes generate it (ex in set comprehension lowering).
// Just to make it clear when printing, print empty set literals as "SET{}".
if (!node->elts.size())
printf("SET");
printf("{");
bool first = true;
......
......@@ -154,16 +154,17 @@ public:
virtual void accept(ASTVisitor* v) = 0;
#ifndef NDEBUG
// #define DEBUG_LINE_NUMBERS 1
#ifdef DEBUG_LINE_NUMBERS
private:
// In debug mode, initialize lineno to something unique, so that if we see something ridiculous
// Initialize lineno to something unique, so that if we see something ridiculous
// appear in the traceback, we can isolate the allocation which created it.
static int next_lineno;
public:
AST(AST_TYPE::AST_TYPE type);
#else
AST(AST_TYPE::AST_TYPE type) : type(type) {}
AST(AST_TYPE::AST_TYPE type) : type(type), lineno(0), col_offset(0) {}
#endif
AST(AST_TYPE::AST_TYPE type, uint32_t lineno, uint32_t col_offset = 0)
: type(type), lineno(lineno), col_offset(col_offset) {}
......
......@@ -172,6 +172,8 @@ private:
std::vector<ContInfo> continuations;
std::vector<ExcBlockInfo> exc_handlers;
unsigned int next_var_index = 0;
friend CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body);
public:
......@@ -196,6 +198,11 @@ private:
return source->getInternedStrings().get(std::forward<T>(s));
}
InternedString createUniqueName(llvm::Twine prefix) {
std::string name = (prefix + llvm::Twine(next_var_index++)).str();
return source->getInternedStrings().get(std::move(name));
}
AST_Name* makeName(InternedString id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0) {
AST_Name* name = new AST_Name(id, ctx_type, lineno, col_offset);
return name;
......@@ -285,7 +292,7 @@ private:
if (exc_handlers.size() == 0)
return call;
auto name = nodeName(e);
auto name = nodeName();
pushAssign(name, call);
return makeLoad(name, e);
}
......@@ -300,7 +307,7 @@ private:
template <typename ResultASTType, typename CompType> AST_expr* remapComprehension(CompType* node) {
assert(curblock);
InternedString rtn_name = nodeName(node);
InternedString rtn_name = nodeName();
pushAssign(rtn_name, new ResultASTType());
std::vector<CFGBlock*> exit_blocks;
......@@ -317,7 +324,7 @@ private:
AST_expr* remapped_iter = remapExpr(c->iter);
AST_LangPrimitive* iter_call = new AST_LangPrimitive(AST_LangPrimitive::GET_ITER);
iter_call->args.push_back(remapped_iter);
InternedString iter_name = nodeName(node, "lc_iter", i);
InternedString iter_name = nodeName("lc_iter", i);
pushAssign(iter_name, iter_call);
AST_expr* next_attr = makeLoadAttribute(makeLoad(iter_name, node), internString("next"), true);
......@@ -350,7 +357,7 @@ private:
push_back(br);
curblock = body_block;
InternedString next_name(nodeName(next_attr));
InternedString next_name(nodeName());
pushAssign(next_name, makeCall(next_attr));
pushAssign(c->target, makeLoad(next_name, node));
......@@ -576,7 +583,7 @@ private:
push_back(assign);
for (int i = 0; i < elts->size(); i++) {
InternedString tmp_name = nodeName(target, "", i);
InternedString tmp_name = nodeName("", i);
new_target->elts.push_back(makeName(tmp_name, AST_TYPE::Store, target->lineno));
pushAssign((*elts)[i], makeLoad(tmp_name, target));
......@@ -600,36 +607,12 @@ private:
return stmt;
}
InternedString nodeName(AST* node) {
char buf[40];
int bytes = snprintf(buf, 40, "#%p", node);
assert(bytes < 40); // double-check
// Uncomment this line to check to make sure we never reuse the same nodeName() accidentally.
// This check is potentially too expensive for even debug mode, since it never frees any memory.
// #define VALIDATE_FAKE_NAMES
#ifdef VALIDATE_FAKE_NAMES
std::string r(buf);
static std::unordered_set<std::string> made;
assert(made.count(r) == 0);
made.insert(r);
return internString(std::move(r));
#else
return internString(buf);
#endif
}
InternedString nodeName() { return createUniqueName("#"); }
InternedString nodeName(AST* node, const std::string& suffix) {
char buf[50];
int bytes = snprintf(buf, 50, "#%p_%s", node, suffix.c_str());
assert(bytes < 50); // double-check
return internString(std::string(buf));
}
InternedString nodeName(llvm::StringRef suffix) { return createUniqueName(llvm::Twine("#") + suffix + "_"); }
InternedString nodeName(AST* node, const std::string& suffix, int idx) {
char buf[50];
int bytes = snprintf(buf, 50, "#%p_%s_%d", node, suffix.c_str(), idx);
assert(bytes < 50); // double-check
return internString(std::string(buf));
InternedString nodeName(llvm::StringRef suffix, int idx) {
return createUniqueName(llvm::Twine("#") + suffix + "_" + llvm::Twine(idx) + "_");
}
AST_expr* remapAttribute(AST_Attribute* node) {
......@@ -698,7 +681,7 @@ private:
AST_expr* remapBoolOp(AST_BoolOp* node) {
assert(curblock);
InternedString name = nodeName(node);
InternedString name = nodeName();
CFGBlock* starting_block = curblock;
CFGBlock* exit_block = cfg->addDeferredBlock();
......@@ -802,7 +785,7 @@ private:
}
return rtn;
} else {
InternedString name = nodeName(node);
InternedString name = nodeName();
CFGBlock* exit_block = cfg->addDeferredBlock();
AST_expr* left = remapExpr(node->left);
......@@ -882,7 +865,8 @@ private:
AST_FunctionDef* func = new AST_FunctionDef();
func->lineno = node->lineno;
func->col_offset = node->col_offset;
InternedString func_name = nodeName(func);
// TODO this should be set off the type of the comprehension (ie <setcomp> or <dictcomp> or <genexpr>)
InternedString func_name = internString("<comprehension>");
func->name = func_name;
func->args = new AST_arguments();
func->args->vararg = internString("");
......@@ -928,20 +912,22 @@ private:
// argument to the function we create. See
// https://www.python.org/dev/peps/pep-0289/#early-binding-versus-late-binding
AST_expr* first = remapExpr(node->generators[0]->iter);
InternedString first_generator_name = nodeName(node->generators[0]);
InternedString arg_name = internString("#arg");
AST_MakeFunction* func = makeFunctionForScope(node);
func->function_def->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
func->function_def->args->args.push_back(makeName(arg_name, AST_TYPE::Param, node->lineno));
emitComprehensionLoops(&func->function_def->body, node->generators,
makeName(first_generator_name, AST_TYPE::Load, node->lineno),
makeName(arg_name, AST_TYPE::Load, node->lineno),
[this, node](std::vector<AST_stmt*>* insert_point) {
auto y = new AST_Yield();
y->value = node->elt;
insert_point->push_back(makeExpr(y));
});
pushAssign(func->function_def->name, func);
return makeCall(makeLoad(func->function_def->name, node), first);
InternedString func_var_name = nodeName();
pushAssign(func_var_name, func);
return makeCall(makeLoad(func_var_name, node), first);
}
void emitComprehensionYield(AST_DictComp* node, InternedString dict_name, std::vector<AST_stmt*>* insert_point) {
......@@ -960,12 +946,12 @@ private:
template <typename ResultType, typename CompType> AST_expr* remapScopedComprehension(CompType* node) {
// See comment in remapGeneratorExp re early vs. late binding.
AST_expr* first = remapExpr(node->generators[0]->iter);
InternedString first_generator_name = nodeName(node->generators[0]);
InternedString arg_name = internString("#arg");
AST_MakeFunction* func = makeFunctionForScope(node);
func->function_def->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
func->function_def->args->args.push_back(makeName(arg_name, AST_TYPE::Param, node->lineno));
InternedString rtn_name = nodeName(node);
InternedString rtn_name = internString("#comp_rtn");
auto asgn = new AST_Assign();
asgn->targets.push_back(makeName(rtn_name, AST_TYPE::Store, node->lineno));
asgn->value = new ResultType();
......@@ -973,22 +959,23 @@ private:
auto lambda =
[&](std::vector<AST_stmt*>* insert_point) { emitComprehensionYield(node, rtn_name, insert_point); };
AST_Name* first_name = makeName(first_generator_name, AST_TYPE::Load, node->lineno);
AST_Name* first_name = makeName(internString("#arg"), AST_TYPE::Load, node->lineno);
emitComprehensionLoops(&func->function_def->body, node->generators, first_name, lambda);
auto rtn = new AST_Return();
rtn->value = makeName(rtn_name, AST_TYPE::Load, node->lineno);
func->function_def->body.push_back(rtn);
pushAssign(func->function_def->name, func);
InternedString func_var_name = nodeName();
pushAssign(func_var_name, func);
return makeCall(makeName(func->function_def->name, AST_TYPE::Load, node->lineno), first);
return makeCall(makeName(func_var_name, AST_TYPE::Load, node->lineno), first);
}
AST_expr* remapIfExp(AST_IfExp* node) {
assert(curblock);
InternedString rtn_name = nodeName(node);
InternedString rtn_name = nodeName();
CFGBlock* iftrue = cfg->addDeferredBlock();
CFGBlock* iffalse = cfg->addDeferredBlock();
CFGBlock* exit_block = cfg->addDeferredBlock();
......@@ -1141,7 +1128,7 @@ private:
rtn->col_offset = node->col_offset;
rtn->value = remapExpr(node->value);
InternedString node_name(nodeName(rtn));
InternedString node_name(nodeName());
pushAssign(node_name, rtn);
push_back(makeExpr(new AST_LangPrimitive(AST_LangPrimitive::UNCACHE_EXC_INFO)));
......@@ -1247,7 +1234,7 @@ private:
// this is the part that actually generates temporaries & assigns to them.
if (wrap_with_assign && (rtn->type != AST_TYPE::Name || ast_cast<AST_Name>(rtn)->id.str()[0] != '#')) {
InternedString name = nodeName(node);
InternedString name = nodeName();
pushAssign(name, rtn);
return makeLoad(name, node);
} else {
......@@ -1430,7 +1417,7 @@ public:
scoping_analysis->registerScopeReplacement(node, def);
auto tmp = nodeName(node);
auto tmp = nodeName();
pushAssign(tmp, new AST_MakeClass(def));
// is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno));
......@@ -1450,7 +1437,7 @@ public:
scoping_analysis->registerScopeReplacement(node, def);
auto tmp = nodeName(node);
auto tmp = nodeName();
pushAssign(tmp, new AST_MakeFunction(def));
// is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno));
......@@ -1493,7 +1480,7 @@ public:
import->args.push_back(new AST_LangPrimitive(AST_LangPrimitive::NONE));
import->args.push_back(new AST_Str(a->name.str()));
InternedString tmpname = nodeName(a);
InternedString tmpname = nodeName();
pushAssign(tmpname, import);
if (a->asname.str().size() == 0) {
......@@ -1549,7 +1536,7 @@ public:
}
import->args.push_back(new AST_Str(node->module.str()));
InternedString tmp_module_name = nodeName(node);
InternedString tmp_module_name = nodeName();
pushAssign(tmp_module_name, import);
for (AST_alias* a : node->names) {
......@@ -1573,7 +1560,7 @@ public:
import_from->args.push_back(makeLoad(tmp_module_name, node));
import_from->args.push_back(new AST_Str(a->name.str()));
InternedString tmp_import_name = nodeName(a);
InternedString tmp_import_name = nodeName();
pushAssign(tmp_import_name, import_from);
pushAssign(a->asname.str().size() ? a->asname : a->name, makeLoad(tmp_import_name, node));
}
......@@ -1665,7 +1652,7 @@ public:
case AST_TYPE::Name: {
AST_Name* n = ast_cast<AST_Name>(node->target);
assert(n->ctx_type == AST_TYPE::Store);
InternedString n_name(nodeName(n));
InternedString n_name(nodeName());
pushAssign(n_name, makeLoad(n->id, node));
remapped_target = n;
remapped_lhs = makeLoad(n_name, node);
......@@ -1726,7 +1713,7 @@ public:
binop->col_offset = node->col_offset;
binop->lineno = node->lineno;
InternedString node_name(nodeName(node));
InternedString node_name(nodeName());
pushAssign(node_name, binop);
pushAssign(remapped_target, makeLoad(node_name, node));
return true;
......@@ -2005,9 +1992,7 @@ public:
AST_LangPrimitive* iter_call = new AST_LangPrimitive(AST_LangPrimitive::GET_ITER);
iter_call->args.push_back(remapped_iter);
char itername_buf[80];
snprintf(itername_buf, 80, "#iter_%p", node);
InternedString itername = internString(itername_buf);
InternedString itername = createUniqueName("#iter_");
pushAssign(itername, iter_call);
AST_expr* next_attr = makeLoadAttribute(makeLoad(itername, node), internString("next"), true);
......@@ -2042,7 +2027,7 @@ public:
pushLoopContinuation(test_block, end_block);
curblock = loop_block;
InternedString next_name(nodeName(next_attr));
InternedString next_name(nodeName());
pushAssign(next_name, makeCall(next_attr));
pushAssign(node->target, makeLoad(next_name, node));
......@@ -2138,9 +2123,9 @@ public:
assert(node->handlers.size() > 0);
CFGBlock* exc_handler_block = cfg->addDeferredBlock();
InternedString exc_type_name = nodeName(node, "type");
InternedString exc_value_name = nodeName(node, "value");
InternedString exc_traceback_name = nodeName(node, "traceback");
InternedString exc_type_name = nodeName("type");
InternedString exc_value_name = nodeName("value");
InternedString exc_traceback_name = nodeName("traceback");
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name });
for (AST_stmt* subnode : node->body) {
......@@ -2253,10 +2238,10 @@ public:
assert(curblock);
CFGBlock* exc_handler_block = cfg->addDeferredBlock();
InternedString exc_type_name = nodeName(node, "type");
InternedString exc_value_name = nodeName(node, "value");
InternedString exc_traceback_name = nodeName(node, "traceback");
InternedString exc_why_name = nodeName(node, "why");
InternedString exc_type_name = nodeName("type");
InternedString exc_value_name = nodeName("value");
InternedString exc_traceback_name = nodeName("traceback");
InternedString exc_why_name = nodeName("why");
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name });
CFGBlock* finally_block = cfg->addDeferredBlock();
......@@ -2345,12 +2330,12 @@ public:
// just translate this into AST_Try{Except,Finally} nodes and recursively visit those. (If there are other
// reasons, I've forgotten them.)
assert(curblock);
InternedString ctxmgrname = nodeName(node, "ctxmgr");
InternedString exitname = nodeName(node, "exit");
InternedString whyname = nodeName(node, "why");
InternedString exc_type_name = nodeName(node, "exc_type");
InternedString exc_value_name = nodeName(node, "exc_value");
InternedString exc_traceback_name = nodeName(node, "exc_traceback");
InternedString ctxmgrname = nodeName("ctxmgr");
InternedString exitname = nodeName("exit");
InternedString whyname = nodeName("why");
InternedString exc_type_name = nodeName("exc_type");
InternedString exc_value_name = nodeName("exc_value");
InternedString exc_traceback_name = nodeName("exc_traceback");
InternedString nonename = internString("None");
CFGBlock* exit_block = cfg->addDeferredBlock();
exit_block->info = "with_exit";
......@@ -2405,7 +2390,7 @@ public:
curblock = exc_block;
// call the context-manager's exit method
InternedString suppressname = nodeName(node, "suppress");
InternedString suppressname = nodeName("suppress");
pushAssign(suppressname, makeCall(makeLoad(exitname, node), makeLoad(exc_type_name, node),
makeLoad(exc_value_name, node), makeLoad(exc_traceback_name, node)));
......
......@@ -50,6 +50,8 @@ int OSR_THRESHOLD_T2 = 10000;
int REOPT_THRESHOLD_T2 = 10000;
int SPECULATION_THRESHOLD = 100;
int MAX_OBJECT_CACHE_ENTRIES = 500;
static bool _GLOBAL_ENABLE = 1;
bool ENABLE_ICS = 1 && _GLOBAL_ENABLE;
bool ENABLE_ICGENERICS = 1 && ENABLE_ICS;
......@@ -71,6 +73,7 @@ bool ENABLE_REOPT = 1 && _GLOBAL_ENABLE;
bool ENABLE_PYSTON_PASSES = 1 && _GLOBAL_ENABLE;
bool ENABLE_TYPE_FEEDBACK = 1 && _GLOBAL_ENABLE;
bool ENABLE_RUNTIME_ICS = 1 && _GLOBAL_ENABLE;
bool ENABLE_JIT_OBJECT_CACHE = 1 && _GLOBAL_ENABLE;
bool ENABLE_FRAME_INTROSPECTION = 1;
bool BOOLS_AS_I64 = ENABLE_FRAME_INTROSPECTION;
......
......@@ -35,6 +35,7 @@ extern int OSR_THRESHOLD_INTERPRETER, REOPT_THRESHOLD_INTERPRETER;
extern int OSR_THRESHOLD_BASELINE, REOPT_THRESHOLD_BASELINE;
extern int OSR_THRESHOLD_T2, REOPT_THRESHOLD_T2;
extern int SPECULATION_THRESHOLD;
extern int MAX_OBJECT_CACHE_ENTRIES;
extern bool SHOW_DISASM, FORCE_INTERPRETER, FORCE_OPTIMIZE, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB,
CONTINUE_AFTER_FATAL, ENABLE_INTERPRETER, ENABLE_PYPA_PARSER, USE_REGALLOC_BASIC, PAUSE_AT_ABORT;
......@@ -42,7 +43,7 @@ extern bool SHOW_DISASM, FORCE_INTERPRETER, FORCE_OPTIMIZE, PROFILE, DUMPJIT, TR
extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS,
ENABLE_SPECULATION, ENABLE_OSR, ENABLE_LLVMOPTS, ENABLE_INLINING, ENABLE_REOPT, ENABLE_PYSTON_PASSES,
ENABLE_TYPE_FEEDBACK, ENABLE_FRAME_INTROSPECTION, ENABLE_RUNTIME_ICS;
ENABLE_TYPE_FEEDBACK, ENABLE_FRAME_INTROSPECTION, ENABLE_RUNTIME_ICS, ENABLE_JIT_OBJECT_CACHE;
// Due to a temporary LLVM limitation, represent bools as i64's instead of i1's.
extern bool BOOLS_AS_I64;
......
......@@ -73,10 +73,11 @@ public:
return this->_str == rhs._str;
}
// This function is slow because it does a string < string comparison and should be avoided.
bool operator<(InternedString rhs) const {
assert(this->_str);
assert(this->pool == rhs.pool);
return this->_str < rhs._str;
return *this->_str < *rhs._str;
}
friend class InternedStringPool;
......
......@@ -188,7 +188,6 @@ public:
uintptr_t code_start;
};
int code_size;
llvm::Value* llvm_code; // the llvm callable.
EffortLevel effort;
......@@ -200,10 +199,9 @@ public:
std::vector<ICInfo*> ics;
CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, bool is_interpreted, void* code,
llvm::Value* llvm_code, EffortLevel effort, const OSREntryDescriptor* entry_descriptor)
EffortLevel effort, const OSREntryDescriptor* entry_descriptor)
: clfunc(NULL), func(func), spec(spec), entry_descriptor(entry_descriptor), is_interpreted(is_interpreted),
code(code), llvm_code(llvm_code), effort(effort), times_called(0), times_speculation_failed(0),
location_map(nullptr) {
code(code), effort(effort), times_called(0), times_speculation_failed(0), location_map(nullptr) {
assert((spec != NULL) + (entry_descriptor != NULL) == 1);
}
......@@ -307,7 +305,6 @@ public:
assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
assert(compiled->clfunc == NULL);
assert(compiled->is_interpreted == (compiled->code == NULL));
assert(compiled->is_interpreted == (compiled->llvm_code == NULL));
compiled->clfunc = this;
if (compiled->entry_descriptor == NULL) {
......
......@@ -9,7 +9,7 @@ add_custom_target(unittests)
macro(add_unittest unittest)
add_executable(${unittest}_unittest EXCLUDE_FROM_ALL ${unittest}.cpp $<TARGET_OBJECTS:PYSTON_OBJECTS> $<TARGET_OBJECTS:FROM_CPYTHON>)
target_link_libraries(${unittest}_unittest stdlib sqlite3 gmp ssl crypto readline pypa double-conversion unwind gtest gtest_main ${LLVM_LIBS} ${LIBLZMA_LIBRARIES})
target_link_libraries(${unittest}_unittest stdlib sqlite3 gmp ssl crypto readline pypa liblz4 double-conversion unwind gtest gtest_main ${LLVM_LIBS} ${LIBLZMA_LIBRARIES})
add_dependencies(unittests ${unittest}_unittest)
endmacro()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment