From 5b819fa23edf7d8d7778d63532753f455dc3d644 Mon Sep 17 00:00:00 2001 From: John Richards Date: Tue, 20 Oct 2020 01:46:38 -0400 Subject: [PATCH 1/2] Adds support for BUILD_CONST_KEY_MAP opcode Tests have also been added. Fixes #172 --- ASTNode.h | 16 ++++++++++ ASTree.cpp | 35 +++++++++++++++++++++ tests/compiled/build_const_key_map.2.7.pyc | Bin 0 -> 766 bytes tests/compiled/build_const_key_map.3.8.pyc | Bin 0 -> 617 bytes tests/input/build_const_key_map.py | 22 +++++++++++++ tests/tokenized/build_const_key_map.txt | 3 ++ 6 files changed, 76 insertions(+) create mode 100644 tests/compiled/build_const_key_map.2.7.pyc create mode 100644 tests/compiled/build_const_key_map.3.8.pyc create mode 100644 tests/input/build_const_key_map.py create mode 100644 tests/tokenized/build_const_key_map.txt diff --git a/ASTNode.h b/ASTNode.h index 728c7f4..7ef68ba 100644 --- a/ASTNode.h +++ b/ASTNode.h @@ -15,6 +15,7 @@ public: NODE_TUPLE, NODE_LIST, NODE_MAP, NODE_SUBSCR, NODE_PRINT, NODE_CONVERT, NODE_KEYWORD, NODE_RAISE, NODE_EXEC, NODE_BLOCK, NODE_COMPREHENSION, NODE_LOADBUILDCLASS, NODE_AWAITABLE, + NODE_CONST_MAP, // Empty node types NODE_LOCALS, @@ -358,6 +359,21 @@ private: map_t m_values; }; +class ASTConstMap : public ASTNode { +public: + typedef std::vector> values_t; + + ASTConstMap(PycRef keys, const values_t& values) + : ASTNode(NODE_CONST_MAP), m_keys(std::move(keys)), m_values(std::move(values)) { } + + const PycRef& keys() const { return m_keys; } + const values_t& values() const { return m_values; } + +private: + PycRef m_keys; + values_t m_values; +}; + class ASTSubscr : public ASTNode { public: diff --git a/ASTree.cpp b/ASTree.cpp index 277c1b9..e7b43cf 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -282,6 +282,23 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(new ASTMap()); } break; + case Pyc::BUILD_CONST_KEY_MAP_A: + // Top of stack will be a tuple of keys. + // Values will start at TOS - 1. + { + PycRef keys = stack.top(); + stack.pop(); + + ASTConstMap::values_t values; + for (int i = 0; i < operand; ++i) { + PycRef value = stack.top(); + stack.pop(); + values.push_back(value); + } + + stack.push(new ASTConstMap(keys, values)); + } + break; case Pyc::STORE_MAP: { PycRef key = stack.top(); @@ -2428,6 +2445,24 @@ void print_src(PycRef node, PycModule* mod) fputs(" }", pyc_output); } break; + case ASTNode::NODE_CONST_MAP: + { + PycRef const_map = node.cast(); + PycTuple::value_t keys = const_map->keys().cast()->object().cast()->values(); + ASTConstMap::values_t values = const_map->values(); + + auto map = new ASTMap; + for (auto key : keys) { + // Values are pushed onto the stack in reverse order. + PycRef value = values.back(); + values.pop_back(); + + map->add(new ASTObject(key), value); + } + + print_src(map, mod); + } + break; case ASTNode::NODE_NAME: fprintf(pyc_output, "%s", node.cast()->name()->value()); break; diff --git a/tests/compiled/build_const_key_map.2.7.pyc b/tests/compiled/build_const_key_map.2.7.pyc new file mode 100644 index 0000000000000000000000000000000000000000..335c15d205b4e59e94fb49ee70035f412a1875db GIT binary patch literal 766 zcmbtS+iuf95M3vbme9}(i09?am24*=jgu;Xh$2L#UWC-3N`0|5yAx-zy=%N1()1&E z;!pVj#!i6>c*BgeC%XTG5kgj^FM9}(dYQ6r(K6Y&7u zLn0dJwusn9hvg=^$3*OGz!thEMC_6faK;`9ubuxHBK9{!YD656OZO=XlTImd4-L!n zRB~peR_#wlE89SD%sJ%N>|+?;%G{#@<|(t_(OF@3e-Zq5ifbWNY@Q(o#^Y@C`E@5a z_CQs^@ILvBsd&j^FxyC0+UJZfz_c)#l#xHdpBFkcO+*ra+-Ir$0=7)Cq=1(i%?nKL zYrgSUtCc_3MdmMy6iPuL%+99Cg0lW}okO*%4+V=eW(usG>sy(otlbYf)V-2Q=#`-t zQ`+qWoe@PKJQ~rP@aT|^aev?nW~b7&`@KQX3#og0GCe=@Xetw+?|~=!kWLnb&Y(T$ z2A!bS9}I)zA-!aCR>-@qYFQr*6#h6yRh6KL)`^5_k2o&PGG!^RunV`mM-^!U*aOUe zlA;AL0fmXW|At?>NG89Hd5-C9DN_+uBccS>QO5EhU)%C9US(P=Q+QKdin6WY)SazA J-e&D@><1x`wbcLs literal 0 HcmV?d00001 diff --git a/tests/compiled/build_const_key_map.3.8.pyc b/tests/compiled/build_const_key_map.3.8.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88487685184ed85f4242b54ccc246583fdfb2276 GIT binary patch literal 617 zcmZvZ-EPw`6vxwagtn~OK!|H|*GNg)()D91AgT&6X&*vbr%AbqT>CUNb?o4zboE2< z1iSzbz{_yU6;CjUE1V3_RBy5?xUX-ldcbOnsP>P&ZKC6$fVGZW6e?z zQCM)CgNNoyKZVRAc>M8ICph*%l+H-kg!Bm}OVEuKKIEZYSuBkpY9FF}fKXxoBd#gKLq{Q`o>{n<8!(0Q+LoM7F!%0T&(*aSjn zD&>lSJ|I$LITkr0CAe^_p>yYkPyWWDC146Fi@N_|FTPsJHZv;a*R%PWaT=AG(F(Rv ig3}<~ey_buBwcfOU5qnp8QHV#%FeoV_IF6dzWoi|q_36$ literal 0 HcmV?d00001 diff --git a/tests/input/build_const_key_map.py b/tests/input/build_const_key_map.py new file mode 100644 index 0000000..da0e09a --- /dev/null +++ b/tests/input/build_const_key_map.py @@ -0,0 +1,22 @@ +cookie = 1 +constant_headers_1 = { + 'Accept': 'application/json', + 'Accept-Encoding': 'gzip, deflate, br', + 'Accept-Language': 'es,ca;q=0.9,en;q=0.8', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Pragma': 'no-cache', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', + 'Cookie': cookie } + +constant_headers_2 = { + 'Accept': 'application/json', + 'Accept-Encoding': 'gzip, deflate, br', + 'Accept-Language': 'es,ca;q=0.9,en;q=0.8', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Pragma': 'no-cache', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', + 'Cookie': 'constant cookie' } diff --git a/tests/tokenized/build_const_key_map.txt b/tests/tokenized/build_const_key_map.txt new file mode 100644 index 0000000..72c9aec --- /dev/null +++ b/tests/tokenized/build_const_key_map.txt @@ -0,0 +1,3 @@ +cookie = 1 +constant_headers_1 = { 'Accept' : 'application/json' , 'Accept-Encoding' : 'gzip, deflate, br' , 'Accept-Language' : 'es,ca;q=0.9,en;q=0.8' , 'Cache-Control' : 'no-cache' , 'Connection' : 'keep-alive' , 'Content-Type' : 'application/x-www-form-urlencoded' , 'Pragma' : 'no-cache' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' , 'Cookie' : cookie } +constant_headers_2 = { 'Accept' : 'application/json' , 'Accept-Encoding' : 'gzip, deflate, br' , 'Accept-Language' : 'es,ca;q=0.9,en;q=0.8' , 'Cache-Control' : 'no-cache' , 'Connection' : 'keep-alive' , 'Content-Type' : 'application/x-www-form-urlencoded' , 'Pragma' : 'no-cache' , 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' , 'Cookie' : 'constant cookie' } From 50dea399752e01aeb07186b388b44eb427d6b864 Mon Sep 17 00:00:00 2001 From: John Richards Date: Tue, 20 Oct 2020 18:07:39 -0400 Subject: [PATCH 2/2] Addresses a couple performance related comments --- ASTree.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ASTree.cpp b/ASTree.cpp index e7b43cf..d727f3e 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -290,6 +290,7 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.pop(); ASTConstMap::values_t values; + values.reserve(operand); for (int i = 0; i < operand; ++i) { PycRef value = stack.top(); stack.pop(); @@ -2452,7 +2453,7 @@ void print_src(PycRef node, PycModule* mod) ASTConstMap::values_t values = const_map->values(); auto map = new ASTMap; - for (auto key : keys) { + for (const auto& key : keys) { // Values are pushed onto the stack in reverse order. PycRef value = values.back(); values.pop_back();