|
|
|
|
| 26 |
#include "jsversion.h" |
26 |
#include "jsversion.h" |
| 27 |
#include "jsfun.h" |
27 |
#include "jsfun.h" |
| 28 |
#include "jsnum.h" |
28 |
#include "jsnum.h" |
| 29 |
#include "jsopcode.h" |
29 |
#include "jsopcode.h" |
| 30 |
#include "jsscope.h" |
30 |
#include "jsscope.h" |
| 31 |
#include "jsscript.h" |
31 |
#include "jsscript.h" |
| 32 |
#include "jsautooplen.h" // generated headers last |
32 |
#include "jsautooplen.h" // generated headers last |
| 33 |
|
33 |
|
|
|
34 |
#include "builtin/Module.h" |
| 34 |
#include "ds/LifoAlloc.h" |
35 |
#include "ds/LifoAlloc.h" |
| 35 |
#include "frontend/BytecodeEmitter.h" |
36 |
#include "frontend/BytecodeEmitter.h" |
| 36 |
#include "frontend/Parser.h" |
37 |
#include "frontend/Parser.h" |
| 37 |
#include "frontend/TokenStream.h" |
38 |
#include "frontend/TokenStream.h" |
| 38 |
#include "vm/Debugger.h" |
39 |
#include "vm/Debugger.h" |
| 39 |
#include "vm/RegExpObject.h" |
40 |
#include "vm/RegExpObject.h" |
| 40 |
|
41 |
|
| 41 |
#include "jsatominlines.h" |
42 |
#include "jsatominlines.h" |
|
Lines 695-716
PushStatementBCE(BytecodeEmitter *bce, S
|
Link Here
|
|---|
|
| 695 |
* block object or compiler created function. |
696 |
* block object or compiler created function. |
| 696 |
*/ |
697 |
*/ |
| 697 |
static JSObject * |
698 |
static JSObject * |
| 698 |
EnclosingStaticScope(BytecodeEmitter *bce) |
699 |
EnclosingStaticScope(BytecodeEmitter *bce) |
| 699 |
{ |
700 |
{ |
| 700 |
if (bce->blockChain) |
701 |
if (bce->blockChain) |
| 701 |
return bce->blockChain; |
702 |
return bce->blockChain; |
| 702 |
|
703 |
|
| 703 |
if (!bce->sc->isFunctionBox()) { |
704 |
if (bce->sc->isGlobalSharedContext()) { |
| 704 |
JS_ASSERT(!bce->parent); |
705 |
JS_ASSERT(!bce->parent); |
| 705 |
return NULL; |
706 |
return NULL; |
| 706 |
} |
707 |
} else if (bce->sc->isModuleBox()) { |
| 707 |
|
708 |
return bce->sc->asModuleBox()->module(); |
| 708 |
return bce->sc->asFunctionBox()->function(); |
709 |
} else { |
|
|
710 |
return bce->sc->asFunctionBox()->function(); |
| 711 |
} |
| 709 |
} |
712 |
} |
| 710 |
|
713 |
|
| 711 |
// Push a block scope statement and link blockObj into bce->blockChain. |
714 |
// Push a block scope statement and link blockObj into bce->blockChain. |
| 712 |
static void |
715 |
static void |
| 713 |
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj, |
716 |
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj, |
| 714 |
ptrdiff_t top) |
717 |
ptrdiff_t top) |
| 715 |
{ |
718 |
{ |
| 716 |
PushStatementBCE(bce, stmt, STMT_BLOCK, top); |
719 |
PushStatementBCE(bce, stmt, STMT_BLOCK, top); |
|
Lines 958-974
EmitAliasedVarOp(JSContext *cx, JSOp op,
|
Link Here
|
|---|
|
| 958 |
} |
961 |
} |
| 959 |
|
962 |
|
| 960 |
return EmitAliasedVarOp(cx, op, sc, bce); |
963 |
return EmitAliasedVarOp(cx, op, sc, bce); |
| 961 |
} |
964 |
} |
| 962 |
|
965 |
|
| 963 |
static bool |
966 |
static bool |
| 964 |
EmitVarOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) |
967 |
EmitVarOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) |
| 965 |
{ |
968 |
{ |
| 966 |
JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME)); |
969 |
JS_ASSERT(pn->isKind(PNK_MODULE) || pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME)); |
| 967 |
JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op)); |
970 |
JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op)); |
| 968 |
JS_ASSERT(!pn->pn_cookie.isFree()); |
971 |
JS_ASSERT(!pn->pn_cookie.isFree()); |
| 969 |
|
972 |
|
| 970 |
if (!bce->isAliasedName(pn)) { |
973 |
if (!bce->isAliasedName(pn)) { |
| 971 |
JS_ASSERT(pn->isUsed() || pn->isDefn()); |
974 |
JS_ASSERT(pn->isUsed() || pn->isDefn()); |
| 972 |
JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0); |
975 |
JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0); |
| 973 |
JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel); |
976 |
JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel); |
| 974 |
return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), bce); |
977 |
return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), bce); |
|
Lines 1441-1457
BindNameToSlot(JSContext *cx, BytecodeEm
|
Link Here
|
|---|
|
| 1441 |
* bloat where a single live function keeps its whole global script |
1444 |
* bloat where a single live function keeps its whole global script |
| 1442 |
* alive.), ScopeCoordinateToTypeSet is not able to find the var/let's |
1445 |
* alive.), ScopeCoordinateToTypeSet is not able to find the var/let's |
| 1443 |
* associated types::TypeSet. |
1446 |
* associated types::TypeSet. |
| 1444 |
*/ |
1447 |
*/ |
| 1445 |
if (skip) { |
1448 |
if (skip) { |
| 1446 |
BytecodeEmitter *bceSkipped = bce; |
1449 |
BytecodeEmitter *bceSkipped = bce; |
| 1447 |
for (unsigned i = 0; i < skip; i++) |
1450 |
for (unsigned i = 0; i < skip; i++) |
| 1448 |
bceSkipped = bceSkipped->parent; |
1451 |
bceSkipped = bceSkipped->parent; |
| 1449 |
if (!bceSkipped->sc->isFunctionBox()) |
1452 |
if (bceSkipped->sc->isGlobalSharedContext()) |
| 1450 |
return true; |
1453 |
return true; |
| 1451 |
} |
1454 |
} |
| 1452 |
|
1455 |
|
| 1453 |
JS_ASSERT(!pn->isOp(op)); |
1456 |
JS_ASSERT(!pn->isOp(op)); |
| 1454 |
pn->setOp(op); |
1457 |
pn->setOp(op); |
| 1455 |
if (!pn->pn_cookie.set(bce->sc->context, skip, dn->pn_cookie.slot())) |
1458 |
if (!pn->pn_cookie.set(bce->sc->context, skip, dn->pn_cookie.slot())) |
| 1456 |
return false; |
1459 |
return false; |
| 1457 |
|
1460 |
|
|
Lines 1694-1710
BytecodeEmitter::needsImplicitThis()
|
Link Here
|
|---|
|
| 1694 |
return true; |
1697 |
return true; |
| 1695 |
} |
1698 |
} |
| 1696 |
return false; |
1699 |
return false; |
| 1697 |
} |
1700 |
} |
| 1698 |
|
1701 |
|
| 1699 |
void |
1702 |
void |
| 1700 |
BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext *cx) |
1703 |
BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext *cx) |
| 1701 |
{ |
1704 |
{ |
| 1702 |
RootedFunction function(cx, script->function()); |
1705 |
RootedFunction function(cx, script->isFunctionScript() ? script->function() : NULL); |
| 1703 |
CallNewScriptHook(cx, script, function); |
1706 |
CallNewScriptHook(cx, script, function); |
| 1704 |
if (!parent) { |
1707 |
if (!parent) { |
| 1705 |
GlobalObject *compileAndGoGlobal = NULL; |
1708 |
GlobalObject *compileAndGoGlobal = NULL; |
| 1706 |
if (script->compileAndGo) |
1709 |
if (script->compileAndGo) |
| 1707 |
compileAndGoGlobal = &script->global(); |
1710 |
compileAndGoGlobal = &script->global(); |
| 1708 |
Debugger::onNewScript(cx, script, compileAndGoGlobal); |
1711 |
Debugger::onNewScript(cx, script, compileAndGoGlobal); |
| 1709 |
} |
1712 |
} |
| 1710 |
} |
1713 |
} |
|
|
| 4779 |
EmitFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) |
4782 |
EmitFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) |
| 4780 |
{ |
4783 |
{ |
| 4781 |
JS_ASSERT(pn->pn_left->isKind(PNK_FORIN) || pn->pn_left->isKind(PNK_FORHEAD)); |
4784 |
JS_ASSERT(pn->pn_left->isKind(PNK_FORIN) || pn->pn_left->isKind(PNK_FORHEAD)); |
| 4782 |
return pn->pn_left->isKind(PNK_FORIN) |
4785 |
return pn->pn_left->isKind(PNK_FORIN) |
| 4783 |
? EmitForIn(cx, bce, pn, top) |
4786 |
? EmitForIn(cx, bce, pn, top) |
| 4784 |
: EmitNormalFor(cx, bce, pn, top); |
4787 |
: EmitNormalFor(cx, bce, pn, top); |
| 4785 |
} |
4788 |
} |
| 4786 |
|
4789 |
|
|
|
4790 |
static bool |
| 4791 |
EmitModule(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) |
| 4792 |
{ |
| 4793 |
if (pn->pn_modulebox->module()->script()) { |
| 4794 |
return EmitIndex32(cx, JSOP_INITMODULE, |
| 4795 |
bce->objectList.indexOf(pn->pn_modulebox->module()), |
| 4796 |
bce); |
| 4797 |
} |
| 4798 |
|
| 4799 |
RootedScript enclosingScript(cx, bce->script); |
| 4800 |
RootedObject enclosingScope(cx, EnclosingStaticScope(bce)); |
| 4801 |
CompileOptions options(cx); |
| 4802 |
options.setPrincipals(enclosingScript->principals) |
| 4803 |
.setOriginPrincipals(enclosingScript->originPrincipals) |
| 4804 |
.setCompileAndGo(enclosingScript->compileAndGo) |
| 4805 |
.setNoScriptRval(false) |
| 4806 |
.setVersion(enclosingScript->getVersion()); |
| 4807 |
RootedScript script(cx, JSScript::Create(cx, enclosingScope, false, options, |
| 4808 |
enclosingScript->staticLevel + 1, |
| 4809 |
enclosingScript->scriptSource(), |
| 4810 |
pn->pn_modulebox->bufStart, |
| 4811 |
pn->pn_modulebox->bufEnd)); |
| 4812 |
if (!script) |
| 4813 |
return false; |
| 4814 |
script->bindings = pn->pn_modulebox->bindings; |
| 4815 |
BytecodeEmitter bce2(bce, bce->parser, pn->pn_modulebox, script, |
| 4816 |
bce->callerFrame, bce->hasGlobalScope, |
| 4817 |
pn->pn_pos.begin.lineno, bce->selfHostingMode); |
| 4818 |
if (!bce2.init()) |
| 4819 |
return false; |
| 4820 |
if (!EmitTree(cx, &bce2, pn->pn_body)) |
| 4821 |
return false; |
| 4822 |
if (Emit1(cx, &bce2, JSOP_STOP) < 0) |
| 4823 |
return false; |
| 4824 |
if (!JSScript::fullyInitFromEmitter(cx, bce2.script, &bce2)) |
| 4825 |
return false; |
| 4826 |
pn->pn_modulebox->module()->setScript(script); |
| 4827 |
|
| 4828 |
if (bce->sc->isGlobalSharedContext()) { |
| 4829 |
unsigned index = bce->objectList.add(pn->pn_modulebox); |
| 4830 |
bce->switchToProlog(); |
| 4831 |
if (!EmitIndex32(cx, JSOP_DEFMODULE, index, bce)) |
| 4832 |
return false; |
| 4833 |
bce->switchToMain(); |
| 4834 |
if (!EmitIndex32(cx, JSOP_INITMODULE, index, bce)) |
| 4835 |
return false; |
| 4836 |
} else { |
| 4837 |
JS_ASSERT(bce->sc->isModuleBox()); |
| 4838 |
if (!EmitObjectOp(cx, pn->pn_modulebox, JSOP_MODULE, bce)) |
| 4839 |
return false; |
| 4840 |
if (!EmitVarOp(cx, pn, JSOP_SETLOCAL, bce)) |
| 4841 |
return false; |
| 4842 |
if (Emit1(cx, bce, JSOP_POP) < 0) |
| 4843 |
return false; |
| 4844 |
} |
| 4845 |
return true; |
| 4846 |
} |
| 4847 |
|
| 4787 |
static JS_NEVER_INLINE bool |
4848 |
static JS_NEVER_INLINE bool |
| 4788 |
EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) |
4849 |
EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) |
| 4789 |
{ |
4850 |
{ |
| 4790 |
AssertCanGC(); |
4851 |
AssertCanGC(); |
| 4791 |
RootedFunction fun(cx, pn->pn_funbox->function()); |
4852 |
RootedFunction fun(cx, pn->pn_funbox->function()); |
| 4792 |
JS_ASSERT(fun->isInterpreted()); |
4853 |
JS_ASSERT(fun->isInterpreted()); |
| 4793 |
if (fun->hasScript()) { |
4854 |
if (fun->hasScript()) { |
| 4794 |
/* |
4855 |
/* |
|
Lines 4853-4869
EmitFunc(JSContext *cx, BytecodeEmitter
|
Link Here
|
|---|
|
| 4853 |
* For a script we emit the code as we parse. Thus the bytecode for |
4914 |
* For a script we emit the code as we parse. Thus the bytecode for |
| 4854 |
* top-level functions should go in the prolog to predefine their |
4915 |
* top-level functions should go in the prolog to predefine their |
| 4855 |
* names in the variable object before the already-generated main code |
4916 |
* names in the variable object before the already-generated main code |
| 4856 |
* is executed. This extra work for top-level scripts is not necessary |
4917 |
* is executed. This extra work for top-level scripts is not necessary |
| 4857 |
* when we emit the code for a function. It is fully parsed prior to |
4918 |
* when we emit the code for a function. It is fully parsed prior to |
| 4858 |
* invocation of the emitter and calls to EmitTree for function |
4919 |
* invocation of the emitter and calls to EmitTree for function |
| 4859 |
* definitions can be scheduled before generating the rest of code. |
4920 |
* definitions can be scheduled before generating the rest of code. |
| 4860 |
*/ |
4921 |
*/ |
| 4861 |
if (!bce->sc->isFunctionBox()) { |
4922 |
if (bce->sc->isGlobalSharedContext()) { |
| 4862 |
JS_ASSERT(pn->pn_cookie.isFree()); |
4923 |
JS_ASSERT(pn->pn_cookie.isFree()); |
| 4863 |
JS_ASSERT(pn->getOp() == JSOP_NOP); |
4924 |
JS_ASSERT(pn->getOp() == JSOP_NOP); |
| 4864 |
JS_ASSERT(!bce->topStmt); |
4925 |
JS_ASSERT(!bce->topStmt); |
| 4865 |
bce->switchToProlog(); |
4926 |
bce->switchToProlog(); |
| 4866 |
if (!EmitIndex32(cx, JSOP_DEFFUN, index, bce)) |
4927 |
if (!EmitIndex32(cx, JSOP_DEFFUN, index, bce)) |
| 4867 |
return false; |
4928 |
return false; |
| 4868 |
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin)) |
4929 |
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin)) |
| 4869 |
return false; |
4930 |
return false; |
|
Lines 5955-5970
frontend::EmitTree(JSContext *cx, Byteco
|
Link Here
|
|---|
|
| 5955 |
ptrdiff_t top = bce->offset(); |
6016 |
ptrdiff_t top = bce->offset(); |
| 5956 |
pn->pn_offset = top; |
6017 |
pn->pn_offset = top; |
| 5957 |
|
6018 |
|
| 5958 |
/* Emit notes to tell the current bytecode's source line number. */ |
6019 |
/* Emit notes to tell the current bytecode's source line number. */ |
| 5959 |
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno)) |
6020 |
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno)) |
| 5960 |
return false; |
6021 |
return false; |
| 5961 |
|
6022 |
|
| 5962 |
switch (pn->getKind()) { |
6023 |
switch (pn->getKind()) { |
|
|
6024 |
case PNK_MODULE: |
| 6025 |
ok = EmitModule(cx, bce, pn); |
| 6026 |
break; |
| 6027 |
|
| 5963 |
case PNK_FUNCTION: |
6028 |
case PNK_FUNCTION: |
| 5964 |
ok = EmitFunc(cx, bce, pn); |
6029 |
ok = EmitFunc(cx, bce, pn); |
| 5965 |
break; |
6030 |
break; |
| 5966 |
|
6031 |
|
| 5967 |
case PNK_ARGSBODY: |
6032 |
case PNK_ARGSBODY: |
| 5968 |
{ |
6033 |
{ |
| 5969 |
RootedFunction fun(cx, bce->sc->asFunctionBox()->function()); |
6034 |
RootedFunction fun(cx, bce->sc->asFunctionBox()->function()); |
| 5970 |
ParseNode *pnlast = pn->last(); |
6035 |
ParseNode *pnlast = pn->last(); |
|
Lines 6140-6155
frontend::EmitTree(JSContext *cx, Byteco
|
Link Here
|
|---|
|
| 6140 |
if (!EmitTree(cx, bce, pn->pn_kid)) |
6205 |
if (!EmitTree(cx, bce, pn->pn_kid)) |
| 6141 |
return false; |
6206 |
return false; |
| 6142 |
if (Emit1(cx, bce, pn->getOp()) < 0) |
6207 |
if (Emit1(cx, bce, pn->getOp()) < 0) |
| 6143 |
return false; |
6208 |
return false; |
| 6144 |
break; |
6209 |
break; |
| 6145 |
#endif |
6210 |
#endif |
| 6146 |
|
6211 |
|
| 6147 |
case PNK_STATEMENTLIST: |
6212 |
case PNK_STATEMENTLIST: |
|
|
6213 |
if (pn->pn_xflags & PNX_MODULEDEFS) { |
| 6214 |
for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { |
| 6215 |
if (pn2->isKind(PNK_MODULE)) { |
| 6216 |
if (!EmitTree(cx, bce, pn2)) |
| 6217 |
return false; |
| 6218 |
} |
| 6219 |
} |
| 6220 |
} |
| 6148 |
ok = EmitStatementList(cx, bce, pn, top); |
6221 |
ok = EmitStatementList(cx, bce, pn, top); |
| 6149 |
break; |
6222 |
break; |
| 6150 |
|
6223 |
|
| 6151 |
case PNK_SEQ: |
6224 |
case PNK_SEQ: |
| 6152 |
ok = EmitSyntheticStatements(cx, bce, pn, top); |
6225 |
ok = EmitSyntheticStatements(cx, bce, pn, top); |
| 6153 |
break; |
6226 |
break; |
| 6154 |
|
6227 |
|
| 6155 |
case PNK_SEMI: |
6228 |
case PNK_SEMI: |
|
Lines 6390-6405
frontend::EmitTree(JSContext *cx, Byteco
|
Link Here
|
|---|
|
| 6390 |
|
6463 |
|
| 6391 |
#if JS_HAS_BLOCK_SCOPE |
6464 |
#if JS_HAS_BLOCK_SCOPE |
| 6392 |
case PNK_LET: |
6465 |
case PNK_LET: |
| 6393 |
ok = pn->isArity(PN_BINARY) |
6466 |
ok = pn->isArity(PN_BINARY) |
| 6394 |
? EmitLet(cx, bce, pn) |
6467 |
? EmitLet(cx, bce, pn) |
| 6395 |
: EmitVariables(cx, bce, pn, InitializeVars); |
6468 |
: EmitVariables(cx, bce, pn, InitializeVars); |
| 6396 |
break; |
6469 |
break; |
| 6397 |
#endif /* JS_HAS_BLOCK_SCOPE */ |
6470 |
#endif /* JS_HAS_BLOCK_SCOPE */ |
|
|
6471 |
|
| 6472 |
case PNK_EXPORT: |
| 6473 |
ok = EmitTree(cx, bce, pn->pn_kid); |
| 6474 |
break; |
| 6475 |
|
| 6398 |
#if JS_HAS_GENERATORS |
6476 |
#if JS_HAS_GENERATORS |
| 6399 |
case PNK_ARRAYPUSH: { |
6477 |
case PNK_ARRAYPUSH: { |
| 6400 |
int slot; |
6478 |
int slot; |
| 6401 |
|
6479 |
|
| 6402 |
/* |
6480 |
/* |
| 6403 |
* The array object's stack index is in bce->arrayCompDepth. See below |
6481 |
* The array object's stack index is in bce->arrayCompDepth. See below |
| 6404 |
* under the array initialiser code generator for array comprehension |
6482 |
* under the array initialiser code generator for array comprehension |
| 6405 |
* special casing. Note that the array object is a pure stack value, |
6483 |
* special casing. Note that the array object is a pure stack value, |