Bug 462300 - Add support for self-hosting syntax and operations (r=luke)

--HG--
extra : rebase_source : 90e33d171ac0b79aebdf2f652909d72dd7ae2601
This commit is contained in:
Till Schneidereit 2012-07-10 00:11:39 +02:00
parent 6988b7f1b0
commit 472c87095c
21 changed files with 209 additions and 31 deletions

View File

@ -1209,7 +1209,7 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
static bool static bool
BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{ {
JS_ASSERT(pn->isKind(PNK_NAME)); JS_ASSERT(pn->isKind(PNK_NAME) || pn->isKind(PNK_INTRINSICNAME));
/* Don't attempt if 'pn' is already bound or deoptimized or a nop. */ /* Don't attempt if 'pn' is already bound or deoptimized or a nop. */
JSOp op = pn->getOp(); JSOp op = pn->getOp();
@ -1746,6 +1746,9 @@ EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool callContext)
case JSOP_NAME: case JSOP_NAME:
op = JSOP_CALLNAME; op = JSOP_CALLNAME;
break; break;
case JSOP_INTRINSICNAME:
op = JSOP_CALLINTRINSIC;
break;
case JSOP_GETGNAME: case JSOP_GETGNAME:
op = JSOP_CALLGNAME; op = JSOP_CALLGNAME;
break; break;
@ -5332,12 +5335,54 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
* value required for calls (which non-strict mode functions * value required for calls (which non-strict mode functions
* will box into the global object). * will box into the global object).
*/ */
uint32_t argc = pn->pn_count - 1;
bool emitArgs = true;
ParseNode *pn2 = pn->pn_head; ParseNode *pn2 = pn->pn_head;
switch (pn2->getKind()) { switch (pn2->getKind()) {
case PNK_NAME: case PNK_NAME:
if (!EmitNameOp(cx, bce, pn2, callop)) if (!EmitNameOp(cx, bce, pn2, callop))
return false; return false;
break; break;
case PNK_INTRINSICNAME:
if (pn2->atom() == cx->runtime->atomState._CallFunctionAtom)
{
/*
* Special-casing of %_CallFunction to emit bytecode that directly
* invokes the callee with the correct |this| object and arguments.
* The call %_CallFunction(receiver, ...args, fun) thus becomes:
* - emit lookup for fun
* - emit lookup for receiver
* - emit lookups for ...args
*
* argc is set to the amount of actually emitted args and the
* emitting of args below is disabled by setting emitArgs to false.
*/
if (pn->pn_count < 3) {
bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "%_CallFunction", "1", "s");
return false;
}
ParseNode *funNode = pn2->pn_next;
while (funNode->pn_next)
funNode = funNode->pn_next;
if (!EmitTree(cx, bce, funNode))
return false;
ParseNode *receiver = pn2->pn_next;
if (!EmitTree(cx, bce, receiver))
return false;
bool oldInForInit = bce->inForInit;
bce->inForInit = false;
for (ParseNode *argpn = receiver->pn_next; argpn != funNode; argpn = argpn->pn_next) {
if (!EmitTree(cx, bce, argpn))
return false;
}
bce->inForInit = oldInForInit;
argc -= 2;
emitArgs = false;
break;
}
if (!EmitNameOp(cx, bce, pn2, callop))
return false;
break;
case PNK_DOT: case PNK_DOT:
if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop)) if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop))
return false; return false;
@ -5364,25 +5409,23 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
if (!callop && Emit1(cx, bce, JSOP_UNDEFINED) < 0) if (!callop && Emit1(cx, bce, JSOP_UNDEFINED) < 0)
return false; return false;
/* Remember start of callable-object bytecode for decompilation hint. */ if (emitArgs) {
ptrdiff_t off = top; /*
* Emit code for each argument in order, then emit the JSOP_*CALL or
/* * JSOP_NEW bytecode with a two-byte immediate telling how many args
* Emit code for each argument in order, then emit the JSOP_*CALL or * were pushed on the operand stack.
* JSOP_NEW bytecode with a two-byte immediate telling how many args */
* were pushed on the operand stack. bool oldInForInit = bce->inForInit;
*/ bce->inForInit = false;
bool oldInForInit = bce->inForInit; for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
bce->inForInit = false; if (!EmitTree(cx, bce, pn3))
for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { return false;
if (!EmitTree(cx, bce, pn3)) }
return false; bce->inForInit = oldInForInit;
} }
bce->inForInit = oldInForInit; if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0)
return false; return false;
uint32_t argc = pn->pn_count - 1;
if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0) if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
return false; return false;
CheckTypeSet(cx, bce, pn->getOp()); CheckTypeSet(cx, bce, pn->getOp());

