Skip to content

Commit e412a95

Browse files
committed
Adjust the ranges of basic block statements in JSC's control flow profiler to be mutually exclusive
https://bugs.webkit.org/show_bug.cgi?id=141095 Reviewed by Mark Lam. Suppose the control flow of a program forms basic block A with successor block B. A's end offset will be the *same* as B's start offset in the current architecture of the control flow profiler. This makes reasoning about the text offsets of the control flow profiler unsound. To make reasoning about offsets sound, all basic block ranges should be mutually exclusive. All calls to emitProfileControlFlow now pass in the *start* of a basic block as the text offset argument. This simplifies all calls to emitProfileControlFlow because the previous implementation had a lot of edge cases for getting the desired basic block text boundaries. This patch also ensures that the basic block boundary of a block statement is the exactly the block's open and close brace offsets (inclusive). For example, in if/for/while statements. This also has the consequence that for statements like "if (cond) foo();", the whitespace preceding "foo()" is not part of the "foo()" basic block, but instead is part of the "if (cond) " basic block. This is okay because these text offsets aren't meant to be human readable. Instead, they reflect the text offsets of JSC's AST nodes. The Web Inspector is the only client of this API and user of these text offsets and it is not negatively effected by this new behavior. * bytecode/CodeBlock.cpp: (JSC::CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler): When computing basic block boundaries in CodeBlock, we ensure that every block's end offset is one less than its successor's start offset to maintain that boundaries' ranges should be mutually exclusive. * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::BytecodeGenerator): Because the control flow profiler needs to know which functions have executed, we can't lazily create functions. This was a bug from before that was hidden because the Type Profiler was always enabled when the control flow profiler was enabled when profiling was turned on from the Web Inspector. But, JSC allows for Control Flow profiling to be turned on without Type Profiling, so we need to ensure the Control Flow profiler has all the data it needs. * bytecompiler/NodesCodegen.cpp: (JSC::ConditionalNode::emitBytecode): (JSC::IfElseNode::emitBytecode): (JSC::WhileNode::emitBytecode): (JSC::ForNode::emitBytecode): (JSC::ForInNode::emitMultiLoopBytecode): (JSC::ForOfNode::emitBytecode): (JSC::TryNode::emitBytecode): * jsc.cpp: (functionHasBasicBlockExecuted): We now assert that the substring argument is indeed a substring of the function argument's text because subtle bugs could be introduced otherwise. * parser/ASTBuilder.h: (JSC::ASTBuilder::setStartOffset): * parser/Nodes.h: (JSC::Node::setStartOffset): * parser/Parser.cpp: (JSC::Parser<LexerType>::parseBlockStatement): (JSC::Parser<LexerType>::parseStatement): (JSC::Parser<LexerType>::parseMemberExpression): For the various function call AST nodes, their m_position member variable is now the start of the entire function call expression and not at the start of the open paren of the arguments list. * runtime/BasicBlockLocation.cpp: (JSC::BasicBlockLocation::getExecutedRanges): * runtime/ControlFlowProfiler.cpp: (JSC::ControlFlowProfiler::getBasicBlocksForSourceID): Function ranges inserted as gaps should follow the same criteria that the bytecode generator uses to ensure that basic blocks start and end offsets are mutually exclusive. * tests/controlFlowProfiler/brace-location.js: Added. (foo): (bar): (baz): (testIf): (testForRegular): (testForIn): (testForOf): (testWhile): (testIfNoBraces): (testForRegularNoBraces): (testForInNoBraces): (testForOfNoBraces): (testWhileNoBraces): * tests/controlFlowProfiler/conditional-expression.js: Added. (foo): (bar): (baz): (testConditionalBasic): (testConditionalFunctionCall): * tests/controlFlowProfiler/driver/driver.js: (checkBasicBlock): Canonical link: https://commits.webkit.org/159941@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@180518 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 182444a commit e412a95

13 files changed

Lines changed: 355 additions & 27 deletions

File tree

