Skip to content

Commit 1c4ede3

Browse files
committed
Experimental Internal Commands
1 parent 8b38076 commit 1c4ede3

22 files changed

+1752
-1576
lines changed

lib/Common/ConfigFlagsList.h

+1
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,7 @@ FLAGR(Boolean, SkipSplitOnNoResult, "If the result of Regex split isn't used, sk
11021102
FLAGNR(String, TestEtwDll , "Path of the TestEtwEventSink DLL", nullptr)
11031103
#endif
11041104
#ifdef ENABLE_TEST_HOOKS
1105+
FLAGNR(Boolean, EnableInternalCommands, "Enable certain internal instructions within JS files - intended for library code only," , false)
11051106
FLAGNR(Boolean, Force32BitByteCode, "Force CC to generate 32bit bytecode intended only for regenerating bytecode headers.", false)
11061107
#endif
11071108

lib/Parser/Parse.cpp

+93
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ Parser::Parser(Js::ScriptContext* scriptContext, BOOL strictMode, PageAllocator
128128

129129
// init PID members
130130
InitPids();
131+
132+
#ifdef ENABLE_TEST_HOOKS
133+
if (scriptContext->GetConfig()->IsInternalCommandsEnabled())
134+
{
135+
InitInternalCommandPids();
136+
}
137+
#endif
131138
}
132139

133140
Parser::~Parser(void)
@@ -2626,6 +2633,74 @@ void Parser::CheckForDuplicateExportEntry(ModuleImportOrExportEntryList* exportE
26262633
}
26272634
}
26282635

2636+
#ifdef ENABLE_TEST_HOOKS
2637+
template<bool buildAST>
2638+
ParseNodePtr Parser::ParseInternalCommand()
2639+
{
2640+
this->GetScanner()->Scan();
2641+
if (m_token.tk != tkID)
2642+
{
2643+
Error(ERRTokenAfter, GetTokenString(m_token.tk), _u("@@"));
2644+
}
2645+
charcount_t ichMin = this->GetScanner()->IchMinTok();
2646+
2647+
// find the command type
2648+
InternalCommandType type;
2649+
IdentPtr id = m_token.GetIdentifier(GetHashTbl());
2650+
2651+
if (id == internalCommandPids.Conv_Num)
2652+
{
2653+
type = InternalCommandType::Conv_Num;
2654+
}
2655+
else if (id == internalCommandPids.Conv_Obj)
2656+
{
2657+
type = InternalCommandType::Conv_Obj;
2658+
}
2659+
else
2660+
{
2661+
Error(ERRTokenAfter, m_token.GetIdentifier(GetHashTbl())->Psz(), _u("@@"));
2662+
}
2663+
2664+
// parse the parameters - currently only accept identifiers
2665+
this->GetScanner()->Scan();
2666+
ChkCurTok(tkLParen, ERRnoLparen);
2667+
ParseNodePtr params = nullptr;
2668+
ParseNodePtr * lastParam = nullptr;
2669+
ParseNodePtr currentParam = nullptr;
2670+
2671+
for (;;)
2672+
{
2673+
currentParam = ParseExpr<buildAST>(0);
2674+
if (buildAST)
2675+
{
2676+
AddToNodeListEscapedUse(&params, &lastParam, currentParam);
2677+
}
2678+
2679+
if (m_token.tk == tkComma)
2680+
{
2681+
this->GetScanner()->Scan();
2682+
}
2683+
else if (m_token.tk == tkRParen)
2684+
{
2685+
this->GetScanner()->Scan();
2686+
break;
2687+
}
2688+
else
2689+
{
2690+
Error(ERRTokenAfter, GetTokenString(m_token.tk), GetTokenString(this->GetScanner()->GetPrevious()));
2691+
}
2692+
}
2693+
2694+
ParseNodePtr command = nullptr;
2695+
if (buildAST)
2696+
{
2697+
command = Anew(&m_nodeAllocator, ParseNodeInternalCommand, ichMin, this->GetScanner()->IchLimTok(), type, params);
2698+
}
2699+
2700+
return command;
2701+
}
2702+
#endif
2703+
26292704
template<bool buildAST>
26302705
void Parser::ParseImportClause(ModuleImportOrExportEntryList* importEntryList, bool parsingAfterComma)
26312706
{
@@ -3744,6 +3819,16 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
37443819
}
37453820
break;
37463821