View File

@ -35,7 +35,7 @@ UpvarCookie::set(JSContext *cx, unsigned newLevel, uint16_t newSlot)
inline PropertyName * inline PropertyName *
ParseNode::atom() const ParseNode::atom() const
{ {
JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME)); JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME) || isKind(PNK_INTRINSICNAME));
JSAtom *atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->atom : pn_atom; JSAtom *atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->atom : pn_atom;
return atom->asPropertyName(); return atom->asPropertyName();
} }

View File

@ -98,6 +98,7 @@ enum ParseNodeKind {
PNK_LP, PNK_LP,
PNK_RP, PNK_RP,
PNK_NAME, PNK_NAME,
PNK_INTRINSICNAME,
PNK_NUMBER, PNK_NUMBER,
PNK_STRING, PNK_STRING,
PNK_REGEXP, PNK_REGEXP,

View File

@ -117,7 +117,8 @@ Parser::Parser(JSContext *cx, const CompileOptions &options,
sct(NULL), sct(NULL),
keepAtoms(cx->runtime), keepAtoms(cx->runtime),
foldConstants(foldConstants), foldConstants(foldConstants),
compileAndGo(options.compileAndGo) compileAndGo(options.compileAndGo),
allowIntrinsicsCalls(options.allowIntrinsicsCalls)
{ {
cx->activeCompilations++; cx->activeCompilations++;
} }
@ -6497,6 +6498,30 @@ Parser::identifierName(bool afterDoubleDot)
return node; return node;
} }
ParseNode *
Parser::intrinsicName()
{
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_MOD));
if (tokenStream.getToken() != TOK_NAME) {
reportError(NULL, JSMSG_SYNTAX_ERROR);
return NULL;
}
PropertyName *name = tokenStream.currentToken().name();
if (!(name == context->runtime->atomState._CallFunctionAtom ||
context->global()->hasIntrinsicFunction(context, name)))
{
reportError(NULL, JSMSG_INTRINSIC_NOT_DEFINED, JS_EncodeString(context, name));
return NULL;
}
ParseNode *node = NameNode::create(PNK_INTRINSICNAME, name, this, this->tc);
if (!node)
return NULL;
JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
node->setOp(JSOP_INTRINSICNAME);
return node;
}
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
ParseNode * ParseNode *
Parser::starOrAtPropertyIdentifier(TokenKind tt) Parser::starOrAtPropertyIdentifier(TokenKind tt)
@ -7054,6 +7079,12 @@ Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
case TOK_NULL: case TOK_NULL:
return new_<NullLiteral>(tokenStream.currentToken().pos); return new_<NullLiteral>(tokenStream.currentToken().pos);
case TOK_MOD:
if (allowIntrinsicsCalls)
return intrinsicName();
else
goto syntaxerror;
case TOK_ERROR: case TOK_ERROR:
/* The scanner or one of its subroutines reported the error. */ /* The scanner or one of its subroutines reported the error. */
return NULL; return NULL;

View File