‎Source/JavaScriptCore/ChangeLog‎

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,102 @@
1+
2015-02-23 Saam Barati <saambarati1@gmail.com>
2+
3+
Adjust the ranges of basic block statements in JSC's control flow profiler to be mutually exclusive
4+
https://bugs.webkit.org/show_bug.cgi?id=141095
5+
6+
Reviewed by Mark Lam.
7+
8+
Suppose the control flow of a program forms basic block A with successor block
9+
B. A's end offset will be the *same* as B's start offset in the current architecture
10+
of the control flow profiler. This makes reasoning about the text offsets of
11+
the control flow profiler unsound. To make reasoning about offsets sound, all
12+
basic block ranges should be mutually exclusive. All calls to emitProfileControlFlow
13+
now pass in the *start* of a basic block as the text offset argument. This simplifies
14+
all calls to emitProfileControlFlow because the previous implementation had a
15+
lot of edge cases for getting the desired basic block text boundaries.
16+
17+
This patch also ensures that the basic block boundary of a block statement
18+
is the exactly the block's open and close brace offsets (inclusive). For example,
19+
in if/for/while statements. This also has the consequence that for statements
20+
like "if (cond) foo();", the whitespace preceding "foo()" is not part of
21+
the "foo()" basic block, but instead is part of the "if (cond) " basic block.
22+
This is okay because these text offsets aren't meant to be human readable.
23+
Instead, they reflect the text offsets of JSC's AST nodes. The Web Inspector
24+
is the only client of this API and user of these text offsets and it is
25+
not negatively effected by this new behavior.
26+
27+
* bytecode/CodeBlock.cpp:
28+
(JSC::CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler):
29+
When computing basic block boundaries in CodeBlock, we ensure that every
30+
block's end offset is one less than its successor's start offset to
31+
maintain that boundaries' ranges should be mutually exclusive.
32+
33+
* bytecompiler/BytecodeGenerator.cpp:
34+
(JSC::BytecodeGenerator::BytecodeGenerator):
35+
Because the control flow profiler needs to know which functions
36+
have executed, we can't lazily create functions. This was a bug
37+
from before that was hidden because the Type Profiler was always
38+
enabled when the control flow profiler was enabled when profiling
39+
was turned on from the Web Inspector. But, JSC allows for Control
40+
Flow profiling to be turned on without Type Profiling, so we need
41+
to ensure the Control Flow profiler has all the data it needs.
42+
43+
* bytecompiler/NodesCodegen.cpp:
44+
(JSC::ConditionalNode::emitBytecode):
45+
(JSC::IfElseNode::emitBytecode):
46+
(JSC::WhileNode::emitBytecode):
47+
(JSC::ForNode::emitBytecode):
48+
(JSC::ForInNode::emitMultiLoopBytecode):
49+
(JSC::ForOfNode::emitBytecode):
50+
(JSC::TryNode::emitBytecode):
51+
* jsc.cpp:
52+
(functionHasBasicBlockExecuted):
53+
We now assert that the substring argument is indeed a substring
54+
of the function argument's text because subtle bugs could be
55+
introduced otherwise.
56+
57+
* parser/ASTBuilder.h:
58+
(JSC::ASTBuilder::setStartOffset):
59+
* parser/Nodes.h:
60+
(JSC::Node::setStartOffset):
61+
* parser/Parser.cpp:
62+
(JSC::Parser<LexerType>::parseBlockStatement):
63+
(JSC::Parser<LexerType>::parseStatement):
64+
(JSC::Parser<LexerType>::parseMemberExpression):
65+
For the various function call AST nodes, their m_position member
66+
variable is now the start of the entire function call expression
67+
and not at the start of the open paren of the arguments list.
68+
69+
* runtime/BasicBlockLocation.cpp:
70+
(JSC::BasicBlockLocation::getExecutedRanges):
71+
* runtime/ControlFlowProfiler.cpp:
72+
(JSC::ControlFlowProfiler::getBasicBlocksForSourceID):
73+
Function ranges inserted as gaps should follow the same criteria
74+
that the bytecode generator uses to ensure that basic blocks
75+
start and end offsets are mutually exclusive.
76+
77+
* tests/controlFlowProfiler/brace-location.js: Added.
78+
(foo):
79+
(bar):
80+
(baz):
81+
(testIf):
82+
(testForRegular):
83+
(testForIn):
84+
(testForOf):
85+
(testWhile):
86+
(testIfNoBraces):
87+
(testForRegularNoBraces):
88+
(testForInNoBraces):
89+
(testForOfNoBraces):
90+
(testWhileNoBraces):
91+
* tests/controlFlowProfiler/conditional-expression.js: Added.
92+
(foo):
93+
(bar):
94+
(baz):
95+
(testConditionalBasic):
96+
(testConditionalFunctionCall):
97+
* tests/controlFlowProfiler/driver/driver.js:
98+
(checkBasicBlock):
99+
1100
2015-02-23 Matthew Mirman <mmirman@apple.com>
2101

3102
r9 is volatile on ARMv7 for iOS 3 and up.

