Skip to content

Commit

Permalink
Merge pull request #13 from tonlabs/0.24
Browse files Browse the repository at this point in the history
0.24
  • Loading branch information
BorisI authored May 7, 2020
2 parents 382bada + 08a9c18 commit 577aa60
Show file tree
Hide file tree
Showing 11 changed files with 849 additions and 56 deletions.
724 changes: 724 additions & 0 deletions API.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion compiler/libsolidity/analysis/GlobalContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ int magicVariableToID(std::string const& _name)
else if (_name == "log2") return -12;
else if (_name == "log3") return -13;
else if (_name == "log4") return -14;
else if (_name == "logtvm") return -101;
else if (_name == "logtvm") return -102;
else if (_name == "msg") return -15;
else if (_name == "mulmod") return -16;
else if (_name == "now") return -17;
Expand Down
36 changes: 36 additions & 0 deletions compiler/libsolidity/analysis/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2401,6 +2401,42 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
}
break;
}
case FunctionType::Kind::TVMMaxMin:
{
if (arguments.size() < 2) {
m_errorReporter.fatalTypeError(
_functionCall.location(),
"This function takes at least two arguments."
);
}

auto isIntegerType = [this](ASTPointer<Expression const> arg){
Type::Category cat = arg->annotation().type->category();
if (cat != Type::Category::Integer && cat != Type::Category::RationalNumber) {
m_errorReporter.fatalTypeError(
arg->location(),
"Argument must have integer type."
);
}
};
for (std::size_t i = 0; i < arguments.size(); ++i) {
isIntegerType(arguments.at(i));
}

TypePointer result = arguments.at(0)->annotation().type;
for (std::size_t i = 1; i < arguments.size(); ++i) {
TypePointer rightType = arguments.at(i)->annotation().type;
result = Type::commonType(result, rightType);
if (result == nullptr) {
m_errorReporter.fatalTypeError(
arguments.at(i)->location(),
"All arguments must have signed or unsigned at the same time."
);
}
}
returnTypes.push_back(result);
break;
}
case FunctionType::Kind::ABIEncode:
case FunctionType::Kind::ABIEncodePacked:
case FunctionType::Kind::ABIEncodeWithSelector:
Expand Down
2 changes: 2 additions & 0 deletions compiler/libsolidity/analysis/ViewPureChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::TVM, "setExtDestAddr"},
{MagicType::Kind::TVM, "transfer"},
{MagicType::Kind::TVM, "transLT"},
{MagicType::Kind::TVM, "min"},
{MagicType::Kind::TVM, "max"},
{MagicType::Kind::MetaType, "creationCode"},
{MagicType::Kind::MetaType, "runtimeCode"},
{MagicType::Kind::MetaType, "name"},
Expand Down
18 changes: 17 additions & 1 deletion compiler/libsolidity/ast/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2827,6 +2827,7 @@ string FunctionType::richIdentifier() const
case Kind::TVMBuilderMethods: id += "tvmbuildermethods"; break;
case Kind::TVMLoadRef: id += "tvmloadref"; break;
case Kind::TVMFunctionId: id += "tvmfunctionid"; break;
case Kind::TVMMaxMin: id += "tvmmaxmin"; break;
case Kind::AddressMakeAddrStd: id += "addressmakeaddrstd"; break;
case Kind::LogTVM: id += "logtvm"; break;
case Kind::MappingGetMinKey: id += "mapgetmin"; break;
Expand Down Expand Up @@ -3966,7 +3967,22 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
FunctionType::Kind::TVMFunctionId,
true, StateMutability::Pure
));

