diff options
| author | kuqin12 <42554914+kuqin12@users.noreply.github.com> | 2026-08-21 15:12:39 -0700 |
|---|---|---|
| committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2026-09-06 23:50:31 +0000 |
| commit | 4d55998e8b0a251b5124bdf240ddaad9921e6257 (patch) | |
| tree | e1cf9fbef71af7f2863b6b358477d1db55df4897 | |
| parent | 263242774a10ce0db7162663eb801aa5a0b3cc7d (diff) | |
| download | edk2-4d55998e8b0a251b5124bdf240ddaad9921e6257.tar.gz edk2-4d55998e8b0a251b5124bdf240ddaad9921e6257.zip | |
BaseTools: Optimize parsing of byte-array PCD values
This change adds a fast path for simple VOID* hexadecimal byte arrays,
avoiding the generic expression tokenizer's repeated processing of large
PCD values. Regression tests for both paths. It does not change the
existing parser for structured and symbolic expressions.
This reduces parsing time for a 28 KiB generated PCD from roughly 2
seconds to 50 milliseconds.
Signed-off-by: Kun Qin <kun.qin@microsoft.com>
| -rw-r--r-- | BaseTools/Source/Python/Common/Expression.py | 31 | ||||
| -rw-r--r-- | BaseTools/Tests/TestRegularExpression.py | 46 |
2 files changed, 71 insertions, 6 deletions
diff --git a/BaseTools/Source/Python/Common/Expression.py b/BaseTools/Source/Python/Common/Expression.py index f8b34aaa58..b18161a5ef 100644 --- a/BaseTools/Source/Python/Common/Expression.py +++ b/BaseTools/Source/Python/Common/Expression.py @@ -45,6 +45,33 @@ _ReLabel = re.compile(r'LABEL\((\w+)\)') _ReOffset = re.compile(r'OFFSET_OF\((\w+)\)')
PcdPattern = re.compile(r'^[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
+## Fast path for the simple byte array
+#
+# Simple byte array refers to PCD data in the form of {0x01, 0x02, 0x03}
+# - Enclosed in {}.
+# - One or more comma-separated elements.
+# - Each element is 0x followed by one or two hexadecimal digits.
+# - Only spaces or tabs surround elements.
+# - Used only for top-level VOID* real-value evaluation.
+#
+# Return the stripped original value when valid. Otherwise None.
+def _NormalizeSimpleByteArray(Value):
+ Value = Value.strip()
+ if not Value.startswith('{') or not Value.endswith('}'):
+ return None
+
+ Items = Value[1:-1].split(',')
+ if not Items:
+ return None
+
+ for Item in Items:
+ Item = Item.strip(' \t')
+ if len(Item) < 3 or len(Item) > 4 or Item[:2].lower() != '0x' or \
+ not all(Char in string.hexdigits for Char in Item[2:]):
+ return None
+
+ return Value
+
## SplitString
# Split string to list according double quote
# For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn']
@@ -821,6 +848,10 @@ class ValueExpressionEx(ValueExpression): def __call__(self, RealValue=False, Depth=0):
PcdValue = self.PcdValue
+ if RealValue and Depth == 0 and self.PcdType == TAB_VOID and "{CODE(" not in PcdValue:
+ SimpleByteArray = _NormalizeSimpleByteArray(PcdValue)
+ if SimpleByteArray is not None:
+ return SimpleByteArray
if "{CODE(" not in PcdValue:
try:
PcdValue = ValueExpression.__call__(self, RealValue, Depth)
diff --git a/BaseTools/Tests/TestRegularExpression.py b/BaseTools/Tests/TestRegularExpression.py index 3e6c5f4463..fbb359e144 100644 --- a/BaseTools/Tests/TestRegularExpression.py +++ b/BaseTools/Tests/TestRegularExpression.py @@ -5,19 +5,53 @@ # SPDX-License-Identifier: BSD-2-Clause-Patent
import unittest
+from Common.DataType import TAB_VOID
+from Common.Expression import ValueExpression, ValueExpressionEx
from Common.Misc import RemoveCComments
from Workspace.BuildClassObject import ArrayIndex
+
+class TestValueExpressionEx(unittest.TestCase):
+ def test_simple_byte_array_matches_legacy_parser(self):
+ value = ' { 0X01, 0xaB, 0xff } '
+
+ self.assertEqual(ValueExpression(value)(True), ValueExpressionEx(value, TAB_VOID)(True))
+
+ def test_nested_simple_byte_array_uses_legacy_parser(self):
+ value = '{ 0X01, 0x02 }'
+
+ self.assertEqual(ValueExpression(value)(True, 1), ValueExpressionEx(value, TAB_VOID)(True, 1))
+
+ def test_multiline_byte_array_uses_legacy_parser(self):
+ value = '{0x01,\n0x02}'
+
+ self.assertEqual('{0x01, 0x02}', ValueExpressionEx(value, TAB_VOID)(True))
+
+ def test_non_dsc_whitespace_uses_legacy_parser(self):
+ value = '{0x01,\v0x02}'
+
+ self.assertEqual('{0x01, 0x02}', ValueExpressionEx(value, TAB_VOID)(True))
+
+ def test_structured_array_uses_legacy_parser(self):
+ value = '{UINT16(0x1234), 0x56}'
+
+ self.assertEqual('{0x34, 0x12, 0x56}', ValueExpressionEx(value, TAB_VOID)(True))
+
+ def test_trailing_comma_uses_legacy_parser(self):
+ value = '{0x01,}'
+
+ self.assertEqual('{0x01}', ValueExpressionEx(value, TAB_VOID)(True))
+
class TestRe(unittest.TestCase):
def test_ccomments(self):
TestStr1 = """ {0x01,0x02} """
- self.assertEquals(TestStr1, RemoveCComments(TestStr1))
+ self.assertEqual(TestStr1, RemoveCComments(TestStr1))
TestStr2 = """ L'TestString' """
- self.assertEquals(TestStr2, RemoveCComments(TestStr2))
+ self.assertEqual(TestStr2, RemoveCComments(TestStr2))
TestStr3 = """ 'TestString' """
- self.assertEquals(TestStr3, RemoveCComments(TestStr3))
+ self.assertEqual(TestStr3, RemoveCComments(TestStr3))
TestStr4 = """
{CODE({
@@ -35,14 +69,14 @@ class TestRe(unittest.TestCase): {0x01, {0x02, 0x03, 0x04 }},
})
}"""
- self.assertEquals(Expect_TestStr4, RemoveCComments(TestStr4).strip())
+ self.assertEqual(Expect_TestStr4, RemoveCComments(TestStr4).strip())
def Test_ArrayIndex(self):
TestStr1 = """[1]"""
- self.assertEquals(['[1]'], ArrayIndex.findall(TestStr1))
+ self.assertEqual(['[1]'], ArrayIndex.findall(TestStr1))
TestStr2 = """[1][2][0x1][0x01][]"""
- self.assertEquals(['[1]','[2]','[0x1]','[0x01]','[]'], ArrayIndex.findall(TestStr2))
+ self.assertEqual(['[1]','[2]','[0x1]','[0x01]','[]'], ArrayIndex.findall(TestStr2))
if __name__ == '__main__':
unittest.main()
|
