1 | /* |
2 | * Copyright (C) 2015 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "DFABytecodeCompiler.h" |
28 | |
29 | #if ENABLE(CONTENT_EXTENSIONS) |
30 | |
31 | #include "ContentExtensionRule.h" |
32 | #include "DFA.h" |
33 | #include "DFANode.h" |
34 | |
35 | namespace WebCore { |
36 | |
37 | namespace ContentExtensions { |
38 | |
39 | template <typename IntType> |
40 | inline void append(Vector<DFABytecode>& bytecode, IntType value) |
41 | { |
42 | bytecode.grow(bytecode.size() + sizeof(IntType)); |
43 | *reinterpret_cast<IntType*>(&bytecode[bytecode.size() - sizeof(IntType)]) = value; |
44 | } |
45 | |
46 | inline void appendZeroes(Vector<DFABytecode>& bytecode, DFABytecodeJumpSize jumpSize) |
47 | { |
48 | switch (jumpSize) { |
49 | case DFABytecodeJumpSize::Int8: |
50 | append<int8_t>(bytecode, 0); // This value will be set when linking. |
51 | break; |
52 | case DFABytecodeJumpSize::Int16: |
53 | append<int16_t>(bytecode, 0); // This value will be set when linking. |
54 | break; |
55 | case DFABytecodeJumpSize::Int24: |
56 | append<uint16_t>(bytecode, 0); |
57 | append<int8_t>(bytecode, 0); // These values will be set when linking. |
58 | break; |
59 | case DFABytecodeJumpSize::Int32: |
60 | append<int32_t>(bytecode, 0); // This value will be set when linking. |
61 | break; |
62 | } |
63 | } |
64 | |
65 | template <typename IntType> |
66 | inline void setBits(Vector<DFABytecode>& bytecode, uint32_t index, IntType value) |
67 | { |
68 | RELEASE_ASSERT(index + sizeof(IntType) <= bytecode.size()); |
69 | ASSERT_WITH_MESSAGE(!*reinterpret_cast<IntType*>(&bytecode[index]), "Right now we should only be using setBits to overwrite values that were zero as a placeholder." ); |
70 | *reinterpret_cast<IntType*>(&bytecode[index]) = value; |
71 | } |
72 | |
73 | static unsigned appendActionBytecodeSize(uint64_t action) |
74 | { |
75 | if (action & ActionFlagMask) |
76 | return sizeof(DFABytecodeInstruction) + sizeof(uint16_t) + sizeof(uint32_t); |
77 | return sizeof(DFABytecodeInstruction) + sizeof(uint32_t); |
78 | } |
79 | |
80 | void DFABytecodeCompiler::emitAppendAction(uint64_t action) |
81 | { |
82 | // High bits are used to store flags. See compileRuleList. |
83 | if (action & ActionFlagMask) { |
84 | if (action & IfConditionFlag) |
85 | append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::TestFlagsAndAppendActionWithIfCondition); |
86 | else |
87 | append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::TestFlagsAndAppendAction); |
88 | append<uint16_t>(m_bytecode, static_cast<uint16_t>(action >> 32)); |
89 | append<uint32_t>(m_bytecode, static_cast<uint32_t>(action)); |
90 | } else { |
91 | if (action & IfConditionFlag) |
92 | append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::AppendActionWithIfCondition); |
93 | else |
94 | append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::AppendAction); |
95 | append<uint32_t>(m_bytecode, static_cast<uint32_t>(action)); |
96 | } |
97 | } |
98 | |
99 | int32_t DFABytecodeCompiler::longestPossibleJump(uint32_t instructionLocation, uint32_t sourceNodeIndex, uint32_t destinationNodeIndex) |
100 | { |
101 | if (m_nodeStartOffsets[destinationNodeIndex] == std::numeric_limits<uint32_t>::max()) { |
102 | // Jumping to a node that hasn't been compiled yet, we don't know exactly how far forward we will need to jump, |
103 | // so make sure we have enough room for the worst possible case, the farthest possible jump |
104 | // which would be the distance if there were no compacted branches between this jump and its destination. |
105 | ASSERT(instructionLocation >= m_nodeStartOffsets[sourceNodeIndex]); |
106 | ASSERT(m_maxNodeStartOffsets[destinationNodeIndex] > m_maxNodeStartOffsets[sourceNodeIndex]); |
107 | ASSERT(m_nodeStartOffsets[sourceNodeIndex] != std::numeric_limits<uint32_t>::max()); |
108 | return m_maxNodeStartOffsets[destinationNodeIndex] - m_maxNodeStartOffsets[sourceNodeIndex] - (m_nodeStartOffsets[sourceNodeIndex] - instructionLocation); |
109 | } |
110 | |
111 | // Jumping to an already compiled node, we already know exactly where we will need to jump to. |
112 | ASSERT(m_nodeStartOffsets[destinationNodeIndex] <= instructionLocation); |
113 | return m_nodeStartOffsets[destinationNodeIndex] - instructionLocation; |
114 | } |
115 | |
116 | void DFABytecodeCompiler::emitJump(uint32_t sourceNodeIndex, uint32_t destinationNodeIndex) |
117 | { |
118 | uint32_t instructionLocation = m_bytecode.size(); |
119 | uint32_t jumpLocation = instructionLocation + sizeof(uint8_t); |
120 | int32_t longestPossibleJumpDistance = longestPossibleJump(instructionLocation, sourceNodeIndex, destinationNodeIndex); |
121 | DFABytecodeJumpSize jumpSize = smallestPossibleJumpSize(longestPossibleJumpDistance); |
122 | append<uint8_t>(m_bytecode, static_cast<uint8_t>(DFABytecodeInstruction::Jump) | jumpSize); |
123 | |
124 | m_linkRecords.append(LinkRecord({jumpSize, longestPossibleJumpDistance, instructionLocation, jumpLocation, destinationNodeIndex})); |
125 | appendZeroes(m_bytecode, jumpSize); |
126 | } |
127 | |
128 | void DFABytecodeCompiler::emitCheckValue(uint8_t value, uint32_t sourceNodeIndex, uint32_t destinationNodeIndex, bool caseSensitive) |
129 | { |
130 | uint32_t instructionLocation = m_bytecode.size(); |
131 | uint32_t jumpLocation = instructionLocation + 2 * sizeof(uint8_t); |
132 | int32_t longestPossibleJumpDistance = longestPossibleJump(instructionLocation, sourceNodeIndex, destinationNodeIndex); |
133 | DFABytecodeJumpSize jumpSize = smallestPossibleJumpSize(longestPossibleJumpDistance); |
134 | DFABytecodeInstruction instruction = caseSensitive ? DFABytecodeInstruction::CheckValueCaseSensitive : DFABytecodeInstruction::CheckValueCaseInsensitive; |
135 | append<uint8_t>(m_bytecode, static_cast<uint8_t>(instruction) | jumpSize); |
136 | append<uint8_t>(m_bytecode, value); |
137 | m_linkRecords.append(LinkRecord({jumpSize, longestPossibleJumpDistance, instructionLocation, jumpLocation, destinationNodeIndex})); |
138 | appendZeroes(m_bytecode, jumpSize); |
139 | } |
140 | |
141 | void DFABytecodeCompiler::emitCheckValueRange(uint8_t lowValue, uint8_t highValue, uint32_t sourceNodeIndex, uint32_t destinationNodeIndex, bool caseSensitive) |
142 | { |
143 | ASSERT_WITH_MESSAGE(lowValue < highValue, "The instruction semantic impose lowValue is strictly less than highValue." ); |
144 | |
145 | uint32_t instructionLocation = m_bytecode.size(); |
146 | uint32_t jumpLocation = instructionLocation + 3 * sizeof(uint8_t); |
147 | int32_t longestPossibleJumpDistance = longestPossibleJump(instructionLocation, sourceNodeIndex, destinationNodeIndex); |
148 | DFABytecodeJumpSize jumpSize = smallestPossibleJumpSize(longestPossibleJumpDistance); |
149 | DFABytecodeInstruction instruction = caseSensitive ? DFABytecodeInstruction::CheckValueRangeCaseSensitive : DFABytecodeInstruction::CheckValueRangeCaseInsensitive; |
150 | append<uint8_t>(m_bytecode, static_cast<uint8_t>(instruction) | jumpSize); |
151 | append<uint8_t>(m_bytecode, lowValue); |
152 | append<uint8_t>(m_bytecode, highValue); |
153 | m_linkRecords.append(LinkRecord({jumpSize, longestPossibleJumpDistance, instructionLocation, jumpLocation, destinationNodeIndex})); |
154 | appendZeroes(m_bytecode, jumpSize); |
155 | } |
156 | |
157 | void DFABytecodeCompiler::emitTerminate() |
158 | { |
159 | append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::Terminate); |
160 | } |
161 | |
162 | void DFABytecodeCompiler::compileNode(uint32_t index, bool root) |
163 | { |
164 | unsigned startSize = m_bytecode.size(); |
165 | |
166 | const DFANode& node = m_dfa.nodes[index]; |
167 | if (node.isKilled()) { |
168 | ASSERT(m_nodeStartOffsets[index] == std::numeric_limits<uint32_t>::max()); |
169 | return; |
170 | } |
171 | |
172 | // Record starting index for linking. |
173 | if (!root) |
174 | m_nodeStartOffsets[index] = m_bytecode.size(); |
175 | |
176 | for (uint64_t action : node.actions(m_dfa)) |
177 | emitAppendAction(action); |
178 | |
179 | // If we jump to the root, we don't want to re-add its actions to a HashSet. |
180 | // We know we have already added them because the root is always compiled first and we always start interpreting at the beginning. |
181 | if (root) |
182 | m_nodeStartOffsets[index] = m_bytecode.size(); |
183 | |
184 | compileNodeTransitions(index); |
185 | |
186 | ASSERT_UNUSED(startSize, m_bytecode.size() - startSize <= compiledNodeMaxBytecodeSize(index)); |
187 | } |
188 | |
189 | unsigned DFABytecodeCompiler::compiledNodeMaxBytecodeSize(uint32_t index) |
190 | { |
191 | const DFANode& node = m_dfa.nodes[index]; |
192 | if (node.isKilled()) |
193 | return 0; |
194 | unsigned size = 0; |
195 | for (uint64_t action : node.actions(m_dfa)) |
196 | size += appendActionBytecodeSize(action); |
197 | size += nodeTransitionsMaxBytecodeSize(node); |
198 | return size; |
199 | } |
200 | |
201 | DFABytecodeCompiler::JumpTable DFABytecodeCompiler::(Vector<DFABytecodeCompiler::Range>& ranges, unsigned firstRange, unsigned lastRange) |
202 | { |
203 | ASSERT(lastRange > firstRange); |
204 | ASSERT(lastRange < ranges.size()); |
205 | |
206 | JumpTable jumpTable; |
207 | jumpTable.min = ranges[firstRange].min; |
208 | jumpTable.max = ranges[lastRange].max; |
209 | jumpTable.caseSensitive = ranges[lastRange].caseSensitive; |
210 | |
211 | unsigned size = lastRange - firstRange + 1; |
212 | jumpTable.destinations.reserveInitialCapacity(size); |
213 | for (unsigned i = firstRange; i <= lastRange; ++i) { |
214 | const Range& range = ranges[i]; |
215 | |
216 | ASSERT(range.caseSensitive == jumpTable.caseSensitive); |
217 | ASSERT(range.min == range.max); |
218 | ASSERT(range.min >= jumpTable.min); |
219 | ASSERT(range.min <= jumpTable.max); |
220 | |
221 | jumpTable.destinations.uncheckedAppend(range.destination); |
222 | } |
223 | |
224 | ranges.remove(firstRange, size); |
225 | |
226 | return jumpTable; |
227 | } |
228 | |
229 | DFABytecodeCompiler::Transitions DFABytecodeCompiler::transitions(const DFANode& node) |
230 | { |
231 | Transitions transitions; |
232 | |
233 | uint32_t destinations[128]; |
234 | memset(destinations, 0xff, sizeof(destinations)); |
235 | const uint32_t noDestination = std::numeric_limits<uint32_t>::max(); |
236 | |
237 | transitions.useFallbackTransition = node.canUseFallbackTransition(m_dfa); |
238 | if (transitions.useFallbackTransition) |
239 | transitions.fallbackTransitionTarget = node.bestFallbackTarget(m_dfa); |
240 | |
241 | for (const auto& transition : node.transitions(m_dfa)) { |
242 | uint32_t targetNodeIndex = transition.target(); |
243 | if (transitions.useFallbackTransition && transitions.fallbackTransitionTarget == targetNodeIndex) |
244 | continue; |
245 | |
246 | for (uint16_t i = transition.range().first; i <= transition.range().last; ++i) |
247 | destinations[i] = targetNodeIndex; |
248 | } |
249 | |
250 | Vector<Range>& ranges = transitions.ranges; |
251 | uint8_t rangeMin; |
252 | bool hasRangeMin = false; |
253 | for (uint8_t i = 0; i < 128; i++) { |
254 | if (hasRangeMin) { |
255 | if (destinations[i] != destinations[rangeMin]) { |
256 | |
257 | // This is the end of a range. Check if it can be case insensitive. |
258 | uint8_t rangeMax = i - 1; |
259 | bool caseSensitive = true; |
260 | if (rangeMin >= 'A' && rangeMax <= 'Z') { |
261 | caseSensitive = false; |
262 | for (uint8_t rangeIndex = rangeMin; rangeIndex <= rangeMax; rangeIndex++) { |
263 | if (destinations[rangeMin] != destinations[toASCIILower(rangeIndex)]) { |
264 | caseSensitive = true; |
265 | break; |
266 | } |
267 | } |
268 | } |
269 | |
270 | if (!caseSensitive) { |
271 | // If all the lower-case destinations are the same as the upper-case destinations, |
272 | // then they will be covered by a case-insensitive range and will not need their own range. |
273 | for (uint8_t rangeIndex = rangeMin; rangeIndex <= rangeMax; rangeIndex++) { |
274 | ASSERT(destinations[rangeMin] == destinations[toASCIILower(rangeIndex)]); |
275 | destinations[toASCIILower(rangeIndex)] = noDestination; |
276 | } |
277 | ranges.append(Range(toASCIILower(rangeMin), toASCIILower(rangeMax), destinations[rangeMin], caseSensitive)); |
278 | } else |
279 | ranges.append(Range(rangeMin, rangeMax, destinations[rangeMin], caseSensitive)); |
280 | |
281 | if (destinations[i] == noDestination) |
282 | hasRangeMin = false; |
283 | else |
284 | rangeMin = i; |
285 | } |
286 | } else { |
287 | if (destinations[i] != noDestination) { |
288 | rangeMin = i; |
289 | hasRangeMin = true; |
290 | } |
291 | } |
292 | } |
293 | if (hasRangeMin) { |
294 | // Ranges are appended after passing the end of them. |
295 | // If a range goes to 127, we will have an uncommitted rangeMin because the loop does not check 128. |
296 | // If a range goes to 127, there will never be values higher than it, so checking for case-insensitive ranges would always fail. |
297 | ranges.append(Range(rangeMin, 127, destinations[rangeMin], true)); |
298 | } |
299 | |
300 | Vector<JumpTable>& jumpTables = transitions.jumpTables; |
301 | unsigned rangePosition = 0; |
302 | unsigned baseRangePosition = std::numeric_limits<unsigned>::max(); |
303 | Range* baseRange = nullptr; |
304 | while (rangePosition < ranges.size()) { |
305 | auto& range = ranges[rangePosition]; |
306 | if (baseRange) { |
307 | if (range.min != range.max |
308 | || baseRange->caseSensitive != range.caseSensitive |
309 | || ranges[rangePosition - 1].max + 1 != range.min) { |
310 | if (rangePosition - baseRangePosition > 1) { |
311 | jumpTables.append(extractJumpTable(ranges, baseRangePosition, rangePosition - 1)); |
312 | rangePosition = baseRangePosition; |
313 | } |
314 | baseRangePosition = std::numeric_limits<unsigned>::max(); |
315 | baseRange = nullptr; |
316 | } |
317 | } else { |
318 | if (range.min == range.max) { |
319 | baseRangePosition = rangePosition; |
320 | baseRange = ⦥ |
321 | } |
322 | } |
323 | ++rangePosition; |
324 | } |
325 | |
326 | if (baseRange && ranges.size() - baseRangePosition > 1) |
327 | jumpTables.append(extractJumpTable(ranges, baseRangePosition, ranges.size() - 1)); |
328 | |
329 | return transitions; |
330 | } |
331 | |
332 | unsigned DFABytecodeCompiler::checkForJumpTableMaxBytecodeSize(const JumpTable& jumpTable) |
333 | { |
334 | unsigned baselineSize = sizeof(DFABytecodeInstruction::CheckValueRangeCaseInsensitive) + 2 * sizeof(uint8_t); |
335 | unsigned targetsSize = (jumpTable.max - jumpTable.min + 1) * sizeof(uint32_t); |
336 | return baselineSize + targetsSize; |
337 | } |
338 | |
339 | unsigned DFABytecodeCompiler::checkForRangeMaxBytecodeSize(const Range& range) |
340 | { |
341 | if (range.min == range.max) |
342 | return sizeof(DFABytecodeInstruction::CheckValueCaseInsensitive) + sizeof(uint8_t) + sizeof(uint32_t); |
343 | return sizeof(DFABytecodeInstruction::CheckValueRangeCaseInsensitive) + 2 * sizeof(uint8_t) + sizeof(uint32_t); |
344 | } |
345 | |
346 | void DFABytecodeCompiler::compileJumpTable(uint32_t nodeIndex, const JumpTable& jumpTable) |
347 | { |
348 | unsigned startSize = m_bytecode.size(); |
349 | ASSERT_WITH_MESSAGE(jumpTable.max < 128, "The DFA engine only supports the ASCII alphabet." ); |
350 | ASSERT(jumpTable.min <= jumpTable.max); |
351 | |
352 | uint32_t instructionLocation = m_bytecode.size(); |
353 | DFABytecodeJumpSize jumpSize = Int8; |
354 | for (uint32_t destinationNodeIndex : jumpTable.destinations) { |
355 | int32_t longestPossibleJumpDistance = longestPossibleJump(instructionLocation, nodeIndex, destinationNodeIndex); |
356 | DFABytecodeJumpSize localJumpSize = smallestPossibleJumpSize(longestPossibleJumpDistance); |
357 | jumpSize = std::max(jumpSize, localJumpSize); |
358 | } |
359 | |
360 | DFABytecodeInstruction instruction = jumpTable.caseSensitive ? DFABytecodeInstruction::JumpTableCaseSensitive : DFABytecodeInstruction::JumpTableCaseInsensitive; |
361 | append<uint8_t>(m_bytecode, static_cast<uint8_t>(instruction) | jumpSize); |
362 | append<uint8_t>(m_bytecode, jumpTable.min); |
363 | append<uint8_t>(m_bytecode, jumpTable.max); |
364 | |
365 | for (uint32_t destinationNodeIndex : jumpTable.destinations) { |
366 | int32_t longestPossibleJumpDistance = longestPossibleJump(instructionLocation, nodeIndex, destinationNodeIndex); |
367 | uint32_t jumpLocation = m_bytecode.size(); |
368 | m_linkRecords.append(LinkRecord({jumpSize, longestPossibleJumpDistance, instructionLocation, jumpLocation, destinationNodeIndex})); |
369 | appendZeroes(m_bytecode, jumpSize); |
370 | } |
371 | |
372 | ASSERT_UNUSED(startSize, m_bytecode.size() - startSize <= checkForJumpTableMaxBytecodeSize(jumpTable)); |
373 | } |
374 | |
375 | void DFABytecodeCompiler::compileCheckForRange(uint32_t nodeIndex, const Range& range) |
376 | { |
377 | unsigned startSize = m_bytecode.size(); |
378 | ASSERT_WITH_MESSAGE(range.max < 128, "The DFA engine only supports the ASCII alphabet." ); |
379 | ASSERT(range.min <= range.max); |
380 | |
381 | if (range.min == range.max) |
382 | emitCheckValue(range.min, nodeIndex, range.destination, range.caseSensitive); |
383 | else |
384 | emitCheckValueRange(range.min, range.max, nodeIndex, range.destination, range.caseSensitive); |
385 | |
386 | ASSERT_UNUSED(startSize, m_bytecode.size() - startSize <= checkForRangeMaxBytecodeSize(range)); |
387 | } |
388 | |
389 | unsigned DFABytecodeCompiler::nodeTransitionsMaxBytecodeSize(const DFANode& node) |
390 | { |
391 | unsigned size = 0; |
392 | Transitions nodeTransitions = transitions(node); |
393 | for (const auto& jumpTable : nodeTransitions.jumpTables) |
394 | size += checkForJumpTableMaxBytecodeSize(jumpTable); |
395 | for (const auto& range : nodeTransitions.ranges) |
396 | size += checkForRangeMaxBytecodeSize(range); |
397 | if (nodeTransitions.useFallbackTransition) |
398 | size += sizeof(DFABytecodeInstruction::Jump) + sizeof(uint32_t); |
399 | else |
400 | size += instructionSizeWithArguments(DFABytecodeInstruction::Terminate); |
401 | return size; |
402 | } |
403 | |
404 | void DFABytecodeCompiler::compileNodeTransitions(uint32_t nodeIndex) |
405 | { |
406 | const DFANode& node = m_dfa.nodes[nodeIndex]; |
407 | unsigned startSize = m_bytecode.size(); |
408 | |
409 | Transitions nodeTransitions = transitions(node); |
410 | for (const auto& jumpTable : nodeTransitions.jumpTables) |
411 | compileJumpTable(nodeIndex, jumpTable); |
412 | for (const auto& range : nodeTransitions.ranges) |
413 | compileCheckForRange(nodeIndex, range); |
414 | if (nodeTransitions.useFallbackTransition) |
415 | emitJump(nodeIndex, nodeTransitions.fallbackTransitionTarget); |
416 | else |
417 | emitTerminate(); |
418 | |
419 | ASSERT_UNUSED(startSize, m_bytecode.size() - startSize <= nodeTransitionsMaxBytecodeSize(node)); |
420 | } |
421 | |
422 | void DFABytecodeCompiler::compile() |
423 | { |
424 | uint32_t startLocation = m_bytecode.size(); |
425 | append<DFAHeader>(m_bytecode, 0); // This will be set when we are finished compiling this DFA. |
426 | |
427 | m_nodeStartOffsets.resize(m_dfa.nodes.size()); |
428 | for (unsigned i = 0; i < m_dfa.nodes.size(); ++i) |
429 | m_nodeStartOffsets[i] = std::numeric_limits<uint32_t>::max(); |
430 | |
431 | // Populate m_maxNodeStartOffsets with a worst-case index of where the node would be with no branch compaction. |
432 | // Compacting the branches using 1-4 byte signed jump distances should only make nodes closer together than this. |
433 | ASSERT(m_maxNodeStartOffsets.isEmpty()); |
434 | m_maxNodeStartOffsets.clear(); |
435 | m_maxNodeStartOffsets.resize(m_dfa.nodes.size()); |
436 | unsigned rootActionsSize = 0; |
437 | for (uint64_t action : m_dfa.nodes[m_dfa.root].actions(m_dfa)) |
438 | rootActionsSize += appendActionBytecodeSize(action); |
439 | m_maxNodeStartOffsets[m_dfa.root] = sizeof(DFAHeader) + rootActionsSize; |
440 | unsigned nextIndex = sizeof(DFAHeader) + compiledNodeMaxBytecodeSize(m_dfa.root); |
441 | for (uint32_t i = 0; i < m_dfa.nodes.size(); i++) { |
442 | if (i != m_dfa.root) { |
443 | m_maxNodeStartOffsets[i] = nextIndex; |
444 | nextIndex += compiledNodeMaxBytecodeSize(i); |
445 | } |
446 | } |
447 | |
448 | // Make sure the root is always at the beginning of the bytecode. |
449 | compileNode(m_dfa.root, true); |
450 | for (uint32_t i = 0; i < m_dfa.nodes.size(); i++) { |
451 | if (i != m_dfa.root) |
452 | compileNode(i, false); |
453 | } |
454 | |
455 | ASSERT(m_maxNodeStartOffsets.size() == m_nodeStartOffsets.size()); |
456 | for (unsigned i = 0; i < m_dfa.nodes.size(); ++i) { |
457 | if (m_nodeStartOffsets[i] != std::numeric_limits<uint32_t>::max()) |
458 | ASSERT(m_maxNodeStartOffsets[i] >= m_nodeStartOffsets[i]); |
459 | } |
460 | |
461 | // Link. |
462 | for (const auto& linkRecord : m_linkRecords) { |
463 | uint32_t destination = m_nodeStartOffsets[linkRecord.destinationNodeIndex]; |
464 | RELEASE_ASSERT(destination < std::numeric_limits<int32_t>::max()); |
465 | int32_t distance = destination - linkRecord.instructionLocation; |
466 | ASSERT(abs(distance) <= abs(linkRecord.longestPossibleJump)); |
467 | |
468 | switch (linkRecord.jumpSize) { |
469 | case Int8: |
470 | RELEASE_ASSERT(distance == static_cast<int8_t>(distance)); |
471 | setBits<int8_t>(m_bytecode, linkRecord.jumpLocation, static_cast<int8_t>(distance)); |
472 | break; |
473 | case Int16: |
474 | RELEASE_ASSERT(distance == static_cast<int16_t>(distance)); |
475 | setBits<int16_t>(m_bytecode, linkRecord.jumpLocation, static_cast<int16_t>(distance)); |
476 | break; |
477 | case Int24: |
478 | RELEASE_ASSERT(distance >= Int24Min && distance <= Int24Max); |
479 | setBits<uint16_t>(m_bytecode, linkRecord.jumpLocation, static_cast<uint16_t>(distance)); |
480 | setBits<int8_t>(m_bytecode, linkRecord.jumpLocation + sizeof(int16_t), static_cast<int8_t>(distance >> 16)); |
481 | break; |
482 | case Int32: |
483 | setBits<int32_t>(m_bytecode, linkRecord.jumpLocation, distance); |
484 | break; |
485 | } |
486 | } |
487 | |
488 | setBits<DFAHeader>(m_bytecode, startLocation, m_bytecode.size() - startLocation); |
489 | } |
490 | |
491 | } // namespace ContentExtensions |
492 | |
493 | } // namespace WebCore |
494 | |
495 | #endif // ENABLE(CONTENT_EXTENSIONS) |
496 | |