Skip to content

Commit 6ff0029

Browse files
author
Suwei Chen
committed
ES6 constructor returns class instead of object upon constructorCache hit.
Github issue chakra-core#1496 ES6 constructor returns class instead of object upon constructorCache hit. constructorCache->ctorHasNoExplicitReturnValue set to 'true' for ES6 class constructors, therefore opcode 'GetNewScObject' is optimized away in inliner. Fix by de-asserting Flags_HasNoExplicitReturnValue for ES6 class constructors.
1 parent 399ba8b commit 6ff0029

File tree

8 files changed

+81
-13
lines changed

8 files changed

+81
-13
lines changed

lib/Parser/Parse.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -6337,7 +6337,7 @@ ParseNodePtr Parser::GenerateEmptyConstructor(bool extends)
63376337
pnodeFnc->sxFnc.SetIsClassMember(TRUE);
63386338
pnodeFnc->sxFnc.SetIsClassConstructor(TRUE);
63396339
pnodeFnc->sxFnc.SetIsBaseClassConstructor(!extends);
6340-
pnodeFnc->sxFnc.SetHasNonThisStmt(extends);
6340+
pnodeFnc->sxFnc.SetHasNonThisStmt();
63416341
pnodeFnc->sxFnc.SetIsGeneratedDefault(TRUE);
63426342

63436343
pnodeFnc->ichLim = m_pscan->IchLimTok();
@@ -7162,6 +7162,7 @@ ParseNodePtr Parser::ParseClassDecl(BOOL isDeclaration, LPCOLESTR pNameHint, uin
71627162
pnodeConstructor->sxFnc.hintOffset = constructorShortNameHintOffset;
71637163
pnodeConstructor->sxFnc.pid = pnodeName && pnodeName->sxVar.pid ? pnodeName->sxVar.pid : wellKnownPropertyPids.constructor;
71647164
pnodeConstructor->sxFnc.SetIsClassConstructor(TRUE);
7165+
pnodeConstructor->sxFnc.SetHasNonThisStmt();
71657166
pnodeConstructor->sxFnc.SetIsBaseClassConstructor(pnodeExtends == nullptr);
71667167
}
71677168
else

lib/Runtime/Base/FunctionBody.cpp

+11-9
Original file line numberDiff line numberDiff line change
@@ -392,38 +392,38 @@ namespace Js
392392
}
393393

394394
FunctionBody * FunctionBody::NewFromRecycler(ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
395-
Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
395+
Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes, FunctionBodyFlags flags
396396
#ifdef PERF_COUNTERS
397397
, bool isDeserializedFunction
398398
#endif
399399
)
400400
{
401401
return FunctionBody::NewFromRecycler(scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo,
402-
scriptContext->GetThreadContext()->NewFunctionNumber(), uScriptId, functionId, boundPropertyRecords, attributes
402+
scriptContext->GetThreadContext()->NewFunctionNumber(), uScriptId, functionId, boundPropertyRecords, attributes, flags
403403
#ifdef PERF_COUNTERS
404404
, isDeserializedFunction
405405
#endif
406406
);
407407
}
408408

409409
FunctionBody * FunctionBody::NewFromRecycler(ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
410-
Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
410+
Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes, FunctionBodyFlags flags
411411
#ifdef PERF_COUNTERS
412412
, bool isDeserializedFunction
413413
#endif
414414
)
415415
{
416416
#ifdef PERF_COUNTERS
417-
return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(), FunctionBody, scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo, uFunctionNumber, uScriptId, functionId, boundPropertyRecords, attributes, isDeserializedFunction);
417+
return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(), FunctionBody, scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo, uFunctionNumber, uScriptId, functionId, boundPropertyRecords, attributes, flags, isDeserializedFunction);
418418
#else
419-
return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(), FunctionBody, scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo, uFunctionNumber, uScriptId, functionId, boundPropertyRecords, attributes);
419+
return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(), FunctionBody, scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo, uFunctionNumber, uScriptId, functionId, boundPropertyRecords, attributes, flags);
420420
#endif
421421
}
422422

423423