members.emplace_back("max", TypeProvider::function(
TypePointers{},
TypePointers{},
strings{},
strings{},
FunctionType::Kind::TVMMaxMin,
true, StateMutability::Pure
));
members.emplace_back("min", TypeProvider::function(
TypePointers{},
TypePointers{},
strings{},
strings{},
FunctionType::Kind::TVMMaxMin,
true, StateMutability::Pure
));
return members;
}
case Kind::Transaction:
Expand Down
1 change: 1 addition & 0 deletions compiler/libsolidity/ast/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,7 @@ class FunctionType: public Type
TVMDeploy, ///< functions to deploy contract from contract
TVMDestAddr, ///< tvm.setExtDestAddr()
TVMFunctionId, ///< tvm.functionId(function_name)
TVMMaxMin, ///< tvm.min(a, b, ...) or tvm.max(a, b, ...)
TVMHash, ///< tvm.hash()
TVMPubkey, ///< tvm.pubkey()
TVMResetStorage, ///< tvm.resetStorage()
Expand Down
1 change: 1 addition & 0 deletions compiler/libsolidity/codegen/ExpressionCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::TVMDeploy:
case FunctionType::Kind::TVMDestAddr:
case FunctionType::Kind::TVMFunctionId:
case FunctionType::Kind::TVMMaxMin:
case FunctionType::Kind::TVMHash:
case FunctionType::Kind::TVMLoadRef:
case FunctionType::Kind::TVMPubkey:
Expand Down
40 changes: 34 additions & 6 deletions compiler/libsolidity/codegen/TVMABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ DecodePosition::Algo DecodePositionAbiV1::updateStateAndGetLoadAlgo(Type const *
maxRestSliceBits = TvmConst::CellBitLength - size.minBits;
minUsedRef = size.minRefs;
maxUsedRef = size.maxRefs;
return NeedLoadNextCell;
return LoadNextCell;
}

return JustLoad;
Expand All @@ -387,6 +387,7 @@ void Position::loadRef() {
usedRefs = 1;
++idCell;
}
solAssert(usedRefs <= 3, "");
}