@ -54,6 +54,12 @@ struct Parser : private AutoGCRooter
/* Script can optimize name references based on scope chain. */ /* Script can optimize name references based on scope chain. */
const bool compileAndGo:1; const bool compileAndGo:1;
/*
* Self-hosted scripts can use the special syntax %funName(..args) to call
* internal functions.
*/
const bool allowIntrinsicsCalls:1;
public: public:
Parser(JSContext *cx, const CompileOptions &options, Parser(JSContext *cx, const CompileOptions &options,
const jschar *chars, size_t length, bool foldConstants); const jschar *chars, size_t length, bool foldConstants);
@ -230,6 +236,7 @@ struct Parser : private AutoGCRooter
bool checkForFunctionNode(PropertyName *name, ParseNode *node); bool checkForFunctionNode(PropertyName *name, ParseNode *node);
ParseNode *identifierName(bool afterDoubleDot); ParseNode *identifierName(bool afterDoubleDot);
ParseNode *intrinsicName();
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
// True if E4X syntax is allowed in the current syntactic context. Note this // True if E4X syntax is allowed in the current syntactic context. Note this

View File

@ -352,3 +352,4 @@ MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' p
MSG_DEF(JSMSG_REST_WITH_DEFAULT, 299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default") MSG_DEF(JSMSG_REST_WITH_DEFAULT, 299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default") MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default")
MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression")
MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")

View File

@ -570,6 +570,8 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
case JSOP_RETRVAL: case JSOP_RETRVAL:
case JSOP_GETGNAME: case JSOP_GETGNAME:
case JSOP_CALLGNAME: case JSOP_CALLGNAME:
case JSOP_INTRINSICNAME:
case JSOP_CALLINTRINSIC:
case JSOP_SETGNAME: case JSOP_SETGNAME:
case JSOP_REGEXP: case JSOP_REGEXP:
case JSOP_OBJECT: case JSOP_OBJECT:

View File

@ -5067,7 +5067,8 @@ JS::CompileOptions::CompileOptions(JSContext *cx)
filename(NULL), filename(NULL),
lineno(1), lineno(1),
compileAndGo(cx->hasRunOption(JSOPTION_COMPILE_N_GO)), compileAndGo(cx->hasRunOption(JSOPTION_COMPILE_N_GO)),
noScriptRval(cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL)) noScriptRval(cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL)),
allowIntrinsicsCalls(false)
{ {
} }

View File

@ -4090,7 +4090,7 @@ struct JSClass {
* with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
* prevously allowed, but is now an ES5 violation and thus unsupported. * prevously allowed, but is now an ES5 violation and thus unsupported.
*/ */
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 23) #define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 24)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \ #define JSCLASS_GLOBAL_FLAGS \
@ -4962,6 +4962,7 @@ struct CompileOptions {
unsigned lineno; unsigned lineno;
bool compileAndGo; bool compileAndGo;
bool noScriptRval; bool noScriptRval;
bool allowIntrinsicsCalls;
CompileOptions(JSContext *cx); CompileOptions(JSContext *cx);
CompileOptions &setPrincipals(JSPrincipals *p) { principals = p; return *this; } CompileOptions &setPrincipals(JSPrincipals *p) { principals = p; return *this; }
@ -4973,6 +4974,7 @@ struct CompileOptions {
} }
CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; } CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
CompileOptions &setAllowIntrinsicsCalls(bool aic) { allowIntrinsicsCalls = aic; return *this; }
}; };
extern JS_PUBLIC_API(JSScript *) extern JS_PUBLIC_API(JSScript *)

View File

@ -149,3 +149,4 @@ DEFINE_ATOM(unescape, "unescape")
DEFINE_ATOM(uneval, "uneval") DEFINE_ATOM(uneval, "uneval")
DEFINE_ATOM(unwatch, "unwatch") DEFINE_ATOM(unwatch, "unwatch")
DEFINE_ATOM(watch, "watch") DEFINE_ATOM(watch, "watch")
DEFINE_ATOM(_CallFunction, "_CallFunction")

