summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--js/src/builtin/Array.js13
-rw-r--r--js/src/builtin/Map.js6
-rw-r--r--js/src/builtin/Set.js6
-rw-r--r--js/src/builtin/String.js9
-rw-r--r--js/src/jit/CodeGenerator.cpp26
-rw-r--r--js/src/jit/CodeGenerator.h1
-rw-r--r--js/src/jit/InlinableNatives.h10
-rw-r--r--js/src/jit/IonBuilder.h1
-rw-r--r--js/src/jit/Lowering.cpp10
-rw-r--r--js/src/jit/Lowering.h1
-rw-r--r--js/src/jit/MCallOptimize.cpp51
-rw-r--r--js/src/jit/MIR.h42
-rw-r--r--js/src/jit/MOpcodes.h1
-rw-r--r--js/src/jit/shared/LIR-shared.h23
-rw-r--r--js/src/jit/shared/LOpcodes-shared.h1
-rw-r--r--js/src/vm/SelfHosting.cpp45
16 files changed, 206 insertions, 40 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js
index 360dd2af17..30e6fb35fb 100644
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -711,13 +711,14 @@ function CreateArrayIterator(obj, kind) {
// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next
function ArrayIteratorNext() {
// Step 1-3.
- if (!IsObject(this) || !IsArrayIterator(this)) {
+ var obj;
+ if (!IsObject(this) || (obj = GuardToArrayIterator(this)) === null) {
return callFunction(CallArrayIteratorMethodIfWrapped, this,
"ArrayIteratorNext");
}
// Step 4.
- var a = UnsafeGetReservedSlot(this, ITERATOR_SLOT_TARGET);
+ var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET);
var result = { value: undefined, done: false };
// Step 5.
@@ -728,10 +729,10 @@ function ArrayIteratorNext() {
// Step 6.
// The index might not be an integer, so we have to do a generic get here.
- var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+ var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
// Step 7.
- var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+ var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
// Step 8-9.
var len = IsPossiblyWrappedTypedArray(a)
@@ -740,13 +741,13 @@ function ArrayIteratorNext() {
// Step 10.
if (index >= len) {
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_TARGET, null);
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null);
result.done = true;
return result;
}
// Step 11.
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1);
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1);
// Step 16.
if (itemKind === ITEM_KIND_VALUE) {
diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js
index 580629a132..434cd6529b 100644
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -62,8 +62,8 @@ function MapIteratorNext() {
var O = this;
// Steps 2-3.
- if (!IsObject(O) || !IsMapIterator(O))
- return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext");
+ if (!IsObject(O) || (O = GuardToMapIterator(O)) === null)
+ return callFunction(CallMapIteratorMethodIfWrapped, this, "MapIteratorNext");
// Steps 4-5 (implemented in _GetNextMapEntryForIterator).
// Steps 8-9 (omitted).
@@ -82,7 +82,7 @@ function MapIteratorNext() {
// Steps 10.b-c (omitted).
// Step 6.
- var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+ var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
var result;
if (itemKind === ITEM_KIND_KEY) {
diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js
index 9af6cf8d1a..e2571e66a8 100644
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -64,8 +64,8 @@ function SetIteratorNext() {
var O = this;
// Steps 2-3.
- if (!IsObject(O) || !IsSetIterator(O))
- return callFunction(CallSetIteratorMethodIfWrapped, O, "SetIteratorNext");
+ if (!IsObject(O) || (O = GuardToSetIterator(O)) === null)
+ return callFunction(CallSetIteratorMethodIfWrapped, this, "SetIteratorNext");
// Steps 4-5 (implemented in _GetNextSetEntryForIterator).
// Steps 8-9 (omitted).
@@ -83,7 +83,7 @@ function SetIteratorNext() {
// Steps 10.b-c (omitted).
// Step 6.
- var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+ var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
var result;
if (itemKind === ITEM_KIND_VALUE) {
diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js
index 6d1d335a05..e5b2ad5525 100644
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -529,16 +529,17 @@ function String_iterator() {
}
function StringIteratorNext() {
- if (!IsObject(this) || !IsStringIterator(this)) {
+ var obj;
+ if (!IsObject(this) || (obj = GuardToStringIterator(this)) === null) {
return callFunction(CallStringIteratorMethodIfWrapped, this,
"StringIteratorNext");
}
- var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET);
+ var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET);
// We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in
// SelfHostring.cpp) so our current index can never be anything other than
// an Int32Value.
- var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+ var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
var size = S.length;
var result = { value: undefined, done: false };
@@ -556,7 +557,7 @@ function StringIteratorNext() {
}
}
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
result.value = callFunction(String_substring, S, index, index + charCount);
return result;
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index 7b2f8214ba..16d0260929 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11529,6 +11529,32 @@ CodeGenerator::visitHasClass(LHasClass* ins)
}
void
+CodeGenerator::visitGuardToClass(LGuardToClass* ins)
+{
+ Register lhs = ToRegister(ins->lhs());
+ Register output = ToRegister(ins->output());
+ Register temp = ToRegister(ins->temp());
+
+ Label notEqual;
+
+ masm.branchTestObjClass(Assembler::NotEqual, lhs, temp, ins->mir()->getClass(), &notEqual);
+ masm.mov(lhs, output);
+
+ if (ins->mir()->type() == MIRType::Object) {
+ // Can't return null-return here, so bail
+ bailoutFrom(&notEqual, ins->snapshot());
+ } else {
+ Label done;
+ masm.jump(&done);
+
+ masm.bind(&notEqual);
+ masm.mov(ImmPtr(0), output);
+
+ masm.bind(&done);
+ }
+}
+
+void
CodeGenerator::visitWasmParameter(LWasmParameter* lir)
{
}
diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
index d3126651bc..b226f6cc91 100644
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -377,6 +377,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitIsObject(LIsObject* lir);
void visitIsObjectAndBranch(LIsObjectAndBranch* lir);
void visitHasClass(LHasClass* lir);
+ void visitGuardToClass(LGuardToClass* lir);
void visitWasmParameter(LWasmParameter* lir);
void visitWasmParameterI64(LWasmParameterI64* lir);
void visitWasmReturn(LWasmReturn* ret);
diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h
index 89c2ff0a45..18535389ad 100644
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -117,14 +117,16 @@
_(IntrinsicDefineDataProperty) \
_(IntrinsicObjectHasPrototype) \
\
- _(IntrinsicIsArrayIterator) \
- _(IntrinsicIsMapIterator) \
- _(IntrinsicIsSetIterator) \
- _(IntrinsicIsStringIterator) \
+ _(IntrinsicGuardToArrayIterator) \
+ _(IntrinsicGuardToMapIterator) \
+ _(IntrinsicGuardToSetIterator) \
_(IntrinsicIsListIterator) \
+ _(IntrinsicGuardToStringIterator) \
\
+ _(IntrinsicGuardToMapObject) \
_(IntrinsicGetNextMapEntryForIterator) \
\
+ _(IntrinsicGuardToSetObject) \
_(IntrinsicGetNextSetEntryForIterator) \
\
_(IntrinsicArrayBufferByteLength) \
diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h
index 35ad120f7d..f24ef30c84 100644
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -969,6 +969,7 @@ class IonBuilder
const Class* clasp2 = nullptr,
const Class* clasp3 = nullptr,
const Class* clasp4 = nullptr);
+ InliningStatus inlineGuardToClass(CallInfo& callInfo, const Class* clasp);
InliningStatus inlineIsConstructing(CallInfo& callInfo);
InliningStatus inlineSubstringKernel(CallInfo& callInfo);
InliningStatus inlineObjectHasPrototype(CallInfo& callInfo);
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
index 730697163f..709de99873 100644
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4171,6 +4171,16 @@ LIRGenerator::visitHasClass(MHasClass* ins)
}
void
+LIRGenerator::visitGuardToClass(MGuardToClass* ins)
+{
+ MOZ_ASSERT(ins->object()->type() == MIRType::Object);
+ MOZ_ASSERT(ins->type() == MIRType::ObjectOrNull|| ins->type() == MIRType::Object);
+ LGuardToClass* lir = new(alloc()) LGuardToClass(useRegister(ins->object()), temp());
+ assignSnapshot(lir, Bailout_TypeBarrierO);
+ define(lir, ins);
+}
+
+void
LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins)
{
MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
index b2805cb7a6..9b4095aec0 100644
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -289,6 +289,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitIsConstructor(MIsConstructor* ins);
void visitIsObject(MIsObject* ins);
void visitHasClass(MHasClass* ins);
+ void visitGuardToClass(MGuardToClass* ins);
void visitWasmAddOffset(MWasmAddOffset* ins);
void visitWasmBoundsCheck(MWasmBoundsCheck* ins);
void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins);
diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp
index 202aef497b..01755094af 100644
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -280,14 +280,14 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineIsConstructing(callInfo);
case InlinableNative::IntrinsicSubstringKernel:
return inlineSubstringKernel(callInfo);
- case InlinableNative::IntrinsicIsArrayIterator:
- return inlineHasClass(callInfo, &ArrayIteratorObject::class_);
- case InlinableNative::IntrinsicIsMapIterator:
- return inlineHasClass(callInfo, &MapIteratorObject::class_);
- case InlinableNative::IntrinsicIsSetIterator:
- return inlineHasClass(callInfo, &SetIteratorObject::class_);
- case InlinableNative::IntrinsicIsStringIterator:
- return inlineHasClass(callInfo, &StringIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToArrayIterator:
+ return inlineGuardToClass(callInfo, &ArrayIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToMapIterator:
+ return inlineGuardToClass(callInfo, &MapIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToSetIterator:
+ return inlineGuardToClass(callInfo, &SetIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToStringIterator:
+ return inlineGuardToClass(callInfo, &StringIteratorObject::class_);
case InlinableNative::IntrinsicIsListIterator:
return inlineHasClass(callInfo, &ListIteratorObject::class_);
case InlinableNative::IntrinsicDefineDataProperty:
@@ -296,10 +296,14 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineObjectHasPrototype(callInfo);
// Map intrinsics.
+ case InlinableNative::IntrinsicGuardToMapObject:
+ return inlineGuardToClass(callInfo, &MapObject::class_);
case InlinableNative::IntrinsicGetNextMapEntryForIterator:
return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map);
// Set intrinsics.
+ case InlinableNative::IntrinsicGuardToSetObject:
+ return inlineGuardToClass(callInfo, &SetObject::class_);
case InlinableNative::IntrinsicGetNextSetEntryForIterator:
return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set);
@@ -2220,6 +2224,37 @@ IonBuilder::inlineHasClass(CallInfo& callInfo,
}
IonBuilder::InliningStatus
+IonBuilder::inlineGuardToClass(CallInfo& callInfo, const Class* clasp)
+{
+ MOZ_ASSERT(!callInfo.constructing());
+ MOZ_ASSERT(callInfo.argc() == 1);
+
+ if (callInfo.getArg(0)->type() != MIRType::Object)
+ return InliningStatus_NotInlined;
+
+ if (getInlineReturnType() != MIRType::ObjectOrNull &&
+ getInlineReturnType() != MIRType::Object)
+ {
+ return InliningStatus_NotInlined;
+ }
+
+ TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
+ const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr;
+
+ if (knownClass && knownClass == clasp) {
+ current->push(callInfo.getArg(0));
+ } else {
+ MGuardToClass* guardToClass = MGuardToClass::New(alloc(), callInfo.getArg(0),
+ clasp, getInlineReturnType());
+ current->add(guardToClass);
+ current->push(guardToClass);
+ }
+
+ callInfo.setImplicitlyUsedUnchecked();
+ return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode)
{
if (callInfo.argc() != 2 || callInfo.constructing()) {
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 2de91e2df4..6ec05af764 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -13192,6 +13192,48 @@ class MHasClass
}
};
+class MGuardToClass
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ const Class* class_;
+
+ MGuardToClass(MDefinition* object, const Class* clasp, MIRType resultType)
+ : MUnaryInstruction(object)
+ , class_(clasp)
+ {
+ MOZ_ASSERT(object->type() == MIRType::Object ||
+ (object->type() == MIRType::Value && object->mightBeType(MIRType::Object)));
+ MOZ_ASSERT(resultType == MIRType::Object || resultType == MIRType::ObjectOrNull);
+ setResultType(resultType);
+ setMovable();
+ if (resultType == MIRType::Object) {
+ // We will bail out if the class type is incorrect,
+ // so we need to ensure we don't eliminate this instruction
+ setGuard();
+ }
+ }
+
+ public:
+ INSTRUCTION_HEADER(GuardToClass)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ const Class* getClass() const {
+ return class_;
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::None();
+ }
+ bool congruentTo(const MDefinition* ins) const override {
+ if (!ins->isGuardToClass())
+ return false;
+ if (getClass() != ins->toGuardToClass()->getClass())
+ return false;
+ return congruentIfOperandsEqual(ins);
+ }
+};
+
class MCheckReturn
: public MBinaryInstruction,
public BoxInputsPolicy::Data
diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
index bb2ab8190d..fddc1e637d 100644
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -272,6 +272,7 @@ namespace jit {
_(IsCallable) \
_(IsObject) \
_(HasClass) \
+ _(GuardToClass) \
_(CopySign) \
_(Rotate) \
_(NewDerivedTypedObject) \
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
index 9dcb527c5d..f4adcc63c0 100644
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7867,6 +7867,29 @@ class LHasClass : public LInstructionHelper<1, 1, 0>
}
};
+class LGuardToClass : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(GuardToClass);
+ explicit LGuardToClass(const LAllocation& lhs, const LDefinition& temp)
+ {
+ setOperand(0, lhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MGuardToClass* mir() const {
+ return mir_->toGuardToClass();
+ }
+};
+
template<size_t Defs, size_t Ops>
class LWasmSelectBase : public LInstructionHelper<Defs, Ops, 0>
{
diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h
index 3eea1b449b..fe2ab5ea35 100644
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -386,6 +386,7 @@
_(IsObject) \
_(IsObjectAndBranch) \
_(HasClass) \
+ _(GuardToClass) \
_(RecompileCheck) \
_(MemoryBarrier) \
_(AssertRangeI) \
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index 653807ce85..08670c8331 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -189,6 +189,22 @@ intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+template<typename T>
+static bool
+intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ if (args[0].toObject().is<T>()) {
+ args.rval().setObject(args[0].toObject());
+ return true;
+ }
+ args.rval().setNull();
+ return true;
+}
+
/**
* Self-hosting intrinsic returning the original constructor for a builtin
* the name of which is the first and only argument.
@@ -2297,18 +2313,18 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
- JS_INLINABLE_FN("IsArrayIterator",
- intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
- IntrinsicIsArrayIterator),
- JS_INLINABLE_FN("IsMapIterator",
- intrinsic_IsInstanceOfBuiltin<MapIteratorObject>, 1,0,
- IntrinsicIsMapIterator),
- JS_INLINABLE_FN("IsSetIterator",
- intrinsic_IsInstanceOfBuiltin<SetIteratorObject>, 1,0,
- IntrinsicIsSetIterator),
- JS_INLINABLE_FN("IsStringIterator",
- intrinsic_IsInstanceOfBuiltin<StringIteratorObject>, 1,0,
- IntrinsicIsStringIterator),
+ JS_INLINABLE_FN("GuardToArrayIterator",
+ intrinsic_GuardToBuiltin<ArrayIteratorObject>, 1,0,
+ IntrinsicGuardToArrayIterator),
+ JS_INLINABLE_FN("GuardToMapIterator",
+ intrinsic_GuardToBuiltin<MapIteratorObject>, 1,0,
+ IntrinsicGuardToMapIterator),
+ JS_INLINABLE_FN("GuardToSetIterator",
+ intrinsic_GuardToBuiltin<SetIteratorObject>, 1,0,
+ IntrinsicGuardToSetIterator),
+ JS_INLINABLE_FN("GuardToStringIterator",
+ intrinsic_GuardToBuiltin<StringIteratorObject>, 1,0,
+ IntrinsicGuardToStringIterator),
JS_INLINABLE_FN("IsListIterator",
intrinsic_IsInstanceOfBuiltin<ListIteratorObject>, 1,0,
IntrinsicIsListIterator),
@@ -2412,7 +2428,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallStarGeneratorMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
+ JS_INLINABLE_FN("GuardToMapObject", intrinsic_GuardToBuiltin<MapObject>, 1, 0,
+ IntrinsicGuardToMapObject),
JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin<WeakSetObject>, 1,0),
+
+ JS_INLINABLE_FN("GuardToSetObject", intrinsic_GuardToBuiltin<SetObject>, 1, 0,
+ IntrinsicGuardToSetObject),
JS_FN("CallWeakSetMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),