int Position::cellNumber() const {
Expand Down Expand Up @@ -427,12 +428,18 @@ DecodePosition::Algo DecodePositionAbiV2::updateStateAndGetLoadAlgo(Type const *
solAssert(0 <= size.minBits && size.minBits <= size.maxBits, "");

if (curTypeIndex == lastRefType) {
minPos.loadRef();
maxPos.loadRef();
if (curTypeIndex + 1 == static_cast<int>(types.size())) {
minPos.loadRef();
maxPos.loadRef();
return JustLoad;
} else {
return CheckBits;
int prevMinCellNumber = minPos.cellNumber();
minPos.loadRef();
maxPos.loadRef();
if (prevMinCellNumber == minPos.cellNumber() && minPos.cellNumber() == maxPos.cellNumber()) {
return JustLoad;
}
return CheckBitsAndRefs;
}
}

Expand All @@ -448,7 +455,7 @@ DecodePosition::Algo DecodePositionAbiV2::updateStateAndGetLoadAlgo(Type const *
if (prevMinCellNumber == prevMaxCellNumber &&
prevMinCellNumber + 1 == minPos.cellNumber() &&
minPos.cellNumber() == maxPos.cellNumber()) {
return NeedLoadNextCell;
return LoadNextCell;
}

if ((type->category() == Type::Category::Array && to<ArrayType>(type)->isByteArray()) ||
Expand Down Expand Up @@ -543,12 +550,29 @@ IF
)");
}

void DecodeFunctionParams::checkBitsAndRefsAndLoadNextSlice() {
// check that bits==0 and ref==1
pusher->pushLines(R"(DUP
SBITREFS
EQINT 1
SWAP
EQINT 0
AND
PUSHCONT {
LDREF
ENDS
CTOS
}
IF
)");
}

void DecodeFunctionParams::loadNextSliceIfNeed(const DecodePosition::Algo algo, VariableDeclaration const *variable,
bool isRefType) {
switch (algo) {
case DecodePosition::JustLoad:
break;
case DecodePosition::NeedLoadNextCell:
case DecodePosition::LoadNextCell:
loadNextSlice();
break;
case DecodePosition::CheckBits:
Expand All @@ -557,6 +581,9 @@ void DecodeFunctionParams::loadNextSliceIfNeed(const DecodePosition::Algo algo,
case DecodePosition::CheckRefs:
checkRefsAndLoadNextSlice();
break;
case DecodePosition::CheckBitsAndRefs:
checkBitsAndRefsAndLoadNextSlice();
break;
case DecodePosition::Unknown:
if (isRefType) {
cast_error(*variable, "Too much refs types");
Expand Down Expand Up @@ -663,6 +690,7 @@ bool EncodePosition::updateState(int i) {

restSliceBits -= size.maxBits;
restFef -= size.maxRefs;
solAssert(restFef >= 0, "");

if (i == lastRefType && restFef == 0 && i + 1 == static_cast<int>(types.size())) {
return false;
Expand Down
3 changes: 2 additions & 1 deletion compiler/libsolidity/codegen/TVMABI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class TVMABI {

class DecodePosition : private boost::noncopyable {
public:
enum Algo {JustLoad, NeedLoadNextCell, CheckBits, CheckRefs, Unknown};
enum Algo {JustLoad, LoadNextCell, CheckBits, CheckRefs, CheckBitsAndRefs, Unknown};
virtual ~DecodePosition() = default;
virtual Algo updateStateAndGetLoadAlgo(Type const* type) = 0;
};
Expand Down Expand Up @@ -99,6 +99,7 @@ class DecodeFunctionParams : private boost::noncopyable {
void loadNextSlice();
void checkBitsAndLoadNextSlice();
void checkRefsAndLoadNextSlice();
void checkBitsAndRefsAndLoadNextSlice();
void loadNextSliceIfNeed(const DecodePosition::Algo algo, VariableDeclaration const* variable, bool isRefType);
void loadq(const DecodePosition::Algo algo, const std::string& opcodeq, const std::string& opcode);
void decodeParameter(VariableDeclaration const* variable, DecodePosition* position);
Expand Down
74 changes: 29 additions & 45 deletions compiler/libsolidity/codegen/TVMFunctionCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,22 +880,14 @@ bool FunctionCallCompiler::checkForTvmFunction(const MemberAccess &_node, Type::
if (_node.memberName() == "cdatasize") { // tvm.cdatasize(cell, uint)
pushArgs();
m_pusher.push(-2 + 3, "CDATASIZE");
return true;
}
if (_node.memberName() == "pubkey") { // tvm.pubkey
} else if (_node.memberName() == "pubkey") { // tvm.pubkey
m_pusher.push(+1, "GETGLOB 2");
return true;
}
if (_node.memberName() == "accept") { // tvm.accept
} else if (_node.memberName() == "accept") { // tvm.accept
m_pusher.push(0, "ACCEPT");
return true;
}
if (_node.memberName() == "hash") { // tvm.hash
} else if (_node.memberName() == "hash") { // tvm.hash
pushArgs();
m_pusher.push(0, "HASHCU");
return true;
}
if (_node.memberName() == "checkSign") { // tvm.checkSign
} else if (_node.memberName() == "checkSign") { // tvm.checkSign
acceptExpr(arguments[0].get());
m_pusher.push(+1, "NEWC");
acceptExpr(arguments[1].get());
Expand All @@ -905,60 +897,52 @@ bool FunctionCallCompiler::checkForTvmFunction(const MemberAccess &_node, Type::
m_pusher.push(0, "ENDC CTOS");
acceptExpr(arguments[3].get());
m_pusher.push(-3+1, "CHKSIGNU");
return true;
}
if (_node.memberName() == "setcode") { // tvm.setcode
} else if (_node.memberName() == "setcode") { // tvm.setcode
pushArgs();
m_pusher.push(-1, "SETCODE");
return true;
}
if (_node.memberName() == "setCurrentCode") { // tvm.setCurrentCode
} else if (_node.memberName() == "setCurrentCode") { // tvm.setCurrentCode
pushArgs();
m_pusher.push(-1+1, "CTOS");
m_pusher.push(0, "BLESS");
m_pusher.push(-1, "POP c3");
return true;
}
if (_node.memberName() == "commit") { // tvm.commit
} else if (_node.memberName() == "commit") { // tvm.commit
m_pusher.pushPrivateFunctionOrMacroCall(0, "c7_to_c4");
m_pusher.push(0, "COMMIT");
return true;
}
if (_node.memberName() == "log") { // tvm.log
} else if (_node.memberName() == "log") { // tvm.log
auto logstr = arguments[0].get();
if (auto literal = to<Literal>(logstr)) {
if (literal->value().length() > 15)
cast_error(_node, "logtvm param should no more than 15 chars");
if (TVMContractCompiler::g_without_logstr) {
return true;
cast_error(_node, "Parameter string should have length no more than 15 chars");
if (!TVMContractCompiler::g_without_logstr) {
m_pusher.push(0, "PRINTSTR " + literal->value());
}
m_pusher.push(0, "PRINTSTR " + literal->value());
} else {
cast_error(_node, "tvm.log() param should be literal");
cast_error(_node, "Parameter should be a literal");
}
return true;
}
if (_node.memberName() == "transLT") { // tvm.transLT
} else if (_node.memberName() == "transLT") { // tvm.transLT
pushArgs();
m_pusher.push(+1, "LTIME");
return true;
}
if (_node.memberName() == "resetStorage") { //tvm.resetStorage
} else if (_node.memberName() == "resetStorage") { //tvm.resetStorage
m_pusher.resetAllStateVars();
return true;
}
if (_node.memberName() == "setExtDestAddr") {
} else if (_node.memberName() == "setExtDestAddr") {
pushArgs();
m_pusher.push(-1, "SETGLOB " + toString(TvmConst::C7::ExtDestAddrIndex));
return true;
}
if (_node.memberName() == "functionId") { // tvm.functionId
} else if (_node.memberName() == "functionId") { // tvm.functionId
auto callDef = getCallableDeclaration(arguments.at(0).get());
EncodeFunctionParams encoder(&m_pusher);
m_pusher.push(+1, "PUSHINT " + to_string(encoder.calculateFunctionID(callDef) & 0x7fffffff));
return true;
} else if (_node.memberName() == "max") {
pushArgs();
for (int i = 0; i + 1 < static_cast<int>(arguments.size()); ++i)
m_pusher.push(-2 + 1, "MAX");
} else if (_node.memberName() == "min") {
pushArgs();
for (int i = 0; i + 1 < static_cast<int>(arguments.size()); ++i)
m_pusher.push(-2 + 1, "MIN");
} else {
return false;
}
return false;
return true;
}

bool FunctionCallCompiler::checkForMemberAccessTypeType(MemberAccess const &_node, Type::Category category) {
Expand Down Expand Up @@ -1215,13 +1199,13 @@ bool FunctionCallCompiler::checkForIdentifier(FunctionCall const &_functionCall)
auto logstr = arguments[0].get();
if (auto literal = to<Literal>(logstr)) {
if (literal->value().length() > 15)
cast_error(_functionCall, "logtvm param should no more than 15 chars");
cast_error(_functionCall, "Parameter string should have length no more than 15 chars");
if (TVMContractCompiler::g_without_logstr) {
return true;
}
m_pusher.push(0, "PRINTSTR " + literal->value());
} else {
cast_error(_functionCall, "logtvm param should be literal");
cast_error(_functionCall, "Parameter should be a literal");
}
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/solc/CommandLineInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ Allowed options)",
(g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.")
// (g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.")
(g_argTvm.c_str(), "Produce TVM assembly (deprecated).")
(g_argTvmWithoutLogStr.c_str(), "Intrisic logstr(...) won't produce log strings")
(g_argTvmWithoutLogStr.c_str(), "Ignore tvm.log(string) and logtvm(string)")
(g_argTvmABI.c_str(), "Produce JSON ABI for contract (deprecated).")
(g_argTvmDumpStorage.c_str(), "Dump state vars")
(g_argTvmPeephole.c_str(), "Run peephole optimization pass")
Expand Down Expand Up @@ -888,7 +888,7 @@ Allowed options)",
serr() << " solc contract.sol" << endl;
serr() << "This command compiles the contract and generates contract.code and contract.abi.json files." << endl;
}

if (m_args.count(g_argTvmPeephole)) {
for (int i = 1; i < _argc; i++) {
string s = _argv[i];
Expand Down

0 comments on commit 577aa60

Please sign in to comment.