View File

@ -3394,11 +3394,13 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
} }
case JSOP_NAME: case JSOP_NAME:
case JSOP_CALLNAME: { case JSOP_INTRINSICNAME:
case JSOP_CALLNAME:
case JSOP_CALLINTRINSIC: {
TypeSet *seen = bytecodeTypes(pc); TypeSet *seen = bytecodeTypes(pc);
addTypeBarrier(cx, pc, seen, Type::UnknownType()); addTypeBarrier(cx, pc, seen, Type::UnknownType());
seen->addSubset(cx, &pushed[0]); seen->addSubset(cx, &pushed[0]);
if (op == JSOP_CALLNAME) if (op == JSOP_CALLNAME || op == JSOP_CALLINTRINSIC)
pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType()); pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
break; break;
} }

View File

@ -1418,8 +1418,6 @@ ADD_EMPTY_CASE(JSOP_NOP)
ADD_EMPTY_CASE(JSOP_UNUSED1) ADD_EMPTY_CASE(JSOP_UNUSED1)
ADD_EMPTY_CASE(JSOP_UNUSED2) ADD_EMPTY_CASE(JSOP_UNUSED2)
ADD_EMPTY_CASE(JSOP_UNUSED3) ADD_EMPTY_CASE(JSOP_UNUSED3)
ADD_EMPTY_CASE(JSOP_UNUSED8)
ADD_EMPTY_CASE(JSOP_UNUSED9)
ADD_EMPTY_CASE(JSOP_UNUSED10) ADD_EMPTY_CASE(JSOP_UNUSED10)
ADD_EMPTY_CASE(JSOP_UNUSED11) ADD_EMPTY_CASE(JSOP_UNUSED11)
ADD_EMPTY_CASE(JSOP_UNUSED12) ADD_EMPTY_CASE(JSOP_UNUSED12)
@ -2524,6 +2522,19 @@ BEGIN_CASE(JSOP_CALLNAME)
} }
END_CASE(JSOP_NAME) END_CASE(JSOP_NAME)
BEGIN_CASE(JSOP_INTRINSICNAME)
BEGIN_CASE(JSOP_CALLINTRINSIC)
{
RootedValue &rval = rootValue0;
if (!IntrinsicNameOperation(cx, script, regs.pc, rval.address()))
goto error;
PUSH_COPY(rval);
TypeScript::Monitor(cx, script, regs.pc, rval);
}
END_CASE(JSOP_INTRINSICNAME)
BEGIN_CASE(JSOP_UINT16) BEGIN_CASE(JSOP_UINT16)
PUSH_INT32((int32_t) GET_UINT16(regs.pc)); PUSH_INT32((int32_t) GET_UINT16(regs.pc));
END_CASE(JSOP_UINT16) END_CASE(JSOP_UINT16)

View File

