author | Till Schneidereit <tschneidereit@gmail.com> |
Wed, 10 Oct 2012 22:53:51 +0200 (2012-10-10) | |
changeset 116169 | 7e44aec095e3cf35eae3543115ed608038a22b2b |
parent 116168 | 18bc32f799d15288898e6f94abd7d0e5585a7373 |
child 116170 | 209a63d0a38fb449620d31e38553f6275db00380 |
push id | 24044 |
push user | emorley@mozilla.com |
push date | Mon, 17 Dec 2012 13:40:16 +0000 (2012-12-17) |
treeherder | mozilla-central@ba26dc1c6267 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jwalden |
bugs | 784293 |
milestone | 20.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1156,27 +1156,31 @@ EmitEnterBlock(JSContext *cx, BytecodeEm * * "use strict"; * function foo() * { * undeclared = 17; // throws ReferenceError * } * foo(); * - * In self-hosting mode, JSOP_NAME is unconditionally converted to - * JSOP_INTRINSICNAME. This causes the lookup to be redirected to the special - * intrinsics holder in the global object, into which any missing objects are + * In self-hosting mode, JSOP_*NAME is unconditionally converted to + * JSOP_*INTRINSIC. This causes lookups to be redirected to the special + * intrinsics holder in the global object, into which any missing values are * cloned lazily upon first access. */ static bool TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op) { if (bce->selfHostingMode) { - JS_ASSERT(*op == JSOP_NAME); - *op = JSOP_INTRINSICNAME; + switch (*op) { + case JSOP_NAME: *op = JSOP_GETINTRINSIC; break; + case JSOP_SETNAME: *op = JSOP_SETINTRINSIC; break; + /* Other *NAME ops aren't (yet) supported in self-hosted code. */ + default: JS_NOT_REACHED("intrinsic"); + } return true; } if (bce->script->compileAndGo && bce->hasGlobalScope && !(bce->sc->isFunction && bce->sc->asFunbox()->mightAliasLocals()) && !pn->isDeoptimized() && !bce->sc->strict) { @@ -1739,17 +1743,17 @@ EmitNameOp(JSContext *cx, BytecodeEmitte return false; op = pn->getOp(); if (callContext) { switch (op) { case JSOP_NAME: op = JSOP_CALLNAME; break; - case JSOP_INTRINSICNAME: + case JSOP_GETINTRINSIC: op = JSOP_CALLINTRINSIC; break; case JSOP_GETGNAME: op = JSOP_CALLGNAME; break; case JSOP_GETARG: op = JSOP_CALLARG; break; @@ -3378,19 +3382,25 @@ EmitVariables(JSContext *cx, BytecodeEmi JS_ASSERT(!pn2->pn_cookie.isFree() || !pn->isOp(JSOP_NOP)); jsatomid atomIndex; if (!MaybeEmitVarDecl(cx, bce, pn->getOp(), pn2, &atomIndex)) return false; if (pn3) { JS_ASSERT(emitOption != DefineVars); - if (op == JSOP_SETNAME || op == JSOP_SETGNAME) { + if (op == JSOP_SETNAME || op == JSOP_SETGNAME || op == JSOP_SETINTRINSIC) { JS_ASSERT(emitOption != PushInitialValues); - JSOp bindOp = (op == JSOP_SETNAME) ? JSOP_BINDNAME : JSOP_BINDGNAME; + JSOp bindOp; + if (op == JSOP_SETNAME) + bindOp = JSOP_BINDNAME; + else if (op == JSOP_SETGNAME) + bindOp = JSOP_BINDGNAME; + else + bindOp = JSOP_BINDINTRINSIC; if (!EmitIndex32(cx, bindOp, atomIndex, bce)) return false; } bool oldEmittingForInit = bce->emittingForInit; bce->emittingForInit = false; if (!EmitTree(cx, bce, pn3)) return false; @@ -3465,18 +3475,24 @@ EmitAssignment(JSContext *cx, BytecodeEm switch (lhs->getKind()) { case PNK_NAME: if (!BindNameToSlot(cx, bce, lhs)) return false; if (lhs->pn_cookie.isFree()) { if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex)) return false; if (!lhs->isConst()) { - JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME; - if (!EmitIndex32(cx, op, atomIndex, bce)) + JSOp bindOp; + if (lhs->isOp(JSOP_SETNAME)) + bindOp = JSOP_BINDNAME; + else if (lhs->isOp(JSOP_SETGNAME)) + bindOp = JSOP_BINDGNAME; + else + bindOp = JSOP_BINDINTRINSIC; + if (!EmitIndex32(cx, bindOp, atomIndex, bce)) return false; offset++; } } break; case PNK_DOT: if (!EmitTree(cx, bce, lhs->expr())) return false; @@ -3538,16 +3554,20 @@ EmitAssignment(JSContext *cx, BytecodeEm if (Emit1(cx, bce, JSOP_DUP) < 0) return false; if (!EmitIndex32(cx, JSOP_GETXPROP, atomIndex, bce)) return false; } else if (lhs->isOp(JSOP_SETGNAME)) { JS_ASSERT(lhs->pn_cookie.isFree()); if (!EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce)) return false; + } else if (lhs->isOp(JSOP_SETINTRINSIC)) { + JS_ASSERT(lhs->pn_cookie.isFree()); + if (!EmitAtomOp(cx, lhs, JSOP_GETINTRINSIC, bce)) + return false; } else { JSOp op = lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL; if (!EmitVarOp(cx, lhs, op, bce)) return false; } break; case PNK_DOT: { if (Emit1(cx, bce, JSOP_DUP) < 0)
--- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -969,21 +969,21 @@ IonBuilder::inspectOpcode(JSOp op) case JSOP_NAME: case JSOP_CALLNAME: { RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName()); return jsop_getname(name); } - case JSOP_INTRINSICNAME: + case JSOP_GETINTRINSIC: case JSOP_CALLINTRINSIC: { RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName()); - return jsop_intrinsicname(name); + return jsop_intrinsic(name); } case JSOP_BINDNAME: return jsop_bindname(info().getName(pc)); case JSOP_DUP: current->pushSlot(current->stackDepth() - 1); return true; @@ -5123,17 +5123,17 @@ IonBuilder::jsop_getname(HandlePropertyN types::StackTypeSet *barrier = oracle->propertyReadBarrier(scriptRoot, pc); types::StackTypeSet *types = oracle->propertyRead(script(), pc); monitorResult(ins, barrier, types); return pushTypeBarrier(ins, types, barrier); } bool -IonBuilder::jsop_intrinsicname(HandlePropertyName name) +IonBuilder::jsop_intrinsic(HandlePropertyName name) { types::StackTypeSet *types = oracle->propertyRead(script(), pc); JSValueType type = types->getKnownTypeTag(); // If we haven't executed this opcode yet, we need to get the intrinsic // value and monitor the result. if (type == JSVAL_TYPE_UNKNOWN) { MCallGetIntrinsicValue *ins = MCallGetIntrinsicValue::New(name);
--- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -344,17 +344,17 @@ class IonBuilder : public MIRGenerator bool jsop_condswitch(); bool jsop_andor(JSOp op); bool jsop_dup2(); bool jsop_loophead(jsbytecode *pc); bool jsop_compare(JSOp op); bool jsop_getgname(HandlePropertyName name); bool jsop_setgname(HandlePropertyName name); bool jsop_getname(HandlePropertyName name); - bool jsop_intrinsicname(HandlePropertyName name); + bool jsop_intrinsic(HandlePropertyName name); bool jsop_bindname(PropertyName *name); bool jsop_getelem(); bool jsop_getelem_dense(); bool jsop_getelem_typed(int arrayType); bool jsop_getelem_string(); bool jsop_setelem(); bool jsop_setelem_dense(); bool jsop_setelem_typed(int arrayType);
--- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -562,17 +562,19 @@ ScriptAnalysis::analyzeBytecode(JSContex case JSOP_INSTANCEOF: case JSOP_LINENO: case JSOP_ENUMELEM: case JSOP_CONDSWITCH: case JSOP_LABEL: case JSOP_RETRVAL: case JSOP_GETGNAME: case JSOP_CALLGNAME: - case JSOP_INTRINSICNAME: + case JSOP_GETINTRINSIC: + case JSOP_SETINTRINSIC: + case JSOP_BINDINTRINSIC: case JSOP_CALLINTRINSIC: case JSOP_SETGNAME: case JSOP_REGEXP: case JSOP_OBJECT: case JSOP_UINT24: case JSOP_GETXPROP: case JSOP_INT8: case JSOP_INT32:
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -558,18 +558,16 @@ struct JSRuntime : js::RuntimeFriendFiel return ionRuntime_ ? ionRuntime_ : createIonRuntime(cx); } bool initSelfHosting(JSContext *cx); void markSelfHostingGlobal(JSTracer *trc); bool isSelfHostingGlobal(js::HandleObject global) { return global == selfHostingGlobal_; } - bool getUnclonedSelfHostedValue(JSContext *cx, js::Handle<js::PropertyName*> name, - js::MutableHandleValue vp); bool cloneSelfHostedFunctionScript(JSContext *cx, js::Handle<js::PropertyName*> name, js::Handle<JSFunction*> targetFun); bool cloneSelfHostedValue(JSContext *cx, js::Handle<js::PropertyName*> name, js::MutableHandleValue vp); /* Base address of the native stack for the current thread. */ uintptr_t nativeStackBase;
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1473,16 +1473,21 @@ js_CloneFunctionObject(JSContext *cx, Ha NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind); if (!cloneobj) return NULL; RootedFunction clone(cx, cloneobj->toFunction()); clone->nargs = fun->nargs; clone->flags = fun->flags & ~JSFunction::EXTENDED; if (fun->isInterpreted()) { + if (fun->isInterpretedLazy()) { + AutoCompartment ac(cx, fun); + if (!fun->getOrCreateScript(cx)) + return NULL; + } clone->initScript(fun->nonLazyScript()); clone->initEnvironment(parent); } else { clone->initNative(fun->native(), fun->jitInfo()); } clone->initAtom(fun->displayAtom()); if (kind == JSFunction::ExtendedFinalizeKind) {
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -3870,38 +3870,40 @@ ScriptAnalysis::analyzeTypesBytecode(JSC if (state.hasPropertyReadTypes) PropertyAccess<PROPERTY_READ_EXISTING>(cx, script, pc, global, seen, id); else PropertyAccess<PROPERTY_READ>(cx, script, pc, global, seen, id); break; } case JSOP_NAME: - case JSOP_INTRINSICNAME: + case JSOP_GETINTRINSIC: case JSOP_CALLNAME: case JSOP_CALLINTRINSIC: { StackTypeSet *seen = bytecodeTypes(pc); addTypeBarrier(cx, pc, seen, Type::UnknownType()); seen->addSubset(cx, &pushed[0]); break; } case JSOP_BINDGNAME: case JSOP_BINDNAME: + case JSOP_BINDINTRINSIC: break; case JSOP_SETGNAME: { jsid id = GetAtomId(cx, script, pc, 0); TypeObject *global = script_->global().getType(cx); PropertyAccess<PROPERTY_WRITE>(cx, script, pc, global, poppedTypes(pc, 0), id); poppedTypes(pc, 0)->addSubset(cx, &pushed[0]); break; } case JSOP_SETNAME: + case JSOP_SETINTRINSIC: case JSOP_SETCONST: cx->compartment->types.monitorBytecode(cx, script, offset); poppedTypes(pc, 0)->addSubset(cx, &pushed[0]); break; case JSOP_GETXPROP: { StackTypeSet *seen = bytecodeTypes(pc); addTypeBarrier(cx, pc, seen, Type::UnknownType()); @@ -5403,16 +5405,17 @@ types::TypeMonitorResult(JSContext *cx, */ static inline bool IgnorePushed(const jsbytecode *pc, unsigned index) { switch (JSOp(*pc)) { /* We keep track of the scopes pushed by BINDNAME separately. */ case JSOP_BINDNAME: case JSOP_BINDGNAME: + case JSOP_BINDINTRINSIC: case JSOP_BINDXMLNAME: return true; /* Stack not consistent in TRY_BRANCH_AFTER_COND. */ case JSOP_IN: case JSOP_EQ: case JSOP_NE: case JSOP_LT:
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1340,18 +1340,16 @@ js::Interpret(JSContext *cx, StackFrame goto do_switch; } /* No-ops for ease of decompilation. */ ADD_EMPTY_CASE(JSOP_NOP) ADD_EMPTY_CASE(JSOP_UNUSED1) ADD_EMPTY_CASE(JSOP_UNUSED2) ADD_EMPTY_CASE(JSOP_UNUSED3) -ADD_EMPTY_CASE(JSOP_UNUSED10) -ADD_EMPTY_CASE(JSOP_UNUSED11) ADD_EMPTY_CASE(JSOP_UNUSED12) ADD_EMPTY_CASE(JSOP_UNUSED13) ADD_EMPTY_CASE(JSOP_UNUSED17) ADD_EMPTY_CASE(JSOP_UNUSED18) ADD_EMPTY_CASE(JSOP_UNUSED19) ADD_EMPTY_CASE(JSOP_UNUSED20) ADD_EMPTY_CASE(JSOP_UNUSED21) ADD_EMPTY_CASE(JSOP_UNUSED22) @@ -1790,16 +1788,20 @@ BEGIN_CASE(JSOP_ENUMCONSTELEM) } END_CASE(JSOP_ENUMCONSTELEM) #endif BEGIN_CASE(JSOP_BINDGNAME) PUSH_OBJECT(regs.fp()->global()); END_CASE(JSOP_BINDGNAME) +BEGIN_CASE(JSOP_BINDINTRINSIC) + PUSH_OBJECT(*cx->global()->intrinsicsHolder()); +END_CASE(JSOP_BINDGNAME) + BEGIN_CASE(JSOP_BINDNAME) { RootedObject &scopeChain = rootObject0; scopeChain = regs.fp()->scopeChain(); RootedPropertyName &name = rootName0; name = script->getName(regs.pc); @@ -2230,16 +2232,28 @@ BEGIN_CASE(JSOP_CALLPROP) TypeScript::Monitor(cx, script, regs.pc, rval); regs.sp[-1] = rval; assertSameCompartmentDebugOnly(cx, regs.sp[-1]); } END_CASE(JSOP_GETPROP) +BEGIN_CASE(JSOP_SETINTRINSIC) +{ + HandleValue value = HandleValue::fromMarkedLocation(®s.sp[-1]); + + if (!SetIntrinsicOperation(cx, script, regs.pc, value)) + goto error; + + regs.sp[-2] = regs.sp[-1]; + regs.sp--; +} +END_CASE(JSOP_SETINTRINSIC) + BEGIN_CASE(JSOP_SETGNAME) BEGIN_CASE(JSOP_SETNAME) { RootedObject &scope = rootObject0; scope = ®s.sp[-2].toObject(); HandleValue value = HandleValue::fromMarkedLocation(®s.sp[-1]); @@ -2467,28 +2481,28 @@ BEGIN_CASE(JSOP_CALLNAME) if (!NameOperation(cx, regs.pc, &rval)) goto error; PUSH_COPY(rval); TypeScript::Monitor(cx, script, regs.pc, rval); } END_CASE(JSOP_NAME) -BEGIN_CASE(JSOP_INTRINSICNAME) +BEGIN_CASE(JSOP_GETINTRINSIC) BEGIN_CASE(JSOP_CALLINTRINSIC) { RootedValue &rval = rootValue0; - if (!IntrinsicNameOperation(cx, script, regs.pc, &rval)) + if (!GetIntrinsicOperation(cx, script, regs.pc, &rval)) goto error; PUSH_COPY(rval); TypeScript::Monitor(cx, script, regs.pc, rval); } -END_CASE(JSOP_INTRINSICNAME) +END_CASE(JSOP_GETINTRINSIC) BEGIN_CASE(JSOP_UINT16) PUSH_INT32((int32_t) GET_UINT16(regs.pc)); END_CASE(JSOP_UINT16) BEGIN_CASE(JSOP_UINT24) PUSH_INT32((int32_t) GET_UINT24(regs.pc)); END_CASE(JSOP_UINT24)
--- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -398,24 +398,31 @@ FetchName(JSContext *cx, HandleObject ob normalized = &normalized->asWith().object(); if (!NativeGet(cx, normalized, obj2, shape, 0, vp)) return false; } return true; } inline bool -IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp) +GetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp) { JSOp op = JSOp(*pc); RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, op)); return cx->global()->getIntrinsicValue(cx, name, vp); } inline bool +SetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleValue val) +{ + RootedPropertyName name(cx, script->getName(pc)); + return cx->global()->setIntrinsicValue(cx, name, val); +} + +inline bool NameOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp) { RootedObject obj(cx, cx->stack.currentScriptedScopeChain()); RootedPropertyName name(cx, cx->stack.currentScript()->getName(pc)); /* * Skip along the scope chain to the enclosing global object. This is * used for GNAME opcodes where the bytecode emitter has determined a
--- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -5,17 +5,18 @@ * 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/. */ /* * JavaScript operation bytecodes. If you need to allocate a bytecode, look * for a name of the form JSOP_UNUSED* and claim it. Otherwise, always add at * the end of the table. * - * When changing the bytecode, don't forget to update JSXDR_BYTECODE_VERSION! + * When changing the bytecode, don't forget to update XDR_BYTECODE_VERSION in + * vm/Xdr.h! * * Includers must define an OPDEF macro of the following form: * * #define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) ... * * Selected arguments can be expanded in initializers. The op argument is * expanded followed by comma in the JSOp enum (jsopcode.h), e.g. The value * field must be dense for now, because jsopcode.c uses an OPDEF() expansion @@ -353,28 +354,28 @@ OPDEF(JSOP_GETALIASEDVAR, 136,"getaliase OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL, 9, 0, 1, 19, JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET) OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL, 9, 1, 1, 3, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL, 10, 0, 1, 15, JOF_SCOPECOORD|JOF_NAME|JOF_DEC|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) /* - * Intrinsic names are emitted instead of JSOP_*NAME ops when the + * Intrinsic names are emitted instead of JSOP_*NAME ops when the * CompileOptions flag "selfHostingMode" is set. * - * They are used in self-hosted code to access other self-hosted values and + * They are used in self-hosted code to access other self-hosted values and * intrinsic functions the runtime doesn't give client JS code access to. */ -OPDEF(JSOP_INTRINSICNAME, 143, "intrinsicname", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) +OPDEF(JSOP_GETINTRINSIC, 143, "getintrinsic", 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) +OPDEF(JSOP_SETINTRINSIC, 145, "setintrinsic", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_BINDINTRINSIC, 146, "bindintrinsic", NULL, 5, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET) /* Unused. */ -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_UNUSED12, 147,"unused12", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED13, 148,"unused13", NULL, 1, 0, 0, 0, JOF_BYTE) /* Placeholders for a real jump opcode set during backpatch chain fixup. */ OPDEF(JSOP_BACKPATCH, 149,"backpatch",NULL, 5, 0, 0, 0, JOF_JUMP|JOF_BACKPATCH) OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL, 5, 1, 0, 0, JOF_JUMP|JOF_BACKPATCH) /* Set pending exception from the stack, to trigger rethrow. */
--- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -2776,25 +2776,25 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_CALLNAME) { PropertyName *name = script_->getName(GET_UINT32_INDEX(PC)); jsop_name(name, knownPushedType(0)); frame.extra(frame.peek(-1)).name = name; } END_CASE(JSOP_NAME) - BEGIN_CASE(JSOP_INTRINSICNAME) + BEGIN_CASE(JSOP_GETINTRINSIC) BEGIN_CASE(JSOP_CALLINTRINSIC) { PropertyName *name = script_->getName(GET_UINT32_INDEX(PC)); - if (!jsop_intrinsicname(name, knownPushedType(0))) + if (!jsop_intrinsic(name, knownPushedType(0))) return Compile_Error; frame.extra(frame.peek(-1)).name = name; } - END_CASE(JSOP_INTRINSICNAME) + END_CASE(JSOP_GETINTRINSIC) BEGIN_CASE(JSOP_IMPLICITTHIS) { prepareStubCall(Uses(0)); masm.move(ImmPtr(script_->getName(GET_UINT32_INDEX(PC))), Registers::ArgReg1); INLINE_STUBCALL(stubs::ImplicitThis, REJOIN_FALLTHROUGH); frame.pushSynced(JSVAL_TYPE_UNKNOWN); } @@ -5802,17 +5802,17 @@ mjit::Compiler::jsop_setprop(PropertyNam labels.setInlineValueStore(masm, pic.fastPathRejoin, inlineValueStore); labels.setInlineShapeJump(masm, pic.shapeGuard, afterInlineShapeJump); pics.append(pic); return true; } bool -mjit::Compiler::jsop_intrinsicname(PropertyName *name, JSValueType type) +mjit::Compiler::jsop_intrinsic(PropertyName *name, JSValueType type) { if (type == JSVAL_TYPE_UNKNOWN) { prepareStubCall(Uses(0)); masm.move(ImmPtr(name), Registers::ArgReg1); INLINE_STUBCALL(stubs::IntrinsicName, REJOIN_FALLTHROUGH); testPushedType(REJOIN_FALLTHROUGH, 0, /* ool = */ false); frame.pushSynced(JSVAL_TYPE_UNKNOWN); return true;
--- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -658,17 +658,17 @@ private: void jsop_setelem_slow(); void jsop_getelem_slow(); bool jsop_getprop(PropertyName *name, JSValueType type, bool typeCheck = true, bool forPrototype = false); bool jsop_getprop_dispatch(PropertyName *name); bool jsop_setprop(PropertyName *name, bool popGuaranteed); void jsop_setprop_slow(PropertyName *name); bool jsop_instanceof(); - bool jsop_intrinsicname(PropertyName *name, JSValueType type); + bool jsop_intrinsic(PropertyName *name, JSValueType type); void jsop_name(PropertyName *name, JSValueType type); bool jsop_xname(PropertyName *name); void enterBlock(StaticBlockObject *block); void leaveBlock(); void emitEval(uint32_t argc); bool jsop_tableswitch(jsbytecode *pc); Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject);
--- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -371,22 +371,27 @@ GlobalObject::initFunctionAndObjectClass RootedFunction throwTypeError(cx, js_NewFunction(cx, NullPtr(), ThrowTypeError, 0, JSFunction::NATIVE_FUN, self, NullPtr())); if (!throwTypeError) return NULL; if (!throwTypeError->preventExtensions(cx)) return NULL; self->setThrowTypeError(throwTypeError); - RootedObject intrinsicsHolder(cx, JS_NewObject(cx, NULL, NULL, self)); - if (!intrinsicsHolder) - return NULL; + RootedObject intrinsicsHolder(cx); + if (cx->runtime->isSelfHostingGlobal(self)) { + intrinsicsHolder = this; + } else { + intrinsicsHolder = NewObjectWithClassProto(cx, &ObjectClass, NULL, self); + if (!intrinsicsHolder) + return NULL; + } self->setIntrinsicsHolder(intrinsicsHolder); /* Define a property 'global' with the current global as its value. */ - RootedValue global(cx, OBJECT_TO_JSVAL(self)); + RootedValue global(cx, ObjectValue(*self)); if (!JSObject::defineProperty(cx, intrinsicsHolder, cx->names().global, global, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return NULL; } /*
--- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -329,21 +329,16 @@ class GlobalObject : public JSObject JSObject *getOrCreateDateTimeFormatPrototype(JSContext *cx) { return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto); } JSObject *getIteratorPrototype() { return &getPrototype(JSProto_Iterator).toObject(); } - JSObject *intrinsicsHolder() { - JS_ASSERT(!getSlotRef(INTRINSICS).isUndefined()); - return &getSlotRef(INTRINSICS).toObject(); - } - private: typedef bool (*ObjectInitOp)(JSContext *cx, Handle<GlobalObject*> global); JSObject *getOrCreateObject(JSContext *cx, unsigned slot, ObjectInitOp init) { Value v = getSlotRef(slot); if (v.isObject()) return &v.toObject(); Rooted<GlobalObject*> self(cx, this); @@ -377,29 +372,44 @@ class GlobalObject : public JSObject if (dataViewClassInitialized()) return &getPrototype(JSProto_DataView).toObject(); Rooted<GlobalObject*> self(cx, this); if (!js_InitTypedArrayClasses(cx, self)) return NULL; return &self->getPrototype(JSProto_DataView).toObject(); } + JSObject *intrinsicsHolder() { + JS_ASSERT(!getSlotRef(INTRINSICS).isUndefined()); + return &getSlotRef(INTRINSICS).toObject(); + } + bool getIntrinsicValue(JSContext *cx, PropertyName *name, MutableHandleValue value) { - RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject()); + RootedObject holder(cx, intrinsicsHolder()); RootedId id(cx, NameToId(name)); if (HasDataProperty(cx, holder, id, value.address())) return true; Rooted<PropertyName*> rootedName(cx, name); if (!cx->runtime->cloneSelfHostedValue(cx, rootedName, value)) return false; mozilla::DebugOnly<bool> ok = JS_DefinePropertyById(cx, holder, id, value, NULL, NULL, 0); JS_ASSERT(ok); return true; } + bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) { +#ifdef DEBUG + RootedObject self(cx, this); + JS_ASSERT(cx->runtime->isSelfHostingGlobal(self)); +#endif + RootedObject holder(cx, intrinsicsHolder()); + RootedValue valCopy(cx, value); + return JSObject::setProperty(cx, holder, holder, name, &valCopy, false); + } + inline RegExpStatics *getRegExpStatics() const; JSObject *getThrowTypeError() const { JS_ASSERT(functionObjectClassesInitialized()); return &getSlot(THROWTYPEERROR).toObject(); } Value booleanValueOf() const {
--- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -9,16 +9,22 @@ #include "jscompartment.h" #include "jsinterp.h" #include "jsnum.h" #include "jsobj.h" #include "gc/Marking.h" #include "jsfuninlines.h" +#include "jstypedarrayinlines.h" + +#include "vm/BooleanObject-inl.h" +#include "vm/NumberObject-inl.h" +#include "vm/RegExpObject-inl.h" +#include "vm/StringObject-inl.h" #include "selfhosted.out.h" using namespace js; static void selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { @@ -123,19 +129,18 @@ intrinsic_DecompileArg(JSContext *cx, un } static JSBool intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(args.length() >= 1); JS_ASSERT(args[0].isObject()); - RootedObject obj(cx, &args[0].toObject()); - JS_ASSERT(obj->isFunction()); - obj->toFunction()->setIsSelfHostedConstructor(); + JS_ASSERT(args[0].toObject().isFunction()); + args[0].toObject().toFunction()->setIsSelfHostedConstructor(); return true; } JSFunctionSpec intrinsic_functions[] = { JS_FN("ToObject", intrinsic_ToObject, 1,0), JS_FN("ToInteger", intrinsic_ToInteger, 1,0), JS_FN("IsCallable", intrinsic_IsCallable, 1,0), JS_FN("ThrowError", intrinsic_ThrowError, 4,0), @@ -147,17 +152,24 @@ bool JSRuntime::initSelfHosting(JSContext *cx) { JS_ASSERT(!selfHostingGlobal_); RootedObject savedGlobal(cx, JS_GetGlobalObject(cx)); if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class, NULL))) return false; JS_SetGlobalObject(cx, selfHostingGlobal_); JSAutoCompartment ac(cx, cx->global()); - RootedObject shg(cx, selfHostingGlobal_); + Rooted<GlobalObject*> shg(cx, &selfHostingGlobal_->asGlobal()); + /* + * During initialization of standard classes for the self-hosting global, + * all self-hosted functions are ignored. Thus, we don't create cyclic + * dependencies in the order of initialization. + */ + if (!GlobalObject::initStandardClasses(cx, shg)) + return false; if (!JS_DefineFunctions(cx, shg, intrinsic_functions)) return false; CompileOptions options(cx); options.setFileAndLine("self-hosted", 1); options.setSelfHostingMode(true); @@ -186,31 +198,151 @@ JSRuntime::initSelfHosting(JSContext *cx } void JSRuntime::markSelfHostingGlobal(JSTracer *trc) { MarkObjectRoot(trc, &selfHostingGlobal_, "self-hosting global"); } -bool -JSRuntime::getUnclonedSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, - MutableHandleValue vp) +typedef AutoObjectObjectHashMap CloneMemory; +static bool CloneValue(JSContext *cx, MutableHandleValue vp, CloneMemory &clonedObjects); + +static bool +GetUnclonedValue(JSContext *cx, Handle<JSObject*> src, HandleId id, MutableHandleValue vp) +{ + AutoCompartment ac(cx, src); + return JSObject::getGeneric(cx, src, src, id, vp); +} + +static bool +CloneProperties(JSContext *cx, HandleObject obj, HandleObject clone, CloneMemory &clonedObjects) +{ + RootedId id(cx); + RootedValue val(cx); + AutoIdVector ids(cx); + { + AutoCompartment ac(cx, obj); + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &ids)) + return false; + } + for (uint32_t i = 0; i < ids.length(); i++) { + id = ids[i]; + if (!GetUnclonedValue(cx, obj, id, &val) || + !CloneValue(cx, &val, clonedObjects) || + !JSObject::setGeneric(cx, clone, clone, id, &val, false)) + { + return false; + } + } + return true; +} +static RawObject +CloneDenseArray(JSContext *cx, HandleObject obj, CloneMemory &clonedObjects) +{ + uint32_t len = obj->getArrayLength(); + RootedObject clone(cx, NewDenseAllocatedArray(cx, len)); + clone->setDenseArrayInitializedLength(len); + for (uint32_t i = 0; i < len; i++) + JSObject::initDenseArrayElementWithType(cx, clone, i, UndefinedValue()); + RootedValue elt(cx); + for (uint32_t i = 0; i < len; i++) { + bool present; + if (!obj->getElementIfPresent(cx, obj, obj, i, &elt, &present)) + return NULL; + if (present) { + if (!CloneValue(cx, &elt, clonedObjects)) + return NULL; + JSObject::setDenseArrayElementWithType(cx, clone, i, elt); + } + } + return clone; +} +static RawObject +CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects) { - RootedObject shg(cx, selfHostingGlobal_); - AutoCompartment ac(cx, shg); - return JS_GetPropertyById(cx, shg, NameToId(name), vp.address()); + CloneMemory::AddPtr p = clonedObjects.lookupForAdd(srcObj.get()); + if (p) + return p->value; + RootedObject clone(cx); + if (srcObj->isFunction()) { + RootedFunction fun(cx, srcObj->toFunction()); + clone = CloneFunctionObject(cx, fun, cx->global(), fun->getAllocKind()); + } else if (srcObj->isRegExp()) { + RegExpObject &reobj = srcObj->asRegExp(); + RootedAtom source(cx, reobj.getSource()); + clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), NULL); + } else if (srcObj->isDate()) { + clone = JS_NewDateObjectMsec(cx, srcObj->getDateUTCTime().toNumber()); + } else if (srcObj->isBoolean()) { + clone = BooleanObject::create(cx, srcObj->asBoolean().unbox()); + } else if (srcObj->isNumber()) { + clone = NumberObject::create(cx, srcObj->asNumber().unbox()); + } else if (srcObj->isString()) { + Rooted<JSStableString*> str(cx, srcObj->asString().unbox()->ensureStable(cx)); + if (!str) + return NULL; + str = js_NewStringCopyN(cx, str->chars().get(), str->length())->ensureStable(cx); + if (!str) + return NULL; + clone = StringObject::create(cx, str); + } else if (srcObj->isDenseArray()) { + return CloneDenseArray(cx, srcObj, clonedObjects); + } else { + if (srcObj->isArray()) { + clone = NewDenseEmptyArray(cx); + } else { + JS_ASSERT(srcObj->isNative()); + clone = NewObjectWithClassProto(cx, srcObj->getClass(), NULL, cx->global(), + srcObj->getAllocKind()); + } + } + if (!clone || !clonedObjects.relookupOrAdd(p, srcObj.get(), clone.get()) || + !CloneProperties(cx, srcObj, clone, clonedObjects)) + { + return NULL; + } + return clone; +} + +static bool +CloneValue(JSContext *cx, MutableHandleValue vp, CloneMemory &clonedObjects) +{ + if (vp.isObject()) { + RootedObject obj(cx, &vp.toObject()); + RootedObject clone(cx, CloneObject(cx, obj, clonedObjects)); + if (!clone) + return false; + vp.setObject(*clone); + } else if (vp.isBoolean() || vp.isNumber() || vp.isNullOrUndefined()) { + // Nothing to do here: these are represented inline in the value + } else if (vp.isString()) { + Rooted<JSStableString*> str(cx, vp.toString()->ensureStable(cx)); + if (!str) + return false; + RootedString clone(cx, js_NewStringCopyN(cx, str->chars().get(), str->length())); + if (!clone) + return false; + vp.setString(clone); + } else { + if (JSString *valSrc = JS_ValueToSource(cx, vp)) + printf("Error: Can't yet clone value: %s\n", JS_EncodeString(cx, valSrc)); + return false; + } + return true; } bool JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> name, Handle<JSFunction*> targetFun) { + RootedObject shg(cx, selfHostingGlobal_); RootedValue funVal(cx); - if (!getUnclonedSelfHostedValue(cx, name, &funVal)) + RootedId id(cx, NameToId(name)); + if (!GetUnclonedValue(cx, shg, id, &funVal)) return false; RootedFunction sourceFun(cx, funVal.toObject().toFunction()); Rooted<JSScript*> sourceScript(cx, sourceFun->nonLazyScript()); JS_ASSERT(!sourceScript->enclosingStaticScope()); RawScript cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript); if (!cscript) return false; @@ -219,30 +351,27 @@ JSRuntime::cloneSelfHostedFunctionScript JS_ASSERT(sourceFun->nargs == targetFun->nargs); targetFun->flags = sourceFun->flags | JSFunction::EXTENDED; return true; } bool JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, MutableHandleValue vp) { - RootedValue funVal(cx); - if (!getUnclonedSelfHostedValue(cx, name, &funVal)) - return false; + RootedObject shg(cx, selfHostingGlobal_); + RootedValue val(cx); + RootedId id(cx, NameToId(name)); + if (!GetUnclonedValue(cx, shg, id, &val)) + return false; /* * We don't clone if we're operating in the self-hosting global, as that * means we're currently executing the self-hosting script while * initializing the runtime (see JSRuntime::initSelfHosting). */ - if (cx->global() == selfHostingGlobal_) { - vp.set(funVal); - } else if (funVal.isObject() && funVal.toObject().isFunction()) { - RootedFunction fun(cx, funVal.toObject().toFunction()); - RootedObject clone(cx, CloneFunctionObject(cx, fun, cx->global(), fun->getAllocKind())); - if (!clone) + if (cx->global() != selfHostingGlobal_) { + CloneMemory clonedObjects(cx); + if (!clonedObjects.init() || !CloneValue(cx, &val, clonedObjects)) return false; - vp.setObject(*clone); - } else { - vp.setUndefined(); } + vp.set(val); return true; }