‎Source/JavaScriptCore/bytecode/CodeBlock.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4052,7 +4052,7 @@ void CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler(Vector<Instruct
40524052
if (i + 1 < offsetsLength) {
40534053
size_t endIdx = bytecodeOffsets[i + 1];
40544054
RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[endIdx].u.opcode) == op_profile_control_flow);
4055-
basicBlockEndOffset = instructions[endIdx + 1].u.operand;
4055+
basicBlockEndOffset = instructions[endIdx + 1].u.operand - 1;
40564056
} else {
40574057
basicBlockEndOffset = m_sourceOffset + m_ownerExecutable->source().length() - 1; // Offset before the closing brace.
40584058
basicBlockStartOffset = std::min(basicBlockStartOffset, basicBlockEndOffset); // Some start offsets may be at the closing brace, ensure it is the offset before.

‎Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
338338

339339
m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset());
340340

341-
bool canLazilyCreateFunctions = !functionNode->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks && !m_vm->typeProfiler();
341+
bool canLazilyCreateFunctions = !functionNode->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks && !m_vm->typeProfiler() && !m_vm->controlFlowProfiler();
342342
m_firstLazyFunction = codeBlock->m_numVars;
343343
if (!shouldCaptureAllTheThings) {
344344
for (size_t i = 0; i < functionStack.size(); ++i) {

‎Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp‎

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,12 +1444,12 @@ RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, Register
14441444
generator.emitJump(afterElse.get());
14451445

14461446
generator.emitLabel(beforeElse.get());
1447-
generator.emitProfileControlFlow(m_expr2->startOffset());
1447+
generator.emitProfileControlFlow(m_expr1->endOffset() + 1);
14481448
generator.emitNode(newDst.get(), m_expr2);
14491449

14501450
generator.emitLabel(afterElse.get());
14511451

1452-
generator.emitProfileControlFlow(m_expr2->endOffset());
1452+
generator.emitProfileControlFlow(m_expr2->endOffset() + 1);
14531453

14541454
return newDst.get();
14551455
}
@@ -1897,12 +1897,13 @@ void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
18971897
generator.emitLabel(beforeElse.get());
18981898

18991899
if (m_elseBlock) {
1900-
generator.emitProfileControlFlow(m_ifBlock->endOffset());
1900+
generator.emitProfileControlFlow(m_ifBlock->endOffset() + (m_ifBlock->isBlock() ? 1 : 0));
19011901
generator.emitNode(dst, m_elseBlock);
19021902
}
19031903

19041904
generator.emitLabel(afterElse.get());
1905-
generator.emitProfileControlFlow(m_elseBlock ? m_elseBlock->endOffset() : m_ifBlock->endOffset());
1905+
StatementNode* endingBlock = m_elseBlock ? m_elseBlock : m_ifBlock;
1906+
generator.emitProfileControlFlow(endingBlock->endOffset() + (endingBlock->isBlock() ? 1 : 0));
19061907
}
19071908

19081909
// ------------------------------ DoWhileNode ----------------------------------
@@ -1948,7 +1949,7 @@ void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
19481949

19491950
generator.emitLabel(scope->breakTarget());
19501951

1951-
generator.emitProfileControlFlow(endOffset());
1952+
generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0));
19521953
}
19531954

19541955
// ------------------------------ ForNode --------------------------------------
@@ -1983,7 +1984,7 @@ void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
19831984
generator.emitJump(topOfLoop.get());
19841985

19851986
generator.emitLabel(scope->breakTarget());
1986-
generator.emitProfileControlFlow(endOffset());
1987+
generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0));
19871988
}
19881989

19891990
// ------------------------------ ForInNode ------------------------------------
@@ -2100,6 +2101,8 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
21002101
generator.emitNode(base.get(), m_expr);
21012102
RefPtr<RegisterID> local = this->tryGetBoundLocal(generator);
21022103