424424
FunctionBody::FunctionBody(ScriptContext* scriptContext, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
425425
Utf8SourceInfo* utf8SourceInfo, uint uFunctionNumber, uint uScriptId,
426-
Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
426+
Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes, FunctionBodyFlags flags
427427
#ifdef PERF_COUNTERS
428428
, bool isDeserializedFunction
429429
#endif
@@ -454,7 +454,7 @@ namespace Js
454454
loopInterpreterLimit(CONFIG_FLAG(LoopInterpretCount)),
455455
savedPolymorphicCacheState(0),
456456
debuggerScopeIndex(0),
457-
flags(Flags_HasNoExplicitReturnValue),
457+
flags(flags),
458458
m_hasFinally(false),
459459
#if ENABLE_PROFILE_INFO
460460
dynamicProfileInfo(nullptr),
@@ -1717,7 +1717,8 @@ namespace Js
17171717
this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId, /* script id */
17181718
this->functionId, /* function id */
17191719
propertyRecordList,
1720-
(Attributes)(this->GetAttributes() & ~(Attributes::DeferredDeserialize | Attributes::DeferredParse))
1720+
(Attributes)(this->GetAttributes() & ~(Attributes::DeferredDeserialize | Attributes::DeferredParse)),
1721+
Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
17211722
#ifdef PERF_COUNTERS
17221723
, false /* is function from deferred deserialized proxy */
17231724
#endif
@@ -1983,7 +1984,8 @@ namespace Js
19831984
this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId, /* script id */
19841985
this->functionId, /* function id */
19851986
propertyRecordList,
1986-
(Attributes)(this->GetAttributes() & ~(Attributes::DeferredDeserialize | Attributes::DeferredParse))
1987+
(Attributes)(this->GetAttributes() & ~(Attributes::DeferredDeserialize | Attributes::DeferredParse)),
1988+
Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
19871989
#ifdef PERF_COUNTERS
19881990
, false /* is function from deferred deserialized proxy */
19891991
#endif

lib/Runtime/Base/FunctionBody.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -2107,7 +2107,7 @@ namespace Js
21072107
#endif
21082108

21092109
FunctionBody(ScriptContext* scriptContext, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, Utf8SourceInfo* sourceInfo,
2110-
uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* propRecordList, Attributes attributes
2110+
uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* propRecordList, Attributes attributes, FunctionBodyFlags flags
21112111
#ifdef PERF_COUNTERS
21122112
, bool isDeserializedFunction = false
21132113
#endif
@@ -2135,12 +2135,14 @@ namespace Js
21352135

21362136
static FunctionBody * NewFromRecycler(Js::ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
21372137
Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
2138+
, FunctionBodyFlags flags
21382139
#ifdef PERF_COUNTERS
21392140
, bool isDeserializedFunction
21402141
#endif
21412142
);
21422143
static FunctionBody * NewFromRecycler(Js::ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
21432144
Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
2145+
, FunctionBodyFlags flags
21442146
#ifdef PERF_COUNTERS
21452147
, bool isDeserializedFunction
21462148
#endif

lib/Runtime/ByteCode/ByteCodeGenerator.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,9 @@ FuncInfo * ByteCodeGenerator::StartBindFunction(const char16 *name, uint nameLen
12761276
parsedFunctionBody = Js::FunctionBody::NewFromRecycler(scriptContext, name, nameLength, shortNameOffset, pnode->sxFnc.nestedCount, m_utf8SourceInfo,
12771277
m_utf8SourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId, functionId, propertyRecordList
12781278
, attributes
1279+
, pnode->sxFnc.IsClassConstructor() ?
1280+
Js::FunctionBody::FunctionBodyFlags::Flags_None :
1281+
Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
12791282
#ifdef PERF_COUNTERS
12801283
, false /* is function from deferred deserialized proxy */
12811284
#endif
@@ -5277,7 +5280,8 @@ Js::FunctionBody * ByteCodeGenerator::MakeGlobalFunctionBody(ParseNode *pnode)
52775280
m_utf8SourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId,
52785281
pnode->sxFnc.functionId,
52795282
propertyRecordList,
5280-
Js::FunctionInfo::Attributes::None
5283+
Js::FunctionInfo::Attributes::None,
5284+
Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
52815285
#ifdef PERF_COUNTERS
52825286
, false /* is function from deferred deserialized proxy */
52835287
#endif

lib/Runtime/ByteCode/ByteCodeSerializer.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -3784,7 +3784,8 @@ class ByteCodeBufferReader
37843784
sourceInfo,
37853785
functionNumber,
37863786
sourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId,
3787-
firstFunctionId + functionId, nullptr, (FunctionInfo::Attributes)attributes
3787+
firstFunctionId + functionId, nullptr, (FunctionInfo::Attributes)attributes,
3788+
Js::FunctionBody::FunctionBodyFlags::Flags_None // bytecode serializer will initialize
37883789
#ifdef PERF_COUNTERS
37893790
, (deferDeserializeFunctionInfo != nullptr)
37903791
#endif

test/es6/bug_issue_1496.baseline

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
0
2+
1
3+
2
4+
3
5+
4
6+
5
7+
6
8+
7
9+
8
10+
9

test/es6/bug_issue_1496.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
// GitHub Issue1496: ES6 constructor returns class instead of object upon constructorCache hit
7+
//
8+
// -mic:1 -maxsimplejitruncount:2
9+
10+
var Test = {};
11+
12+
class A {
13+
constructor(foo) { this.foo = foo; }
14+
toB() {
15+
return new Test.B(this);
16+
}
17+
}
18+
19+
class B {
20+
constructor(bar) { this.bar = bar; }
21+
}
22+
23+
Test.B = B;
24+
25+
for (var i=0; i<10; i++)
26+
{
27+
var a = new A(i);
28+
var b = a.toB();
29+
30+
try
31+
{
32+
WScript.Echo(b.bar.foo);
33+
}
34+
catch (e)
35+
{
36+
WScript.Echo(e);
37+
WScript.Echo(b);
38+
break;
39+
}
40+
}

test/es6/rlexe.xml

+8
Original file line numberDiff line numberDiff line change
@@ -1331,4 +1331,12 @@
13311331
<compile-flags>-force:deferparse -args summary -endargs</compile-flags>
13321332
</default>
13331333
</test>
1334+
<test>
1335+
<default>
1336+
<files>bug_issue_1496.js</files>
1337+
<compile-flags>-mic:1 -maxsimplejitruncount:2</compile-flags>
1338+
<baseline>bug_issue_1496.baseline</baseline>
1339+
<tags>BugFix</tags>
1340+
</default>
1341+
</test>
13341342
</regress-exe>

0 commit comments

Comments
 (0)