mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team.
This commit is contained in:
commit
bb0194dcf5
@ -2478,22 +2478,6 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
|
||||
bce->switchToMain();
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a prologue for run-once scripts which will deoptimize JIT code if
|
||||
* the script ends up running multiple times via foo.caller related
|
||||
* shenanigans.
|
||||
*/
|
||||
bool runOnce = bce->parent &&
|
||||
bce->parent->emittingRunOnceLambda &&
|
||||
!funbox->argumentsHasLocalBinding() &&
|
||||
!funbox->isGenerator();
|
||||
if (runOnce) {
|
||||
bce->switchToProlog();
|
||||
if (!Emit1(cx, bce, JSOP_RUNONCE) < 0)
|
||||
return false;
|
||||
bce->switchToMain();
|
||||
}
|
||||
|
||||
if (!EmitTree(cx, bce, body))
|
||||
return false;
|
||||
|
||||
@ -2511,10 +2495,8 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
|
||||
* If this function is only expected to run once, mark the script so that
|
||||
* initializers created within it may be given more precise types.
|
||||
*/
|
||||
if (runOnce) {
|
||||
if (bce->parent && bce->parent->emittingRunOnceLambda)
|
||||
bce->script->treatAsRunOnce = true;
|
||||
JS_ASSERT(!bce->script->hasRunOnce);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark as singletons any function which will only be executed once, or
|
||||
|
@ -1669,22 +1669,14 @@ BaselineCompiler::emit_JSOP_DELPROP()
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BaselineCompiler::getScopeCoordinateObject(Register reg)
|
||||
Address
|
||||
BaselineCompiler::getScopeCoordinateAddress(Register reg)
|
||||
{
|
||||
ScopeCoordinate sc(pc);
|
||||
|
||||
masm.loadPtr(frame.addressOfScopeChain(), reg);
|
||||
for (unsigned i = sc.hops; i; i--)
|
||||
masm.extractObject(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
|
||||
}
|
||||
|
||||
Address
|
||||
BaselineCompiler::getScopeCoordinateAddress(Register reg)
|
||||
{
|
||||
getScopeCoordinateObject(reg);
|
||||
|
||||
ScopeCoordinate sc(pc);
|
||||
|
||||
Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script, pc);
|
||||
Address addr;
|
||||
@ -1721,29 +1713,6 @@ BaselineCompiler::emit_JSOP_CALLALIASEDVAR()
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SETALIASEDVAR()
|
||||
{
|
||||
JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script, pc);
|
||||
if (outerScript && outerScript->treatAsRunOnce) {
|
||||
// Type updates for this operation might need to be tracked, so treat
|
||||
// this as a SETPROP.
|
||||
|
||||
// Load rhs into R1.
|
||||
frame.syncStack(1);
|
||||
frame.popValue(R1);
|
||||
|
||||
// Load and box lhs into R0.
|
||||
getScopeCoordinateObject(R2.scratchReg());
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
|
||||
|
||||
// Call SETPROP IC.
|
||||
ICSetProp_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_)))
|
||||
return false;
|
||||
|
||||
// The IC will return the RHS value in R0, mark it as pushed value.
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sync everything except the top value, so that we can use R0 as scratch
|
||||
// (storeValue does not touch it if the top value is in R0).
|
||||
frame.syncStack(1);
|
||||
@ -2469,23 +2438,6 @@ BaselineCompiler::emit_JSOP_ARGUMENTS()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
|
||||
static const VMFunction RunOnceScriptPrologueInfo =
|
||||
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_RUNONCE()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
masm.movePtr(ImmGCPtr(script), R0.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
return callVM(RunOnceScriptPrologueInfo);
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_REST()
|
||||
{
|
||||
|
@ -152,7 +152,6 @@ namespace ion {
|
||||
_(JSOP_EXCEPTION) \
|
||||
_(JSOP_DEBUGGER) \
|
||||
_(JSOP_ARGUMENTS) \
|
||||
_(JSOP_RUNONCE) \
|
||||
_(JSOP_REST) \
|
||||
_(JSOP_TOID) \
|
||||
_(JSOP_TABLESWITCH) \
|
||||
@ -237,7 +236,6 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
||||
|
||||
bool addPCMappingEntry(bool addIndexEntry);
|
||||
|
||||
void getScopeCoordinateObject(Register reg);
|
||||
Address getScopeCoordinateAddress(Register reg);
|
||||
};
|
||||
|
||||
|
@ -6191,17 +6191,9 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
|
||||
JSOp op = JSOp(*pc);
|
||||
FallbackICSpew(cx, stub, "SetProp(%s)", js_CodeName[op]);
|
||||
|
||||
JS_ASSERT(op == JSOP_SETPROP ||
|
||||
op == JSOP_SETNAME ||
|
||||
op == JSOP_SETGNAME ||
|
||||
op == JSOP_INITPROP ||
|
||||
op == JSOP_SETALIASEDVAR);
|
||||
JS_ASSERT(op == JSOP_SETPROP || op == JSOP_SETNAME || op == JSOP_SETGNAME || op == JSOP_INITPROP);
|
||||
|
||||
RootedPropertyName name(cx);
|
||||
if (op == JSOP_SETALIASEDVAR)
|
||||
name = ScopeCoordinateName(cx, script, pc);
|
||||
else
|
||||
name = script->getName(pc);
|
||||
RootedPropertyName name(cx, script->getName(pc));
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
RootedObject obj(cx, ToObjectFromStack(cx, lhs));
|
||||
@ -6217,8 +6209,6 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
|
||||
} else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
|
||||
if (!SetNameOperation(cx, script, pc, obj, rhs))
|
||||
return false;
|
||||
} else if (op == JSOP_SETALIASEDVAR) {
|
||||
obj->asScope().setAliasedVar(cx, pc, name, rhs);
|
||||
} else if (script->strict) {
|
||||
if (!js::SetProperty<true>(cx, obj, id, rhs))
|
||||
return false;
|
||||
|
@ -2806,7 +2806,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
|
||||
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape,
|
||||
HandleTypeObject, HeapSlot *);
|
||||
static const VMFunction NewCallObjectInfo =
|
||||
FunctionInfo<NewCallObjectFn>(NewCallObject);
|
||||
@ -2822,33 +2822,25 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
|
||||
OutOfLineCode *ool;
|
||||
if (lir->slots()->isRegister()) {
|
||||
ool = oolCallVM(NewCallObjectInfo, lir,
|
||||
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
|
||||
ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->hasLazyType() ? NULL : templateObj->type()),
|
||||
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->type()),
|
||||
ToRegister(lir->slots())),
|
||||
StoreRegisterTo(obj));
|
||||
} else {
|
||||
ool = oolCallVM(NewCallObjectInfo, lir,
|
||||
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
|
||||
ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->hasLazyType() ? NULL : templateObj->type()),
|
||||
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->type()),
|
||||
ImmWord((void *)NULL)),
|
||||
StoreRegisterTo(obj));
|
||||
}
|
||||
if (!ool)
|
||||
return false;
|
||||
|
||||
if (lir->mir()->needsSingletonType()) {
|
||||
// Objects can only be given singleton types in VM calls.
|
||||
masm.jump(ool->entry());
|
||||
} else {
|
||||
masm.newGCThing(obj, templateObj, ool->entry());
|
||||
masm.initGCThing(obj, templateObj);
|
||||
|
||||
if (lir->slots()->isRegister())
|
||||
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
|
||||
}
|
||||
masm.newGCThing(obj, templateObj, ool->entry());
|
||||
masm.initGCThing(obj, templateObj);
|
||||
|
||||
if (lir->slots()->isRegister())
|
||||
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
|
||||
masm.bind(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
@ -5015,17 +5007,6 @@ CodeGenerator::visitGetArgument(LGetArgument *lir)
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
|
||||
static const VMFunction RunOnceScriptPrologueInfo =
|
||||
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitRunOncePrologue(LRunOncePrologue *lir)
|
||||
{
|
||||
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
|
||||
return callVM(RunOnceScriptPrologueInfo, lir);
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
@ -5703,7 +5684,7 @@ CodeGenerator::visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic)
|
||||
}
|
||||
|
||||
typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
|
||||
HandlePropertyName, const HandleValue, bool, int);
|
||||
HandlePropertyName, const HandleValue, bool, bool);
|
||||
static const VMFunction SetPropertyInfo =
|
||||
FunctionInfo<SetPropertyFn>(SetProperty);
|
||||
|
||||
@ -5713,9 +5694,10 @@ CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
|
||||
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
|
||||
|
||||
const Register objReg = ToRegister(ins->getOperand(0));
|
||||
JSOp op = JSOp(*ins->mir()->resumePoint()->pc());
|
||||
jsbytecode *pc = ins->mir()->resumePoint()->pc();
|
||||
bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
|
||||
|
||||
pushArg(Imm32(op));
|
||||
pushArg(Imm32(isSetName));
|
||||
pushArg(Imm32(ins->mir()->strict()));
|
||||
|
||||
pushArg(value);
|
||||
|
@ -215,7 +215,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitIteratorEnd(LIteratorEnd *lir);
|
||||
bool visitArgumentsLength(LArgumentsLength *lir);
|
||||
bool visitGetArgument(LGetArgument *lir);
|
||||
bool visitRunOncePrologue(LRunOncePrologue *lir);
|
||||
bool emitRest(LInstruction *lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
JSObject *templateObject, const VMFunction &f);
|
||||
|
@ -1191,9 +1191,6 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_ARGUMENTS:
|
||||
return jsop_arguments();
|
||||
|
||||
case JSOP_RUNONCE:
|
||||
return jsop_runonce();
|
||||
|
||||
case JSOP_REST:
|
||||
return jsop_rest();
|
||||
|
||||
@ -1305,8 +1302,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_CALLGNAME:
|
||||
{
|
||||
RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
|
||||
RootedObject obj(cx, &script()->global());
|
||||
return getStaticName(obj, name);
|
||||
return jsop_getgname(name);
|
||||
}
|
||||
|
||||
case JSOP_BINDGNAME:
|
||||
@ -1315,8 +1311,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_SETGNAME:
|
||||
{
|
||||
RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
|
||||
RootedObject obj(cx, &script()->global());
|
||||
return setStaticName(obj, name);
|
||||
return jsop_setgname(name);
|
||||
}
|
||||
|
||||
case JSOP_NAME:
|
||||
@ -4284,9 +4279,8 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
|
||||
|
||||
// Allocate the actual object. It is important that no intervening
|
||||
// instructions could potentially bailout, thus leaking the dynamic slots
|
||||
// pointer. Run-once scripts need a singleton type, so always do a VM call
|
||||
// in such cases.
|
||||
MInstruction *callObj = MNewCallObject::New(templateObj, script()->treatAsRunOnce, slots);
|
||||
// pointer.
|
||||
MInstruction *callObj = MNewCallObject::New(templateObj, slots);
|
||||
current->add(callObj);
|
||||
|
||||
// Initialize the object's reserved slots. No post barrier is needed here,
|
||||
@ -5906,45 +5900,44 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
IonBuilder::jsop_getgname(HandlePropertyName name)
|
||||
{
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
|
||||
// Optimize undefined, NaN, and Infinity.
|
||||
if (name == cx->names().undefined)
|
||||
return pushConstant(UndefinedValue());
|
||||
if (name == cx->names().NaN)
|
||||
return pushConstant(cx->runtime->NaNValue);
|
||||
if (name == cx->names().Infinity)
|
||||
return pushConstant(cx->runtime->positiveInfinityValue);
|
||||
|
||||
if (staticObject->isGlobal()) {
|
||||
// Optimize undefined, NaN, and Infinity.
|
||||
if (name == cx->names().undefined)
|
||||
return pushConstant(UndefinedValue());
|
||||
if (name == cx->names().NaN)
|
||||
return pushConstant(cx->runtime->NaNValue);
|
||||
if (name == cx->names().Infinity)
|
||||
return pushConstant(cx->runtime->positiveInfinityValue);
|
||||
}
|
||||
RootedObject globalObj(cx, &script()->global());
|
||||
JS_ASSERT(globalObj->isNative());
|
||||
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
// For the fastest path, the property must be found, and it must be found
|
||||
// as a normal data property on exactly the global object.
|
||||
RootedShape shape(cx, staticObject->nativeLookup(cx, id));
|
||||
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
return jsop_getname(name);
|
||||
|
||||
types::TypeObject *staticType = staticObject->getType(cx);
|
||||
if (!staticType)
|
||||
types::TypeObject *globalType = globalObj->getType(cx);
|
||||
if (!globalType)
|
||||
return false;
|
||||
types::HeapTypeSet *propertyTypes = NULL;
|
||||
if (!staticType->unknownProperties()) {
|
||||
propertyTypes = staticType->getProperty(cx, id, false);
|
||||
if (!globalType->unknownProperties()) {
|
||||
propertyTypes = globalType->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
}
|
||||
if (propertyTypes && propertyTypes->isOwnProperty(cx, staticType, true)) {
|
||||
if (propertyTypes && propertyTypes->isOwnProperty(cx, globalType, true)) {
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
return jsop_getname(name);
|
||||
}
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, staticType, name, types);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, globalType, name, types);
|
||||
|
||||
// If the property is permanent, a shape guard isn't necessary.
|
||||
|
||||
@ -5955,7 +5948,7 @@ IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
if (singleton) {
|
||||
// Try to inline a known constant value.
|
||||
bool isKnownConstant;
|
||||
if (!TestSingletonProperty(cx, staticObject, singleton, id, &isKnownConstant))
|
||||
if (!TestSingletonProperty(cx, globalObj, singleton, id, &isKnownConstant))
|
||||
return false;
|
||||
if (isKnownConstant)
|
||||
return pushConstant(ObjectValue(*singleton));
|
||||
@ -5966,19 +5959,27 @@ IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
return pushConstant(NullValue());
|
||||
}
|
||||
|
||||
MInstruction *obj = MConstant::New(ObjectValue(*staticObject));
|
||||
current->add(obj);
|
||||
MInstruction *global = MConstant::New(ObjectValue(*globalObj));
|
||||
current->add(global);
|
||||
|
||||
// If we have a property typeset, the isOwnProperty call will trigger recompilation if
|
||||
// the property is deleted or reconfigured.
|
||||
if (!propertyTypes && shape->configurable())
|
||||
obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard);
|
||||
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
|
||||
if (barrier)
|
||||
rvalType = MIRType_Value;
|
||||
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
|
||||
|
||||
return loadSlot(obj, shape, rvalType, barrier, types);
|
||||
MSlots *slots = MSlots::New(global);
|
||||
current->add(slots);
|
||||
MLoadSlot *load = MLoadSlot::New(slots, shape->slot() - globalObj->numFixedSlots());
|
||||
current->add(load);
|
||||
|
||||
// Slot loads can be typed, if they have a single, known, definitive type.
|
||||
if (knownType != JSVAL_TYPE_UNKNOWN && !barrier)
|
||||
load->setResultType(MIRTypeFromValueType(knownType));
|
||||
|
||||
current->push(load);
|
||||
return pushTypeBarrier(load, types, barrier);
|
||||
}
|
||||
|
||||
// Whether 'types' includes all possible values represented by input/inputTypes.
|
||||
@ -6015,33 +6016,34 @@ ion::NeedsPostBarrier(CompileInfo &info, MDefinition *value)
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::setStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
IonBuilder::jsop_setgname(HandlePropertyName name)
|
||||
{
|
||||
RootedObject globalObj(cx, &script()->global());
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
|
||||
JS_ASSERT(globalObj->isNative());
|
||||
|
||||
MDefinition *value = current->peek(-1);
|
||||
|
||||
if (staticObject->watched())
|
||||
if (globalObj->watched())
|
||||
return jsop_setprop(name);
|
||||
|
||||
// For the fastest path, the property must be found, and it must be found
|
||||
// as a normal data property on exactly the global object.
|
||||
RootedShape shape(cx, staticObject->nativeLookup(cx, id));
|
||||
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
|
||||
if (!shape || !shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot())
|
||||
return jsop_setprop(name);
|
||||
|
||||
types::TypeObject *staticType = staticObject->getType(cx);
|
||||
if (!staticType)
|
||||
types::TypeObject *globalType = globalObj->getType(cx);
|
||||
if (!globalType)
|
||||
return false;
|
||||
types::HeapTypeSet *propertyTypes = NULL;
|
||||
if (!staticType->unknownProperties()) {
|
||||
propertyTypes = staticType->getProperty(cx, id, false);
|
||||
if (!globalType->unknownProperties()) {
|
||||
propertyTypes = globalType->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
}
|
||||
if (!propertyTypes || propertyTypes->isOwnProperty(cx, staticType, true)) {
|
||||
if (!propertyTypes || propertyTypes->isOwnProperty(cx, globalType, true)) {
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
return jsop_setprop(name);
|
||||
@ -6049,36 +6051,48 @@ IonBuilder::setStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
if (!TypeSetIncludes(propertyTypes, value->type(), value->resultTypeSet()))
|
||||
return jsop_setprop(name);
|
||||
|
||||
current->pop();
|
||||
|
||||
// Pop the bound object on the stack.
|
||||
MDefinition *obj = current->pop();
|
||||
JS_ASSERT(&obj->toConstant()->value().toObject() == staticObject);
|
||||
MInstruction *global = MConstant::New(ObjectValue(*globalObj));
|
||||
current->add(global);
|
||||
|
||||
// If we have a property type set, the isOwnProperty call will trigger recompilation
|
||||
// if the property is deleted or reconfigured. Without TI, we always need a shape guard
|
||||
// to guard against the property being reconfigured as non-writable.
|
||||
if (!propertyTypes)
|
||||
obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard);
|
||||
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
|
||||
|
||||
MSlots *slots = MSlots::New(global);
|
||||
current->add(slots);
|
||||
|
||||
// Note: we do not use a post barrier when writing to the global object.
|
||||
// Slots in the global object will be treated as roots during a minor GC.
|
||||
if (!staticObject->isGlobal() && NeedsPostBarrier(info(), value))
|
||||
current->add(MPostWriteBarrier::New(obj, value));
|
||||
current->pop();
|
||||
MStoreSlot *store = MStoreSlot::New(slots, shape->slot() - globalObj->numFixedSlots(), value);
|
||||
current->add(store);
|
||||
|
||||
// Determine whether write barrier is required.
|
||||
if (!propertyTypes || propertyTypes->needsBarrier(cx))
|
||||
store->setNeedsBarrier();
|
||||
|
||||
// Pop the global object pushed by bindgname.
|
||||
DebugOnly<MDefinition *> pushedGlobal = current->pop();
|
||||
JS_ASSERT(&pushedGlobal->toConstant()->value().toObject() == globalObj);
|
||||
|
||||
// If the property has a known type, we may be able to optimize typed stores by not
|
||||
// storing the type tag. This only works if the property does not have its initial
|
||||
// |undefined| value; if |undefined| is assigned at a later point, it will be added
|
||||
// to the type set.
|
||||
MIRType slotType = MIRType_None;
|
||||
if (propertyTypes && !staticObject->getSlot(shape->slot()).isUndefined()) {
|
||||
if (propertyTypes && !globalObj->getSlot(shape->slot()).isUndefined()) {
|
||||
JSValueType knownType = propertyTypes->getKnownTypeTag(cx);
|
||||
if (knownType != JSVAL_TYPE_UNKNOWN)
|
||||
slotType = MIRTypeFromValueType(knownType);
|
||||
store->setSlotType(MIRTypeFromValueType(knownType));
|
||||
}
|
||||
|
||||
bool needsBarrier = !propertyTypes || propertyTypes->needsBarrier(cx);
|
||||
return storeSlot(obj, shape, value, needsBarrier, slotType);
|
||||
JS_ASSERT_IF(store->needsBarrier(), store->slotType() != MIRType_None);
|
||||
|
||||
current->push(value);
|
||||
return resumeAfter(store);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -7004,14 +7018,6 @@ GetDefiniteSlot(JSContext *cx, types::StackTypeSet *types, JSAtom *atom)
|
||||
return propertyTypes;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_runonce()
|
||||
{
|
||||
MRunOncePrologue *ins = MRunOncePrologue::New();
|
||||
current->add(ins);
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_not()
|
||||
{
|
||||
@ -7358,8 +7364,7 @@ IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
|
||||
MIRType slotType /* = MIRType_None */)
|
||||
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier)
|
||||
{
|
||||
JS_ASSERT(shape->hasDefaultSetter());
|
||||
JS_ASSERT(shape->writable());
|
||||
@ -7382,8 +7387,6 @@ IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool n
|
||||
current->push(value);
|
||||
if (needsBarrier)
|
||||
store->setNeedsBarrier();
|
||||
if (slotType != MIRType_None)
|
||||
store->setSlotType(slotType);
|
||||
return resumeAfter(store);
|
||||
}
|
||||
|
||||
@ -8092,70 +8095,9 @@ IonBuilder::walkScopeChain(unsigned hops)
|
||||
return scope;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall)
|
||||
{
|
||||
JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script(), pc);
|
||||
if (!outerScript || !outerScript->treatAsRunOnce)
|
||||
return false;
|
||||
|
||||
types::TypeObject *funType = outerScript->function()->getType(cx);
|
||||
if (!funType)
|
||||
return false;
|
||||
if (types::HeapTypeSet::HasObjectFlags(cx, funType, types::OBJECT_FLAG_RUNONCE_INVALIDATED))
|
||||
return false;
|
||||
|
||||
// The script this aliased var operation is accessing will run only once,
|
||||
// so there will be only one call object and the aliased var access can be
|
||||
// compiled in the same manner as a global access. We still need to find
|
||||
// the call object though.
|
||||
|
||||
// Look for the call object on the current script's function's scope chain.
|
||||
// If the current script is inner to the outer script and the function has
|
||||
// singleton type then it should show up here.
|
||||
|
||||
MDefinition *scope = current->getSlot(info().scopeChainSlot());
|
||||
scope->setFoldedUnchecked();
|
||||
|
||||
JSObject *environment = script()->function()->environment();
|
||||
while (environment && !environment->isGlobal()) {
|
||||
if (environment->isCall() &&
|
||||
!environment->asCall().isForEval() &&
|
||||
environment->asCall().callee().nonLazyScript() == outerScript)
|
||||
{
|
||||
JS_ASSERT(environment->hasSingletonType());
|
||||
pcall.set(environment);
|
||||
return true;
|
||||
}
|
||||
environment = environment->enclosingScope();
|
||||
}
|
||||
|
||||
// Look for the call object on the current frame, if we are compiling the
|
||||
// outer script itself. Don't do this if we are at entry to the outer
|
||||
// script, as the call object we see will not be the real one --- after
|
||||
// entering the Ion code a different call object will be created.
|
||||
|
||||
if (script() == outerScript && fp && info().osrPc()) {
|
||||
JSObject *scope = fp.scopeChain();
|
||||
if (scope->isCall() && scope->asCall().callee().nonLazyScript() == outerScript) {
|
||||
JS_ASSERT(scope->hasSingletonType());
|
||||
pcall.set(scope);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
||||
{
|
||||
RootedObject call(cx);
|
||||
if (hasStaticScopeObject(sc, &call) && call) {
|
||||
RootedPropertyName name(cx, ScopeCoordinateName(cx, script(), pc));
|
||||
return getStaticName(call, name);
|
||||
}
|
||||
|
||||
MDefinition *obj = walkScopeChain(sc.hops);
|
||||
|
||||
RootedShape shape(cx, ScopeCoordinateToStaticScopeShape(cx, script(), pc));
|
||||
@ -8180,34 +8122,6 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
||||
bool
|
||||
IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
|
||||
{
|
||||
RootedObject call(cx);
|
||||
if (hasStaticScopeObject(sc, &call)) {
|
||||
uint32_t depth = current->stackDepth() + 1;
|
||||
if (depth > current->nslots()) {
|
||||
if (!current->increaseSlots(depth - current->nslots()))
|
||||
return false;
|
||||
}
|
||||
MDefinition *value = current->pop();
|
||||
RootedPropertyName name(cx, ScopeCoordinateName(cx, script(), pc));
|
||||
|
||||
if (call) {
|
||||
// Push the object on the stack to match the bound object expected in
|
||||
// the global and property set cases.
|
||||
MInstruction *constant = MConstant::New(ObjectValue(*call));
|
||||
current->add(constant);
|
||||
current->push(constant);
|
||||
current->push(value);
|
||||
return setStaticName(call, name);
|
||||
}
|
||||
|
||||
// The call object has type information we need to respect but we
|
||||
// couldn't find it. Just do a normal property assign.
|
||||
MDefinition *obj = walkScopeChain(sc.hops);
|
||||
current->push(obj);
|
||||
current->push(value);
|
||||
return jsop_setprop(name);
|
||||
}
|
||||
|
||||
MDefinition *rval = current->peek(-1);
|
||||
MDefinition *obj = walkScopeChain(sc.hops);
|
||||
|
||||
|
@ -339,11 +339,9 @@ class IonBuilder : public MIRGenerator
|
||||
|
||||
bool invalidatedIdempotentCache();
|
||||
|
||||
bool hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall);
|
||||
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
bool barrier, types::StackTypeSet *types);
|
||||
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
|
||||
MIRType slotType = MIRType_None);
|
||||
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier);
|
||||
|
||||
// jsop_getprop() helpers.
|
||||
bool getPropTryArgumentsLength(bool *emitted);
|
||||
@ -383,8 +381,8 @@ class IonBuilder : public MIRGenerator
|
||||
bool jsop_dup2();
|
||||
bool jsop_loophead(jsbytecode *pc);
|
||||
bool jsop_compare(JSOp op);
|
||||
bool getStaticName(HandleObject staticObject, HandlePropertyName name);
|
||||
bool setStaticName(HandleObject staticObject, HandlePropertyName name);
|
||||
bool jsop_getgname(HandlePropertyName name);
|
||||
bool jsop_setgname(HandlePropertyName name);
|
||||
bool jsop_getname(HandlePropertyName name);
|
||||
bool jsop_intrinsic(HandlePropertyName name);
|
||||
bool jsop_bindname(PropertyName *name);
|
||||
@ -408,7 +406,6 @@ class IonBuilder : public MIRGenerator
|
||||
bool jsop_arguments_length();
|
||||
bool jsop_arguments_getelem();
|
||||
bool jsop_arguments_setelem(MDefinition *object, MDefinition *index, MDefinition *value);
|
||||
bool jsop_runonce();
|
||||
bool jsop_rest();
|
||||
bool jsop_not();
|
||||
bool jsop_getprop(HandlePropertyName name);
|
||||
|
@ -4106,16 +4106,6 @@ class LGetArgument : public LInstructionHelper<BOX_PIECES, 1, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LRunOncePrologue : public LCallInstructionHelper<0, 0, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(RunOncePrologue)
|
||||
|
||||
MRunOncePrologue *mir() const {
|
||||
return mir_->toRunOncePrologue();
|
||||
}
|
||||
};
|
||||
|
||||
// Create the rest parameter.
|
||||
class LRest : public LCallInstructionHelper<1, 1, 3>
|
||||
{
|
||||
@ -4161,6 +4151,7 @@ class LParRest : public LCallInstructionHelper<1, 2, 3>
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class LParWriteGuard : public LCallInstructionHelper<0, 2, 1>
|
||||
{
|
||||
public:
|
||||
|
@ -205,7 +205,6 @@
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetArgument) \
|
||||
_(RunOncePrologue) \
|
||||
_(Rest) \
|
||||
_(ParRest) \
|
||||
_(TypeOfV) \
|
||||
|
@ -2472,13 +2472,6 @@ LIRGenerator::visitGetArgument(MGetArgument *ins)
|
||||
return defineBox(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitRunOncePrologue(MRunOncePrologue *ins)
|
||||
{
|
||||
LRunOncePrologue *lir = new LRunOncePrologue;
|
||||
return add(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitRest(MRest *ins)
|
||||
{
|
||||
|
@ -219,7 +219,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitStringLength(MStringLength *ins);
|
||||
bool visitArgumentsLength(MArgumentsLength *ins);
|
||||
bool visitGetArgument(MGetArgument *ins);
|
||||
bool visitRunOncePrologue(MRunOncePrologue *ins);
|
||||
bool visitRest(MRest *ins);
|
||||
bool visitParRest(MParRest *ins);
|
||||
bool visitThrow(MThrow *ins);
|
||||
|
@ -2273,23 +2273,6 @@ class MSetArgumentsObjectArg
|
||||
}
|
||||
};
|
||||
|
||||
class MRunOncePrologue
|
||||
: public MNullaryInstruction
|
||||
{
|
||||
protected:
|
||||
MRunOncePrologue()
|
||||
{
|
||||
setGuard();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(RunOncePrologue)
|
||||
|
||||
static MRunOncePrologue *New() {
|
||||
return new MRunOncePrologue();
|
||||
}
|
||||
};
|
||||
|
||||
// Given a MIRType_Value A and a MIRType_Object B:
|
||||
// If the Value may be safely unboxed to an Object, return Object(A).
|
||||
// Otherwise, return B.
|
||||
@ -7367,12 +7350,10 @@ class MNewDeclEnvObject : public MNullaryInstruction
|
||||
class MNewCallObject : public MUnaryInstruction
|
||||
{
|
||||
CompilerRootObject templateObj_;
|
||||
bool needsSingletonType_;
|
||||
|
||||
MNewCallObject(HandleObject templateObj, bool needsSingletonType, MDefinition *slots)
|
||||
MNewCallObject(HandleObject templateObj, MDefinition *slots)
|
||||
: MUnaryInstruction(slots),
|
||||
templateObj_(templateObj),
|
||||
needsSingletonType_(needsSingletonType)
|
||||
templateObj_(templateObj)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
}
|
||||
@ -7380,8 +7361,8 @@ class MNewCallObject : public MUnaryInstruction
|
||||
public:
|
||||
INSTRUCTION_HEADER(NewCallObject)
|
||||
|
||||
static MNewCallObject *New(HandleObject templateObj, bool needsSingletonType, MDefinition *slots) {
|
||||
return new MNewCallObject(templateObj, needsSingletonType, slots);
|
||||
static MNewCallObject *New(HandleObject templateObj, MDefinition *slots) {
|
||||
return new MNewCallObject(templateObj, slots);
|
||||
}
|
||||
|
||||
MDefinition *slots() {
|
||||
@ -7390,9 +7371,6 @@ class MNewCallObject : public MUnaryInstruction
|
||||
JSObject *templateObject() {
|
||||
return templateObj_;
|
||||
}
|
||||
bool needsSingletonType() {
|
||||
return needsSingletonType_;
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
@ -154,7 +154,6 @@ namespace ion {
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetArgument) \
|
||||
_(RunOncePrologue) \
|
||||
_(Rest) \
|
||||
_(Floor) \
|
||||
_(Round) \
|
||||
|
@ -239,7 +239,6 @@ class ParallelArrayVisitor : public MInstructionVisitor
|
||||
SAFE_OP(StringLength)
|
||||
UNSAFE_OP(ArgumentsLength)
|
||||
UNSAFE_OP(GetArgument)
|
||||
UNSAFE_OP(RunOncePrologue)
|
||||
CUSTOM_OP(Rest)
|
||||
SAFE_OP(ParRest)
|
||||
SAFE_OP(Floor)
|
||||
|
@ -388,22 +388,13 @@ StringFromCharCode(JSContext *cx, int32_t code)
|
||||
|
||||
bool
|
||||
SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
|
||||
bool strict, int jsop)
|
||||
bool strict, bool isSetName)
|
||||
{
|
||||
RootedValue v(cx, value);
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
if (jsop == JSOP_SETALIASEDVAR) {
|
||||
// Aliased var assigns ignore readonly attributes on the property, as
|
||||
// required for initializing 'const' closure variables.
|
||||
Shape *shape = obj->nativeLookup(cx, name);
|
||||
JS_ASSERT(shape && shape->hasSlot());
|
||||
JSObject::nativeSetSlotWithType(cx, obj, shape, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (JS_LIKELY(!obj->getOps()->setProperty)) {
|
||||
unsigned defineHow = (jsop == JSOP_SETNAME || jsop == JSOP_SETGNAME) ? DNP_UNQUALIFIED : 0;
|
||||
unsigned defineHow = isSetName ? DNP_UNQUALIFIED : 0;
|
||||
return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict);
|
||||
}
|
||||
|
||||
@ -434,10 +425,9 @@ NewSlots(JSRuntime *rt, unsigned nslots)
|
||||
}
|
||||
|
||||
JSObject *
|
||||
NewCallObject(JSContext *cx, HandleScript script,
|
||||
HandleShape shape, HandleTypeObject type, HeapSlot *slots)
|
||||
NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
|
||||
{
|
||||
return CallObject::create(cx, script, shape, type, slots);
|
||||
return CallObject::create(cx, shape, type, slots);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -510,13 +510,12 @@ bool CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code);
|
||||
JSFlatString *StringFromCharCode(JSContext *cx, int32_t code);
|
||||
|
||||
bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
|
||||
bool strict, int jsop);
|
||||
bool strict, bool isSetName);
|
||||
|
||||
bool InterruptCheck(JSContext *cx);
|
||||
|
||||
HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
|
||||
JSObject *NewCallObject(JSContext *cx, HandleScript script,
|
||||
HandleShape shape, HandleTypeObject type, HeapSlot *slots);
|
||||
JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
|
||||
JSObject *NewStringObject(JSContext *cx, HandleString str);
|
||||
|
||||
bool SPSEnter(JSContext *cx, HandleScript script);
|
||||
|
@ -1,8 +0,0 @@
|
||||
assertEq((function() {
|
||||
for (var i = 0; i < 5; i++) {
|
||||
print(i);
|
||||
}
|
||||
const x = 3;
|
||||
(function() x++)();
|
||||
return x
|
||||
})(), 3);
|
@ -1,28 +0,0 @@
|
||||
// Test that closures are deoptimized if they unexpectedly run multiple times.
|
||||
|
||||
with({}){}
|
||||
|
||||
(function(n) {
|
||||
if (n == 20) {
|
||||
outer = (function f() { return f.caller; })();
|
||||
inner = function g() { return x++; }
|
||||
}
|
||||
var x = 0;
|
||||
for (var i = 0; i < n; i++)
|
||||
x++;
|
||||
if (n != 20)
|
||||
inner = function g() { return x++; }
|
||||
})(20);
|
||||
|
||||
oldInner = inner;
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(oldInner(), 20 + i);
|
||||
|
||||
outer(40);
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(inner(), 40 + i);
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(oldInner(), 25 + i);
|
@ -4123,7 +4123,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
||||
case JSOP_TABLESWITCH:
|
||||
case JSOP_TRY:
|
||||
case JSOP_LABEL:
|
||||
case JSOP_RUNONCE:
|
||||
break;
|
||||
|
||||
/* Bytecodes pushing values of known type. */
|
||||
|
@ -395,14 +395,8 @@ enum {
|
||||
/* Whether any objects emulate undefined; see EmulatesUndefined. */
|
||||
OBJECT_FLAG_EMULATES_UNDEFINED = 0x00400000,
|
||||
|
||||
/*
|
||||
* For the function on a run-once script, whether the function has actually
|
||||
* run multiple times.
|
||||
*/
|
||||
OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00800000,
|
||||
|
||||
/* Flags which indicate dynamic properties of represented objects. */
|
||||
OBJECT_FLAG_DYNAMIC_MASK = 0x00ff0000,
|
||||
OBJECT_FLAG_DYNAMIC_MASK = 0x007f0000,
|
||||
|
||||
/*
|
||||
* Whether all properties of this object are considered unknown.
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include "jscompartment.h"
|
||||
#include "jsinfer.h"
|
||||
#include "jsprf.h"
|
||||
#include "jsproxy.h"
|
||||
#include "jstypedarray.h"
|
||||
|
||||
#include "builtin/ParallelArray.h"
|
||||
#ifdef JS_ION
|
||||
|
@ -1287,6 +1287,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool
|
||||
|
||||
/* No-ops for ease of decompilation. */
|
||||
ADD_EMPTY_CASE(JSOP_NOP)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED71)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED132)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED148)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED161)
|
||||
@ -2520,13 +2521,6 @@ BEGIN_CASE(JSOP_ARGUMENTS)
|
||||
}
|
||||
END_CASE(JSOP_ARGUMENTS)
|
||||
|
||||
BEGIN_CASE(JSOP_RUNONCE)
|
||||
{
|
||||
if (!RunOnceScriptPrologue(cx, script))
|
||||
goto error;
|
||||
}
|
||||
END_CASE(JSOP_RUNONCE)
|
||||
|
||||
BEGIN_CASE(JSOP_REST)
|
||||
{
|
||||
RootedObject &rest = rootObject0;
|
||||
@ -2555,13 +2549,7 @@ END_CASE(JSOP_GETALIASEDVAR)
|
||||
BEGIN_CASE(JSOP_SETALIASEDVAR)
|
||||
{
|
||||
ScopeCoordinate sc = ScopeCoordinate(regs.pc);
|
||||
ScopeObject &obj = regs.fp()->aliasedVarScope(sc);
|
||||
|
||||
// Avoid computing the name if no type updates are needed, as this may be
|
||||
// expensive on scopes with large numbers of variables.
|
||||
PropertyName *name = obj.hasSingletonType() ? ScopeCoordinateName(cx, script, regs.pc) : NULL;
|
||||
|
||||
obj.setAliasedVar(cx, sc, name, regs.sp[-1]);
|
||||
regs.fp()->aliasedVarScope(sc).setAliasedVar(sc, regs.sp[-1]);
|
||||
}
|
||||
END_CASE(JSOP_SETALIASEDVAR)
|
||||
|
||||
@ -3654,22 +3642,3 @@ js::ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyNa
|
||||
|
||||
return ComputeImplicitThis(cx, obj, res);
|
||||
}
|
||||
|
||||
bool
|
||||
js::RunOnceScriptPrologue(JSContext *cx, HandleScript script)
|
||||
{
|
||||
JS_ASSERT(script->treatAsRunOnce);
|
||||
|
||||
if (!script->hasRunOnce) {
|
||||
script->hasRunOnce = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Force instantiation of the script's function's type to ensure the flag
|
||||
// is preserved in type information.
|
||||
if (!script->function()->getType(cx))
|
||||
return false;
|
||||
|
||||
types::MarkTypeObjectFlags(cx, script->function(), types::OBJECT_FLAG_RUNONCE_INVALIDATED);
|
||||
return true;
|
||||
}
|
||||
|
@ -414,9 +414,6 @@ IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rv
|
||||
bool
|
||||
IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval);
|
||||
|
||||
bool
|
||||
RunOnceScriptPrologue(JSContext *cx, HandleScript script);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsinterp_h___ */
|
||||
|
@ -160,12 +160,7 @@ OPDEF(JSOP_AND, 69, "and", NULL, 5, 1, 1, 6, JOF_JUMP|J
|
||||
|
||||
/* The switch bytecodes have variable length. */
|
||||
OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING)
|
||||
|
||||
/*
|
||||
* Prologue emitted in scripts expected to run once, which deoptimizes code if
|
||||
* it executes multiple times.
|
||||
*/
|
||||
OPDEF(JSOP_RUNONCE, 71, "runonce", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_UNUSED71, 71, "unused71", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/* New, infallible/transitive identity ops. */
|
||||
OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH)
|
||||
|
@ -2776,7 +2776,7 @@ js::SetFrameArgumentsObject(JSContext *cx, AbstractFramePtr frame,
|
||||
JS_ASSERT(*pc == JSOP_SETALIASEDVAR);
|
||||
|
||||
if (frame.callObj().asScope().aliasedVar(pc).isMagic(JS_OPTIMIZED_ARGUMENTS))
|
||||
frame.callObj().asScope().setAliasedVar(cx, pc, cx->names().arguments, ObjectValue(*argsobj));
|
||||
frame.callObj().asScope().setAliasedVar(pc, ObjectValue(*argsobj));
|
||||
} else {
|
||||
if (frame.unaliasedLocal(var).isMagic(JS_OPTIMIZED_ARGUMENTS))
|
||||
frame.unaliasedLocal(var) = ObjectValue(*argsobj);
|
||||
|
@ -411,7 +411,6 @@ class JSScript : public js::gc::Cell
|
||||
script */
|
||||
bool hasSingletons:1; /* script has singleton objects */
|
||||
bool treatAsRunOnce:1; /* script is a lambda to treat as running once. */
|
||||
bool hasRunOnce:1; /* if treatAsRunOnce, whether script has executed. */
|
||||
bool hasBeenCloned:1; /* script has been reused for a clone. */
|
||||
bool isActiveEval:1; /* script came from eval(), and is still active */
|
||||
bool isCachedEval:1; /* script came from eval(), and is in eval cache */
|
||||
|
@ -81,7 +81,7 @@ ArgumentsObject::element(uint32_t i) const
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setElement(JSContext *cx, uint32_t i, const Value &v)
|
||||
ArgumentsObject::setElement(uint32_t i, const Value &v)
|
||||
{
|
||||
JS_ASSERT(!isElementDeleted(i));
|
||||
HeapValue &lhs = data()->args[i];
|
||||
@ -89,7 +89,7 @@ ArgumentsObject::setElement(JSContext *cx, uint32_t i, const Value &v)
|
||||
CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall();
|
||||
for (AliasedFormalIter fi(callobj.callee().nonLazyScript()); ; fi++) {
|
||||
if (fi.frameIndex() == i) {
|
||||
callobj.setAliasedVar(cx, fi, fi->name(), v);
|
||||
callobj.setAliasedVar(fi, v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHa
|
||||
if (JSID_IS_INT(id)) {
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
|
||||
argsobj.setElement(cx, arg, vp);
|
||||
argsobj.setElement(arg, vp);
|
||||
if (arg < script->function()->nargs)
|
||||
types::TypeScript::SetArgument(cx, script, arg, vp);
|
||||
return true;
|
||||
@ -475,7 +475,7 @@ StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Mut
|
||||
if (JSID_IS_INT(id)) {
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
if (arg < argsobj->initialLength()) {
|
||||
argsobj->setElement(cx, arg, vp);
|
||||
argsobj->setElement(arg, vp);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
@ -177,7 +177,7 @@ class ArgumentsObject : public JSObject
|
||||
* needed, the frontend should have emitted JSOP_GETALIASEDVAR.
|
||||
*/
|
||||
inline const Value &element(uint32_t i) const;
|
||||
inline void setElement(JSContext *cx, uint32_t i, const Value &v);
|
||||
inline void setElement(uint32_t i, const Value &v);
|
||||
inline const Value &arg(unsigned i) const;
|
||||
inline void setArg(unsigned i, const Value &v);
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "ScopeObject.h"
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
namespace js {
|
||||
@ -43,17 +42,11 @@ ScopeObject::aliasedVar(ScopeCoordinate sc)
|
||||
}
|
||||
|
||||
inline void
|
||||
ScopeObject::setAliasedVar(JSContext *cx, ScopeCoordinate sc, PropertyName *name, const Value &v)
|
||||
ScopeObject::setAliasedVar(ScopeCoordinate sc, const Value &v)
|
||||
{
|
||||
JS_ASSERT(isCall() || isClonedBlock());
|
||||
JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == BlockObject::RESERVED_SLOTS);
|
||||
|
||||
// name may be null for non-singletons, whose types do not need to be tracked.
|
||||
JS_ASSERT_IF(hasSingletonType(), name);
|
||||
|
||||
setSlot(sc.slot, v);
|
||||
if (hasSingletonType())
|
||||
types::AddTypePropertyId(cx, this, NameToId(name), v);
|
||||
}
|
||||
|
||||
/*static*/ inline size_t
|
||||
@ -84,12 +77,9 @@ CallObject::aliasedVar(AliasedFormalIter fi)
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::setAliasedVar(JSContext *cx, AliasedFormalIter fi, PropertyName *name, const Value &v)
|
||||
CallObject::setAliasedVar(AliasedFormalIter fi, const Value &v)
|
||||
{
|
||||
JS_ASSERT(name == fi->name());
|
||||
setSlot(fi.scopeSlot(), v);
|
||||
if (hasSingletonType())
|
||||
types::AddTypePropertyId(cx, this, NameToId(name), v);
|
||||
}
|
||||
|
||||
/*static*/ inline size_t
|
||||
|
@ -28,7 +28,7 @@ typedef Rooted<ArgumentsObject *> RootedArgumentsObject;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
StaticScopeIter::StaticScopeIter(JSContext *cx, JSObject *objArg)
|
||||
StaticScopeIter::StaticScopeIter(JSContext *cx, HandleObject objArg)
|
||||
: obj(cx, objArg), onNamedLambda(false)
|
||||
{
|
||||
JS_ASSERT_IF(obj, obj->isStaticBlock() || obj->isFunction());
|
||||
@ -97,23 +97,20 @@ StaticScopeIter::funScript() const
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static JSObject *
|
||||
InnermostStaticScope(JSScript *script, jsbytecode *pc)
|
||||
Shape *
|
||||
js::ScopeCoordinateToStaticScopeShape(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(pc >= script->code && pc < script->code + script->length);
|
||||
JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
|
||||
|
||||
uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t));
|
||||
|
||||
RootedObject innermostStaticScope(cx, NULL);
|
||||
if (blockIndex == UINT32_MAX)
|
||||
return script->function();
|
||||
return &script->getObject(blockIndex)->asStaticBlock();
|
||||
}
|
||||
innermostStaticScope = script->function();
|
||||
else
|
||||
innermostStaticScope = &script->getObject(blockIndex)->asStaticBlock();
|
||||
|
||||
Shape *
|
||||
js::ScopeCoordinateToStaticScopeShape(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
StaticScopeIter ssi(cx, InnermostStaticScope(script, pc));
|
||||
StaticScopeIter ssi(cx, innermostStaticScope);
|
||||
ScopeCoordinate sc(pc);
|
||||
while (true) {
|
||||
if (ssi.hasDynamicScopeObject()) {
|
||||
@ -141,24 +138,6 @@ js::ScopeCoordinateName(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
return JSID_TO_ATOM(id)->asPropertyName();
|
||||
}
|
||||
|
||||
JSScript *
|
||||
js::ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
StaticScopeIter ssi(cx, InnermostStaticScope(script, pc));
|
||||
ScopeCoordinate sc(pc);
|
||||
while (true) {
|
||||
if (ssi.hasDynamicScopeObject()) {
|
||||
if (!sc.hops)
|
||||
break;
|
||||
sc.hops--;
|
||||
}
|
||||
ssi++;
|
||||
}
|
||||
if (ssi.type() != StaticScopeIter::FUNCTION)
|
||||
return NULL;
|
||||
return ssi.funScript();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
@ -166,24 +145,16 @@ js::ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *p
|
||||
* The call object must be further initialized to be usable.
|
||||
*/
|
||||
CallObject *
|
||||
CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
|
||||
CallObject::create(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
|
||||
{
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
|
||||
JS_ASSERT(CanBeFinalizedInBackground(kind, &CallClass));
|
||||
kind = gc::GetBackgroundAllocKind(kind);
|
||||
|
||||
gc::InitialHeap heap = script->treatAsRunOnce ? gc::TenuredHeap : gc::DefaultHeap;
|
||||
JSObject *obj = JSObject::create(cx, kind, heap, shape, type, slots);
|
||||
JSObject *obj = JSObject::create(cx, kind, GetInitialHeap(GenericObject, &CallClass),
|
||||
shape, type, slots);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
if (script->treatAsRunOnce) {
|
||||
RootedObject nobj(cx, obj);
|
||||
if (!JSObject::setSingletonType(cx, nobj))
|
||||
return NULL;
|
||||
return &nobj->asCall();
|
||||
}
|
||||
|
||||
return &obj->asCall();
|
||||
}
|
||||
|
||||
@ -228,14 +199,6 @@ CallObject::create(JSContext *cx, HandleScript script, HandleObject enclosing, H
|
||||
|
||||
callobj->asScope().setEnclosingScope(enclosing);
|
||||
callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
|
||||
|
||||
if (script->treatAsRunOnce) {
|
||||
Rooted<CallObject*> ncallobj(cx, callobj);
|
||||
if (!JSObject::setSingletonType(cx, ncallobj))
|
||||
return NULL;
|
||||
return ncallobj;
|
||||
}
|
||||
|
||||
return callobj;
|
||||
}
|
||||
|
||||
@ -273,10 +236,8 @@ CallObject::createForFunction(JSContext *cx, AbstractFramePtr frame)
|
||||
return NULL;
|
||||
|
||||
/* Copy in the closed-over formal arguments. */
|
||||
for (AliasedFormalIter i(frame.script()); i; i++) {
|
||||
callobj->setAliasedVar(cx, i, i->name(),
|
||||
frame.unaliasedFormal(i.frameIndex(), DONT_CHECK_ALIASING));
|
||||
}
|
||||
for (AliasedFormalIter i(frame.script()); i; i++)
|
||||
callobj->setAliasedVar(i, frame.unaliasedFormal(i.frameIndex(), DONT_CHECK_ALIASING));
|
||||
|
||||
return callobj;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class StaticScopeIter
|
||||
bool onNamedLambda;
|
||||
|
||||
public:
|
||||
explicit StaticScopeIter(JSContext *cx, JSObject *obj);
|
||||
explicit StaticScopeIter(JSContext *cx, HandleObject obj);
|
||||
|
||||
bool done() const;
|
||||
void operator++(int);
|
||||
@ -106,10 +106,6 @@ ScopeCoordinateToStaticScopeShape(JSContext *cx, JSScript *script, jsbytecode *p
|
||||
extern PropertyName *
|
||||
ScopeCoordinateName(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
/* Return the function script accessed by the given ALIASEDVAR op, or NULL. */
|
||||
extern JSScript *
|
||||
ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
@ -171,7 +167,7 @@ class ScopeObject : public JSObject
|
||||
* take a ScopeCoordinate instead of just the slot index.
|
||||
*/
|
||||
inline const Value &aliasedVar(ScopeCoordinate sc);
|
||||
inline void setAliasedVar(JSContext *cx, ScopeCoordinate sc, PropertyName *name, const Value &v);
|
||||
inline void setAliasedVar(ScopeCoordinate sc, const Value &v);
|
||||
|
||||
/* For jit access. */
|
||||
static inline size_t offsetOfEnclosingScope();
|
||||
@ -191,7 +187,7 @@ class CallObject : public ScopeObject
|
||||
public:
|
||||
/* These functions are internal and are exposed only for JITs. */
|
||||
static CallObject *
|
||||
create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
|
||||
create(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
|
||||
|
||||
static CallObject *
|
||||
createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);
|
||||
@ -214,7 +210,7 @@ class CallObject : public ScopeObject
|
||||
|
||||
/* Get/set the aliased variable referred to by 'bi'. */
|
||||
inline const Value &aliasedVar(AliasedFormalIter fi);
|
||||
inline void setAliasedVar(JSContext *cx, AliasedFormalIter fi, PropertyName *name, const Value &v);
|
||||
inline void setAliasedVar(AliasedFormalIter fi, const Value &v);
|
||||
|
||||
/* For jit access. */
|
||||
static inline size_t offsetOfCallee();
|
||||
|
@ -26,7 +26,7 @@ namespace js {
|
||||
* and saved versions. If deserialization fails, the data should be
|
||||
* invalidated if possible.
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 145);
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 144);
|
||||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
|
@ -23,13 +23,12 @@ dl.google.com: did not receive HSTS header
|
||||
dm.lookout.com: did not receive HSTS header
|
||||
dm.mylookout.com: did not receive HSTS header
|
||||
docs.google.com: did not receive HSTS header
|
||||
download.jitsi.org: did not receive HSTS header
|
||||
drive.google.com: did not receive HSTS header
|
||||
dropcam.com: did not receive HSTS header
|
||||
ebanking.indovinabank.com.vn: could not connect to host
|
||||
emailprivacytester.com: max-age too low: 8640000
|
||||
encrypted.google.com: did not receive HSTS header
|
||||
epoxate.com: max-age too low: 259200
|
||||
espra.com: could not connect to host
|
||||
fatzebra.com.au: did not receive HSTS header
|
||||
fj.simple.com: did not receive HSTS header
|
||||
gmail.com: did not receive HSTS header
|
||||
@ -49,12 +48,10 @@ kiwiirc.com: max-age too low: 5256000
|
||||
ledgerscope.net: max-age too low: 86400
|
||||
linx.net: did not receive HSTS header
|
||||
lists.mayfirst.org: did not receive HSTS header
|
||||
lookout.com: did not receive HSTS header
|
||||
mail.google.com: did not receive HSTS header
|
||||
market.android.com: did not receive HSTS header
|
||||
my.alfresco.com: did not receive HSTS header
|
||||
mydigipass.com: did not receive HSTS header
|
||||
mylookout.com: did not receive HSTS header
|
||||
neonisi.com: could not connect to host
|
||||
openshift.redhat.com: did not receive HSTS header
|
||||
ottospora.nl: could not connect to host
|
||||
@ -65,6 +62,7 @@ profiles.google.com: did not receive HSTS header
|
||||
romab.com: max-age too low: 2628000
|
||||
sah3.net: could not connect to host
|
||||
script.google.com: did not receive HSTS header
|
||||
security.google.com: did not receive HSTS header
|
||||
shops.neonisi.com: could not connect to host
|
||||
silentcircle.org: could not connect to host
|
||||
simon.butcher.name: max-age too low: 2629743
|
||||
@ -92,7 +90,6 @@ www.ledgerscope.net: max-age too low: 86400
|
||||
www.logentries.com: did not receive HSTS header
|
||||
www.makeyourlaws.org: did not receive HSTS header
|
||||
www.moneybookers.com: did not receive HSTS header
|
||||
www.mylookout.com: did not receive HSTS header
|
||||
www.neonisi.com: could not connect to host
|
||||
www.paycheckrecords.com: did not receive HSTS header
|
||||
www.paypal.com: max-age too low: 14400
|
||||
|
@ -8,7 +8,7 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "mozilla/StandardInteger.h"
|
||||
const PRTime gPreloadListExpirationTime = INT64_C(1379758102034000);
|
||||
const PRTime gPreloadListExpirationTime = INT64_C(1380363248599000);
|
||||
|
||||
class nsSTSPreload
|
||||
{
|
||||
@ -35,6 +35,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "csawctf.poly.edu", true },
|
||||
{ "developer.mydigipass.com", false },
|
||||
{ "dist.torproject.org", false },
|
||||
{ "download.jitsi.org", false },
|
||||
{ "ebanking.indovinabank.com.vn", false },
|
||||
{ "entropia.de", false },
|
||||
{ "espra.com", true },
|
||||
@ -51,6 +52,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "logentries.com", false },
|
||||
{ "login.persona.org", true },
|
||||
{ "login.sapo.pt", true },
|
||||
{ "lookout.com", false },
|
||||
{ "luneta.nearbuysystems.com", false },
|
||||
{ "makeyourlaws.org", false },
|
||||
{ "mattmccutchen.net", true },
|
||||
@ -58,6 +60,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "members.mayfirst.org", false },
|
||||
{ "members.nearlyfreespeech.net", false },
|
||||
{ "my.onlime.ch", false },
|
||||
{ "mylookout.com", false },
|
||||
{ "neg9.org", false },
|
||||
{ "passwd.io", true },
|
||||
{ "pay.gigahost.dk", true },
|
||||
@ -93,6 +96,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "www.irccloud.com", false },
|
||||
{ "www.lookout.com", false },
|
||||
{ "www.mydigipass.com", false },
|
||||
{ "www.mylookout.com", false },
|
||||
{ "www.noisebridge.net", false },
|
||||
{ "www.simple.com", false },
|
||||
{ "www.surfeasy.com", false },
|
||||
|
@ -21,9 +21,5 @@ CPPSRCS = \
|
||||
nsMediaSnifferModule.cpp \
|
||||
$(NULL)
|
||||
|
||||
CSRCS = \
|
||||
mp3sniff.c
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -1,166 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
/* MPEG format parsing */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mp3sniff.h"
|
||||
|
||||
/* Maximum packet size is 320 kbits/s * 144 / 32 kHz + 1 padding byte */
|
||||
#define MP3_MAX_SIZE 1441
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
int layer;
|
||||
int errp;
|
||||
int bitrate;
|
||||
int freq;
|
||||
int pad;
|
||||
int priv;
|
||||
int mode;
|
||||
int modex;
|
||||
int copyright;
|
||||
int original;
|
||||
int emphasis;
|
||||
} mp3_header;
|
||||
|
||||
/* Parse the 4-byte header in p and fill in the header struct. */
|
||||
static void mp3_parse(const uint8_t *p, mp3_header *header)
|
||||
{
|
||||
const int bitrates[16] =
|
||||
{0, 32000, 40000, 48000, 56000, 64000, 80000, 96000,
|
||||
112000, 128000, 160000, 192000, 224000, 256000, 320000, 0};
|
||||
const int samplerates[4] = {44100, 48000, 32000, 0};
|
||||
|
||||
header->version = (p[1] & 0x08) >> 3;
|
||||
header->layer = 4 - ((p[1] & 0x06) >> 1);
|
||||
header->errp = (p[1] & 0x01);
|
||||
|
||||
header->bitrate = bitrates[(p[2] & 0xf0) >> 4];
|
||||
header->freq = samplerates[(p[2] & 0x0c) >> 2];
|
||||
header->pad = (p[2] & 0x02) >> 1;
|
||||
header->priv = (p[2] & 0x01);
|
||||
|
||||
header->mode = (p[3] & 0xc0) >> 6;
|
||||
header->modex = (p[3] & 0x30) >> 4;
|
||||
header->copyright = (p[3] & 0x08) >> 3;
|
||||
header->original = (p[3] & 0x04) >> 2;
|
||||
header->emphasis = (p[3] & 0x03);
|
||||
}
|
||||
|
||||
/* calculate the size of an mp3 frame from its header */
|
||||
static int mp3_framesize(mp3_header *header)
|
||||
{
|
||||
int size;
|
||||
int scale;
|
||||
|
||||
if (header->layer == 1) scale = 48;
|
||||
else scale = 144;
|
||||
|
||||
size = header->bitrate * scale / header->freq;
|
||||
/* divide by an extra factor of 2 for MPEG-2? */
|
||||
|
||||
if (header->pad) size += 1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int is_mp3(const uint8_t *p, long length) {
|
||||
/* Do we have enough room to see a 4 byte header? */
|
||||
if (length < 4) return 0;
|
||||
/* Do we have a sync pattern? */
|
||||
if (p[0] == 0xff && (p[1]&0xe0) == 0xe0) {
|
||||
/* Do we have any illegal field values? */
|
||||
if (((p[1] & 0x06) >> 1) == 0) return 0; /* No layer 4 */
|
||||
if (((p[2] & 0xf0) >> 4) == 15) return 0; /* Bitrate can't be 1111 */
|
||||
if (((p[2] & 0x0c) >> 2) == 3) return 0; /* Samplerate can't be 11 */
|
||||
/* Looks like a header. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Identify an ID3 tag based on its header. */
|
||||
/* http://id3.org/id3v2.4.0-structure */
|
||||
static int is_id3(const uint8_t *p, long length) {
|
||||
/* Do we have enough room to see the header? */
|
||||
if (length < 10) return 0;
|
||||
/* Do we have a sync pattern? */
|
||||
if (p[0] == 'I' && p[1] == 'D' && p[2] == '3') {
|
||||
if (p[3] == 0xff || p[4] == 0xff) return 0; /* Illegal version. */
|
||||
if (p[6] & 0x80 || p[7] & 0x80 ||
|
||||
p[8] & 0x80) return 0; /* Bad length encoding. */
|
||||
/* Looks like an id3 header. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the size of an id3 tag structure from its header. */
|
||||
static int id3_framesize(const uint8_t *p, long length)
|
||||
{
|
||||
int size;
|
||||
|
||||
/* Header is 10 bytes. */
|
||||
if (length < 10) {
|
||||
return 0;
|
||||
}
|
||||
/* Frame is header plus declared size. */
|
||||
size = 10 + (p[9] | (p[8] << 7) | (p[7] << 14) | (p[6] << 21));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int mp3_sniff(const uint8_t *buf, long length)
|
||||
{
|
||||
mp3_header header;
|
||||
const uint8_t *p, *q;
|
||||
long skip;
|
||||
long avail;
|
||||
|
||||
p = buf;
|
||||
q = p;
|
||||
avail = length;
|
||||
while (avail > 0) {
|
||||
if (is_id3(p, avail)) {
|
||||
/* Skip over any id3 tags */
|
||||
skip = id3_framesize(p, avail);
|
||||
p += skip;
|
||||
avail -= skip;
|
||||
/* Is there enough data to continue? */
|
||||
if (skip + 4 > avail) {
|
||||
return 0;
|
||||
}
|
||||
} else if (is_mp3(p, avail)) {
|
||||
mp3_parse(p, &header);
|
||||
skip = mp3_framesize(&header);
|
||||
if (skip + 4 > avail) {
|
||||
return 0;
|
||||
}
|
||||
p += skip;
|
||||
avail -= skip;
|
||||
/* Check for a second header at the expected offset. */
|
||||
if (is_mp3(p, avail)) {
|
||||
/* Looks like mp3. */
|
||||
return 1;
|
||||
} else {
|
||||
/* Give up. */
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Advance one byte and look for sync again. */
|
||||
p++;
|
||||
avail--;
|
||||
/* Don't scan for more than the maximum frame size. */
|
||||
if (length - avail > MP3_MAX_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int mp3_sniff(const uint8_t *buf, long length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -10,7 +10,6 @@
|
||||
#include "nsString.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mp3sniff.h"
|
||||
#ifdef MOZ_WEBM
|
||||
#include "nestegg/nestegg.h"
|
||||
#endif
|
||||
@ -85,13 +84,6 @@ static bool MatchesWebM(const uint8_t* aData, const uint32_t aLength)
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function implements mp3 sniffing based on parsing
|
||||
// packet headers and looking for expected boundaries.
|
||||
static bool MatchesMP3(const uint8_t* aData, const uint32_t aLength)
|
||||
{
|
||||
return mp3_sniff(aData, (long)aLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
const uint8_t* aData,
|
||||
@ -142,11 +134,6 @@ nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (MatchesMP3(aData, clampedLength)) {
|
||||
aSniffedType.AssignLiteral(AUDIO_MP3);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Could not sniff the media type, we are required to set it to
|
||||
// application/octet-stream.
|
||||
aSniffedType.AssignLiteral(APPLICATION_OCTET_STREAM);
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -18,23 +18,15 @@ var httpserver = new HttpServer();
|
||||
var testRan = 0;
|
||||
|
||||
// The tests files we want to test, and the type we should have after sniffing.
|
||||
// Those file are real webm and mkv files truncated to 512 bytes.
|
||||
const tests = [
|
||||
// Real webm and mkv files truncated to 512 bytes.
|
||||
{ path: "data/file.webm", expected: "video/webm" },
|
||||
{ path: "data/file.mkv", expected: "application/octet-stream" },
|
||||
// MP3 files with and without id3 headers truncated to 512 bytes.
|
||||
// NB these have 208/209 byte frames, but mp3 can require up to
|
||||
// 1445 bytes to detect with our method.
|
||||
{ path: "data/id3tags.mp3", expected: "audio/mpeg" },
|
||||
{ path: "data/notags.mp3", expected: "audio/mpeg" },
|
||||
// Padding bit flipped in the first header: sniffing should fail.
|
||||
{ path: "data/notags-bad.mp3", expected: "application/octet-stream" },
|
||||
];
|
||||
|
||||
// A basic listener that reads checks the if we sniffed properly.
|
||||
var listener = {
|
||||
onStartRequest: function(request, context) {
|
||||
do_print("Sniffing " + tests[testRan].path);
|
||||
do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType, tests[testRan].expected);
|
||||
},
|
||||
|
@ -3,4 +3,4 @@ head =
|
||||
tail =
|
||||
|
||||
[test_mediasniffer.js]
|
||||
[test_mediasniffer_ext.js]
|
||||
[test_mediasniffer_webm.js]
|
||||
|
Loading…
Reference in New Issue
Block a user