2104+
int profilerStartOffset = m_statement->startOffset();
2105+
int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0);
21032106
// Indexed property loop.
21042107
{
21052108
LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
@@ -2121,13 +2124,13 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
21212124
generator.emitToIndexString(propertyName.get(), i.get());
21222125
this->emitLoopHeader(generator, propertyName.get());
21232126

2124-
generator.emitProfileControlFlow(m_statement->startOffset());
2127+
generator.emitProfileControlFlow(profilerStartOffset);
21252128

21262129
generator.pushIndexedForInScope(local.get(), i.get());
21272130
generator.emitNode(dst, m_statement);
21282131
generator.popIndexedForInScope(local.get());
21292132

2130-
generator.emitProfileControlFlow(m_statement->endOffset());
2133+
generator.emitProfileControlFlow(profilerEndOffset);
21312134

21322135
generator.emitLabel(scope->continueTarget());
21332136
generator.emitInc(i.get());
@@ -2159,13 +2162,13 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
21592162

21602163
this->emitLoopHeader(generator, propertyName.get());
21612164

2162-
generator.emitProfileControlFlow(m_statement->startOffset());
2165+
generator.emitProfileControlFlow(profilerStartOffset);
21632166

21642167
generator.pushStructureForInScope(local.get(), i.get(), propertyName.get(), structureEnumerator.get());
21652168
generator.emitNode(dst, m_statement);
21662169
generator.popStructureForInScope(local.get());
21672170

2168-
generator.emitProfileControlFlow(m_statement->endOffset());
2171+
generator.emitProfileControlFlow(profilerEndOffset);
21692172

21702173
generator.emitLabel(scope->continueTarget());
21712174
generator.emitInc(i.get());
@@ -2196,7 +2199,7 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
21962199

21972200
this->emitLoopHeader(generator, propertyName.get());
21982201

2199-
generator.emitProfileControlFlow(m_statement->startOffset());
2202+
generator.emitProfileControlFlow(profilerStartOffset);
22002203

22012204
generator.emitNode(dst, m_statement);
22022205

@@ -2217,7 +2220,7 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
22172220

22182221
generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
22192222
generator.emitLabel(end.get());
2220-
generator.emitProfileControlFlow(m_statement->endOffset());
2223+
generator.emitProfileControlFlow(profilerEndOffset);
22212224
}
22222225

22232226
void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -2285,7 +2288,7 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
22852288
generator.emitNode(dst, m_statement);
22862289
};
22872290
generator.emitEnumeration(this, m_expr, extractor);
2288-
generator.emitProfileControlFlow(m_statement->endOffset());
2291+
generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0));
22892292
}
22902293

22912294
// ------------------------------ ContinueNode ---------------------------------
@@ -2631,7 +2634,7 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
26312634
}
26322635

26332636
generator.emitPushCatchScope(generator.scopeRegister(), m_exceptionIdent, exceptionRegister.get(), DontDelete);
2634-
generator.emitProfileControlFlow(m_tryBlock->endOffset());
2637+
generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1);
26352638
generator.emitNode(dst, m_catchBlock);
26362639
generator.emitPopScope(generator.scopeRegister());
26372640
generator.emitLabel(catchEndLabel.get());
@@ -2644,12 +2647,12 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
26442647

26452648
RefPtr<Label> finallyEndLabel = generator.newLabel();
26462649

2647-
int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() : m_tryBlock->endOffset();
2650+
int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() + 1 : m_tryBlock->endOffset() + 1;
26482651

26492652
// Normal path: run the finally code, and jump to the end.
26502653
generator.emitProfileControlFlow(finallyStartOffset);
26512654
generator.emitNode(dst, m_finallyBlock);
2652-
generator.emitProfileControlFlow(m_finallyBlock->endOffset());
2655+
generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1);
26532656
generator.emitJump(finallyEndLabel.get());
26542657

26552658
// Uncaught exception path: invoke the finally block, then re-throw the exception.
@@ -2659,9 +2662,9 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
26592662
generator.emitThrow(tempExceptionRegister.get());
26602663

26612664
generator.emitLabel(finallyEndLabel.get());
2662-
generator.emitProfileControlFlow(m_finallyBlock->endOffset());
2665+
generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1);
26632666
} else
2664-
generator.emitProfileControlFlow(m_catchBlock->endOffset());
2667+
generator.emitProfileControlFlow(m_catchBlock->endOffset() + 1);
26652668

26662669
}
26672670

‎Source/JavaScriptCore/jsc.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,7 @@ EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
11271127
RELEASE_ASSERT(exec->argument(1).isString());
11281128
String substring = exec->argument(1).getString(exec);
11291129
String sourceCodeText = executable->source().toString();
1130+
RELEASE_ASSERT(sourceCodeText.contains(substring));
11301131
int offset = sourceCodeText.find(substring) + executable->source().startOffset();
11311132

11321133
bool hasExecuted = exec->vm().controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), exec->vm());