3822+
#ifdef ENABLE_TEST_HOOKS
3823+
case tkIntCommand:
3824+
if (!m_scriptContext->GetConfig()->IsInternalCommandsEnabled())
3825+
{
3826+
Error(ERRTokenAfter, _u("@@"), GetTokenString(GetScanner()->GetPrevious()));
3827+
}
3828+
pnode = ParseInternalCommand<buildAST>();
3829+
break;
3830+
#endif
3831+
37473832
#if ENABLE_BACKGROUND_PARSING
37483833
case tkCASE:
37493834
{
@@ -11775,6 +11860,14 @@ void Parser::InitPids()
1177511860
wellKnownPropertyPids._importMeta = this->GetHashTbl()->PidHashNameLen(_u("*import.meta*"), sizeof("*import.meta*") - 1);
1177611861
}
1177711862

11863+
#ifdef ENABLE_TEST_HOOKS
11864+
void Parser::InitInternalCommandPids()
11865+
{
11866+
internalCommandPids.Conv_Num = this->GetHashTbl()->PidHashNameLen(_u("Conv_Num"), sizeof("Conv_Num") - 1);
11867+
internalCommandPids.Conv_Obj = this->GetHashTbl()->PidHashNameLen(_u("Conv_Obj"), sizeof("Conv_Obj") - 1);
11868+
}
11869+
#endif
11870+
1177811871
void Parser::RestoreScopeInfo(Js::ScopeInfo * scopeInfo)
1177911872
{
1178011873
if (!scopeInfo)

lib/Parser/Parse.h

+17
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ class Parser
342342

343343
void InitPids();
344344

345+
#ifdef ENABLE_TEST_HOOKS
346+
void InitInternalCommandPids();
347+
#endif
348+
345349
/***********************************************************************
346350
Members needed just for parsing.
347351
***********************************************************************/
@@ -504,6 +508,15 @@ class Parser
504508

505509
WellKnownPropertyPids wellKnownPropertyPids;
506510

511+
#ifdef ENABLE_TEST_HOOKS
512+
struct InternalCommandPids
513+
{
514+
IdentPtr Conv_Num;
515+
IdentPtr Conv_Obj;
516+
};
517+
InternalCommandPids internalCommandPids;
518+
#endif
519+
507520
charcount_t m_sourceLim; // The actual number of characters parsed.
508521

509522
Js::ParseableFunctionInfo* m_functionBody; // For a deferred parsed function, the function body is non-null
@@ -975,6 +988,10 @@ class Parser
975988
charcount_t ichMin,
976989
_Out_opt_ BOOL* pfCanAssign = nullptr);
977990

991+
#ifdef ENABLE_TEST_HOOKS
992+
template<bool buildAST> ParseNodePtr ParseInternalCommand();
993+
#endif
994+
978995
void CheckIfImportOrExportStatementValidHere();
979996
bool IsTopLevelModuleFunc();
980997

lib/Parser/Scan.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -2195,6 +2195,16 @@ tokens Scanner<EncodingPolicy>::ScanCore(bool identifyKwds)
21952195
token = this->ScanStringConstant((OLECHAR)ch, &pchT);
21962196
p = pchT;
21972197
break;
2198+
#ifdef ENABLE_TEST_HOOKS
2199+
case '@':
2200+
if(!this->PeekFirst(p,last) == '@')
2201+
{
2202+
goto LDefault;
2203+
}
2204+
p++;
2205+
token = tkIntCommand;
2206+
break;
2207+
#endif
21982208
}
21992209