@ -21,6 +21,7 @@
#include "jsfuninlines.h" #include "jsfuninlines.h"
#include "jsinferinlines.h" #include "jsinferinlines.h"
#include "jsopcodeinlines.h"
#include "jspropertycacheinlines.h" #include "jspropertycacheinlines.h"
#include "jstypedarrayinlines.h" #include "jstypedarrayinlines.h"
@ -359,6 +360,17 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
return true; return true;
} }
inline bool
IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp)
{
JSOp op = JSOp(*pc);
RootedPropertyName name(cx);
name = GetNameFromBytecode(cx, script, pc, op);
JSFunction *fun = cx->global()->getIntrinsicFunction(cx, name);
vp->setObject(*fun);
return true;
}
inline bool inline bool
NameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp) NameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp)
{ {

View File

@ -350,9 +350,17 @@ OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPEC
OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
/*
* Intrinsic names have the syntax %name and can only be used when the
* CompileOptions flag "allowIntrinsicsCalls" is set.
*
* They are used to access intrinsic functions the runtime doesn't give client
* JS code access to from self-hosted code.
*/
OPDEF(JSOP_INTRINSICNAME, 143, "intrinsicname", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET)
OPDEF(JSOP_CALLINTRINSIC, 144, "callintrinsic", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET)
/* Unused. */ /* Unused. */
OPDEF(JSOP_UNUSED8, 143,"unused8", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED9, 144,"unused9", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED10, 145,"unused10", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED10, 145,"unused10", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED11, 146,"unused11", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED11, 146,"unused11", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED12, 147,"unused12", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED12, 147,"unused12", NULL, 1, 0, 0, 0, JOF_BYTE)

View File

@ -4,6 +4,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jsopcodeinlines_h__
#define jsopcodeinlines_h__
#include "jsautooplen.h" #include "jsautooplen.h"
#include "frontend/BytecodeEmitter.h" #include "frontend/BytecodeEmitter.h"
@ -118,3 +121,5 @@ public:
}; };
} }
#endif /* jsopcodeinlines_h__ */

View File

@ -2645,6 +2645,15 @@ mjit::Compiler::generateMethod()
} }
END_CASE(JSOP_NAME) END_CASE(JSOP_NAME)
BEGIN_CASE(JSOP_INTRINSICNAME)
BEGIN_CASE(JSOP_CALLINTRINSIC)
{
PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
jsop_intrinsicname(name, knownPushedType(0));
frame.extra(frame.peek(-1)).name = name;
}
END_CASE(JSOP_INTRINSICNAME)
BEGIN_CASE(JSOP_IMPLICITTHIS) BEGIN_CASE(JSOP_IMPLICITTHIS)
{ {
prepareStubCall(Uses(0)); prepareStubCall(Uses(0));
@ -5552,6 +5561,13 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
return true; return true;
} }
void
mjit::Compiler::jsop_intrinsicname(PropertyName *name, JSValueType type)
{
JSFunction *fun = cx->global().get()->getIntrinsicFunction(cx, name);
frame.push(ObjectValue(*fun));
}
void void
mjit::Compiler::jsop_name(PropertyName *name, JSValueType type) mjit::Compiler::jsop_name(PropertyName *name, JSValueType type)
{ {

View File

@ -653,6 +653,7 @@ private:
bool jsop_setprop(PropertyName *name, bool popGuaranteed); bool jsop_setprop(PropertyName *name, bool popGuaranteed);
void jsop_setprop_slow(PropertyName *name); void jsop_setprop_slow(PropertyName *name);
bool jsop_instanceof(); bool jsop_instanceof();
void jsop_intrinsicname(PropertyName *name, JSValueType type);
void jsop_name(PropertyName *name, JSValueType type); void jsop_name(PropertyName *name, JSValueType type);
bool jsop_xname(PropertyName *name); bool jsop_xname(PropertyName *name);
void enterBlock(StaticBlockObject *block); void enterBlock(StaticBlockObject *block);

View File

@ -213,6 +213,13 @@ GlobalObject::setProtoGetter(JSFunction *protoGetter)
setSlot(PROTO_GETTER, ObjectValue(*protoGetter)); setSlot(PROTO_GETTER, ObjectValue(*protoGetter));
} }
void
GlobalObject::setIntrinsicsHolder(JSObject *obj)
{
JS_ASSERT(getSlotRef(INTRINSICS).isUndefined());
setSlot(INTRINSICS, ObjectValue(*obj));
}
} // namespace js } // namespace js
#endif #endif

View File