‎Source/JavaScriptCore/parser/ASTBuilder.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,11 @@ class ASTBuilder {
713713
{
714714
node->setStartOffset(offset);
715715
}
716+
717+
void setStartOffset(Node* node, int offset)
718+
{
719+
node->setStartOffset(offset);
720+
}
716721

717722
private:
718723
struct Scope {

‎Source/JavaScriptCore/parser/Nodes.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ namespace JSC {
132132
int lineStartOffset() const { return m_position.lineStartOffset; }
133133
const JSTextPosition& position() const { return m_position; }
134134
void setEndOffset(int offset) { m_endOffset = offset; }
135+
void setStartOffset(int offset) { m_position.offset = offset; }
135136

136137
protected:
137138
JSTextPosition m_position;

‎Source/JavaScriptCore/parser/Parser.cpp‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,21 +1115,24 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatemen
11151115
{
11161116
ASSERT(match(OPENBRACE));
11171117
JSTokenLocation location(tokenLocation());
1118+
int startOffset = m_token.m_data.offset;
11181119
int start = tokenLine();
11191120
next();
11201121
if (match(CLOSEBRACE)) {
1121-
unsigned endOffset = m_lexer->currentOffset();
1122+
int endOffset = m_token.m_data.offset;
11221123
next();
11231124
TreeStatement result = context.createBlockStatement(location, 0, start, m_lastTokenEndPosition.line);
1125+
context.setStartOffset(result, startOffset);
11241126
context.setEndOffset(result, endOffset);
11251127
return result;
11261128
}
11271129
TreeSourceElements subtree = parseSourceElements(context, DontCheckForStrictMode);
11281130
failIfFalse(subtree, "Cannot parse the body of the block statement");
11291131
matchOrFail(CLOSEBRACE, "Expected a closing '}' at the end of a block statement");
1130-
unsigned endOffset = m_lexer->currentOffset();
1132+
int endOffset = m_token.m_data.offset;
11311133
next();
11321134
TreeStatement result = context.createBlockStatement(location, subtree, start, m_lastTokenEndPosition.line);
1135+
context.setStartOffset(result, startOffset);
11331136
context.setEndOffset(result, endOffset);
11341137
return result;
11351138
}
@@ -1143,9 +1146,11 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
11431146
int nonTrivialExpressionCount = 0;
11441147
failIfStackOverflow();
11451148
TreeStatement result = 0;
1149+
bool shouldSetEndOffset = true;
11461150
switch (m_token.m_type) {
11471151
case OPENBRACE:
11481152
result = parseBlockStatement(context);
1153+
shouldSetEndOffset = false;
11491154
break;
11501155
case VAR:
11511156
result = parseVarDeclaration(context);
@@ -1228,7 +1233,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(Tre
12281233
break;
12291234
}
12301235

1231-
if (result)
1236+
if (result && shouldSetEndOffset)
12321237
context.setEndOffset(result, m_lastTokenEndPosition.offset);
12331238
return result;
12341239
}
@@ -2312,6 +2317,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
23122317
TreeExpression base = 0;
23132318
JSTextPosition expressionStart = tokenStartPosition();
23142319
int newCount = 0;
2320+
JSTokenLocation startLocation = tokenLocation();
23152321
JSTokenLocation location;
23162322
while (match(NEW)) {
23172323
next();
@@ -2350,7 +2356,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
23502356
JSTextPosition expressionEnd = lastTokenEndPosition();
23512357
TreeArguments arguments = parseArguments(context, AllowSpread);
23522358
failIfFalse(arguments, "Cannot parse call arguments");
2353-
base = context.makeFunctionCallNode(location, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
2359+
base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
23542360
}
23552361
m_nonLHSCount = nonLHSCount;
23562362
break;

‎Source/JavaScriptCore/runtime/BasicBlockLocation.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ Vector<std::pair<int, int>> BasicBlockLocation::getExecutedRanges() const
6262
minIdx = idx;
6363
}
6464
}
65-
result.append(Gap(nextRangeStart, minGap.first));
66-
nextRangeStart = minGap.second;
65+
result.append(Gap(nextRangeStart, minGap.first - 1));
66+
nextRangeStart = minGap.second + 1;
6767
gaps.remove(minIdx);
6868
}
6969

‎Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Vector<BasicBlockRange> ControlFlowProfiler::getBasicBlocksForSourceID(intptr_t
9191
BasicBlockRange range;
9292
range.m_hasExecuted = std::get<0>(functionRange);
9393
range.m_startOffset = static_cast<int>(std::get<1>(functionRange));
94-
range.m_endOffset = static_cast<int>(std::get<2>(functionRange) + 1);
94+
range.m_endOffset = static_cast<int>(std::get<2>(functionRange));
9595
result.append(range);
9696
}
9797

0 commit comments

Comments
 (0)