22002210
break;

lib/Parser/kwd-lsc.h

+3
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ TOK_DCL(tkEllipsis , No, knopNone ,Spr, knopEllipsis ) // ...
173173
TOK_DCL(tkLParen , No, knopNone , No, knopNone ) // (
174174
TOK_DCL(tkLBrack , No, knopNone , No, knopNone ) // [
175175
TOK_DCL(tkDot , No, knopNone , No, knopNone ) // .
176+
#ifdef ENABLE_TEST_HOOKS
177+
TOK_DCL(tkIntCommand , No, knopNone , No, knopNone ) //@@
178+
#endif
176179

177180
// String template tokens
178181
TOK_DCL(tkStrTmplBasic , No, knopNone , No, knopNone ) // `...`

lib/Parser/pnodewalk.h

+4
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,10 @@ class ParseNodeWalker : public WalkerPolicy
536536
case knopExportDefault:
537537
return Walk(pnode->AsParseNodeExportDefault()->pnodeExpr, context);
538538

539+
#ifdef ENABLE_TEST_HOOKS
540+
case knopIntCommand:
541+
return Walk(pnode->AsParseNodeInternalCommand()->params, context);
542+
#endif
539543
default:
540544
{
541545
uint fnop = ParseNode::Grfnop(pnode->nop);

lib/Parser/ptlist.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ PTNODE(knopObjectPatternMember, "{:} = " , Nop , Bin , fnopBin
155155
PTNODE(knopArrayPattern, "[] = " , Nop , ArrLit , fnopUni , "ArrayAssignmentPattern" )
156156
PTNODE(knopParamPattern, "({[]})" , Nop , ParamPattern, fnopUni , "DestructurePattern" )
157157
PTNODE(knopExportDefault, "export default" , Nop , ExportDefault,fnopNone , "ExportDefault" )
158-
159-
158+
#ifdef ENABLE_TEST_HOOKS
159+
PTNODE(knopIntCommand, "intCommand" , Nop , None , fnopNone , "Internal Command" )
160+
#endif
160161
#undef PTNODE
161162
#undef OP

lib/Parser/ptree.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ ParseNodeModule * ParseNode::AsParseNodeModule()
263263
return reinterpret_cast<ParseNodeModule*>(this);
264264
}
265265

266+
#ifdef ENABLE_TEST_HOOKS
267+
ParseNodeInternalCommand * ParseNode::AsParseNodeInternalCommand()
268+
{
269+
Assert(this->nop == knopIntCommand);
270+
return reinterpret_cast<ParseNodeInternalCommand *>(this);
271+
}
272+
#endif
273+
266274
IdentPtr ParseNode::name()
267275
{
268276
if (this->nop == knopStr)

lib/Parser/ptree.h

+28
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ class ParseNodeForInOrForOf;
110110
class ParseNodeFnc;
111111
class ParseNodeProg;
112112
class ParseNodeModule;
113+
#ifdef ENABLE_TEST_HOOKS
114+
class ParseNodeInternalCommand;
115+
#endif
116+
113117

114118
class ParseNode
115119
{
@@ -163,6 +167,10 @@ class ParseNode
163167
ParseNodeProg * AsParseNodeProg();
164168
ParseNodeModule * AsParseNodeModule();
165169

170+
#ifdef ENABLE_TEST_HOOKS
171+
ParseNodeInternalCommand * AsParseNodeInternalCommand();
172+
#endif
173+
166174
static uint Grfnop(int nop)
167175
{
168176
Assert(nop < knopLim);
@@ -434,6 +442,26 @@ class ParseNodeObjLit : public ParseNodeUni
434442
DISABLE_SELF_CAST(ParseNodeObjLit);
435443
};
436444

445+
#ifdef ENABLE_TEST_HOOKS
446+
447+
typedef enum InternalCommandType
448+
{
449+
Conv_Num,
450+
Conv_Obj
451+
} InternalCommandType;
452+
453+
class ParseNodeInternalCommand : public ParseNode
454+
{
455+
public:
456+
ParseNodeInternalCommand(charcount_t ichMin, charcount_t ichLim, InternalCommandType type, ParseNodePtr parameters) :
457+
commandType(type), params(parameters), ParseNode(knopIntCommand, ichMin, ichLim) {}
458+
459+
InternalCommandType commandType;
460+
ParseNodePtr params;
461+
};
462+
#endif
463+
464+
437465
class FuncInfo;
438466

439467
enum PnodeBlockType : unsigned

lib/Runtime/Base/ThreadConfigFlagsList.h

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ FLAG_RELEASE(IsESSymbolDescriptionEnabled, ESSymbolDescription)
5555
FLAG_RELEASE(IsESGlobalThisEnabled, ESGlobalThis)
5656
FLAG_RELEASE(IsES2018AsyncIterationEnabled, ES2018AsyncIteration)
5757
#ifdef ENABLE_TEST_HOOKS
58+
FLAG_RELEASE(IsInternalCommandsEnabled, EnableInternalCommands)
5859
FLAG_RELEASE(Force32BitByteCode, Force32BitByteCode)
5960
#endif
6061
#ifdef ENABLE_PROJECTION

lib/Runtime/ByteCode/ByteCodeCacheReleaseFileVersion.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// NOTE: If there is a merge conflict the correct fix is to make a new GUID.
66
// This file was generated with tools/xplatRegenByteCode.py
77

8-
// {51f0edaa-63a2-4d76-bcac-160b8dd6c2ad}
8+
// {45bcaca5-bf94-42fc-aec0-6eab7fc28e68}
99
const GUID byteCodeCacheReleaseFileVersion =
10-
{ 0x51f0edaa, 0x63a2, 0x4d76, {0xbc, 0xac, 0x16, 0x0b, 0x8d, 0xd6, 0xc2, 0xad } };
10+
{ 0x45bcaca5, 0xbf94, 0x42fc, {0xae, 0xc0, 0x6e, 0xab, 0x7f, 0xc2, 0x8e, 0x68 } };

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -12295,6 +12295,33 @@ void Emit(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* func
1229512295
funcInfo->ReleaseLoc(pnode->AsParseNodeExportDefault()->pnodeExpr);
1229612296
pnode = pnode->AsParseNodeExportDefault()->pnodeExpr;
1229712297
break;
12298+
#ifdef ENABLE_TEST_HOOKS
12299+
case knopIntCommand:
12300+
{
12301+
byteCodeGenerator->StartStatement(pnode);
12302+
funcInfo->AcquireLoc(pnode);
12303+
ParseNodeInternalCommand* command = pnode->AsParseNodeInternalCommand();
12304+
ParseNode* params = command->params;
12305+
//ParseNode* param1 = params->AsParseNodeBin()->pnode1;
12306+
Emit(params, byteCodeGenerator, funcInfo, false);
12307+
12308+
switch (command->commandType)
12309+
{
12310+
case InternalCommandType::Conv_Num:
12311+
byteCodeGenerator->Writer()->Reg2(Js::OpCode::Conv_Num, pnode->location, params->location);
12312+
break;
12313+
case InternalCommandType::Conv_Obj:
12314+
byteCodeGenerator->Writer()->Reg2(Js::OpCode::Conv_Obj, pnode->location, params->location);
12315+
break;
12316+
12317+
default:
12318+
AssertOrFailFast(0);
12319+
}
12320+
funcInfo->ReleaseLoc(params);
12321+
byteCodeGenerator->EndStatement(pnode);
12322+
break;
12323+
}
12324+
#endif
1229812325
default:
1229912326
AssertMsg(0, "emit unhandled pnode op");
1230012327
break;

lib/Runtime/ByteCode/ByteCodeGenerator.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,13 @@ void Visit(ParseNode *pnode, ByteCodeGenerator* byteCodeGenerator, PrefixFn pref
326326
Visit(pnode->AsParseNodeStrTemplate()->pnodeSubstitutionExpressions, byteCodeGenerator, prefix, postfix);
327327
break;
328328
}
329+
#ifdef ENABLE_TEST_HOOKS
330+
case knopIntCommand:
331+
{
332+
Visit(pnode->AsParseNodeInternalCommand()->params, byteCodeGenerator, prefix, postfix);
333+
break;
334+
}
335+
#endif
329336
case knopExportDefault:
330337
Visit(pnode->AsParseNodeExportDefault()->pnodeExpr, byteCodeGenerator, prefix, postfix);
331338
break;

lib/Runtime/Library/InJavascript/GenByteCode.cmd

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ call :Generate %1 %_BinLocation%\x64_debug %1%_suffix%.bc.64b.h
7676
exit /B 0
7777

7878
:Generate
79-
%2\%_binary% -GenerateLibraryByteCodeHeader:%3 -Intl %1
79+
%2\%_binary% -GenerateLibraryByteCodeHeader:%3 -Intl -EnableInternalCommands%1
8080
if "%errorlevel%" NEQ "0" (
8181
echo %1: Error generating bytecode file. Ensure %3 writable.
8282
set _HASERROR=1

lib/Runtime/Library/JsBuiltIn/GenByteCode.cmd

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ call :Generate %1 %_BinLocation%\x64_debug %1%_suffix%.bc.64b.h
7676
exit /B 0
7777

7878
:Generate
79-
%2\%_binary% -GenerateLibraryByteCodeHeader:%3 -JsBuiltIn -LdChakraLib %1
79+
%2\%_binary% -GenerateLibraryByteCodeHeader:%3 -JsBuiltIn -LdChakraLib -EnableInternalCommands %1
8080
if "%errorlevel%" NEQ "0" (
8181
echo %1: Error generating bytecode file. Ensure %3 writable.
8282
set _HASERROR=1

lib/Runtime/Library/JsBuiltIn/JsBuiltIn.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,23 @@
9696
if (this === null || this === undefined) {
9797
__chakraLibrary.raiseThis_NullOrUndefined("Array.prototype.keys");
9898
}
99-
let o = __chakraLibrary.Object(this);
99+
let o = @@Conv_Obj(this);
100100
return __chakraLibrary.CreateArrayIterator(o, 0 /* ArrayIterationKind.Key*/);
101101
});
102102

103103
platform.registerFunction(platform.FunctionKind.Array_values, function () {
104104
if (this === null || this === undefined) {
105105
__chakraLibrary.raiseThis_NullOrUndefined("Array.prototype.values");
106106
}
107-
let o = __chakraLibrary.Object(this);
107+
let o = @@Conv_Obj(this);
108108
return __chakraLibrary.CreateArrayIterator(o, 1 /* ArrayIterationKind.Value*/);
109109
});
110110

111111
platform.registerFunction(platform.FunctionKind.Array_entries, function () {
112112
if (this === null || this === undefined) {
113113
__chakraLibrary.raiseThis_NullOrUndefined("Array.prototype.entries");
114114
}
115-
let o = __chakraLibrary.Object(this);
115+
let o = @@Conv_Obj(this);
116116
return __chakraLibrary.CreateArrayIterator(o, 2 /* ArrayIterationKind.KeyAndValue*/);
117117
});
118118

@@ -170,7 +170,7 @@
170170
if (obj === null || obj === undefined) {
171171
__chakraLibrary.raiseThis_NullOrUndefined(builtInFunc);
172172
}
173-
return { o: __chakraLibrary.Object(obj), len: __chakraLibrary.toLength(obj["length"]) };
173+
return { o: @@Conv_Obj(obj), len: __chakraLibrary.toLength(obj["length"]) };
174174
}
175175
});
176176

0 commit comments

Comments
 (0)