@ -173,6 +173,10 @@ ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
return CallNonGenericMethod(cx, TestProtoSetterThis, ProtoSetterImpl, args); return CallNonGenericMethod(cx, TestProtoSetterThis, ProtoSetterImpl, args);
} }
JSFunctionSpec intrinsic_functions[] = {
JS_FN("ThrowTypeError", ThrowTypeError, 0,0),
JS_FS_END
};
JSObject * JSObject *
GlobalObject::initFunctionAndObjectClasses(JSContext *cx) GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
{ {
@ -369,14 +373,20 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
self->setOriginalEval(evalobj); self->setOriginalEval(evalobj);
/* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */ /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
RootedFunction throwTypeError(cx); RootedFunction throwTypeError(cx, js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL));
throwTypeError = js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL);
if (!throwTypeError) if (!throwTypeError)
return NULL; return NULL;
if (!throwTypeError->preventExtensions(cx)) if (!throwTypeError->preventExtensions(cx))
return NULL; return NULL;
self->setThrowTypeError(throwTypeError); self->setThrowTypeError(throwTypeError);
RootedObject intrinsicsHolder(cx, JS_NewObject(cx, NULL, NULL, self));
if (!intrinsicsHolder)
return NULL;
self->setIntrinsicsHolder(intrinsicsHolder);
if (!JS_DefineFunctions(cx, intrinsicsHolder, intrinsic_functions))
return NULL;
/* /*
* The global object should have |Object.prototype| as its [[Prototype]]. * The global object should have |Object.prototype| as its [[Prototype]].
* Eventually we'd like to have standard classes be there from the start, * Eventually we'd like to have standard classes be there from the start,

View File

@ -100,9 +100,10 @@ class GlobalObject : public JSObject
static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1; static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
static const unsigned FLAGS = RUNTIME_CODEGEN_ENABLED + 1; static const unsigned FLAGS = RUNTIME_CODEGEN_ENABLED + 1;
static const unsigned DEBUGGERS = FLAGS + 1; static const unsigned DEBUGGERS = FLAGS + 1;
static const unsigned INTRINSICS = DEBUGGERS + 1;
/* Total reserved-slot count for global objects. */ /* Total reserved-slot count for global objects. */
static const unsigned RESERVED_SLOTS = DEBUGGERS + 1; static const unsigned RESERVED_SLOTS = INTRINSICS + 1;
void staticAsserts() { void staticAsserts() {
/* /*
@ -135,6 +136,8 @@ class GlobalObject : public JSObject
inline void setOriginalEval(JSObject *evalobj); inline void setOriginalEval(JSObject *evalobj);
inline void setProtoGetter(JSFunction *protoGetter); inline void setProtoGetter(JSFunction *protoGetter);
inline void setIntrinsicsHolder(JSObject *obj);
Value getConstructor(JSProtoKey key) const { Value getConstructor(JSProtoKey key) const {
JS_ASSERT(key <= JSProto_LIMIT); JS_ASSERT(key <= JSProto_LIMIT);
return getSlot(key); return getSlot(key);
@ -360,6 +363,20 @@ class GlobalObject : public JSObject
return &self->getPrototype(JSProto_DataView).toObject(); return &self->getPrototype(JSProto_DataView).toObject();
} }
bool hasIntrinsicFunction(JSContext *cx, PropertyName *name) {
RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject());
Value fun = NullValue();
return HasDataProperty(cx, holder, NameToId(name), &fun);
}
JSFunction *getIntrinsicFunction(JSContext *cx, PropertyName *name) {
RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject());
Value fun = NullValue();
DebugOnly<bool> ok = HasDataProperty(cx, holder, NameToId(name), &fun);
JS_ASSERT(ok);
return fun.toObject().toFunction();
}
inline RegExpStatics *getRegExpStatics() const; inline RegExpStatics *getRegExpStatics() const;
JSObject *getThrowTypeError() const { JSObject *getThrowTypeError() const {

View File

@ -25,7 +25,7 @@ namespace js {
* and saved versions. If deserialization fails, the data should be * and saved versions. If deserialization fails, the data should be
* invalidated if possible. * invalidated if possible.
*/ */
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 124); static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 125);
class XDRBuffer { class XDRBuffer {
public: public: