import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1177892 part 1 - Remove BOOLEAN_TO_JSVAL and STRING_TO_JSVAL. r=evilpie (1fac17ff3)
- Bug 1177892 part 2 - Remove PRIVATE_TO_JSVAL. r=evilpie (4d7e80200)
- pointer style (cd27bd41a)
- Bug 1177892 part 3 - Remove OBJECT_TO_JSVAL. r=evilpie (ff66aebe5)
- Bug 1155342 - Disallow flagging a [NewObject] method with a [DependsOn] value that implies it might return the same value when called twice. r=bzbarsky (7ba1bb806)
- Bug 1129239. Don't require 'optional' keyword on trailing dictionary arguments if the dictionary has a required member. r=smaug (3ee24f57b)
- Bug 1152902 part 1. Add a way to flag a method in webidl as being identity-testable, so we'll expose such an identity test from bindings to other C++ code. r=peterv (43e038677)
- Bug 1152902 part 2. Add a fast path for the case when a Promise is resolved with another Promise. r=nsm (59f56603e)
- Bug 1172785 - Adding StaticClassOverride routing for JS implemented WebIDL, r=peterv (6ae76e198)
- Bug 1172785 - Using RTCCertificate for WebRTC, r=ekr (a69ee6167)
- fix build, file built twice (04f7e3d75)
- Bug 1155942. Treat USVString and ByteString as serializable values. r=bkelly (33e635737)
- Bug 913053. Split up IDLTypedef and IDLTypedefType, and likewise for IDLCallback vs IDLCallbackType, so it's clearer whether we're operating on types or objects represented by those types. r=khuey (661f45319)
- Bug 1168471 - Implement support for SharedArrayBuffers and SharedArrayViews in WebIDL. r=bz, r=lth, r=luke (77d63babc)
- Bug 1151269 - Fix the test used by Ion ICs for whether values can definitely be written to an unboxed object, r=jandem. (0463d6b53)
- Bug 1139474 - Watch for unboxed object properties when attaching Ion SETPROP ICs, r=jandem. (67bc9884d)
- Bug 1162199 - Use unboxed objects by default, r=jandem. (4dba9da90)
- Bug 1166678 - Inline first ObjectGroup::maybeSweep test, r=jandem. (ff179acb3)
- Bug 1166709 - After converting unboxed objects created by some initializer to natives, create native objects at that allocation site in the future, r=jandem. (14a5c92b5)
- Bug 1166709 - Mark definite properties when replacing the unboxed group used for literals at some pc, r=jandem. (487017105)
- Bug 1170372 - Use unboxed arrays for Array() and other functions keyed to allocation sites, r=jandem. (9153a5313)
- Bug 1175535 - Don't require objects embedded in MIR nodes to always be tenured, r=jandem. (75399d353)
- Bug 1190272 - Improve type checks when storing values into unboxed objects in Ion code, r=jandem. (0a91a08d5)
- Bug 1216130 - Fix extra checks for unboxed objects in PropertyWriteNeedsTypeBarrier. r=bhackett (4862b91ca)
- Bug 1166700 - Tolerate null failures targets when storing to an unboxed object must fail, r=jandem. (87a07aa3d)
- backport of Bug 1389436 - Explicitly instantiate gfxFont::GetShapedWord<uint8_t> for its use in gfxTextRun.cpp. r=jfkthame (5f6fc9f18)
- Bug 1164374 - Use StaticMutex in BrowserProcessSubThread. r=froydnj. (b0ad93d17)
- Bug 1167771 - Simplify the pre-barrier verifier's tracer use; r=sfink (0fc926804)
- Bug 1166037 - Part 2 - Modify common Baseline code for ARM64. r=djvj (739b36d83)
- Bug 1168864 followup - Remove unnecessary addProperty check from CheckHasNoSuchProperty. r=bhackett (3a464d07e)
- Bug 1166037 - Follow-up - Revert SimulatorType to Simulator. no_r=me (613b095d3)
- Bug 1166944 - Inline the only user of TraceObjectSlots; r=jonco (d830d12f0)
- pointer style (d567d3be2)
- Bug 1167291 - Generalize the marking tracer's cross-compartment check; r=jonco (b5f753147)
- Bug 1167318 - Remove GetGCThingTraceKind in favor of the typed Cell variants; r=jonco (f698f3a64)
- Bug 1167323 - Use internal interfaces to implement MarkCycleCollectorChildren; r=jonco (4acf85bdb)
- Bug 1167433 - AccessorShape is an AllocKind but not a TraceKind; r=jonco (ea92cd26a)
- pointer style (403e83b64)
- remove namespace hack (e3663d39b)
- Bug 1167453 - Rename JSGCTraceKind and make it a C++11 enum class; r=jonco (f7f435a16)
- Bug 1165966 - Update destructor assertions to handle failed initalization r=terrence (48237ed24)
- pointer style (f637042fc)
- Bug 774364 - Part 1: Inline Math.random() in Ion on x86_64. r=sstangl (8379ab0b2)
- Bug 1167677 - Try harder to find scratch registers for memory->memory MoveGroup moves, r=sunfish. (14d4b9962)
- pointer style (93bb53345)
- Bug 1185653 - Fix enumerate hook on unboxed objects to skip non-enume#able properties. r=jorendorff (4ecf41a10)
- Bug 1125624, part 1 - Implement ValidateAndApplyPropertyDescriptor steps 3-4, so that (once the corresponding code in StandardDefineProperty is deleted) freezing an already-frozen object with an addProperty class hook will not call the hook. r=Waldo. (f67f98231)
- Bug 1125624, part 2 - Change js::StandardDefineProperty to forward to s::DefineProperty. r=Waldo. (3ac5d9e30)
- Bug 1148568 - In JSON.parse with a reviver callback, ignore failure when defining properties. r=Waldo. (30c35a758)
- pointer style (826d092cf)
- Bug 1166950 - Only give constructor functions a prototype. r=efaust (d1b909603)
- Bug 1140482 - Add JSPROP_RESOLVING. Give NativeDefineProperty standard behavior in cases where a non-resolving define needs to trigger a resolve hook. r=Waldo. (b2d650abd)
- Bug 1140482 followup: Update ResolveInterpretedFunctionPrototype() failure-cases to return false instead of nullptr, now that return type is bool. rs=jorendorff (38eef1812)
- Bug 1148188 - part1: defaultShims. r=billm (9eb98a8fa)
- pointer style (ec74889f1)
- Bug 1101182 - One interpose call for one property access. r=bholley (111afff12)
- pointer style (b8dd593e9)
- Bug 1148188 - part2: interposeCall. r=billm (6fce5829e)
- Bug 1125624, part 3 - Remove js::StandardDefineProperty and js::DefineOwnProperty. r=Waldo. (a8a228f6e)
- Bug 1167244 - Handle nullptr return from maybeGetProperty(). r=bhackett (91958bdfc)
- pointer style (ebfc629a6)
- Bug 1170355 - Watch for indexes that don't fit in a jsid in Array.shift, r=jandem. (6c2f0a8a2)
- pointer style (a31367643)
- Bug 1165348 - Move Scalar Replacement after GVN. r=jandem (9296335d1)
- Bug 1161584 - Add TrackedStrategy::SetProp_InlineCache. r=shu (612ea0b32)
- Bug 923717 - Add IC fuzzing mode. r=efaust (a6a6a7460)
- Bug 1166711 part 2.1 - Check Scalar Replacement with both unboxed object and without. r=bhackett (e839f034a)
- Bug 1172943 - Use unboxed arrays for JSON and script literal arrays, r=jandem. (964d5a42f)
- Bug 1162986 - Relax type requirements for using baseline cache information when compiling GETPROP, r=jandem. (68e234a08)
- Bug 1168500 - Replace the operator, by variadic templates. r=Waldo (ccb173cb7)
- Bug 1166711 part 0.1 - Use JitSpewPrinter instead of stderr. r=bhackett (239022b72)
- Bug 1166711 part 0.2 - JitSpew add scope-base indentation level. r=bhackett (89288621e)
- Bug 1129313 - Scalar Replacement: Remove PostWriteBarrier at the same time as the stores. r=h4writer (f9df0503e)
This commit is contained in:
2020-10-30 11:49:49 +08:00
parent e3d7542d66
commit 16988569b9
254 changed files with 4875 additions and 3534 deletions
+1 -1
View File
@@ -201,7 +201,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
return NS_ERROR_FAILURE;
}
*aValue = OBJECT_TO_JSVAL(array);
aValue->setObject(*array);
return NS_OK;
}
+1 -1
View File
@@ -1271,7 +1271,7 @@ EventSource::DispatchAllMessageEvents()
message->mData.Length());
NS_ENSURE_TRUE_VOID(jsString);
jsData = STRING_TO_JSVAL(jsString);
jsData.setString(jsString);
}
// create an event that uses the MessageEvent interface,
+2 -2
View File
@@ -1814,7 +1814,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
arrayBuf.address());
NS_ENSURE_SUCCESS(rv, rv);
jsData = OBJECT_TO_JSVAL(arrayBuf);
jsData.setObject(*arrayBuf);
} else {
NS_RUNTIMEABORT("Unknown binary type!");
return NS_ERROR_UNEXPECTED;
@@ -1826,7 +1826,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
jsString = JS_NewUCStringCopyN(aCx, utf16Data.get(), utf16Data.Length());
NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
jsData = STRING_TO_JSVAL(jsString);
jsData.setString(jsString);
}
// create an event that uses the MessageEvent interface,
+7 -5
View File
@@ -1169,10 +1169,12 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
mData, nullptr, nameSpaceManager, proto,
&desc);
NS_ENSURE_SUCCESS(rv, rv);
if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
NS_strlen(mData->mNameUTF16), desc)) {
return NS_ERROR_UNEXPECTED;
if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined()) {
desc.attributesRef() |= JSPROP_RESOLVING;
if (!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
NS_strlen(mData->mNameUTF16), desc)) {
return NS_ERROR_UNEXPECTED;
}
}
return NS_OK;
@@ -1906,7 +1908,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
}
}
v = OBJECT_TO_JSVAL(dot_prototype);
v.setObject(*dot_prototype);
JSAutoCompartment ac(cx, class_obj);
+2 -2
View File
@@ -392,7 +392,7 @@ nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
JS::Rooted<JSObject*> arrayBuf(cx);
rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
NS_ENSURE_SUCCESS(rv, rv);
jsData = OBJECT_TO_JSVAL(arrayBuf);
jsData.setObject(*arrayBuf);
} else {
NS_RUNTIMEABORT("Unknown binary type!");
return NS_ERROR_UNEXPECTED;
@@ -402,7 +402,7 @@ nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
JSString* jsString = JS_NewUCStringCopyN(cx, utf16data.get(), utf16data.Length());
NS_ENSURE_TRUE(jsString, NS_ERROR_FAILURE);
jsData = STRING_TO_JSVAL(jsString);
jsData.setString(jsString);
}
nsCOMPtr<nsIDOMEvent> event;
+2
View File
@@ -145,6 +145,8 @@ NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
const nsAString& aExpression,
mozilla::ErrorResult& aError);
extern const js::Class OuterWindowProxyClass;
/*
* Timeout struct that holds information about each script
* timeout. Holds a strong reference to an nsIScriptTimeoutHandler, which
+4 -4
View File
@@ -945,7 +945,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
aArgv->setString(str);
break;
}
@@ -963,7 +963,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
::JS_NewUCStringCopyN(cx, data.get(), data.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
aArgv->setString(str);
break;
}
case nsISupportsPrimitive::TYPE_PRBOOL : {
@@ -974,7 +974,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
p->GetData(&data);
*aArgv = BOOLEAN_TO_JSVAL(data);
aArgv->setBoolean(data);
break;
}
@@ -1025,7 +1025,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
JSString *str = ::JS_NewStringCopyN(cx, &data, 1);
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*aArgv = STRING_TO_JSVAL(str);
aArgv->setString(str);
break;
}
+2 -2
View File
@@ -549,7 +549,7 @@ DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
// This is Enumerable: False per spec.
return alreadyDefined ||
JS_DefineProperty(cx, global, name, constructor, 0);
JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
}
static JSObject*
@@ -2407,7 +2407,7 @@ IsInCertifiedApp(JSContext* aCx, JSObject* aObj)
#ifdef DEBUG
void
VerifyTraceProtoAndIfaceCacheCalled(JS::CallbackTracer *trc, void **thingp,
JSGCTraceKind kind)
JS::TraceKind kind)
{
// We don't do anything here, we only want to verify that
// TraceProtoAndIfaceCache was called.
+2 -2
View File
@@ -522,7 +522,7 @@ AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
#ifdef DEBUG
void
VerifyTraceProtoAndIfaceCacheCalled(JS::CallbackTracer *trc, void **thingp,
JSGCTraceKind kind);
JS::TraceKind kind);
struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
{
@@ -3035,7 +3035,7 @@ CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
JSAutoCompartment ac(aCx, aGlobal);
{
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
NS_ADDREF(aNative);
aCache->SetWrapper(aGlobal);
+56 -24
View File
@@ -1081,8 +1081,7 @@ class CGHeaders(CGWrapper):
elif unrolled.isDictionary():
headerSet.add(self.getDeclarationFilename(unrolled.inner))
elif unrolled.isCallback():
# Callbacks are both a type and an object
headerSet.add(self.getDeclarationFilename(unrolled))
headerSet.add(self.getDeclarationFilename(unrolled.callback))
elif unrolled.isFloat() and not unrolled.isUnrestricted():
# Restricted floats are tested for finiteness
bindingHeaders.add("mozilla/FloatingPoint.h")
@@ -1130,6 +1129,9 @@ class CGHeaders(CGWrapper):
for m in desc.interface.members:
addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"))
staticTypeOverride = PropertyDefiner.getStringAttr(m, "StaticClassOverride")
if staticTypeOverride:
bindingHeaders.add("/".join(staticTypeOverride.split("::")) + ".h")
# getExtendedAttribute() returns a list, extract the entry.
funcList = desc.interface.getExtendedAttribute("Func")
if funcList is not None:
@@ -1271,7 +1273,7 @@ def UnionTypes(unionTypes, config):
# Callbacks always use strong refs, so we need to include
# the right header to be able to Release() in our inlined
# code.
headers.add(CGHeaders.getDeclarationFilename(f))
headers.add(CGHeaders.getDeclarationFilename(f.callback))
elif f.isMozMap():
headers.add("mozilla/dom/MozMap.h")
# And add headers for the type we're parametrized over
@@ -4704,7 +4706,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
extraConditionForNull=extraConditionForNull)
elif (not type.hasNullableType and defaultValue and
isinstance(defaultValue, IDLNullValue)):
assert type.hasDictionaryType
assert type.hasDictionaryType()
assert defaultValue.type.isDictionary()
if not isOwningUnion and typeNeedsRooting(defaultValue.type):
ctorArgs = "cx"
@@ -5062,7 +5064,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not type.treatNonObjectAsNull() or type.nullable()
assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
name = type.unroll().identifier.name
callback = type.unroll().callback
name = callback.identifier.name
if type.nullable():
declType = CGGeneric("nsRefPtr<%s>" % name)
else:
@@ -6165,7 +6168,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
result = CGGeneric("auto")
return result, None, None, None, conversion
if returnType.isCallback():
name = returnType.unroll().identifier.name
name = returnType.unroll().callback.identifier.name
return CGGeneric("nsRefPtr<%s>" % name), None, None, None, None
if returnType.isAny():
if isMember:
@@ -6629,8 +6632,11 @@ class CGPerSignatureCall(CGThing):
argsPre = []
if static:
nativeMethodName = "%s::%s" % (descriptor.nativeType,
nativeMethodName)
nativeType = descriptor.nativeType
staticTypeOverride = PropertyDefiner.getStringAttr(idlNode, "StaticClassOverride")
if (staticTypeOverride):
nativeType = staticTypeOverride
nativeMethodName = "%s::%s" % (nativeType, nativeMethodName)
# If we're a constructor, "obj" may not be a function, so calling
# XrayAwareCalleeGlobal() on it is not safe. Of course in the
# constructor case either "obj" is an Xray or we're already in the
@@ -6667,9 +6673,10 @@ class CGPerSignatureCall(CGThing):
needsUnwrappedVar = False
unwrappedVar = "obj"
elif descriptor.interface.isJSImplemented():
needsUnwrap = True
needsUnwrappedVar = True
argsPost.append("js::GetObjectCompartment(unwrappedObj ? *unwrappedObj : obj)")
if not idlNode.isStatic():
needsUnwrap = True
needsUnwrappedVar = True
argsPost.append("js::GetObjectCompartment(unwrappedObj ? *unwrappedObj : obj)")
elif needScopeObject(returnType, arguments, self.extendedAttributes,
descriptor.wrapperCache, True,
idlNode.getExtendedAttribute("StoreInSlot")):
@@ -7732,9 +7739,11 @@ class CGResolveHook(CGAbstractClassHook):
// If desc.value() is undefined, then the DoResolve call
// has already defined it on the object. Don't try to also
// define it.
if (!desc.value().isUndefined() &&
!JS_DefinePropertyById(cx, obj, id, desc)) {
return false;
if (!desc.value().isUndefined()) {
desc.attributesRef() |= JSPROP_RESOLVING;
if (!JS_DefinePropertyById(cx, obj, id, desc)) {
return false;
}
}
*resolvedp = true;
return true;
@@ -8571,6 +8580,26 @@ class CGStaticMethodJitinfo(CGGeneric):
IDLToCIdentifier(method.identifier.name))))
class CGMethodIdentityTest(CGAbstractMethod):
"""
A class to generate a method-identity test for a given IDL operation.
"""
def __init__(self, descriptor, method):
self.method = method
name = "Is%sMethod" % MakeNativeName(method.identifier.name)
CGAbstractMethod.__init__(self, descriptor, name, 'bool',
[Argument('JS::Handle<JSObject*>', 'aObj')])
def definition_body(self):
return dedent(
"""
MOZ_ASSERT(aObj);
return js::IsFunctionObject(aObj) &&
js::FunctionObjectIsNative(aObj) &&
FUNCTION_VALUE_TO_JITINFO(JS::ObjectValue(*aObj)) == &%s_methodinfo;
""" % IDLToCIdentifier(self.method.identifier.name))
def getEnumValueName(value):
# Some enum values can be empty strings. Others might have weird
# characters in them. Deal with the former by returning "_empty",
@@ -8694,7 +8723,7 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
return CGGeneric(type.inner.identifier.name)
if type.isCallback():
return CGGeneric("%s&" % type.unroll().identifier.name)
return CGGeneric("%s&" % type.unroll().callback.identifier.name)
if type.isAny():
return CGGeneric("JS::Value")
@@ -10900,7 +10929,7 @@ class CGDOMJSProxyHandler_getElements(ClassMethod):
'jsvalRef': 'temp',
'jsvalHandle': '&temp',
'obj': 'proxy',
'successCode': ("adder->append(cx, temp);\n"
'successCode': ("if (!adder->append(cx, temp)) return false;\n"
"continue;\n")
}
get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define()
@@ -11171,6 +11200,8 @@ class CGDescriptor(CGThing):
cgThings.append(CGMemberJITInfo(descriptor, m))
if props.isCrossOriginMethod:
crossOriginMethods.add(m.identifier.name)
if m.getExtendedAttribute("MethodIdentityTestable"):
cgThings.append(CGMethodIdentityTest(descriptor, m))
elif m.isAttr():
if m.stringifier:
raise TypeError("Stringifier attributes not supported yet. "
@@ -12341,7 +12372,7 @@ class CGForwardDeclarations(CGWrapper):
# Note: Spidermonkey interfaces are typedefs, so can't be
# forward-declared
elif t.isCallback():
builder.addInMozillaDom(str(t))
builder.addInMozillaDom(t.callback.identifier.name)
elif t.isDictionary():
builder.addInMozillaDom(t.inner.identifier.name, isStruct=True)
elif t.isCallbackInterface():
@@ -12368,12 +12399,12 @@ class CGForwardDeclarations(CGWrapper):
builder.add(d.nativeType + "Atoms", isStruct=True)
for callback in mainCallbacks:
forwardDeclareForType(callback)
builder.addInMozillaDom(callback.identifier.name)
for t in getTypesFromCallback(callback):
forwardDeclareForType(t, workerness='mainthreadonly')
for callback in workerCallbacks:
forwardDeclareForType(callback)
builder.addInMozillaDom(callback.identifier.name)
for t in getTypesFromCallback(callback):
forwardDeclareForType(t, workerness='workeronly')
@@ -12756,7 +12787,7 @@ class CGNativeMember(ClassMethod):
# .forget() to get our already_AddRefed.
return result.define(), "nullptr", "return ${declName}.forget();\n"
if type.isCallback():
return ("already_AddRefed<%s>" % type.unroll().identifier.name,
return ("already_AddRefed<%s>" % type.unroll().callback.identifier.name,
"nullptr", "return ${declName}.forget();\n")
if type.isAny():
if isMember:
@@ -12986,7 +13017,7 @@ class CGNativeMember(ClassMethod):
else:
declType = "%s&"
if type.isCallback():
name = type.unroll().identifier.name
name = type.unroll().callback.identifier.name
else:
name = type.unroll().inner.identifier.name
return declType % name, False, False
@@ -13100,7 +13131,7 @@ class CGBindingImplClass(CGClass):
"""
Common codegen for generating a C++ implementation of a WebIDL interface
"""
def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True, wrapMethodName="WrapObject"):
def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True, wrapMethodName="WrapObject", skipStaticMethods=False):
"""
cgMethod, cgGetter and cgSetter are classes used to codegen methods,
getters and setters.
@@ -13131,7 +13162,8 @@ class CGBindingImplClass(CGClass):
if m.isMethod():
if m.isIdentifierLess():
continue
appendMethod(m)
if not m.isStatic() or not skipStaticMethods:
appendMethod(m)
elif m.isAttr():
self.methodDecls.append(cgGetter(descriptor, m))
if not m.readonly:
@@ -13592,7 +13624,7 @@ class CGJSImplSetter(CGJSImplMember):
class CGJSImplClass(CGBindingImplClass):
def __init__(self, descriptor):
CGBindingImplClass.__init__(self, descriptor, CGJSImplMethod, CGJSImplGetter, CGJSImplSetter)
CGBindingImplClass.__init__(self, descriptor, CGJSImplMethod, CGJSImplGetter, CGJSImplSetter, skipStaticMethods=True)
if descriptor.interface.parent:
parentClass = descriptor.getDescriptor(
+7 -8
View File
@@ -47,11 +47,10 @@ class Configuration:
"%s\n"
"%s" %
(thing.location, thing.implementor.location))
# Some toplevel things are sadly types, and those have an
# isInterface that doesn't mean the same thing as IDLObject's
# isInterface()...
if (not isinstance(thing, IDLInterface) and
not isinstance(thing, IDLExternalInterface)):
assert not thing.isType();
if not thing.isInterface():
continue
iface = thing
self.interfaces[iface.identifier.name] = iface
@@ -788,9 +787,9 @@ def findCallbacksAndDictionaries(inputTypes):
def doFindCallbacksAndDictionaries(types, callbacks, dictionaries):
unhandledTypes = set()
for type in types:
if type.isCallback() and type not in callbacks:
unhandledTypes |= getFlatTypes(getTypesFromCallback(type))
callbacks.add(type)
if type.isCallback() and type.callback not in callbacks:
unhandledTypes |= getFlatTypes(getTypesFromCallback(type.callback))
callbacks.add(type.callback)
elif type.isDictionary() and type.inner not in dictionaries:
d = type.inner
unhandledTypes |= getFlatTypes(getTypesFromDictionary(d))
+2 -2
View File
@@ -210,12 +210,12 @@ DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::
return result.succeed();
}
JSObject* expando = EnsureExpandoObject(cx, proxy);
JS::Rooted<JSObject*> expando(cx, EnsureExpandoObject(cx, proxy));
if (!expando) {
return false;
}
if (!js::DefineOwnProperty(cx, expando, id, desc, result)) {
if (!JS_DefinePropertyById(cx, expando, id, desc, result)) {
return false;
}
*defined = true;
+33
View File
@@ -223,6 +223,39 @@ typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
ArrayBuffer;
typedef TypedArray<int8_t, js::UnwrapSharedInt8Array, JS_GetSharedInt8ArrayData,
js::GetSharedInt8ArrayLengthAndData, JS_NewSharedInt8Array>
SharedInt8Array;
typedef TypedArray<uint8_t, js::UnwrapSharedUint8Array, JS_GetSharedUint8ArrayData,
js::GetSharedUint8ArrayLengthAndData, JS_NewSharedUint8Array>
SharedUint8Array;
typedef TypedArray<uint8_t, js::UnwrapSharedUint8ClampedArray, JS_GetSharedUint8ClampedArrayData,
js::GetSharedUint8ClampedArrayLengthAndData, JS_NewSharedUint8ClampedArray>
SharedUint8ClampedArray;
typedef TypedArray<int16_t, js::UnwrapSharedInt16Array, JS_GetSharedInt16ArrayData,
js::GetSharedInt16ArrayLengthAndData, JS_NewSharedInt16Array>
SharedInt16Array;
typedef TypedArray<uint16_t, js::UnwrapSharedUint16Array, JS_GetSharedUint16ArrayData,
js::GetSharedUint16ArrayLengthAndData, JS_NewSharedUint16Array>
SharedUint16Array;
typedef TypedArray<int32_t, js::UnwrapSharedInt32Array, JS_GetSharedInt32ArrayData,
js::GetSharedInt32ArrayLengthAndData, JS_NewSharedInt32Array>
SharedInt32Array;
typedef TypedArray<uint32_t, js::UnwrapSharedUint32Array, JS_GetSharedUint32ArrayData,
js::GetSharedUint32ArrayLengthAndData, JS_NewSharedUint32Array>
SharedUint32Array;
typedef TypedArray<float, js::UnwrapSharedFloat32Array, JS_GetSharedFloat32ArrayData,
js::GetSharedFloat32ArrayLengthAndData, JS_NewSharedFloat32Array>
SharedFloat32Array;
typedef TypedArray<double, js::UnwrapSharedFloat64Array, JS_GetSharedFloat64ArrayData,
js::GetSharedFloat64ArrayLengthAndData, JS_NewSharedFloat64Array>
SharedFloat64Array;
typedef TypedArray_base<uint8_t, js::UnwrapSharedArrayBufferView, js::GetSharedArrayBufferViewLengthAndData>
SharedArrayBufferView;
typedef TypedArray<uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBufferData,
js::GetSharedArrayBufferLengthAndData, JS_NewSharedArrayBuffer>
SharedArrayBuffer;
// A class for converting an nsTArray to a TypedArray
// Note: A TypedArrayCreator must not outlive the nsTArray it was created from.
// So this is best used to pass from things that understand nsTArray to
+291 -121
View File
@@ -164,6 +164,9 @@ class IDLObject(object):
def isUnion(self):
return False
def isTypedef(self):
return False
def getUserData(self, key, default):
return self.userData.get(key, default)
@@ -1429,6 +1432,14 @@ class IDLDictionary(IDLObjectWithScope):
def isDictionary(self):
return True;
def canBeEmpty(self):
"""
Returns true if this dictionary can be empty (that is, it has no
required members and neither do any of its ancestors).
"""
return (all(member.optional for member in self.members) and
(not self.parent or self.parent.canBeEmpty()))
def finish(self, scope):
if self._finished:
return
@@ -1676,9 +1687,18 @@ class IDLType(IDLObject):
def isArrayBufferView(self):
return False
def isSharedArrayBuffer(self):
return False
def isSharedArrayBufferView(self):
return False
def isTypedArray(self):
return False
def isSharedTypedArray(self):
return False
def isCallbackInterface(self):
return False
@@ -1698,7 +1718,10 @@ class IDLType(IDLObject):
only returns true for the types from the TypedArray spec. """
return self.isInterface() and (self.isArrayBuffer() or \
self.isArrayBufferView() or \
self.isTypedArray())
self.isSharedArrayBuffer() or \
self.isSharedArrayBufferView() or \
self.isTypedArray() or \
self.isSharedTypedArray())
def isDictionary(self):
return False
@@ -1739,11 +1762,11 @@ class IDLType(IDLObject):
def treatNonCallableAsNull(self):
assert self.tag() == IDLType.Tags.callback
return self.nullable() and self.inner._treatNonCallableAsNull
return self.nullable() and self.inner.callback._treatNonCallableAsNull
def treatNonObjectAsNull(self):
assert self.tag() == IDLType.Tags.callback
return self.nullable() and self.inner._treatNonObjectAsNull
return self.nullable() and self.inner.callback._treatNonObjectAsNull
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
@@ -1783,11 +1806,17 @@ class IDLUnresolvedType(IDLType):
assert obj
if obj.isType():
# obj itself might not be complete; deal with that.
assert obj != self
if not obj.isComplete():
obj = obj.complete(scope)
return obj
print obj
assert not obj.isType()
if obj.isTypedef():
assert self.name.name == obj.identifier.name
typedefType = IDLTypedefType(self.location, obj.innerType,
obj.identifier)
assert not typedefType.isComplete()
return typedefType.complete(scope)
elif obj.isCallback() and not obj.isInterface():
assert self.name.name == obj.identifier.name
return IDLCallbackType(self.location, obj)
if self._promiseInnerType and not self._promiseInnerType.isComplete():
self._promiseInnerType = self._promiseInnerType.complete(scope)
@@ -1874,9 +1903,18 @@ class IDLNullableType(IDLType):
def isArrayBufferView(self):
return self.inner.isArrayBufferView()
def isSharedArrayBuffer(self):
return self.inner.isSharedArrayBuffer()
def isSharedArrayBufferView(self):
return self.inner.isSharedArrayBufferView()
def isTypedArray(self):
return self.inner.isTypedArray()
def isSharedTypedArray(self):
return self.inner.isSharedTypedArray()
def isDictionary(self):
return self.inner.isDictionary()
@@ -2091,7 +2129,7 @@ class IDLUnionType(IDLType):
IDLType.__init__(self, location, "")
self.memberTypes = memberTypes
self.hasNullableType = False
self.hasDictionaryType = False
self._dictionaryType = None
self.flatMemberTypes = None
self.builtin = False
@@ -2147,10 +2185,10 @@ class IDLUnionType(IDLType):
if self.hasNullableType:
raise WebIDLError("Can't have more than one nullable types in a union",
[nullableType.location, self.flatMemberTypes[i].location])
if self.hasDictionaryType:
if self.hasDictionaryType():
raise WebIDLError("Can't have a nullable type and a "
"dictionary type in a union",
[dictionaryType.location,
[self._dictionaryType.location,
self.flatMemberTypes[i].location])
self.hasNullableType = True
nullableType = self.flatMemberTypes[i]
@@ -2162,8 +2200,7 @@ class IDLUnionType(IDLType):
"dictionary type in a union",
[nullableType.location,
self.flatMemberTypes[i].location])
self.hasDictionaryType = True
dictionaryType = self.flatMemberTypes[i]
self._dictionaryType = self.flatMemberTypes[i]
elif self.flatMemberTypes[i].isUnion():
self.flatMemberTypes[i:i + 1] = self.flatMemberTypes[i].memberTypes
continue
@@ -2202,6 +2239,13 @@ class IDLUnionType(IDLType):
return False
return True
def hasDictionaryType(self):
return self._dictionaryType is not None
def hasPossiblyEmptyDictionaryType(self):
return (self._dictionaryType is not None and
self._dictionaryType.inner.canBeEmpty())
def _getDependentObjects(self):
return set(self.memberTypes)
@@ -2302,23 +2346,17 @@ class IDLArrayType(IDLType):
def _getDependentObjects(self):
return self.inner._getDependentObjects()
class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
class IDLTypedefType(IDLType):
def __init__(self, location, innerType, name):
IDLType.__init__(self, location, innerType.name)
identifier = IDLUnresolvedIdentifier(location, name)
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
IDLType.__init__(self, location, name)
self.inner = innerType
self.name = name
self.builtin = False
def __eq__(self, other):
return isinstance(other, IDLTypedefType) and self.inner == other.inner
def __str__(self):
return self.identifier.name
return self.name
def nullable(self):
return self.inner.nullable()
@@ -2365,9 +2403,18 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
def isArrayBufferView(self):
return self.inner.isArrayBufferView()
def isSharedArrayBuffer(self):
return self.inner.isSharedArrayBuffer()
def isSharedArrayBufferView(self):
return self.inner.isSharedArrayBufferView()
def isTypedArray(self):
return self.inner.isTypedArray()
def isSharedTypedArray(self):
return self.inner.isSharedTypedArray()
def isInterface(self):
return self.inner.isInterface()
@@ -2386,16 +2433,6 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
assert self.inner.isComplete()
return self.inner
def finish(self, parentScope):
# Maybe the IDLObjectWithIdentifier for the typedef should be
# a separate thing from the type? If that happens, we can
# remove some hackery around avoiding isInterface() in
# Configuration.py.
self.complete(parentScope)
def validate(self):
pass
# Do we need a resolveType impl? I don't think it's particularly useful....
def tag(self):
@@ -2410,6 +2447,31 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
def _getDependentObjects(self):
return self.inner._getDependentObjects()
class IDLTypedef(IDLObjectWithIdentifier):
def __init__(self, location, parentScope, innerType, name):
identifier = IDLUnresolvedIdentifier(location, name)
IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
self.innerType = innerType
def __str__(self):
return "Typedef %s %s" % (self.identifier.name, self.innerType)
def finish(self, parentScope):
if not self.innerType.isComplete():
self.innerType = self.innerType.complete(parentScope)
def validate(self):
pass
def isTypedef(self):
return True
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
def _getDependentObjects(self):
return self.innerType._getDependentObjects()
class IDLWrapperType(IDLType):
def __init__(self, location, inner, promiseInnerType=None):
IDLType.__init__(self, location, inner.identifier.name)
@@ -2610,6 +2672,8 @@ class IDLBuiltinType(IDLType):
# Funny stuff
'ArrayBuffer',
'ArrayBufferView',
'SharedArrayBuffer',
'SharedArrayBufferView',
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
@@ -2618,7 +2682,16 @@ class IDLBuiltinType(IDLType):
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array'
'Float64Array',
'SharedInt8Array',
'SharedUint8Array',
'SharedUint8ClampedArray',
'SharedInt16Array',
'SharedUint16Array',
'SharedInt32Array',
'SharedUint32Array',
'SharedFloat32Array',
'SharedFloat64Array'
)
TagLookup = {
@@ -2644,6 +2717,8 @@ class IDLBuiltinType(IDLType):
Types.void: IDLType.Tags.void,
Types.ArrayBuffer: IDLType.Tags.interface,
Types.ArrayBufferView: IDLType.Tags.interface,
Types.SharedArrayBuffer: IDLType.Tags.interface,
Types.SharedArrayBufferView: IDLType.Tags.interface,
Types.Int8Array: IDLType.Tags.interface,
Types.Uint8Array: IDLType.Tags.interface,
Types.Uint8ClampedArray: IDLType.Tags.interface,
@@ -2652,7 +2727,16 @@ class IDLBuiltinType(IDLType):
Types.Int32Array: IDLType.Tags.interface,
Types.Uint32Array: IDLType.Tags.interface,
Types.Float32Array: IDLType.Tags.interface,
Types.Float64Array: IDLType.Tags.interface
Types.Float64Array: IDLType.Tags.interface,
Types.SharedInt8Array: IDLType.Tags.interface,
Types.SharedUint8Array: IDLType.Tags.interface,
Types.SharedUint8ClampedArray: IDLType.Tags.interface,
Types.SharedInt16Array: IDLType.Tags.interface,
Types.SharedUint16Array: IDLType.Tags.interface,
Types.SharedInt32Array: IDLType.Tags.interface,
Types.SharedUint32Array: IDLType.Tags.interface,
Types.SharedFloat32Array: IDLType.Tags.interface,
Types.SharedFloat64Array: IDLType.Tags.interface
}
def __init__(self, location, name, type):
@@ -2692,17 +2776,30 @@ class IDLBuiltinType(IDLType):
def isArrayBufferView(self):
return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
def isSharedArrayBuffer(self):
return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer
def isSharedArrayBufferView(self):
return self._typeTag == IDLBuiltinType.Types.SharedArrayBufferView
def isTypedArray(self):
return self._typeTag >= IDLBuiltinType.Types.Int8Array and \
self._typeTag <= IDLBuiltinType.Types.Float64Array
def isSharedTypedArray(self):
return self._typeTag >= IDLBuiltinType.Types.SharedInt8Array and \
self._typeTag <= IDLBuiltinType.Types.SharedFloat64Array
def isInterface(self):
# TypedArray things are interface types per the TypedArray spec,
# but we handle them as builtins because SpiderMonkey implements
# all of it internally.
return self.isArrayBuffer() or \
self.isArrayBufferView() or \
self.isTypedArray()
self.isSharedArrayBuffer() or \
self.isSharedArrayBufferView() or \
self.isTypedArray() or \
self.isSharedTypedArray()
def isNonCallbackInterface(self):
# All the interfaces we can be are non-callback
@@ -2720,7 +2817,7 @@ class IDLBuiltinType(IDLType):
self._typeTag == IDLBuiltinType.Types.unrestricted_double
def isSerializable(self):
return self.isPrimitive() or self.isDOMString() or self.isDate()
return self.isPrimitive() or self.isString() or self.isDate()
def includesRestrictedFloat(self):
return self.isFloat() and not self.isUnrestricted()
@@ -2773,15 +2870,20 @@ class IDLBuiltinType(IDLType):
# ArrayBuffer is distinguishable from everything
# that's not an ArrayBuffer or a callback interface
(self.isArrayBuffer() and not other.isArrayBuffer()) or
(self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
# ArrayBufferView is distinguishable from everything
# that's not an ArrayBufferView or typed array.
(self.isArrayBufferView() and not other.isArrayBufferView() and
not other.isTypedArray()) or
(self.isSharedArrayBufferView() and not other.isSharedArrayBufferView() and
not other.isSharedTypedArray()) or
# Typed arrays are distinguishable from everything
# except ArrayBufferView and the same type of typed
# array
(self.isTypedArray() and not other.isArrayBufferView() and not
(other.isTypedArray() and other.name == self.name)))))
(other.isTypedArray() and other.name == self.name)) or
(self.isSharedTypedArray() and not other.isSharedArrayBufferView() and not
(other.isSharedTypedArray() and other.name == self.name)))))
def _getDependentObjects(self):
return set()
@@ -2853,6 +2955,12 @@ BuiltinTypes = {
IDLBuiltinType.Types.ArrayBufferView:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView",
IDLBuiltinType.Types.ArrayBufferView),
IDLBuiltinType.Types.SharedArrayBuffer:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBuffer",
IDLBuiltinType.Types.SharedArrayBuffer),
IDLBuiltinType.Types.SharedArrayBufferView:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBufferView",
IDLBuiltinType.Types.SharedArrayBufferView),
IDLBuiltinType.Types.Int8Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array",
IDLBuiltinType.Types.Int8Array),
@@ -2879,7 +2987,34 @@ BuiltinTypes = {
IDLBuiltinType.Types.Float32Array),
IDLBuiltinType.Types.Float64Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array",
IDLBuiltinType.Types.Float64Array)
IDLBuiltinType.Types.Float64Array),
IDLBuiltinType.Types.SharedInt8Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt8Array",
IDLBuiltinType.Types.SharedInt8Array),
IDLBuiltinType.Types.SharedUint8Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8Array",
IDLBuiltinType.Types.SharedUint8Array),
IDLBuiltinType.Types.SharedUint8ClampedArray:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8ClampedArray",
IDLBuiltinType.Types.SharedUint8ClampedArray),
IDLBuiltinType.Types.SharedInt16Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt16Array",
IDLBuiltinType.Types.SharedInt16Array),
IDLBuiltinType.Types.SharedUint16Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint16Array",
IDLBuiltinType.Types.SharedUint16Array),
IDLBuiltinType.Types.SharedInt32Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt32Array",
IDLBuiltinType.Types.SharedInt32Array),
IDLBuiltinType.Types.SharedUint32Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint32Array",
IDLBuiltinType.Types.SharedUint32Array),
IDLBuiltinType.Types.SharedFloat32Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat32Array",
IDLBuiltinType.Types.SharedFloat32Array),
IDLBuiltinType.Types.SharedFloat64Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat64Array",
IDLBuiltinType.Types.SharedFloat64Array)
}
@@ -2994,14 +3129,14 @@ class IDLNullValue(IDLObject):
def coerceToType(self, type, location):
if (not isinstance(type, IDLNullableType) and
not (type.isUnion() and type.hasNullableType) and
not (type.isUnion() and type.hasDictionaryType) and
not (type.isUnion() and type.hasDictionaryType()) and
not type.isDictionary() and
not type.isAny()):
raise WebIDLError("Cannot coerce null value to type %s." % type,
[location])
nullValue = IDLNullValue(self.location)
if type.isUnion() and not type.nullable() and type.hasDictionaryType:
if type.isUnion() and not type.nullable() and type.hasDictionaryType():
# We're actually a default value for the union's dictionary member.
# Use its type.
for t in type.flatMemberTypes:
@@ -3131,6 +3266,12 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
"That seems rather unlikely.",
[self.location])
if self.getExtendedAttribute("NewObject"):
if self.dependsOn == "Nothing" or self.dependsOn == "DOMState":
raise WebIDLError("A [NewObject] method is not idempotent, "
"so it has to depend on something other than DOM state.",
[self.location])
def _setDependsOn(self, dependsOn):
if self.dependsOn != "Everything":
raise WebIDLError("Trying to specify multiple different DependsOn, "
@@ -3568,7 +3709,7 @@ class IDLArgument(IDLObjectWithIdentifier):
self.type = type
if ((self.type.isDictionary() or
self.type.isUnion() and self.type.unroll().hasDictionaryType) and
self.type.isUnion() and self.type.unroll().hasDictionaryType()) and
self.optional and not self.defaultValue and not self.variadic):
# Default optional non-variadic dictionaries to null,
# for simplicity, so the codegen doesn't have to special-case this.
@@ -3601,12 +3742,10 @@ class IDLArgument(IDLObjectWithIdentifier):
def canHaveMissingValue(self):
return self.optional and not self.defaultValue
class IDLCallbackType(IDLType, IDLObjectWithScope):
class IDLCallback(IDLObjectWithScope):
def __init__(self, location, parentScope, identifier, returnType, arguments):
assert isinstance(returnType, IDLType)
IDLType.__init__(self, location, identifier.name)
self._returnType = returnType
# Clone the list
self._arguments = list(arguments)
@@ -3626,9 +3765,6 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
def signatures(self):
return [(self._returnType, self._arguments)]
def tag(self):
return IDLType.Tags.callback
def finish(self, scope):
if not self._returnType.isComplete():
type = self._returnType.complete(scope)
@@ -3652,14 +3788,6 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
def validate(self):
pass
def isDistinguishableFrom(self, other):
if other.isUnion():
# Just forward to the union; it'll deal
return other.isDistinguishableFrom(self)
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isNonCallbackInterface() or other.isDate() or
other.isSequence())
def addExtendedAttributes(self, attrs):
unhandledAttrs = []
for attr in attrs:
@@ -3678,6 +3806,28 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
def _getDependentObjects(self):
return set([self._returnType] + self._arguments)
class IDLCallbackType(IDLType):
def __init__(self, location, callback):
IDLType.__init__(self, location, callback.identifier.name)
self.callback = callback
def isCallback(self):
return True
def tag(self):
return IDLType.Tags.callback
def isDistinguishableFrom(self, other):
if other.isUnion():
# Just forward to the union; it'll deal
return other.isDistinguishableFrom(self)
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isNonCallbackInterface() or other.isDate() or
other.isSequence())
def _getDependentObjects(self):
return self.callback._getDependentObjects()
class IDLMethodOverload:
"""
A class that represents a single overload of a WebIDL method. This is not
@@ -3889,45 +4039,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def finish(self, scope):
IDLInterfaceMember.finish(self, scope)
overloadWithPromiseReturnType = None
overloadWithoutPromiseReturnType = None
for overload in self._overloads:
variadicArgument = None
arguments = overload.arguments
for (idx, argument) in enumerate(arguments):
if not argument.isComplete():
argument.complete(scope)
assert argument.type.isComplete()
if (argument.type.isDictionary() or
(argument.type.isUnion() and
argument.type.unroll().hasDictionaryType)):
# Dictionaries and unions containing dictionaries at the
# end of the list or followed by optional arguments must be
# optional.
if (not argument.optional and
all(arg.optional for arg in arguments[idx+1:])):
raise WebIDLError("Dictionary argument or union "
"argument containing a dictionary "
"not followed by a required argument "
"must be optional",
[argument.location])
# An argument cannot be a Nullable Dictionary
if argument.type.nullable():
raise WebIDLError("An argument cannot be a nullable "
"dictionary or nullable union "
"containing a dictionary",
[argument.location])
# Only the last argument can be variadic
if variadicArgument:
raise WebIDLError("Variadic argument is not last argument",
[variadicArgument.location])
if argument.variadic:
variadicArgument = argument
returnType = overload.returnType
if not returnType.isComplete():
returnType = returnType.complete(scope)
@@ -3936,22 +4048,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert not isinstance(returnType.name, IDLUnresolvedIdentifier)
overload.returnType = returnType
if returnType.isPromise():
overloadWithPromiseReturnType = overload
else:
overloadWithoutPromiseReturnType = overload
# Make sure either all our overloads return Promises or none do
if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType:
raise WebIDLError("We have overloads with both Promise and "
"non-Promise return types",
[overloadWithPromiseReturnType.location,
overloadWithoutPromiseReturnType.location])
if overloadWithPromiseReturnType and self._legacycaller:
raise WebIDLError("May not have a Promise return type for a "
"legacycaller.",
[overloadWithPromiseReturnType.location])
for argument in overload.arguments:
if not argument.isComplete():
argument.complete(scope)
assert argument.type.isComplete()
# Now compute various information that will be used by the
# WebIDL overload resolution algorithm.
@@ -3981,12 +4081,73 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
distinguishingIndex),
[self.location, overload.location])
overloadWithPromiseReturnType = None
overloadWithoutPromiseReturnType = None
for overload in self._overloads:
if not overload.returnType.unroll().isExposedInAllOf(self.exposureSet):
returnType = overload.returnType
if not returnType.unroll().isExposedInAllOf(self.exposureSet):
raise WebIDLError("Overload returns a type that is not exposed "
"everywhere where the method is exposed",
[overload.location])
variadicArgument = None
arguments = overload.arguments
for (idx, argument) in enumerate(arguments):
assert argument.type.isComplete()
if ((argument.type.isDictionary() and
argument.type.inner.canBeEmpty())or
(argument.type.isUnion() and
argument.type.unroll().hasPossiblyEmptyDictionaryType())):
# Optional dictionaries and unions containing optional
# dictionaries at the end of the list or followed by
# optional arguments must be optional.
if (not argument.optional and
all(arg.optional for arg in arguments[idx+1:])):
raise WebIDLError("Dictionary argument or union "
"argument containing a dictionary "
"not followed by a required argument "
"must be optional",
[argument.location])
# An argument cannot be a Nullable Dictionary
if argument.type.nullable():
raise WebIDLError("An argument cannot be a nullable "
"dictionary or nullable union "
"containing a dictionary",
[argument.location])
# Only the last argument can be variadic
if variadicArgument:
raise WebIDLError("Variadic argument is not last argument",
[variadicArgument.location])
if argument.variadic:
variadicArgument = argument
if returnType.isPromise():
overloadWithPromiseReturnType = overload
else:
overloadWithoutPromiseReturnType = overload
# Make sure either all our overloads return Promises or none do
if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType:
raise WebIDLError("We have overloads with both Promise and "
"non-Promise return types",
[overloadWithPromiseReturnType.location,
overloadWithoutPromiseReturnType.location])
if overloadWithPromiseReturnType and self._legacycaller:
raise WebIDLError("May not have a Promise return type for a "
"legacycaller.",
[overloadWithPromiseReturnType.location])
if self.getExtendedAttribute("StaticClassOverride") and not \
(self.identifier.scope.isJSImplemented() and self.isStatic()):
raise WebIDLError("StaticClassOverride can be applied to static"
" methods on JS-implemented classes only.",
[self.location])
def overloadsForArgCount(self, argc):
return [overload for overload in self._overloads if
len(overload.arguments) == argc or
@@ -4106,7 +4267,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
identifier == "Func" or
identifier == "AvailableIn" or
identifier == "CheckPermissions" or
identifier == "BinaryName"):
identifier == "BinaryName" or
identifier == "MethodIdentityTestable" or
identifier == "StaticClassOverride"):
# Known attributes that we don't need to do anything with here
pass
else:
@@ -4322,6 +4485,7 @@ class Tokenizer(object):
"<": "LT",
">": "GT",
"ArrayBuffer": "ARRAYBUFFER",
"SharedArrayBuffer": "SHAREDARRAYBUFFER",
"or": "OR"
}
@@ -4680,8 +4844,8 @@ class Parser(Tokenizer):
CallbackRest : IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON
"""
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
p[0] = IDLCallbackType(self.getLocation(p, 1), self.globalScope(),
identifier, p[3], p[5])
p[0] = IDLCallback(self.getLocation(p, 1), self.globalScope(),
identifier, p[3], p[5])
def p_ExceptionMembers(self, p):
"""
@@ -4694,8 +4858,8 @@ class Parser(Tokenizer):
"""
Typedef : TYPEDEF Type IDENTIFIER SEMICOLON
"""
typedef = IDLTypedefType(self.getLocation(p, 1), p[2], p[3])
typedef.resolve(self.globalScope())
typedef = IDLTypedef(self.getLocation(p, 1), self.globalScope(),
p[2], p[3])
p[0] = typedef
def p_ImplementsStatement(self, p):
@@ -5369,12 +5533,15 @@ class Parser(Tokenizer):
"""
NonAnyType : PrimitiveOrStringType TypeSuffix
| ARRAYBUFFER TypeSuffix
| SHAREDARRAYBUFFER TypeSuffix
| OBJECT TypeSuffix
"""
if p[1] == "object":
type = BuiltinTypes[IDLBuiltinType.Types.object]
elif p[1] == "ArrayBuffer":
type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
elif p[1] == "SharedArrayBuffer":
type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer]
else:
type = BuiltinTypes[p[1]]
@@ -5430,8 +5597,12 @@ class Parser(Tokenizer):
try:
if self.globalScope()._lookupIdentifier(p[1]):
obj = self.globalScope()._lookupIdentifier(p[1])
if obj.isType():
type = obj
assert not obj.isType()
if obj.isTypedef():
type = IDLTypedefType(self.getLocation(p, 1), obj.innerType,
obj.identifier.name)
elif obj.isCallback() and not obj.isInterface():
type = IDLCallbackType(self.getLocation(p, 1), obj)
else:
type = IDLWrapperType(self.getLocation(p, 1), p[1])
p[0] = self.handleModifiers(type, p[2])
@@ -5764,12 +5935,10 @@ class Parser(Tokenizer):
assert isinstance(scope, IDLScope)
# xrange omits the last value.
for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1):
for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.SharedFloat64Array + 1):
builtin = BuiltinTypes[x]
name = builtin.name
typedef = IDLTypedefType(BuiltinLocation("<builtin type>"), builtin, name)
typedef.resolve(scope)
typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name)
@ staticmethod
def handleModifiers(type, modifiers):
@@ -5827,6 +5996,7 @@ class Parser(Tokenizer):
_builtins = """
typedef unsigned long long DOMTimeStamp;
typedef (ArrayBufferView or ArrayBuffer) BufferSource;
typedef (SharedArrayBufferView or SharedArrayBuffer) SharedBufferSource;
"""
def main():
@@ -160,7 +160,8 @@ def WebIDLTest(parser, harness):
"optional Dict2", "sequence<long>", "sequence<short>",
"MozMap<object>", "MozMap<Dict>", "MozMap<long>",
"long[]", "short[]", "Date", "Date?", "any",
"USVString" ]
"USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "SharedArrayBufferView",
"Uint8Array", "SharedUint8Array", "Uint16Array", "SharedUint16Array" ]
# When we can parse Date and RegExp, we need to add them here.
# Try to categorize things a bit to keep list lengths down
@@ -175,8 +176,10 @@ def WebIDLTest(parser, harness):
nonStrings = allBut(argTypes, strings)
nonObjects = primitives + strings
objects = allBut(argTypes, nonObjects )
bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"]
sharedBufferSourceTypes = ["SharedArrayBuffer", "SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array"]
interfaces = [ "Interface", "Interface?", "AncestorInterface",
"UnrelatedInterface", "ImplementedInterface" ]
"UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
nullables = ["long?", "short?", "boolean?", "Interface?",
"CallbackInterface?", "optional Dict", "optional Dict2",
"Date?", "any"]
@@ -186,7 +189,7 @@ def WebIDLTest(parser, harness):
nonUserObjects = nonObjects + interfaces + dates + sequences
otherObjects = allBut(argTypes, nonUserObjects + ["object"])
notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] +
otherObjects + dates + sequences)
otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes)
mozMaps = [ "MozMap<object>", "MozMap<Dict>", "MozMap<long>" ]
# Build a representation of the distinguishability table as a dict
@@ -235,6 +238,14 @@ def WebIDLTest(parser, harness):
setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
setDistinguishable("any", [])
setDistinguishable("ArrayBuffer", allBut(argTypes, ["ArrayBuffer", "object"]))
setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"]))
setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"]))
setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"]))
setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"]))
setDistinguishable("SharedArrayBufferView", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array", "object"]))
setDistinguishable("SharedUint8Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "object"]))
setDistinguishable("SharedUint16Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint16Array", "object"]))
def areDistinguishable(type1, type2):
return data[type1].get(type2, False)
+1
View File
@@ -713,6 +713,7 @@ public:
// Dictionary tests
void PassDictionary(JSContext*, const Dict&);
void PassDictionary2(JSContext*, const Dict&);
void GetReadonlyDictionary(JSContext*, Dict&);
void GetReadonlyNullableDictionary(JSContext*, Nullable<Dict>&);
void GetWritableDictionary(JSContext*, Dict&);
+3
View File
@@ -7,6 +7,7 @@
typedef long myLong;
typedef TestInterface AnotherNameForTestInterface;
typedef TestInterface? NullableTestInterface;
typedef CustomEventInit TestDictionaryTypedef;
interface TestExternalInterface;
@@ -685,6 +686,7 @@ interface TestInterface {
attribute byte otherAttributeRenamedFrom;
void passDictionary(optional Dict x);
void passDictionary2(Dict x);
[Cached, Pure]
readonly attribute Dict readonlyDictionary;
[Cached, Pure]
@@ -1018,6 +1020,7 @@ dictionary Dict : ParentDict {
required object requiredObject;
CustomEventInit customEventInit;
TestDictionaryTypedef dictionaryTypedef;
};
dictionary ParentDict : GrandparentDict {
+1
View File
@@ -549,6 +549,7 @@ interface TestExampleInterface {
attribute byte otherAttributeRenamedFrom;
void passDictionary(optional Dict x);
void passDictionary2(Dict x);
[Cached, Pure]
readonly attribute Dict readonlyDictionary;
[Cached, Pure]
+1
View File
@@ -562,6 +562,7 @@ interface TestJSImplInterface {
attribute byte otherAttributeRenamedFrom;
void passDictionary(optional Dict x);
void passDictionary2(Dict x);
[Cached, Pure]
readonly attribute Dict readonlyDictionary;
[Cached, Pure]
+3 -3
View File
@@ -152,14 +152,14 @@ SetJsObject(JSContext* aContext,
v.get_nsString().BeginReading(),
v.get_nsString().Length());
NS_ENSURE_TRUE(jsData, false);
val = STRING_TO_JSVAL(jsData);
val.setString(jsData);
break;
}
case BluetoothValue::Tuint32_t:
val = INT_TO_JSVAL(v.get_uint32_t());
break;
case BluetoothValue::Tbool:
val = BOOLEAN_TO_JSVAL(v.get_bool());
val.setBoolean(v.get_bool());
break;
default:
BT_WARNING("SetJsObject: Parameter is not handled");
@@ -194,7 +194,7 @@ BroadcastSystemMessage(const nsAString& aType,
JSString* jsData = JS_NewUCStringCopyN(cx,
aData.get_nsString().BeginReading(),
aData.get_nsString().Length());
value = STRING_TO_JSVAL(jsData);
value.setString(jsData);
} else if (aData.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
if (!obj) {
+1 -1
View File
@@ -365,7 +365,7 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue,
}
}
*aOutVal = OBJECT_TO_JSVAL(arrayObj);
aOutVal->setObject(*arrayObj);
return NS_OK;
}
+55 -25
View File
@@ -385,6 +385,7 @@ RTCPeerConnection.prototype = {
this._impl.initialize(this._observer, this._win, rtcConfig,
Services.tm.currentThread);
this._initCertificate(rtcConfig.certificates);
this._initIdp();
_globalPCList.notifyLifecycleObservers(this, "initialized");
},
@@ -398,6 +399,30 @@ RTCPeerConnection.prototype = {
return this._pc;
},
_initCertificate: function(certificates) {
let certPromise;
if (certificates && certificates.length > 0) {
if (certificates.length > 1) {
throw new this._win.DOMException(
"RTCPeerConnection does not currently support multiple certificates",
"NotSupportedError");
}
let cert = certificates.find(c => c.expires.getTime() > Date.now());
if (!cert) {
throw new this._win.DOMException(
"Unable to create RTCPeerConnection with an expired certificate",
"InvalidParameterError");
}
certPromise = Promise.resolve(cert);
} else {
certPromise = this._win.mozRTCPeerConnection.generateCertificate({
name: "ECDSA", namedCurve: "P-256"
});
}
this._certificateReady = certPromise
.then(cert => this._impl.certificate = cert);
},
_initIdp: function() {
this._peerIdentity = new this._win.Promise((resolve, reject) => {
this._resolvePeerIdentity = resolve;
@@ -641,11 +666,13 @@ RTCPeerConnection.prototype = {
let origin = Cu.getWebIDLCallerPrincipal().origin;
return this._chain(() => {
let p = new this._win.Promise((resolve, reject) => {
this._onCreateOfferSuccess = resolve;
this._onCreateOfferFailure = reject;
this._impl.createOffer(options);
});
let p = this._certificateReady.then(
() => new this._win.Promise((resolve, reject) => {
this._onCreateOfferSuccess = resolve;
this._onCreateOfferFailure = reject;
this._impl.createOffer(options);
})
);
p = this._addIdentityAssertion(p, origin);
return p.then(
sdp => new this._win.mozRTCSessionDescription({ type: "offer", sdp: sdp }));
@@ -657,22 +684,24 @@ RTCPeerConnection.prototype = {
return this._legacyCatch(onSuccess, onError, () => {
let origin = Cu.getWebIDLCallerPrincipal().origin;
return this._chain(() => {
let p = new this._win.Promise((resolve, reject) => {
// We give up line-numbers in errors by doing this here, but do all
// state-checks inside the chain, to support the legacy feature that
// callers don't have to wait for setRemoteDescription to finish.
if (!this.remoteDescription) {
throw new this._win.DOMException("setRemoteDescription not called",
"InvalidStateError");
}
if (this.remoteDescription.type != "offer") {
throw new this._win.DOMException("No outstanding offer",
"InvalidStateError");
}
this._onCreateAnswerSuccess = resolve;
this._onCreateAnswerFailure = reject;
this._impl.createAnswer();
});
let p = this._certificateReady.then(
() => new this._win.Promise((resolve, reject) => {
// We give up line-numbers in errors by doing this here, but do all
// state-checks inside the chain, to support the legacy feature that
// callers don't have to wait for setRemoteDescription to finish.
if (!this.remoteDescription) {
throw new this._win.DOMException("setRemoteDescription not called",
"InvalidStateError");
}
if (this.remoteDescription.type != "offer") {
throw new this._win.DOMException("No outstanding offer",
"InvalidStateError");
}
this._onCreateAnswerSuccess = resolve;
this._onCreateAnswerFailure = reject;
this._impl.createAnswer();
})
);
p = this._addIdentityAssertion(p, origin);
return p.then(sdp => {
return new this._win.mozRTCSessionDescription({ type: "answer", sdp: sdp });
@@ -681,7 +710,6 @@ RTCPeerConnection.prototype = {
});
},
setLocalDescription: function(desc, onSuccess, onError) {
return this._legacyCatch(onSuccess, onError, () => {
this._localType = desc.type;
@@ -797,9 +825,11 @@ RTCPeerConnection.prototype = {
getIdentityAssertion: function() {
let origin = Cu.getWebIDLCallerPrincipal().origin;
return this._chain(() => {
return this._localIdp.getIdentityAssertion(this._impl.fingerprint, origin);
});
return this._chain(
() => this._certificateReady.then(
() => this._localIdp.getIdentityAssertion(this._impl.fingerprint, origin)
)
);
},
updateIce: function(config) {
+2
View File
@@ -105,6 +105,8 @@ skip-if = toolkit == 'gonk' # b2g emulator seems to be too slow (Bug 1016498 and
skip-if = buildapp == 'b2g' || os == 'android' # bug 1043403
[test_peerConnection_capturedVideo.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_certificates.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
[test_peerConnection_close.html]
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
[test_peerConnection_errorCallbacks.html]
@@ -0,0 +1,173 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1172785",
title: "Certificate management"
});
function badCertificate(config, expectedError, message) {
return mozRTCPeerConnection.generateCertificate(config)
.then(() => ok(false, message),
e => is(e.name, expectedError, message));
}
// Checks a handful of obviously bad options to RTCCertificate.create(). Most
// of the checking is done by the WebCrypto code underpinning this, hence the
// baffling error codes, but a sanity check is still in order.
function checkBadParameters() {
return Promise.all([
badCertificate({
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
modulusLength: 1023,
publicExponent: new Uint8Array([1, 0, 1])
}, "NotSupportedError", "1023-bit is too small to succeed"),
badCertificate({
name: "ECDH",
namedCurve: "P-256"
}, "DataError", "otherwise valid ECDH config is rejected"),
badCertificate({
name: "not a valid algorithm"
}, "SyntaxError", "not a valid algorithm"),
badCertificate("ECDSA", "SyntaxError", "a bare name is not enough"),
badCertificate({
name: "ECDSA",
namedCurve: "not a curve"
}, "NotSupportedError", "ECDSA with an unknown curve")
]);
}
function createDB() {
var openDB = indexedDB.open("genericstore");
openDB.onupgradeneeded = e => {
var db = e.target.result;
db.createObjectStore("data");
};
return new Promise(resolve => {
openDB.onsuccess = e => resolve(e.target.result);
});
}
function resultPromise(tx, op) {
return new Promise((resolve, reject) => {
op.onsuccess = e => resolve(e.target.result);
op.onerror = () => reject(op.error);
tx.onabort = () => reject(tx.error);
});
}
function store(db, value) {
var tx = db.transaction("data", "readwrite");
var store = tx.objectStore("data");
return resultPromise(tx, store.put(value, "value"));
}
function retrieve(db) {
var tx = db.transaction("data", "readonly");
var store = tx.objectStore("data");
return resultPromise(tx, store.get("value"));
}
// Creates a database, stores a value, retrieves it.
function storeAndRetrieve(value) {
return createDB().then(db => {
return store(db, value)
.then(() => retrieve(db))
.then(retrieved => {
db.close();
return retrieved;
});
});
}
var test;
runNetworkTest(function (options) {
var expiredCert;
return Promise.resolve()
.then(() => mozRTCPeerConnection.generateCertificate({
name: "ECDSA",
namedCurve: "P-256",
expires: 1 // smallest possible expiration window
}))
.then(cert => {
ok(cert.expires instanceof Date, 'cert has expiration time');
info('Expires at ' + cert.expires);
expiredCert = cert;
})
.then(() => checkBadParameters())
.then(() => {
var delay = expiredCert.expires.getTime() - Date.now();
// Hopefully this delay is never needed.
if (delay > 0) {
return new Promise(r => setTimeout(r, delay));
}
})
.then(() => {
ok(expiredCert.expires <= Date.now(), 'Cert should be at or past expiration');
try {
new mozRTCPeerConnection({ certificates: [expiredCert] });
ok(false, 'Constructing peer connection with an expired cert is not allowed');
} catch(e) {
is(e.name, 'InvalidParameterError',
'Constructing peer connection with an expired certs is not allowed');
}
})
.then(() => Promise.all([
mozRTCPeerConnection.generateCertificate({
name: "ECDSA",
namedCurve: "P-256"
}),
mozRTCPeerConnection.generateCertificate({
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1])
})
]))
// A round trip through indexedDB should not do anything.
.then(storeAndRetrieve)
.then(certs => {
try {
new mozRTCPeerConnection({ certificates: certs });
ok(false, 'Constructing peer connection with multiple certs is not allowed');
} catch(e) {
is(e.name, 'NotSupportedError',
'Constructing peer connection with multiple certs is not allowed');
}
return certs;
})
.then(certs => {
test = new PeerConnectionTest({
config_local: {
certificates: [certs[0]]
},
config_remote: {
certificates: [certs[1]]
}
});
test.setMediaConstraints([{audio: true}], [{audio: true}]);
return test.run();
})
.catch(e => {
console.log('test failure', e);
ok(false, 'test failed: ' + e);
});
});
</script>
</pre>
</body>
</html>
+3
View File
@@ -61,6 +61,9 @@ UNIFIED_SOURCES += [
EXPORTS.mozilla += [
'PeerIdentity.h',
]
EXPORTS.mozilla.dom += [
'RTCCertificate.h',
]
include('/ipc/chromium/chromium-config.mozbuild')
+1 -1
View File
@@ -271,7 +271,7 @@ MobileMessageCallback::NotifyGetSmscAddress(const nsAString& aSmscAddress)
return NotifyError(nsIMobileMessageCallback::INTERNAL_ERROR);
}
JS::Rooted<JS::Value> val(cx, STRING_TO_JSVAL(smsc));
JS::Rooted<JS::Value> val(cx, JS::StringValue(smsc));
return NotifySuccess(val);
}
+6 -5
View File
@@ -177,7 +177,8 @@ static bool
NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
static bool
NPObjWrapper_Enumerate(JSContext *cx, JS::Handle<JSObject*> obj, JS::AutoIdVector &properties);
NPObjWrapper_Enumerate(JSContext *cx, JS::Handle<JSObject*> obj, JS::AutoIdVector &properties,
bool enumerableOnly);
static bool
NPObjWrapper_Resolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
@@ -498,7 +499,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
case NPVariantType_Null :
return JSVAL_NULL;
case NPVariantType_Bool :
return BOOLEAN_TO_JSVAL(NPVARIANT_TO_BOOLEAN(*variant));
return JS::BooleanValue(NPVARIANT_TO_BOOLEAN(*variant));
case NPVariantType_Int32 :
{
// Don't use INT_TO_JSVAL directly to prevent bugs when dealing
@@ -518,7 +519,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
::JS_NewUCStringCopyN(cx, utf16String.get(), utf16String.Length());
if (str) {
return STRING_TO_JSVAL(str);
return JS::StringValue(str);
}
break;
@@ -530,7 +531,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
nsNPObjWrapper::GetNewOrUsed(npp, cx, NPVARIANT_TO_OBJECT(*variant));
if (obj) {
return OBJECT_TO_JSVAL(obj);
return JS::ObjectValue(*obj);
}
}
@@ -1627,7 +1628,7 @@ CallNPMethod(JSContext *cx, unsigned argc, JS::Value *vp)
static bool
NPObjWrapper_Enumerate(JSContext *cx, JS::Handle<JSObject*> obj,
JS::AutoIdVector &properties)
JS::AutoIdVector &properties, bool enumerableOnly)
{
NPObject *npobj = GetNPObject(cx, obj);
if (!npobj || !npobj->_class) {
+3 -3
View File
@@ -825,7 +825,7 @@ bool SetStringProperty(JSContext *cx, JS::Handle<JSObject*> aObject, const char
}
JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
NS_ENSURE_TRUE(strValue, false);
JS::Rooted<JS::Value> valValue(cx, STRING_TO_JSVAL(strValue));
JS::Rooted<JS::Value> valValue(cx, JS::StringValue(strValue));
return JS_SetProperty(cx, aObject, aProperty, valValue);
}
@@ -890,7 +890,7 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
if (!strVersion){
return false;
}
JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
JS::Rooted<JS::Value> valVersion(cx, JS::StringValue(strVersion));
if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
return false;
}
@@ -906,7 +906,7 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
return false;
}
JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
JS::Rooted<JS::Value> valVersion(cx, JS::StringValue(strVersion));
if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
return false;
}
+1 -1
View File
@@ -598,7 +598,7 @@ workerdebuggersandbox_convert(JSContext *cx, JS::Handle<JSObject *> obj,
JSType type, JS::MutableHandle<JS::Value> vp)
{
if (type == JSTYPE_OBJECT) {
vp.set(OBJECT_TO_JSVAL(obj));
vp.setObject(*obj);
return true;
}
+1 -1
View File
@@ -2459,7 +2459,7 @@ XMLHttpRequest::GetResponse(JSContext* /* unused */,
return;
}
mStateData.mResponse = STRING_TO_JSVAL(str);
mStateData.mResponse.setString(str);
}
}
+1 -1
View File
@@ -1039,7 +1039,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx,
nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
::JS_SetPrivate(proto, docInfo);
NS_ADDREF(docInfo);
JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
JS_SetReservedSlot(proto, 0, JS::PrivateValue(aProtoBinding));
// Next, enter the compartment of the property holder, wrap the proto, and
// stick it on.
+11
View File
@@ -2430,6 +2430,17 @@ gfxFont::GetShapedWord(gfxContext *aContext,
return sw;
}
template gfxShapedWord*
gfxFont::GetShapedWord(gfxContext *aContext,
const uint8_t *aText,
uint32_t aLength,
uint32_t aHash,
int32_t aRunScript,
bool aVertical,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags,
gfxTextPerfMetrics *aTextPerf GFX_MAYBE_UNUSED);
bool
gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
{
+5 -4
View File
@@ -30,7 +30,7 @@ static const char* kBrowserThreadNames[BrowserProcessSubThread::ID_COUNT] = {
#endif
};
Lock BrowserProcessSubThread::sLock;
/* static */ StaticMutex BrowserProcessSubThread::sLock;
BrowserProcessSubThread* BrowserProcessSubThread::sBrowserThreads[ID_COUNT] = {
nullptr, // IO
// nullptr, // FILE
@@ -46,7 +46,7 @@ BrowserProcessSubThread::BrowserProcessSubThread(ID aId) :
mIdentifier(aId),
mNotificationService(nullptr)
{
AutoLock lock(sLock);
StaticMutexAutoLock lock(sLock);
DCHECK(aId >= 0 && aId < ID_COUNT);
DCHECK(sBrowserThreads[aId] == nullptr);
sBrowserThreads[aId] = this;
@@ -55,7 +55,8 @@ BrowserProcessSubThread::BrowserProcessSubThread(ID aId) :
BrowserProcessSubThread::~BrowserProcessSubThread()
{
Stop();
{AutoLock lock(sLock);
{
StaticMutexAutoLock lock(sLock);
sBrowserThreads[mIdentifier] = nullptr;
}
@@ -88,7 +89,7 @@ BrowserProcessSubThread::CleanUp()
MessageLoop*
BrowserProcessSubThread::GetMessageLoop(ID aId)
{
AutoLock lock(sLock);
StaticMutexAutoLock lock(sLock);
DCHECK(aId >= 0 && aId < ID_COUNT);
if (sBrowserThreads[aId])
+2 -4
View File
@@ -9,7 +9,7 @@
#define mozilla_ipc_BrowserProcessSubThread_h
#include "base/thread.h"
#include "base/lock.h"
#include "mozilla/StaticMutex.h"
#include "nsDebug.h"
@@ -60,9 +60,7 @@ private:
// This lock protects |browser_threads_|. Do not read or modify that array
// without holding this lock. Do not block while holding this lock.
// FIXME/cjones: XPCOM doesn't like static vars, so can't use
// mozilla::Mutex
static Lock sLock;
static StaticMutex sLock;
// An array of the ChromeThread objects. This array is protected by |lock_|.
// The threads are not owned by this array. Typically, the threads are owned
+1 -1
View File
@@ -362,7 +362,7 @@ JavaScriptShared::fromVariant(JSContext* cx, const JSVariant& from, MutableHandl
return true;
case JSVariant::Tbool:
to.set(BOOLEAN_TO_JSVAL(from.get_bool()));
to.setBoolean(from.get_bool());
return true;
case JSVariant::TnsString:
+1 -1
View File
@@ -189,7 +189,7 @@ WrapperAnswer::RecvDefineProperty(const ObjectId& objId, const JSIDVariant& idVa
return fail(jsapi, rs);
ObjectOpResult success;
if (!js::DefineOwnProperty(cx, obj, id, desc, success))
if (!JS_DefinePropertyById(cx, obj, id, desc, success))
return fail(jsapi, rs);
return ok(rs, success);
}
+13 -12
View File
@@ -253,19 +253,20 @@ typedef bool
(* JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
JS::ObjectOpResult& result);
// The type of ObjectOps::enumerate. This callback overrides a portion of SpiderMonkey's default
// [[Enumerate]] internal method. When an ordinary object is enumerated, that object and each object
// on its prototype chain is tested for an enumerate op, and those ops are called in order.
// The properties each op adds to the 'properties' vector are added to the set of values the
// for-in loop will iterate over. All of this is nonstandard.
// The type of ObjectOps::enumerate. This callback overrides a portion of
// SpiderMonkey's default [[Enumerate]] internal method. When an ordinary object
// is enumerated, that object and each object on its prototype chain is tested
// for an enumerate op, and those ops are called in order. The properties each
// op adds to the 'properties' vector are added to the set of values the for-in
// loop will iterate over. All of this is nonstandard.
//
// An object is "enumerated" when it's the target of a for-in loop or JS_Enumerate().
// All other property inspection, including Object.keys(obj), goes through [[OwnKeys]].
//
// The callback's job is to populate 'properties' with all property keys that the for-in loop
// should visit.
// An object is "enumerated" when it's the target of a for-in loop or
// JS_Enumerate(). The callback's job is to populate 'properties' with the
// object's property keys. If `enumerableOnly` is true, the callback should only
// add enumerable properties.
typedef bool
(* JSNewEnumerateOp)(JSContext *cx, JS::HandleObject obj, JS::AutoIdVector &properties);
(* JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
bool enumerableOnly);
// The old-style JSClass.enumerate op should define all lazy properties not
// yet reflected in obj.
@@ -404,7 +405,7 @@ class JS_FRIEND_API(ElementAdder)
GetBehavior getBehavior() const { return getBehavior_; }
void append(JSContext* cx, JS::HandleValue v);
bool append(JSContext* cx, JS::HandleValue v);
void appendHole();
};
+2 -2
View File
@@ -545,7 +545,7 @@ class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC
/*
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
* JSTRACE_SHAPE. |thing| should be non-null.
* JS::TraceKind::Shape. |thing| should be non-null.
*/
extern JS_FRIEND_API(bool)
UnmarkGrayGCThingRecursively(GCCellPtr thing);
@@ -558,7 +558,7 @@ namespace gc {
static MOZ_ALWAYS_INLINE void
ExposeGCThingToActiveJS(JS::GCCellPtr thing)
{
MOZ_ASSERT(thing.kind() != JSTRACE_SHAPE);
MOZ_ASSERT(thing.kind() != JS::TraceKind::Shape);
/*
* GC things residing in the nursery cannot be gray: they have no mark bits.
+31 -31
View File
@@ -81,10 +81,10 @@ const uintptr_t ChunkLocationAnyNursery = ChunkLocationBitNursery;
#ifdef JS_DEBUG
/* When downcasting, ensure we are actually the right type. */
extern JS_FRIEND_API(void)
AssertGCThingHasType(js::gc::Cell* cell, JSGCTraceKind kind);
AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind);
#else
inline void
AssertGCThingHasType(js::gc::Cell* cell, JSGCTraceKind kind) {}
AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {}
#endif
MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell);
@@ -155,60 +155,60 @@ class JS_FRIEND_API(GCCellPtr)
{
public:
// Construction from a void* and trace kind.
GCCellPtr(void* gcthing, JSGCTraceKind traceKind) : ptr(checkedCast(gcthing, traceKind)) {}
GCCellPtr(void* gcthing, JS::TraceKind traceKind) : ptr(checkedCast(gcthing, traceKind)) {}
// Automatically construct a null GCCellPtr from nullptr.
MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) : ptr(checkedCast(nullptr, JSTRACE_NULL)) {}
MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {}
// Construction from an explicit type.
explicit GCCellPtr(JSObject* obj) : ptr(checkedCast(obj, JSTRACE_OBJECT)) { }
explicit GCCellPtr(JSFunction* fun) : ptr(checkedCast(fun, JSTRACE_OBJECT)) { }
explicit GCCellPtr(JSString* str) : ptr(checkedCast(str, JSTRACE_STRING)) { }
explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JSTRACE_STRING)) { }
explicit GCCellPtr(JSScript* script) : ptr(checkedCast(script, JSTRACE_SCRIPT)) { }
explicit GCCellPtr(JSObject* obj) : ptr(checkedCast(obj, JS::TraceKind::Object)) { }
explicit GCCellPtr(JSFunction* fun) : ptr(checkedCast(fun, JS::TraceKind::Object)) { }
explicit GCCellPtr(JSString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { }
explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { }
explicit GCCellPtr(JSScript* script) : ptr(checkedCast(script, JS::TraceKind::Script)) { }
explicit GCCellPtr(const Value& v);
JSGCTraceKind kind() const {
JSGCTraceKind traceKind = JSGCTraceKind(ptr & JSTRACE_OUTOFLINE);
if (traceKind != JSTRACE_OUTOFLINE)
JS::TraceKind kind() const {
JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask);
if (uintptr_t(traceKind) != OutOfLineTraceKindMask)
return traceKind;
return outOfLineKind();
}
// Allow GCCellPtr to be used in a boolean context.
explicit operator bool() const {
MOZ_ASSERT(bool(asCell()) == (kind() != JSTRACE_NULL));
MOZ_ASSERT(bool(asCell()) == (kind() != JS::TraceKind::Null));
return asCell();
}
// Simplify checks to the kind.
bool isObject() const { return kind() == JSTRACE_OBJECT; }
bool isScript() const { return kind() == JSTRACE_SCRIPT; }
bool isString() const { return kind() == JSTRACE_STRING; }
bool isSymbol() const { return kind() == JSTRACE_SYMBOL; }
bool isShape() const { return kind() == JSTRACE_SHAPE; }
bool isObjectGroup() const { return kind() == JSTRACE_OBJECT_GROUP; }
bool isObject() const { return kind() == JS::TraceKind::Object; }
bool isScript() const { return kind() == JS::TraceKind::Script; }
bool isString() const { return kind() == JS::TraceKind::String; }
bool isSymbol() const { return kind() == JS::TraceKind::Symbol; }
bool isShape() const { return kind() == JS::TraceKind::Shape; }
bool isObjectGroup() const { return kind() == JS::TraceKind::ObjectGroup; }
// Conversions to more specific types must match the kind. Access to
// further refined types is not allowed directly from a GCCellPtr.
JSObject* toObject() const {
MOZ_ASSERT(kind() == JSTRACE_OBJECT);
MOZ_ASSERT(kind() == JS::TraceKind::Object);
return reinterpret_cast<JSObject*>(asCell());
}
JSString* toString() const {
MOZ_ASSERT(kind() == JSTRACE_STRING);
MOZ_ASSERT(kind() == JS::TraceKind::String);
return reinterpret_cast<JSString*>(asCell());
}
JSScript* toScript() const {
MOZ_ASSERT(kind() == JSTRACE_SCRIPT);
MOZ_ASSERT(kind() == JS::TraceKind::Script);
return reinterpret_cast<JSScript*>(asCell());
}
Symbol* toSymbol() const {
MOZ_ASSERT(kind() == JSTRACE_SYMBOL);
MOZ_ASSERT(kind() == JS::TraceKind::Symbol);
return reinterpret_cast<Symbol*>(asCell());
}
js::gc::Cell* asCell() const {
return reinterpret_cast<js::gc::Cell*>(ptr & ~JSTRACE_OUTOFLINE);
return reinterpret_cast<js::gc::Cell*>(ptr & ~OutOfLineTraceKindMask);
}
// The CC's trace logger needs an identity that is XPIDL serializable.
@@ -225,18 +225,18 @@ class JS_FRIEND_API(GCCellPtr)
bool mayBeOwnedByOtherRuntime() const;
private:
uintptr_t checkedCast(void* p, JSGCTraceKind traceKind) {
static uintptr_t checkedCast(void* p, JS::TraceKind traceKind) {
js::gc::Cell* cell = static_cast<js::gc::Cell*>(p);
MOZ_ASSERT((uintptr_t(p) & JSTRACE_OUTOFLINE) == 0);
MOZ_ASSERT((uintptr_t(p) & OutOfLineTraceKindMask) == 0);
AssertGCThingHasType(cell, traceKind);
// Note: the JSTRACE_OUTOFLINE bits are set on all out-of-line kinds
// Note: the OutOfLineTraceKindMask bits are set on all out-of-line kinds
// so that we can mask instead of branching.
MOZ_ASSERT_IF(traceKind >= JSTRACE_OUTOFLINE,
(traceKind & JSTRACE_OUTOFLINE) == JSTRACE_OUTOFLINE);
return uintptr_t(p) | (traceKind & JSTRACE_OUTOFLINE);
MOZ_ASSERT_IF(uintptr_t(traceKind) >= OutOfLineTraceKindMask,
(uintptr_t(traceKind) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask);
return uintptr_t(p) | (uintptr_t(traceKind) & OutOfLineTraceKindMask);
}
JSGCTraceKind outOfLineKind() const;
JS::TraceKind outOfLineKind() const;
uintptr_t ptr;
};
+2 -2
View File
@@ -141,9 +141,9 @@ JSID_TO_GCTHING(jsid id)
{
void* thing = (void*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
if (JSID_IS_STRING(id))
return JS::GCCellPtr(thing, JSTRACE_STRING);
return JS::GCCellPtr(thing, JS::TraceKind::String);
MOZ_ASSERT(JSID_IS_SYMBOL(id));
return JS::GCCellPtr(thing, JSTRACE_SYMBOL);
return JS::GCCellPtr(thing, JS::TraceKind::Symbol);
}
static MOZ_ALWAYS_INLINE bool
+10 -10
View File
@@ -463,17 +463,17 @@ struct GCThingSizes
dummy()
{}
void addToKind(JSGCTraceKind kind, intptr_t n) {
void addToKind(JS::TraceKind kind, intptr_t n) {
switch (kind) {
case JSTRACE_OBJECT: object += n; break;
case JSTRACE_STRING: string += n; break;
case JSTRACE_SYMBOL: symbol += n; break;
case JSTRACE_SCRIPT: script += n; break;
case JSTRACE_SHAPE: shape += n; break;
case JSTRACE_BASE_SHAPE: baseShape += n; break;
case JSTRACE_JITCODE: jitcode += n; break;
case JSTRACE_LAZY_SCRIPT: lazyScript += n; break;
case JSTRACE_OBJECT_GROUP: objectGroup += n; break;
case JS::TraceKind::Object: object += n; break;
case JS::TraceKind::String: string += n; break;
case JS::TraceKind::Symbol: symbol += n; break;
case JS::TraceKind::Script: script += n; break;
case JS::TraceKind::Shape: shape += n; break;
case JS::TraceKind::BaseShape: baseShape += n; break;
case JS::TraceKind::JitCode: jitcode += n; break;
case JS::TraceKind::LazyScript: lazyScript += n; break;
case JS::TraceKind::ObjectGroup: objectGroup += n; break;
default:
MOZ_CRASH("Bad trace kind for GCThingSizes");
}
+26 -28
View File
@@ -18,7 +18,6 @@ namespace JS {
class JS_PUBLIC_API(CallbackTracer);
template <typename T> class Heap;
template <typename T> class TenuredHeap;
}
// When tracing a thing, the GC needs to know about the layout of the object it
// is looking at. There are a fixed number of different layouts that the GC
@@ -29,41 +28,40 @@ template <typename T> class TenuredHeap;
// the matching C++ types are exposed, and those that are, are opaque.
//
// See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
enum JSGCTraceKind
enum class TraceKind
{
// These trace kinds have a publicly exposed, although opaque, C++ type.
// Note: The order here is determined by our Value packing. Other users
// should sort alphabetically, for consistency.
JSTRACE_OBJECT = 0x00,
JSTRACE_STRING = 0x01,
JSTRACE_SYMBOL = 0x02,
JSTRACE_SCRIPT = 0x03,
Object = 0x00,
String = 0x01,
Symbol = 0x02,
Script = 0x03,
// Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
JSTRACE_SHAPE = 0x04,
Shape = 0x04,
// ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
JSTRACE_OBJECT_GROUP = 0x05,
ObjectGroup = 0x05,
// The kind associated with a nullptr.
JSTRACE_NULL = 0x06,
// A kind that indicates the real kind should be looked up in the arena.
JSTRACE_OUTOFLINE = 0x07,
Null = 0x06,
// The following kinds do not have an exposed C++ idiom.
JSTRACE_BASE_SHAPE = 0x0F,
JSTRACE_JITCODE = 0x1F,
JSTRACE_LAZY_SCRIPT = 0x2F,
JSTRACE_LAST = JSTRACE_OBJECT_GROUP
BaseShape = 0x0F,
JitCode = 0x1F,
LazyScript = 0x2F
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
namespace JS {
// Returns a static string equivalent of |kind|.
JS_FRIEND_API(const char*)
GCTraceKindToAscii(JSGCTraceKind kind);
}
GCTraceKindToAscii(JS::TraceKind kind);
} // namespace JS
// Tracer callback, called for each traceable thing directly referenced by a
// particular object or runtime structure. It is the callback responsibility
@@ -71,16 +69,16 @@ GCTraceKindToAscii(JSGCTraceKind kind);
// JS_TraceChildren on the passed thing. In this case the callback must be
// prepared to deal with cycles in the traversal graph.
//
// kind argument is one of JSTRACE_OBJECT, JSTRACE_STRING or a tag denoting
// internal implementation-specific traversal kind. In the latter case the only
// operations on thing that the callback can do is to call JS_TraceChildren or
// JS_GetTraceThingInfo.
// kind argument is one of JS::TraceKind::Object, JS::TraceKind::String or a
// tag denoting internal implementation-specific traversal kind. In the latter
// case the only operations on thing that the callback can do is to call
// JS_TraceChildren or JS_GetTraceThingInfo.
//
// If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all
// of its mappings. This should be used in cases where the tracer
// wants to use the existing liveness of entries.
typedef void
(* JSTraceCallback)(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind);
(* JSTraceCallback)(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind);
enum WeakMapTraceKind {
DoNotTraceWeakMaps = 0,
@@ -146,7 +144,7 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
}
// Call the callback.
void invoke(void** thing, JSGCTraceKind kind) {
void invoke(void** thing, JS::TraceKind kind) {
callback(this, thing, kind);
}
@@ -350,7 +348,7 @@ extern JS_PUBLIC_API(void)
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name);
extern JS_PUBLIC_API(void)
JS_TraceChildren(JSTracer* trc, void* thing, JSGCTraceKind kind);
JS_TraceChildren(JSTracer* trc, void* thing, JS::TraceKind kind);
namespace JS {
typedef js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy> ZoneSet;
@@ -363,6 +361,6 @@ JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones);
extern JS_PUBLIC_API(void)
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
void* thing, JSGCTraceKind kind, bool includeDetails);
void* thing, JS::TraceKind kind, bool includeDetails);
#endif /* js_TracingAPI_h */
+1
View File
@@ -31,6 +31,7 @@ namespace JS {
_(SetProp_DefiniteSlot) \
_(SetProp_Unboxed) \
_(SetProp_InlineAccess) \
_(SetProp_InlineCache) \
\
_(GetElem_TypedObject) \
_(GetElem_Dense) \
+1 -1
View File
@@ -302,7 +302,7 @@ class Node {
// JS::ubi::Node are both essentially tagged references to other sorts of
// objects, so letting conversions happen automatically is appropriate.
MOZ_IMPLICIT Node(JS::HandleValue value);
Node(JSGCTraceKind kind, void* ptr);
Node(JS::TraceKind kind, void* ptr);
// copy construction and copy assignment just use memcpy, since we know
// instances contain nothing but a vtable pointer and a data pointer.
+15 -43
View File
@@ -613,12 +613,12 @@ JSVAL_TO_GCTHING_IMPL(jsval_layout l)
static inline uint32_t
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
{
static_assert((JSVAL_TAG_STRING & 0x03) == JSTRACE_STRING,
"Value type tags must correspond with JSGCTraceKinds.");
static_assert((JSVAL_TAG_SYMBOL & 0x03) == JSTRACE_SYMBOL,
"Value type tags must correspond with JSGCTraceKinds.");
static_assert((JSVAL_TAG_OBJECT & 0x03) == JSTRACE_OBJECT,
"Value type tags must correspond with JSGCTraceKinds.");
static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
"Value type tags must correspond with JS::TraceKinds.");
static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
"Value type tags must correspond with JS::TraceKinds.");
static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
"Value type tags must correspond with JS::TraceKinds.");
return l.s.tag & 0x03;
}
@@ -854,12 +854,12 @@ JSVAL_TO_GCTHING_IMPL(jsval_layout l)
static inline uint32_t
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
{
static_assert((JSVAL_TAG_STRING & 0x03) == JSTRACE_STRING,
"Value type tags must correspond with JSGCTraceKinds.");
static_assert((JSVAL_TAG_SYMBOL & 0x03) == JSTRACE_SYMBOL,
"Value type tags must correspond with JSGCTraceKinds.");
static_assert((JSVAL_TAG_OBJECT & 0x03) == JSTRACE_OBJECT,
"Value type tags must correspond with JSGCTraceKinds.");
static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
"Value type tags must correspond with JS::TraceKinds.");
static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
"Value type tags must correspond with JS::TraceKinds.");
static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
"Value type tags must correspond with JS::TraceKinds.");
return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03;
}
@@ -1179,9 +1179,9 @@ class Value
return JSVAL_IS_TRACEABLE_IMPL(data);
}
JSGCTraceKind gcKind() const {
JS::TraceKind traceKind() const {
MOZ_ASSERT(isMarkable());
return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data));
return JS::TraceKind(JSVAL_TRACE_KIND_IMPL(data));
}
JSWhyMagic whyMagic() const {
@@ -1249,7 +1249,7 @@ class Value
}
GCCellPtr toGCCellPtr() const {
return GCCellPtr(toGCThing(), gcKind());
return GCCellPtr(toGCThing(), traceKind());
}
bool toBoolean() const {
@@ -1969,34 +1969,6 @@ UINT_TO_JSVAL(uint32_t i)
: DOUBLE_TO_JSVAL((double)i);
}
static inline jsval
STRING_TO_JSVAL(JSString* str)
{
return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str));
}
static inline jsval
OBJECT_TO_JSVAL(JSObject* obj)
{
if (obj)
return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj));
return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
}
static inline jsval
BOOLEAN_TO_JSVAL(bool b)
{
return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b));
}
/* To be GC-safe, privates are tagged as doubles. */
static inline jsval
PRIVATE_TO_JSVAL(void* ptr)
{
return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr));
}
// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
// constructing values from scratch (e.g. Int32Value(0)). These constants are
// stored in memory and initialized at startup, so testing against them and
+3 -7
View File
@@ -253,8 +253,7 @@ function ArrayMap(callbackfn/*, thisArg*/) {
if (k in O) {
/* Step c.i-iii. */
var mappedValue = callFunction(callbackfn, T, O[k], k, O);
// UnsafePutElements doesn't invoke setters, so we can use it here.
UnsafePutElements(A, k, mappedValue);
_DefineDataProperty(A, k, mappedValue);
}
}
@@ -714,9 +713,6 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
var T = thisArg;
// All elements defined by this algorithm have the same attrs:
var attrs = ATTR_CONFIGURABLE | ATTR_ENUMERABLE | ATTR_WRITABLE;
// Steps 4-5.
var usingIterator = GetMethod(items, std_iterator);
@@ -753,7 +749,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
var mappedValue = mapping ? callFunction(mapfn, thisArg, nextValue, k) : nextValue;
// Steps 6.g.ix-xi.
_DefineDataProperty(A, k++, mappedValue, attrs);
_DefineDataProperty(A, k++, mappedValue);
}
}
@@ -778,7 +774,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
var mappedValue = mapping ? callFunction(mapfn, thisArg, kValue, k) : kValue;
// Steps 16.f-g.
_DefineDataProperty(A, k, mappedValue, attrs);
_DefineDataProperty(A, k, mappedValue);
}
// Steps 17-18.
+4 -1
View File
@@ -1220,8 +1220,11 @@ AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
RootedValue AtomicsValue(cx, ObjectValue(*Atomics));
// Everything is set up, install Atomics on the global object.
if (!DefineProperty(cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr, 0))
if (!DefineProperty(cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr,
JSPROP_RESOLVING))
{
return nullptr;
}
global->setConstructor(JSProto_Atomics, AtomicsValue);
return Atomics;
+4 -1
View File
@@ -2049,8 +2049,11 @@ js::InitIntlClass(JSContext *cx, HandleObject obj)
return nullptr;
RootedValue IntlValue(cx, ObjectValue(*Intl));
if (!DefineProperty(cx, global, cx->names().Intl, IntlValue, nullptr, nullptr, 0))
if (!DefineProperty(cx, global, cx->names().Intl, IntlValue, nullptr, nullptr,
JSPROP_RESOLVING))
{
return nullptr;
}
if (!JS_DefineFunctions(cx, Intl, intl_static_methods))
return nullptr;
+11 -20
View File
@@ -1068,15 +1068,6 @@ function GetNumberOption(options, property, minimum, maximum, fallback) {
/********** Property access for Intl objects **********/
/**
* Set a normal public property p of o to value v, but use Object.defineProperty
* to avoid interference from setters on Object.prototype.
*/
function defineProperty(o, p, v) {
_DefineDataProperty(o, p, v, ATTR_ENUMERABLE | ATTR_CONFIGURABLE | ATTR_WRITABLE);
}
/**
* Weak map used to track the initialize-as-Intl status (and, if an object has
* been so initialized, the Intl-specific internal properties) of all objects.
@@ -1599,7 +1590,7 @@ function Intl_Collator_resolvedOptions() {
for (var i = 0; i < relevantExtensionKeys.length; i++) {
var key = relevantExtensionKeys[i];
var property = (key === "co") ? "collation" : collatorKeyMappings[key].property;
defineProperty(result, property, internals[property]);
_DefineDataProperty(result, property, internals[property]);
}
return result;
}
@@ -2045,7 +2036,7 @@ function Intl_NumberFormat_resolvedOptions() {
for (var i = 0; i < optionalProperties.length; i++) {
var p = optionalProperties[i];
if (callFunction(std_Object_hasOwnProperty, internals, p))
defineProperty(result, p, internals[p]);
_DefineDataProperty(result, p, internals[p]);
}
return result;
}
@@ -2510,17 +2501,17 @@ function ToDateTimeOptions(options, required, defaults) {
// the Throw parameter, while Object.defineProperty uses true. For the
// calls here, the difference doesn't matter because we're adding
// properties to a new object.
defineProperty(options, "year", "numeric");
defineProperty(options, "month", "numeric");
defineProperty(options, "day", "numeric");
_DefineDataProperty(options, "year", "numeric");
_DefineDataProperty(options, "month", "numeric");
_DefineDataProperty(options, "day", "numeric");
}
// Step 8.
if (needDefaults && (defaults === "time" || defaults === "all")) {
// See comment for step 7.
defineProperty(options, "hour", "numeric");
defineProperty(options, "minute", "numeric");
defineProperty(options, "second", "numeric");
_DefineDataProperty(options, "hour", "numeric");
_DefineDataProperty(options, "minute", "numeric");
_DefineDataProperty(options, "second", "numeric");
}
// Step 9.
@@ -2826,11 +2817,11 @@ function resolveICUPattern(pattern, result) {
// skip other pattern characters and literal text
}
if (callFunction(std_Object_hasOwnProperty, icuPatternCharToComponent, c))
defineProperty(result, icuPatternCharToComponent[c], value);
_DefineDataProperty(result, icuPatternCharToComponent[c], value);
if (c === "h" || c === "K")
defineProperty(result, "hour12", true);
_DefineDataProperty(result, "hour12", true);
else if (c === "H" || c === "k")
defineProperty(result, "hour12", false);
_DefineDataProperty(result, "hour12", false);
}
}
}
+3 -2
View File
@@ -823,7 +823,7 @@ js::obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
return false;
// Steps 6-8.
if (!StandardDefineProperty(cx, obj, id, desc))
if (!DefineProperty(cx, obj, id, desc))
return false;
args.rval().setObject(*obj);
return true;
@@ -1125,7 +1125,8 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
/* ES5 15.1.2.1. */
RootedId evalId(cx, NameToId(cx->names().eval));
JSObject* evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1, JSFUN_STUB_GSOPS);
JSObject* evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1,
JSFUN_STUB_GSOPS | JSPROP_RESOLVING);
if (!evalobj)
return false;
self->setOriginalEval(evalobj);
+4 -1
View File
@@ -475,8 +475,11 @@ SIMDObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
// Everything is set up, install SIMD on the global object.
RootedValue SIMDValue(cx, ObjectValue(*SIMD));
if (!DefineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0))
if (!DefineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr,
JSPROP_RESOLVING))
{
return nullptr;
}
global->setConstructor(JSProto_SIMD, SIMDValue);
return SIMD;
+8 -12
View File
@@ -789,7 +789,7 @@ NondeterministicGetWeakMapKeys(JSContext* cx, unsigned argc, jsval* vp)
struct JSCountHeapNode {
void* thing;
JSGCTraceKind kind;
JS::TraceKind kind;
JSCountHeapNode* next;
};
@@ -807,7 +807,7 @@ class CountHeapTracer : public JS::CallbackTracer
};
static void
CountHeapNotify(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
CountHeapNotify(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind)
{
CountHeapTracer* countTracer = (CountHeapTracer*)trc;
void* thing = *thingp;
@@ -842,12 +842,12 @@ CountHeapNotify(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
static const struct TraceKindPair {
const char* name;
int32_t kind;
int32_t kind;
} traceKindNames[] = {
{ "all", -1 },
{ "object", JSTRACE_OBJECT },
{ "string", JSTRACE_STRING },
{ "symbol", JSTRACE_SYMBOL },
{ "all", -1 },
{ "object", int32_t(JS::TraceKind::Object) },
{ "string", int32_t(JS::TraceKind::String) },
{ "symbol", int32_t(JS::TraceKind::Symbol) },
};
static bool
@@ -926,7 +926,7 @@ CountHeap(JSContext* cx, unsigned argc, jsval* vp)
while ((node = countTracer.traceList) != nullptr) {
if (traceThing == nullptr) {
// We are looking for all nodes with a specific kind
if (traceKind == -1 || node->kind == traceKind)
if (traceKind == -1 || int32_t(node->kind) == traceKind)
counter++;
} else {
// We are looking for some specific thing
@@ -951,10 +951,6 @@ CountHeap(JSContext* cx, unsigned argc, jsval* vp)
return true;
}
// Stolen from jsmath.cpp
static const uint64_t RNG_MULTIPLIER = 0x5DEECE66DLL;
static const uint64_t RNG_MASK = (1LL << 48) - 1;
static bool
SetSavedStacksRNGState(JSContext* cx, unsigned argc, jsval* vp)
{
+6 -2
View File
@@ -1325,8 +1325,11 @@ GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global)
// Everything is setup, install module on the global object:
RootedValue moduleValue(cx, ObjectValue(*module));
global->setConstructor(JSProto_TypedObject, moduleValue);
if (!DefineProperty(cx, global, cx->names().TypedObject, moduleValue, nullptr, nullptr, 0))
if (!DefineProperty(cx, global, cx->names().TypedObject, moduleValue, nullptr, nullptr,
JSPROP_RESOLVING))
{
return false;
}
return module;
}
@@ -2056,7 +2059,8 @@ TypedObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, Ob
}
bool
TypedObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties)
TypedObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly)
{
MOZ_ASSERT(obj->is<TypedObject>());
Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
+2 -1
View File
@@ -549,7 +549,8 @@ class TypedObject : public JSObject
static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
ObjectOpResult& result);
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties);
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly);
public:
TypedProto& typedProto() const {
+1 -3
View File
@@ -14,9 +14,7 @@
AssertionFailed: false,
MakeConstructible: false, DecompileArg: false,
RuntimeDefaultLocale: false,
ParallelDo: false, ParallelSlices: false, NewDenseArray: false,
UnsafePutElements: false,
ParallelTestsShouldPass: false,
NewDenseArray: false,
Dump: false,
callFunction: false,
TO_UINT32: false,
+30 -31
View File
@@ -1633,7 +1633,7 @@ InitTypeConstructor(JSContext* cx,
// Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
// the type constructor, for faster lookup.
js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, ObjectValue(*typeProto));
// Create an object to serve as the common ancestor for all CData objects
// created from the given type constructor. This has ctypes.CData.prototype
@@ -1653,7 +1653,7 @@ InitTypeConstructor(JSContext* cx,
return false;
// Link the type prototype to the data prototype.
JS_SetReservedSlot(typeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(dataProto));
JS_SetReservedSlot(typeProto, SLOT_OURDATAPROTO, ObjectValue(*dataProto));
if (!JS_FreezeObject(cx, obj) ||
//!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212!
@@ -1690,8 +1690,7 @@ InitInt64Class(JSContext* cx,
if (!fun)
return nullptr;
js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO,
OBJECT_TO_JSVAL(prototype));
js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO, ObjectValue(*prototype));
if (!JS_FreezeObject(cx, ctor))
return nullptr;
@@ -1708,7 +1707,7 @@ AttachProtos(JSObject* proto, const AutoObjectVector& protos)
// to the appropriate CTypeProtoSlot. (SLOT_CTYPES is the last slot
// of [[Class]] "CTypeProto" that we fill in this automated manner.)
for (uint32_t i = 0; i <= SLOT_CTYPES; ++i)
JS_SetReservedSlot(proto, i, OBJECT_TO_JSVAL(protos[i]));
JS_SetReservedSlot(proto, i, ObjectOrNullValue(protos[i]));
}
static bool
@@ -1747,7 +1746,7 @@ InitTypeClasses(JSContext* cx, HandleObject ctypesObj)
return false;
// Link CTypeProto to CDataProto.
JS_SetReservedSlot(CTypeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(CDataProto));
JS_SetReservedSlot(CTypeProto, SLOT_OURDATAPROTO, ObjectValue(*CDataProto));
// Create and attach the special class constructors: ctypes.PointerType,
// ctypes.ArrayType, ctypes.StructType, and ctypes.FunctionType.
@@ -1997,7 +1996,7 @@ JS_SetCTypesCallbacks(JSObject* ctypesObj, const JSCTypesCallbacks* callbacks)
// Set the callbacks on a reserved slot.
JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS,
PRIVATE_TO_JSVAL(const_cast<JSCTypesCallbacks*>(callbacks)));
PrivateValue(const_cast<JSCTypesCallbacks*>(callbacks)));
}
namespace js {
@@ -3916,9 +3915,9 @@ CType::Create(JSContext* cx,
// Set up the reserved slots.
JS_SetReservedSlot(typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type));
if (ffiType)
JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(ffiType));
JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PrivateValue(ffiType));
if (name)
JS_SetReservedSlot(typeObj, SLOT_NAME, STRING_TO_JSVAL(name));
JS_SetReservedSlot(typeObj, SLOT_NAME, StringValue(name));
JS_SetReservedSlot(typeObj, SLOT_SIZE, size);
JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
@@ -3935,7 +3934,7 @@ CType::Create(JSContext* cx,
// Set the 'prototype' object.
//if (!JS_FreezeObject(cx, prototype)) // XXX fixme - see bug 541212!
// return nullptr;
JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
JS_SetReservedSlot(typeObj, SLOT_PROTO, ObjectValue(*prototype));
}
if (!JS_FreezeObject(cx, typeObj))
@@ -4255,7 +4254,7 @@ CType::GetFFIType(JSContext* cx, JSObject* obj)
if (!result)
return nullptr;
JS_SetReservedSlot(obj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(result.get()));
JS_SetReservedSlot(obj, SLOT_FFITYPE, PrivateValue(result.get()));
return result.release();
}
@@ -4272,7 +4271,7 @@ CType::GetName(JSContext* cx, HandleObject obj)
JSString* name = BuildTypeName(cx, obj);
if (!name)
return nullptr;
JS_SetReservedSlot(obj, SLOT_NAME, STRING_TO_JSVAL(name));
JS_SetReservedSlot(obj, SLOT_NAME, StringValue(name));
return name;
}
@@ -4611,10 +4610,10 @@ PointerType::CreateInternal(JSContext* cx, HandleObject baseType)
return nullptr;
// Set the target type. (This will be 'null' for an opaque pointer type.)
JS_SetReservedSlot(typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType));
JS_SetReservedSlot(typeObj, SLOT_TARGET_T, ObjectValue(*baseType));
// Finally, cache our newly-created PointerType on our pointed-to CType.
JS_SetReservedSlot(baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj));
JS_SetReservedSlot(baseType, SLOT_PTR, ObjectValue(*typeObj));
return typeObj;
}
@@ -4936,7 +4935,7 @@ ArrayType::CreateInternal(JSContext* cx,
return nullptr;
// Set the element type.
JS_SetReservedSlot(typeObj, SLOT_ELEMENT_T, OBJECT_TO_JSVAL(baseType));
JS_SetReservedSlot(typeObj, SLOT_ELEMENT_T, ObjectValue(*baseType));
// Set the length.
JS_SetReservedSlot(typeObj, SLOT_LENGTH, lengthVal);
@@ -5596,13 +5595,13 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
if (!SizeTojsval(cx, structSize, &sizeVal))
return false;
JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PRIVATE_TO_JSVAL(fields.release()));
JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PrivateValue(fields.release()));
JS_SetReservedSlot(typeObj, SLOT_SIZE, sizeVal);
JS_SetReservedSlot(typeObj, SLOT_ALIGN, INT_TO_JSVAL(structAlign));
//if (!JS_FreezeObject(cx, prototype)0 // XXX fixme - see bug 541212!
// return false;
JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
JS_SetReservedSlot(typeObj, SLOT_PROTO, ObjectValue(*prototype));
return true;
}
@@ -5882,7 +5881,7 @@ StructType::FieldsArrayGetter(JSContext* cx, const JS::CallArgs& args)
JSObject* fields = BuildFieldsArray(cx, obj);
if (!fields)
return false;
JS_SetReservedSlot(obj, SLOT_FIELDS, OBJECT_TO_JSVAL(fields));
JS_SetReservedSlot(obj, SLOT_FIELDS, ObjectValue(*fields));
args.rval().setObject(*fields);
}
@@ -6167,7 +6166,7 @@ PrepareCIF(JSContext* cx,
FunctionInfo* fninfo)
{
ffi_abi abi;
if (!GetABI(cx, OBJECT_TO_JSVAL(fninfo->mABI), &abi)) {
if (!GetABI(cx, ObjectOrNullValue(fninfo->mABI), &abi)) {
JS_ReportError(cx, "Invalid ABI specification");
return false;
}
@@ -6257,7 +6256,7 @@ CreateFunctionInfo(JSContext* cx,
}
// Stash the FunctionInfo in a reserved slot.
JS_SetReservedSlot(typeObj, SLOT_FNINFO, PRIVATE_TO_JSVAL(fninfo));
JS_SetReservedSlot(typeObj, SLOT_FNINFO, PrivateValue(fninfo));
ffi_abi abi;
if (!GetABI(cx, abiType, &abi)) {
@@ -6432,7 +6431,7 @@ FunctionType::ConstructData(JSContext* cx,
return false;
// Set the closure object as the referent of the new CData object.
JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(closureObj));
JS_SetReservedSlot(dataObj, SLOT_REFERENT, ObjectValue(*closureObj));
// Seal the CData object, to prevent modification of the function pointer.
// This permanently associates this object with the closure, and avoids
@@ -6554,7 +6553,7 @@ FunctionType::Call(JSContext* cx,
return false;
}
if (!(type = CData::GetCType(obj)) ||
!(type = PrepareType(cx, OBJECT_TO_JSVAL(type))) ||
!(type = PrepareType(cx, ObjectValue(*type))) ||
// Relying on ImplicitConvert only for the limited purpose of
// converting one CType to another (e.g., T[] to T*).
!ConvertArgument(cx, obj, i, args[i], type, &values[i], &strings) ||
@@ -6803,7 +6802,7 @@ CClosure::Create(JSContext* cx,
cinfo->jsfnObj = fnObj;
// Stash the ClosureInfo struct on our new object.
JS_SetReservedSlot(result, SLOT_CLOSUREINFO, PRIVATE_TO_JSVAL(cinfo));
JS_SetReservedSlot(result, SLOT_CLOSUREINFO, PrivateValue(cinfo));
// Create an ffi_closure object and initialize it.
void* code;
@@ -7045,14 +7044,14 @@ CData::Create(JSContext* cx,
return nullptr;
// set the CData's associated type
JS_SetReservedSlot(dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj));
JS_SetReservedSlot(dataObj, SLOT_CTYPE, ObjectValue(*typeObj));
// Stash the referent object, if any, for GC safety.
if (refObj)
JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(refObj));
JS_SetReservedSlot(dataObj, SLOT_REFERENT, ObjectValue(*refObj));
// Set our ownership flag.
JS_SetReservedSlot(dataObj, SLOT_OWNS, BOOLEAN_TO_JSVAL(ownResult));
JS_SetReservedSlot(dataObj, SLOT_OWNS, BooleanValue(ownResult));
// attach the buffer. since it might not be 2-byte aligned, we need to
// allocate an aligned space for it and store it there. :(
@@ -7083,7 +7082,7 @@ CData::Create(JSContext* cx,
}
*buffer = data;
JS_SetReservedSlot(dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer));
JS_SetReservedSlot(dataObj, SLOT_DATA, PrivateValue(buffer));
return dataObj;
}
@@ -7743,15 +7742,15 @@ CDataFinalizer::Construct(JSContext* cx, unsigned argc, jsval* vp)
// Used by GetCType
JS_SetReservedSlot(objResult,
SLOT_DATAFINALIZER_VALTYPE,
OBJECT_TO_JSVAL(objBestArgType));
ObjectOrNullValue(objBestArgType));
// Used by ToSource
JS_SetReservedSlot(objResult,
SLOT_DATAFINALIZER_CODETYPE,
OBJECT_TO_JSVAL(objCodePtrType));
ObjectValue(*objCodePtrType));
ffi_abi abi;
if (!GetABI(cx, OBJECT_TO_JSVAL(funInfoFinalizer->mABI), &abi)) {
if (!GetABI(cx, ObjectOrNullValue(funInfoFinalizer->mABI), &abi)) {
JS_ReportError(cx, "Internal Error: "
"Invalid ABI specification in CDataFinalizer");
return false;
@@ -8027,7 +8026,7 @@ Int64Base::Construct(JSContext* cx,
return nullptr;
}
JS_SetReservedSlot(result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer));
JS_SetReservedSlot(result, SLOT_INT64, PrivateValue(buffer));
if (!JS_FreezeObject(cx, result))
return nullptr;
+3 -3
View File
@@ -89,7 +89,7 @@ Library::Create(JSContext* cx, jsval path_, const JSCTypesCallbacks* callbacks)
return nullptr;
// initialize the library
JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(nullptr));
JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(nullptr));
// attach API functions
if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions))
@@ -166,7 +166,7 @@ Library::Create(JSContext* cx, jsval path_, const JSCTypesCallbacks* callbacks)
#endif
// stash the library
JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(library));
JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(library));
return libraryObj;
}
@@ -244,7 +244,7 @@ Library::Close(JSContext* cx, unsigned argc, jsval* vp)
// delete our internal objects
UnloadLibrary(obj);
JS_SetReservedSlot(obj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(nullptr));
JS_SetReservedSlot(obj, SLOT_LIBRARY, PrivateValue(nullptr));
args.rval().setUndefined();
return true;
+21 -20
View File
@@ -4347,7 +4347,6 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
return true;
case PNK_CALLSITEOBJ:
case PNK_ARRAY: {
RootedValue value(cx);
unsigned count;
ParseNode* pn;
@@ -4355,8 +4354,12 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
vp.setMagic(JS_GENERIC_MAGIC);
return true;
}
if (allowObjects == DontAllowNestedObjects)
ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal;
if (allowObjects == ForCopyOnWriteArray) {
arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite;
allowObjects = DontAllowObjects;
}
if (getKind() == PNK_CALLSITEOBJ) {
count = pn_count - 1;
@@ -4367,26 +4370,25 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
pn = pn_head;
}
RootedArrayObject obj(cx, NewDenseFullyAllocatedArray(cx, count, nullptr, newKind));
if (!obj)
AutoValueVector values(cx);
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), count))
return false;
unsigned idx = 0;
RootedId id(cx);
for (; pn; idx++, pn = pn->pn_next) {
if (!pn->getConstantValue(cx, allowObjects, &value))
size_t idx;
for (idx = 0; pn; idx++, pn = pn->pn_next) {
if (!pn->getConstantValue(cx, allowObjects, values[idx]))
return false;
if (value.isMagic(JS_GENERIC_MAGIC)) {
if (values[idx].isMagic(JS_GENERIC_MAGIC)) {
vp.setMagic(JS_GENERIC_MAGIC);
return true;
}
id = INT_TO_JSID(idx);
if (!DefineProperty(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
return false;
}
MOZ_ASSERT(idx == count);
ObjectGroup::fixArrayGroup(cx, obj);
JSObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
newKind, arrayKind);
if (!obj)
return false;
vp.setObject(*obj);
return true;
}
@@ -4398,8 +4400,7 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
vp.setMagic(JS_GENERIC_MAGIC);
return true;
}
if (allowObjects == DontAllowNestedObjects)
allowObjects = DontAllowObjects;
MOZ_ASSERT(allowObjects == AllowObjects);
AutoIdValueVector properties(cx);
@@ -7635,7 +7636,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
// every time the initializer executes.
if (emitterMode != BytecodeEmitter::SelfHosting && pn->pn_count != 0) {
RootedValue value(cx);
if (!pn->getConstantValue(cx, ParseNode::DontAllowNestedObjects, &value))
if (!pn->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value))
return false;
if (!value.isMagic(JS_GENERIC_MAGIC)) {
// Note: the group of the template object might not yet reflect
@@ -7645,9 +7646,9 @@ BytecodeEmitter::emitTree(ParseNode* pn)
// group for the template is accurate. We don't do this here as we
// want to use ObjectGroup::allocationSiteGroup, which requires a
// finished script.
NativeObject* obj = &value.toObject().as<NativeObject>();
if (!ObjectElements::MakeElementsCopyOnWrite(cx, obj))
return false;
JSObject* obj = &value.toObject();
MOZ_ASSERT(obj->is<ArrayObject>() &&
obj->as<ArrayObject>().denseElementsAreCopyOnWrite());
ObjectBox* objbox = parser->newObjectBox(obj);
if (!objbox)
+3 -3
View File
@@ -903,11 +903,11 @@ class ParseNode
enum AllowConstantObjects {
DontAllowObjects = 0,
DontAllowNestedObjects,
AllowObjects
AllowObjects,
ForCopyOnWriteArray
};
bool getConstantValue(ExclusiveContext *cx, AllowConstantObjects allowObjects, MutableHandleValue vp,
bool getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects, MutableHandleValue vp,
NewObjectKind newKind = TenuredObject);
inline bool isConstant();
+7
View File
@@ -50,6 +50,13 @@ js::CurrentThreadIsGCSweeping()
return js::TlsPerThreadData.get()->gcSweeping;
}
bool
js::CurrentThreadIsHandlingInitFailure()
{
JSRuntime* rt = js::TlsPerThreadData.get()->runtimeIfOnOwnerThread();
return rt && rt->handlingInitFailure;
}
#endif // DEBUG
template <typename S>
+7 -34
View File
@@ -104,7 +104,7 @@
* reference them. The solution is to maintain information about these pointers,
* and mark their targets when we start a minor collection.
*
* The pointers can be thoughs of as edges in object graph, and the set of edges
* The pointers can be thought of as edges in object graph, and the set of edges
* from the tenured generation into the nursery is know as the remembered set.
* Post barriers are used to track this remembered set.
*
@@ -195,42 +195,13 @@ CurrentThreadIsIonCompiling();
bool
CurrentThreadIsGCSweeping();
bool
CurrentThreadIsHandlingInitFailure();
#endif
namespace gc {
template <typename T> struct MapTypeToTraceKind {};
template <> struct MapTypeToTraceKind<NativeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArgumentsObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferObjectMaybeShared>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<BaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<GlobalObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JS::Symbol> { static const JSGCTraceKind kind = JSTRACE_SYMBOL; };
template <> struct MapTypeToTraceKind<JSAtom> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSFlatString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSFunction> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSLinearString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<JSObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<JSScript> { static const JSGCTraceKind kind = JSTRACE_SCRIPT; };
template <> struct MapTypeToTraceKind<JSString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<LazyScript> { static const JSGCTraceKind kind = JSTRACE_LAZY_SCRIPT; };
template <> struct MapTypeToTraceKind<NestedScopeObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<PlainObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<PropertyName> { static const JSGCTraceKind kind = JSTRACE_STRING; };
template <> struct MapTypeToTraceKind<SavedFrame> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<ScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<Shape> { static const JSGCTraceKind kind = JSTRACE_SHAPE; };
template <> struct MapTypeToTraceKind<AccessorShape> { static const JSGCTraceKind kind = JSTRACE_SHAPE; };
template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<SharedTypedArrayObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
template <> struct MapTypeToTraceKind<jit::JitCode> { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
template <> struct MapTypeToTraceKind<ObjectGroup> { static const JSGCTraceKind kind = JSTRACE_OBJECT_GROUP; };
// Marking.h depends on these barrier definitions, so we need a separate
// entry point for marking to implement the pre-barrier.
void MarkValueForBarrier(JSTracer* trc, Value* v, const char* name);
@@ -423,7 +394,9 @@ class HeapPtr : public BarrieredBase<T>
explicit HeapPtr(const HeapPtr<T>& v) : BarrieredBase<T>(v) { post(); }
#ifdef DEBUG
~HeapPtr() {
MOZ_ASSERT(CurrentThreadIsGCSweeping());
// No prebarrier necessary as this only happens when we are sweeping or
// before the containing obect becomes part of the GC graph.
MOZ_ASSERT(CurrentThreadIsGCSweeping() || CurrentThreadIsHandlingInitFailure());
}
#endif
+1 -1
View File
@@ -141,7 +141,7 @@ CheckHashTablesAfterMovingGC(JSRuntime* rt);
struct MovingTracer : JS::CallbackTracer {
explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, Visit, TraceWeakMapKeysValues) {}
static void Visit(JS::CallbackTracer* jstrc, void** thingp, JSGCTraceKind kind);
static void Visit(JS::CallbackTracer* jstrc, void** thingp, JS::TraceKind kind);
static bool IsMovingTracer(JSTracer* trc) {
return trc->isCallbackTracer() && trc->asCallbackTracer()->hasCallback(Visit);
}
+37 -34
View File
@@ -51,7 +51,7 @@ CurrentThreadIsIonCompiling();
#endif
extern bool
UnmarkGrayCellRecursively(gc::Cell* cell, JSGCTraceKind kind);
UnmarkGrayCellRecursively(gc::Cell* cell, JS::TraceKind kind);
extern void
TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, const char* name);
@@ -167,35 +167,35 @@ template<typename ValueType> using AllAllocKindArray =
template<typename ValueType> using ObjectAllocKindArray =
mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;
static inline JSGCTraceKind
static inline JS::TraceKind
MapAllocToTraceKind(AllocKind kind)
{
static const JSGCTraceKind map[] = {
JSTRACE_OBJECT, /* AllocKind::FUNCTION */
JSTRACE_OBJECT, /* AllocKind::FUNCTION_EXTENDED */
JSTRACE_OBJECT, /* AllocKind::OBJECT0 */
JSTRACE_OBJECT, /* AllocKind::OBJECT0_BACKGROUND */
JSTRACE_OBJECT, /* AllocKind::OBJECT2 */
JSTRACE_OBJECT, /* AllocKind::OBJECT2_BACKGROUND */
JSTRACE_OBJECT, /* AllocKind::OBJECT4 */
JSTRACE_OBJECT, /* AllocKind::OBJECT4_BACKGROUND */
JSTRACE_OBJECT, /* AllocKind::OBJECT8 */
JSTRACE_OBJECT, /* AllocKind::OBJECT8_BACKGROUND */
JSTRACE_OBJECT, /* AllocKind::OBJECT12 */
JSTRACE_OBJECT, /* AllocKind::OBJECT12_BACKGROUND */
JSTRACE_OBJECT, /* AllocKind::OBJECT16 */
JSTRACE_OBJECT, /* AllocKind::OBJECT16_BACKGROUND */
JSTRACE_SCRIPT, /* AllocKind::SCRIPT */
JSTRACE_LAZY_SCRIPT, /* AllocKind::LAZY_SCRIPT */
JSTRACE_SHAPE, /* AllocKind::SHAPE */
JSTRACE_SHAPE, /* AllocKind::ACCESSOR_SHAPE */
JSTRACE_BASE_SHAPE, /* AllocKind::BASE_SHAPE */
JSTRACE_OBJECT_GROUP, /* AllocKind::OBJECT_GROUP */
JSTRACE_STRING, /* AllocKind::FAT_INLINE_STRING */
JSTRACE_STRING, /* AllocKind::STRING */
JSTRACE_STRING, /* AllocKind::EXTERNAL_STRING */
JSTRACE_SYMBOL, /* AllocKind::SYMBOL */
JSTRACE_JITCODE, /* AllocKind::JITCODE */
static const JS::TraceKind map[] = {
JS::TraceKind::Object, /* AllocKind::FUNCTION */
JS::TraceKind::Object, /* AllocKind::FUNCTION_EXTENDED */
JS::TraceKind::Object, /* AllocKind::OBJECT0 */
JS::TraceKind::Object, /* AllocKind::OBJECT0_BACKGROUND */
JS::TraceKind::Object, /* AllocKind::OBJECT2 */
JS::TraceKind::Object, /* AllocKind::OBJECT2_BACKGROUND */
JS::TraceKind::Object, /* AllocKind::OBJECT4 */
JS::TraceKind::Object, /* AllocKind::OBJECT4_BACKGROUND */
JS::TraceKind::Object, /* AllocKind::OBJECT8 */
JS::TraceKind::Object, /* AllocKind::OBJECT8_BACKGROUND */
JS::TraceKind::Object, /* AllocKind::OBJECT12 */
JS::TraceKind::Object, /* AllocKind::OBJECT12_BACKGROUND */
JS::TraceKind::Object, /* AllocKind::OBJECT16 */
JS::TraceKind::Object, /* AllocKind::OBJECT16_BACKGROUND */
JS::TraceKind::Script, /* AllocKind::SCRIPT */
JS::TraceKind::LazyScript, /* AllocKind::LAZY_SCRIPT */
JS::TraceKind::Shape, /* AllocKind::SHAPE */
JS::TraceKind::Shape, /* AllocKind::ACCESSOR_SHAPE */
JS::TraceKind::BaseShape, /* AllocKind::BASE_SHAPE */
JS::TraceKind::ObjectGroup, /* AllocKind::OBJECT_GROUP */
JS::TraceKind::String, /* AllocKind::FAT_INLINE_STRING */
JS::TraceKind::String, /* AllocKind::STRING */
JS::TraceKind::String, /* AllocKind::EXTERNAL_STRING */
JS::TraceKind::Symbol, /* AllocKind::SYMBOL */
JS::TraceKind::JitCode, /* AllocKind::JITCODE */
};
static_assert(MOZ_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT),
@@ -228,9 +228,12 @@ struct Cell
inline JSRuntime* runtimeFromAnyThread() const;
inline JS::shadow::Runtime* shadowRuntimeFromAnyThread() const;
// May be overridden by GC thing kinds that have a compartment pointer.
inline JSCompartment* maybeCompartment() const { return nullptr; }
inline StoreBuffer* storeBuffer() const;
inline JSGCTraceKind getTraceKind() const;
inline JS::TraceKind getTraceKind() const;
static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
@@ -265,7 +268,7 @@ class TenuredCell : public Cell
// Access to the arena header.
inline ArenaHeader* arenaHeader() const;
inline AllocKind getAllocKind() const;
inline JSGCTraceKind getTraceKind() const;
inline JS::TraceKind getTraceKind() const;
inline JS::Zone* zone() const;
inline JS::Zone* zoneFromAnyThread() const;
inline bool isInsideZone(JS::Zone* zone) const;
@@ -1311,10 +1314,10 @@ Cell::storeBuffer() const
return chunk()->info.trailer.storeBuffer;
}
inline JSGCTraceKind
inline JS::TraceKind
Cell::getTraceKind() const
{
return isTenured() ? asTenured().getTraceKind() : JSTRACE_OBJECT;
return isTenured() ? asTenured().getTraceKind() : JS::TraceKind::Object;
}
inline bool
@@ -1396,7 +1399,7 @@ TenuredCell::getAllocKind() const
return arenaHeader()->getAllocKind();
}
JSGCTraceKind
JS::TraceKind
TenuredCell::getTraceKind() const
{
return MapAllocToTraceKind(getAllocKind());
@@ -1458,7 +1461,7 @@ static MOZ_ALWAYS_INLINE void
AssertValidToSkipBarrier(TenuredCell* thing)
{
MOZ_ASSERT(!IsInsideNursery(thing));
MOZ_ASSERT_IF(thing, MapAllocToTraceKind(thing->getAllocKind()) != JSTRACE_OBJECT);
MOZ_ASSERT_IF(thing, MapAllocToTraceKind(thing->getAllocKind()) != JS::TraceKind::Object);
}
/* static */ MOZ_ALWAYS_INLINE void
+1 -1
View File
@@ -39,7 +39,7 @@ IterateCompartmentsArenasCells(JSRuntime* rt, Zone* zone, void* data,
(*compartmentCallback)(rt, data, comp);
for (auto thingKind : AllAllocKinds()) {
JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind);
JS::TraceKind traceKind = MapAllocToTraceKind(thingKind);
size_t thingSize = Arena::thingSize(thingKind);
for (ArenaIter aiter(zone, thingKind); !aiter.done(); aiter.next()) {
+41 -179
View File
@@ -30,6 +30,7 @@
#include "gc/Nursery-inl.h"
#include "vm/String-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;
using namespace js::gc;
@@ -203,7 +204,7 @@ js::CheckTracedThing(JSTracer* trc, T thing)
MOZ_ASSERT(thing->isAligned());
MOZ_ASSERT(MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind ==
GetGCThingTraceKind(thing));
thing->getTraceKind());
/*
* Do not check IsMarkingTracer directly -- it should only be used in paths
@@ -348,14 +349,8 @@ AssertRootMarkingPhase(JSTracer* trc)
/*** Tracing Interface ***************************************************************************/
// A C++ version of JSGCTraceKind
enum class TraceKind {
#define NAMES(name, _, __) name,
FOR_EACH_GC_LAYOUT(NAMES)
#undef NAMES
};
#define FOR_EACH_GC_POINTER_TYPE(D) \
D(AccessorShape*) \
D(BaseShape*) \
D(UnownedBaseShape*) \
D(jit::JitCode*) \
@@ -402,18 +397,18 @@ FOR_EACH_GC_LAYOUT(NAMES)
// BaseGCType<UnownedBaseShape>::type => BaseShape
// etc.
template <typename T,
TraceKind = IsBaseOf<JSObject, T>::value ? TraceKind::Object
: IsBaseOf<JSString, T>::value ? TraceKind::String
: IsBaseOf<JS::Symbol, T>::value ? TraceKind::Symbol
: IsBaseOf<JSScript, T>::value ? TraceKind::Script
: IsBaseOf<Shape, T>::value ? TraceKind::Shape
: IsBaseOf<BaseShape, T>::value ? TraceKind::BaseShape
: IsBaseOf<jit::JitCode, T>::value ? TraceKind::JitCode
: IsBaseOf<LazyScript, T>::value ? TraceKind::LazyScript
: TraceKind::ObjectGroup>
JS::TraceKind = IsBaseOf<JSObject, T>::value ? JS::TraceKind::Object
: IsBaseOf<JSString, T>::value ? JS::TraceKind::String
: IsBaseOf<JS::Symbol, T>::value ? JS::TraceKind::Symbol
: IsBaseOf<JSScript, T>::value ? JS::TraceKind::Script
: IsBaseOf<Shape, T>::value ? JS::TraceKind::Shape
: IsBaseOf<BaseShape, T>::value ? JS::TraceKind::BaseShape
: IsBaseOf<jit::JitCode, T>::value ? JS::TraceKind::JitCode
: IsBaseOf<LazyScript, T>::value ? JS::TraceKind::LazyScript
: JS::TraceKind::ObjectGroup>
struct BaseGCType;
#define IMPL_BASE_GC_TYPE(name, type_, _) \
template <typename T> struct BaseGCType<T, TraceKind:: name> { typedef type_ type; };
template <typename T> struct BaseGCType<T, JS::TraceKind:: name> { typedef type_ type; };
FOR_EACH_GC_LAYOUT(IMPL_BASE_GC_TYPE);
#undef IMPL_BASE_GC_TYPE
@@ -530,7 +525,7 @@ js::TraceProcessGlobalRoot(JSTracer* trc, T* thing, const char* name)
// things so they do not need to go through the mark stack and may simply
// be marked directly. Moreover, well-known symbols can refer only to
// permanent atoms, so likewise require no subsquent marking.
CheckTracedThing(trc, thing);
CheckTracedThing(trc, *ConvertToBase(&thing));
if (trc->isMarkingTracer())
thing->markIfUnmarked(gc::BLACK);
else
@@ -539,18 +534,6 @@ js::TraceProcessGlobalRoot(JSTracer* trc, T* thing, const char* name)
template void js::TraceProcessGlobalRoot<JSAtom>(JSTracer*, JSAtom*, const char*);
template void js::TraceProcessGlobalRoot<JS::Symbol>(JSTracer*, JS::Symbol*, const char*);
void
js::TraceObjectSlots(JSTracer* trc, NativeObject* obj, uint32_t start, uint32_t nslots)
{
JS::AutoTracingIndex index(trc, start);
for (uint32_t i = start; i < (start + nslots); ++i) {
HeapSlot& slot = obj->getSlotRef(i);
if (InternalGCMethods<Value>::isMarkable(slot))
DispatchToTracer(trc, slot.unsafeGet(), "object slot");
++index;
}
}
// A typed functor adaptor for TraceRoot.
struct TraceRootFunctor {
template <typename T>
@@ -760,21 +743,23 @@ template <typename S, typename T>
void
js::GCMarker::traverseEdge(S source, T target)
{
// Atoms and Symbols do not have or mark their internal pointers, respectively.
MOZ_ASSERT(!ThingIsPermanentAtomOrWellKnownSymbol(source));
// The Zones must match, unless the target is an atom.
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(target),
target->zone()->isAtomsZone() || target->zone() == source->zone());
traverse(target);
}
namespace js {
// Special-case JSObject->JSObject edges to check the compartment too.
template <>
void
GCMarker::traverseEdge(JSObject* source, JSObject* target)
{
MOZ_ASSERT(target->compartment() == source->compartment());
// Atoms and Symbols do not have access to a compartment pointer, or we'd need
// to adjust the subsequent check to catch that case.
MOZ_ASSERT_IF(ThingIsPermanentAtomOrWellKnownSymbol(target), !target->maybeCompartment());
MOZ_ASSERT_IF(target->zoneFromAnyThread()->isAtomsZone(), !target->maybeCompartment());
// If we have access to a compartment pointer for both things, they must match.
MOZ_ASSERT_IF(source->maybeCompartment() && target->maybeCompartment(),
source->maybeCompartment() == target->maybeCompartment());
traverse(target);
}
} // namespace js
template <typename V, typename S> struct TraverseEdgeFunctor : public VoidDefaultAdaptor<V> {
template <typename T> void operator()(T t, GCMarker* gcmarker, S s) {
@@ -951,9 +936,9 @@ js::GCMarker::eagerlyMarkChildren(JSRope* rope)
// other ropes or linear strings, it cannot refer to GC things of other
// types.
ptrdiff_t savedPos = stack.position();
JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
JS_DIAGNOSTICS_ASSERT(rope->getTraceKind() == JS::TraceKind::String);
while (true) {
JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
JS_DIAGNOSTICS_ASSERT(rope->getTraceKind() == JS::TraceKind::String);
JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope());
AssertZoneIsMarking(rope);
MOZ_ASSERT(rope->isMarked());
@@ -1817,8 +1802,8 @@ void
js::gc::StoreBuffer::WholeCellEdges::trace(TenuringTracer& mover) const
{
MOZ_ASSERT(edge->isTenured());
JSGCTraceKind kind = GetGCThingTraceKind(edge);
if (kind <= JSTRACE_OBJECT) {
JS::TraceKind kind = edge->getTraceKind();
if (kind == JS::TraceKind::Object) {
JSObject *object = static_cast<JSObject*>(edge);
mover.traceObject(object);
@@ -1835,7 +1820,7 @@ js::gc::StoreBuffer::WholeCellEdges::trace(TenuringTracer& mover) const
return;
}
MOZ_ASSERT(kind == JSTRACE_JITCODE);
MOZ_ASSERT(kind == JS::TraceKind::JitCode);
static_cast<jit::JitCode*>(edge)->traceChildren(&mover);
}
@@ -1845,7 +1830,7 @@ js::gc::StoreBuffer::CellPtrEdge::trace(TenuringTracer& mover) const
if (!*edge)
return;
MOZ_ASSERT(GetGCThingTraceKind(*edge) == JSTRACE_OBJECT);
MOZ_ASSERT((*edge)->getTraceKind() == JS::TraceKind::Object);
mover.traverse(reinterpret_cast<JSObject**>(edge));
}
@@ -2288,135 +2273,12 @@ TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name)
}
}
/*** Cycle Collector Helpers **********************************************************************/
// This function is used by the cycle collector to trace through a shape. The
// cycle collector does not care about shapes or base shapes, so those are not
// marked. Instead, any shapes or base shapes that are encountered have their
// children marked. Stack space is bounded.
//
// Note: The canonical way for an embedding to implement this functionality
// would be through a custom CallbackTracer that ignores unrequired children
// and pushes to a separate mark stack in order to bound the call stack usage.
// We've implemented like this purely for performance.
void
gc::MarkCycleCollectorChildren(JSTracer* trc, Shape* shape)
{
// We need to mark the global, but it's OK to only do this once instead of
// doing it for every Shape in our lineage, since it's always the same
// global.
JSObject* global = shape->compartment()->unsafeUnbarrieredMaybeGlobal();
MOZ_ASSERT(global);
TraceManuallyBarrieredEdge(trc, &global, "global");
do {
MOZ_ASSERT(global == shape->compartment()->unsafeUnbarrieredMaybeGlobal());
MOZ_ASSERT(shape->base());
shape->base()->assertConsistency();
TraceEdge(trc, &shape->propidRef(), "propid");
if (shape->hasGetterObject()) {
JSObject* tmp = shape->getterObject();
TraceManuallyBarrieredEdge(trc, &tmp, "getter");
MOZ_ASSERT(tmp == shape->getterObject());
}
if (shape->hasSetterObject()) {
JSObject* tmp = shape->setterObject();
TraceManuallyBarrieredEdge(trc, &tmp, "setter");
MOZ_ASSERT(tmp == shape->setterObject());
}
shape = shape->previous();
} while (shape);
}
void
TraceObjectGroupCycleCollectorChildrenCallback(JS::CallbackTracer* trc,
void** thingp, JSGCTraceKind kind);
// Object groups can point to other object groups via an UnboxedLayout or the
// the original unboxed group link. There can potentially be deep or cyclic
// chains of such groups to trace through without going through a thing that
// participates in cycle collection. These need to be handled iteratively to
// avoid blowing the stack when running the cycle collector's callback tracer.
struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
{
explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer)
: JS::CallbackTracer(innerTracer->runtime(),
TraceObjectGroupCycleCollectorChildrenCallback,
DoNotTraceWeakMaps),
innerTracer(innerTracer)
{}
JS::CallbackTracer* innerTracer;
Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
};
void
TraceObjectGroupCycleCollectorChildrenCallback(JS::CallbackTracer* trcArg,
void** thingp, JSGCTraceKind kind)
{
ObjectGroupCycleCollectorTracer* trc = static_cast<ObjectGroupCycleCollectorTracer*>(trcArg);
JS::GCCellPtr thing(*thingp, kind);
if (thing.isObject() || thing.isScript()) {
// Invoke the inner cycle collector callback on this child. It will not
// recurse back into TraceChildren.
trc->innerTracer->invoke(thingp, kind);
return;
}
if (thing.isObjectGroup()) {
// If this group is required to be in an ObjectGroup chain, trace it
// via the provided worklist rather than continuing to recurse.
ObjectGroup* group = static_cast<ObjectGroup*>(thing.asCell());
if (group->maybeUnboxedLayout()) {
for (size_t i = 0; i < trc->seen.length(); i++) {
if (trc->seen[i] == group)
return;
}
if (trc->seen.append(group) && trc->worklist.append(group)) {
return;
} else {
// If append fails, keep tracing normally. The worst that will
// happen is we end up overrecursing.
}
}
}
TraceChildren(trc, thing.asCell(), thing.kind());
}
void
gc::MarkCycleCollectorChildren(JSTracer* trc, ObjectGroup* group)
{
MOZ_ASSERT(trc->isCallbackTracer());
// Early return if this group is not required to be in an ObjectGroup chain.
if (!group->maybeUnboxedLayout()) {
TraceChildren(trc, group, JSTRACE_OBJECT_GROUP);
return;
}
ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer());
TraceChildren(&groupTracer, group, JSTRACE_OBJECT_GROUP);
while (!groupTracer.worklist.empty()) {
ObjectGroup* innerGroup = groupTracer.worklist.popCopy();
TraceChildren(&groupTracer, innerGroup, JSTRACE_OBJECT_GROUP);
}
}
/*** Cycle Collector Barrier Implementation *******************************************************/
#ifdef DEBUG
static void
AssertNonGrayGCThing(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
AssertNonGrayGCThing(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind)
{
DebugOnly<Cell*> thing(static_cast<Cell*>(*thingp));
MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY));
@@ -2424,7 +2286,7 @@ AssertNonGrayGCThing(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
#endif
static void
UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind);
UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind);
struct UnmarkGrayTracer : public JS::CallbackTracer
{
@@ -2487,7 +2349,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
* containers.
*/
static void
UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind)
{
int stackDummy;
if (!JS_CHECK_STACK_SIZE(trc->runtime()->mainThread.nativeStackLimit[StackForSystemCode],
@@ -2526,16 +2388,16 @@ UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
// The parent will later trace |tenured|. This is done to avoid increasing
// the stack depth during shape tracing. It is safe to do because a shape
// can only have one child that is a shape.
UnmarkGrayTracer childTracer(tracer, kind == JSTRACE_SHAPE);
UnmarkGrayTracer childTracer(tracer, kind == JS::TraceKind::Shape);
if (kind != JSTRACE_SHAPE) {
if (kind != JS::TraceKind::Shape) {
TraceChildren(&childTracer, &tenured, kind);
MOZ_ASSERT(!childTracer.previousShape);
tracer->unmarkedAny |= childTracer.unmarkedAny;
return;
}
MOZ_ASSERT(kind == JSTRACE_SHAPE);
MOZ_ASSERT(kind == JS::TraceKind::Shape);
Shape* shape = static_cast<Shape*>(&tenured);
if (tracer->tracingShape) {
MOZ_ASSERT(!tracer->previousShape);
@@ -2545,7 +2407,7 @@ UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
do {
MOZ_ASSERT(!shape->isMarked(js::gc::GRAY));
TraceChildren(&childTracer, shape, JSTRACE_SHAPE);
TraceChildren(&childTracer, shape, JS::TraceKind::Shape);
shape = childTracer.previousShape;
childTracer.previousShape = nullptr;
} while (shape);
@@ -2553,7 +2415,7 @@ UnmarkGrayChildren(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind)
}
bool
js::UnmarkGrayCellRecursively(gc::Cell* cell, JSGCTraceKind kind)
js::UnmarkGrayCellRecursively(gc::Cell* cell, JS::TraceKind kind)
{
MOZ_ASSERT(cell);
@@ -2582,7 +2444,7 @@ js::UnmarkGrayCellRecursively(gc::Cell* cell, JSGCTraceKind kind)
bool
js::UnmarkGrayShapeRecursively(Shape* shape)
{
return js::UnmarkGrayCellRecursively(shape, JSTRACE_SHAPE);
return js::UnmarkGrayCellRecursively(shape, JS::TraceKind::Shape);
}
JS_FRIEND_API(bool)
-9
View File
@@ -307,15 +307,6 @@ namespace gc {
/*** Special Cases ***/
/*
* Trace through a shape or group iteratively during cycle collection to avoid
* deep or infinite recursion.
*/
void
MarkCycleCollectorChildren(JSTracer* trc, Shape* shape);
void
MarkCycleCollectorChildren(JSTracer* trc, ObjectGroup* group);
void
PushArena(GCMarker* gcmarker, ArenaHeader* aheader);
+3 -3
View File
@@ -553,14 +553,14 @@ class BufferGrayRootsTracer : public JS::CallbackTracer
// Set to false if we OOM while buffering gray roots.
bool bufferingGrayRootsFailed;
void appendGrayRoot(gc::TenuredCell* thing, JSGCTraceKind kind);
void appendGrayRoot(gc::TenuredCell* thing, JS::TraceKind kind);
public:
explicit BufferGrayRootsTracer(JSRuntime* rt)
: JS::CallbackTracer(rt, grayTraceCallback), bufferingGrayRootsFailed(false)
{}
static void grayTraceCallback(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind) {
static void grayTraceCallback(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind) {
auto tracer = static_cast<BufferGrayRootsTracer*>(trc);
tracer->appendGrayRoot(gc::TenuredCell::fromPointer(*thingp), kind);
}
@@ -596,7 +596,7 @@ struct SetMaybeAliveFunctor {
};
void
BufferGrayRootsTracer::appendGrayRoot(TenuredCell* thing, JSGCTraceKind kind)
BufferGrayRootsTracer::appendGrayRoot(TenuredCell* thing, JS::TraceKind kind)
{
MOZ_ASSERT(runtime()->isHeapBusy());
+143 -17
View File
@@ -26,6 +26,8 @@
#include "jsgcinlines.h"
#include "vm/ObjectGroup-inl.h"
using namespace js;
using namespace js::gc;
using mozilla::DebugOnly;
@@ -44,7 +46,7 @@ T
DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name)
{
CheckTracedThing(trc, *thingp);
JSGCTraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
JS::TraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
JS::AutoTracingName ctx(trc, name);
trc->invoke((void**)thingp, kind);
return *thingp;
@@ -174,7 +176,7 @@ JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, cons
}
JS_PUBLIC_API(void)
JS_TraceChildren(JSTracer* trc, void* thing, JSGCTraceKind kind)
JS_TraceChildren(JSTracer* trc, void* thing, JS::TraceKind kind)
{
js::TraceChildren(trc, thing, kind);
}
@@ -187,7 +189,7 @@ struct TraceChildrenFunctor {
};
void
js::TraceChildren(JSTracer* trc, void* thing, JSGCTraceKind kind)
js::TraceChildren(JSTracer* trc, void* thing, JS::TraceKind kind)
{
MOZ_ASSERT(thing);
TraceChildrenFunctor f;
@@ -248,6 +250,130 @@ JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones)
}
}
/*** Cycle Collector Helpers **********************************************************************/
// This function is used by the Cycle Collector (CC) to trace through -- or in
// CC parlance, traverse -- a Shape tree. The CC does not care about Shapes or
// BaseShapes, only the JSObjects held live by them. Thus, we walk the Shape
// lineage, but only report non-Shape things. This effectively makes the entire
// shape lineage into a single node in the CC, saving tremendous amounts of
// space and time in its algorithms.
//
// The algorithm implemented here uses only bounded stack space. This would be
// possible to implement outside the engine, but would require much extra
// infrastructure and many, many more slow GOT lookups. We have implemented it
// inside SpiderMonkey, despite the lack of general applicability, for the
// simplicity and performance of FireFox's embedding of this engine.
void
gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape)
{
// We need to mark the global, but it's OK to only do this once instead of
// doing it for every Shape in our lineage, since it's always the same
// global.
JSObject* global = shape->compartment()->unsafeUnbarrieredMaybeGlobal();
MOZ_ASSERT(global);
DoCallback(trc, &global, "global");
do {
MOZ_ASSERT(global == shape->compartment()->unsafeUnbarrieredMaybeGlobal());
MOZ_ASSERT(shape->base());
shape->base()->assertConsistency();
TraceEdge(trc, &shape->propidRef(), "propid");
if (shape->hasGetterObject()) {
JSObject* tmp = shape->getterObject();
DoCallback(trc, &tmp, "getter");
MOZ_ASSERT(tmp == shape->getterObject());
}
if (shape->hasSetterObject()) {
JSObject* tmp = shape->setterObject();
DoCallback(trc, &tmp, "setter");
MOZ_ASSERT(tmp == shape->setterObject());
}
shape = shape->previous();
} while (shape);
}
void
TraceObjectGroupCycleCollectorChildrenCallback(JS::CallbackTracer* trc,
void** thingp, JS::TraceKind kind);
// Object groups can point to other object groups via an UnboxedLayout or the
// the original unboxed group link. There can potentially be deep or cyclic
// chains of such groups to trace through without going through a thing that
// participates in cycle collection. These need to be handled iteratively to
// avoid blowing the stack when running the cycle collector's callback tracer.
struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
{
explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer)
: JS::CallbackTracer(innerTracer->runtime(),
TraceObjectGroupCycleCollectorChildrenCallback,
DoNotTraceWeakMaps),
innerTracer(innerTracer)
{}
JS::CallbackTracer* innerTracer;
Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
};
void
TraceObjectGroupCycleCollectorChildrenCallback(JS::CallbackTracer* trcArg,
void** thingp, JS::TraceKind kind)
{
ObjectGroupCycleCollectorTracer* trc = static_cast<ObjectGroupCycleCollectorTracer*>(trcArg);
JS::GCCellPtr thing(*thingp, kind);
if (thing.isObject() || thing.isScript()) {
// Invoke the inner cycle collector callback on this child. It will not
// recurse back into TraceChildren.
trc->innerTracer->invoke(thingp, kind);
return;
}
if (thing.isObjectGroup()) {
// If this group is required to be in an ObjectGroup chain, trace it
// via the provided worklist rather than continuing to recurse.
ObjectGroup* group = static_cast<ObjectGroup*>(thing.asCell());
if (group->maybeUnboxedLayout()) {
for (size_t i = 0; i < trc->seen.length(); i++) {
if (trc->seen[i] == group)
return;
}
if (trc->seen.append(group) && trc->worklist.append(group)) {
return;
} else {
// If append fails, keep tracing normally. The worst that will
// happen is we end up overrecursing.
}
}
}
TraceChildren(trc, thing.asCell(), thing.kind());
}
void
gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group)
{
MOZ_ASSERT(trc->isCallbackTracer());
// Early return if this group is not required to be in an ObjectGroup chain.
if (!group->maybeUnboxedLayout())
return group->traceChildren(trc);
ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer());
group->traceChildren(&groupTracer);
while (!groupTracer.worklist.empty()) {
ObjectGroup* innerGroup = groupTracer.worklist.popCopy();
innerGroup->traceChildren(&groupTracer);
}
}
/*** Traced Edge Printer *************************************************************************/
@@ -265,7 +391,7 @@ CountDecimalDigits(size_t num)
JS_PUBLIC_API(void)
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
JSGCTraceKind kind, bool details)
JS::TraceKind kind, bool details)
{
const char* name = nullptr; /* silence uninitialized warning */
size_t n;
@@ -274,43 +400,43 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
return;
switch (kind) {
case JSTRACE_OBJECT:
case JS::TraceKind::Object:
{
name = static_cast<JSObject*>(thing)->getClass()->name;
break;
}
case JSTRACE_SCRIPT:
case JS::TraceKind::Script:
name = "script";
break;
case JSTRACE_STRING:
case JS::TraceKind::String:
name = ((JSString*)thing)->isDependent()
? "substring"
: "string";
break;
case JSTRACE_SYMBOL:
case JS::TraceKind::Symbol:
name = "symbol";
break;
case JSTRACE_BASE_SHAPE:
case JS::TraceKind::BaseShape:
name = "base_shape";
break;
case JSTRACE_JITCODE:
case JS::TraceKind::JitCode:
name = "jitcode";
break;
case JSTRACE_LAZY_SCRIPT:
case JS::TraceKind::LazyScript:
name = "lazyscript";
break;
case JSTRACE_SHAPE:
case JS::TraceKind::Shape:
name = "shape";
break;
case JSTRACE_OBJECT_GROUP:
case JS::TraceKind::ObjectGroup:
name = "object_group";
break;
@@ -329,7 +455,7 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
if (details && bufsize > 2) {
switch (kind) {
case JSTRACE_OBJECT:
case JS::TraceKind::Object:
{
JSObject* obj = (JSObject*)thing;
if (obj->is<JSFunction>()) {
@@ -347,14 +473,14 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
break;
}
case JSTRACE_SCRIPT:
case JS::TraceKind::Script:
{
JSScript* script = static_cast<JSScript*>(thing);
JS_snprintf(buf, bufsize, " %s:%" PRIuSIZE, script->filename(), script->lineno());
break;
}
case JSTRACE_STRING:
case JS::TraceKind::String:
{
*buf++ = ' ';
bufsize--;
@@ -377,7 +503,7 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
break;
}
case JSTRACE_SYMBOL:
case JS::TraceKind::Symbol:
{
JS::Symbol* sym = static_cast<JS::Symbol*>(thing);
if (JSString* desc = sym->description()) {
+12 -6
View File
@@ -109,14 +109,20 @@ TraceGenericPointerRoot(JSTracer* trc, gc::Cell** thingp, const char* name);
void
TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, const char* name);
// Object slots are not stored as a contiguous vector, so marking them as such
// will lead to the wrong indicies, if such are requested when tracing.
void
TraceObjectSlots(JSTracer* trc, NativeObject* obj, uint32_t start, uint32_t nslots);
// Depricated. Please use one of the strongly typed variants above.
void
TraceChildren(JSTracer* trc, void* thing, JSGCTraceKind kind);
TraceChildren(JSTracer* trc, void* thing, JS::TraceKind kind);
namespace gc {
// Trace through a shape or group iteratively during cycle collection to avoid
// deep or infinite recursion.
void
TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape);
void
TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group);
} // namespace gc
} // namespace js
+31 -26
View File
@@ -50,20 +50,23 @@ using namespace js::gc;
struct EdgeValue
{
void* thing;
JSGCTraceKind kind;
JS::TraceKind kind;
const char* label;
};
struct VerifyNode
{
void* thing;
JSGCTraceKind kind;
JS::TraceKind kind;
uint32_t count;
EdgeValue edges[1];
};
typedef HashMap<void*, VerifyNode*, DefaultHasher<void*>, SystemAllocPolicy> NodeMap;
static void
AccumulateEdge(JS::CallbackTracer* jstrc, void** thingp, JS::TraceKind kind);
/*
* The verifier data structures are simple. The entire graph is stored in a
* single block of memory. At the beginning is a VerifyNode for the root
@@ -94,8 +97,8 @@ struct VerifyPreTracer : JS::CallbackTracer
char* term;
NodeMap nodemap;
VerifyPreTracer(JSRuntime* rt, JSTraceCallback callback)
: JS::CallbackTracer(rt, callback), noggc(rt), number(rt->gc.gcNumber()), count(0),
explicit VerifyPreTracer(JSRuntime* rt)
: JS::CallbackTracer(rt, AccumulateEdge), noggc(rt), number(rt->gc.gcNumber()), count(0),
root(nullptr)
{}
@@ -109,9 +112,9 @@ struct VerifyPreTracer : JS::CallbackTracer
* node.
*/
static void
AccumulateEdge(JS::CallbackTracer* jstrc, void** thingp, JSGCTraceKind kind)
AccumulateEdge(JS::CallbackTracer* jstrc, void** thingp, JS::TraceKind kind)
{
VerifyPreTracer* trc = (VerifyPreTracer*)jstrc;
VerifyPreTracer* trc = static_cast<VerifyPreTracer*>(jstrc);
MOZ_ASSERT(!IsInsideNursery(*reinterpret_cast<Cell**>(thingp)));
@@ -131,7 +134,7 @@ AccumulateEdge(JS::CallbackTracer* jstrc, void** thingp, JSGCTraceKind kind)
}
static VerifyNode*
MakeNode(VerifyPreTracer* trc, void* thing, JSGCTraceKind kind)
MakeNode(VerifyPreTracer* trc, void* thing, JS::TraceKind kind)
{
NodeMap::AddPtr p = trc->nodemap.lookupForAdd(thing);
if (!p) {
@@ -179,18 +182,12 @@ gc::GCRuntime::startVerifyPreBarriers()
number++;
VerifyPreTracer* trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr));
VerifyPreTracer* trc = js_new<VerifyPreTracer>(rt);
if (!trc)
return;
gcstats::AutoPhase ap(stats, gcstats::PHASE_TRACE_HEAP);
/*
* Passing a function pointer directly to js_new trips a compiler bug in
* MSVC. Work around by filling the pointer after allocating with nullptr.
*/
trc->setTraceCallback(AccumulateEdge);
const size_t size = 64 * 1024 * 1024;
trc->root = (VerifyNode*)js_malloc(size);
if (!trc->root)
@@ -202,7 +199,7 @@ gc::GCRuntime::startVerifyPreBarriers()
goto oom;
/* Create the root node. */
trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0));
trc->curnode = MakeNode(trc, nullptr, JS::TraceKind(0));
incrementalState = MARK_ROOTS;
@@ -255,6 +252,14 @@ IsMarkedOrAllocated(TenuredCell* cell)
return cell->isMarked() || cell->arenaHeader()->allocatedDuringIncremental;
}
static void
CheckEdge(JS::CallbackTracer* jstrc, void** thingp, JS::TraceKind kind);
struct CheckEdgeTracer : public JS::CallbackTracer {
VerifyNode* node;
explicit CheckEdgeTracer(JSRuntime* rt) : JS::CallbackTracer(rt, CheckEdge), node(nullptr) {}
};
static const uint32_t MAX_VERIFIER_EDGES = 1000;
/*
@@ -265,10 +270,10 @@ static const uint32_t MAX_VERIFIER_EDGES = 1000;
* been modified) must point to marked objects.
*/
static void
CheckEdge(JS::CallbackTracer* jstrc, void** thingp, JSGCTraceKind kind)
CheckEdge(JS::CallbackTracer* jstrc, void** thingp, JS::TraceKind kind)
{
VerifyPreTracer* trc = (VerifyPreTracer*)jstrc;
VerifyNode* node = trc->curnode;
CheckEdgeTracer* trc = static_cast<CheckEdgeTracer*>(jstrc);
VerifyNode* node = trc->node;
/* Avoid n^2 behavior. */
if (node->count > MAX_VERIFIER_EDGES)
@@ -290,9 +295,9 @@ AssertMarkedOrAllocated(const EdgeValue& edge)
return;
// Permanent atoms and well-known symbols aren't marked during graph traversal.
if (edge.kind == JSTRACE_STRING && static_cast<JSString*>(edge.thing)->isPermanentAtom())
if (edge.kind == JS::TraceKind::String && static_cast<JSString*>(edge.thing)->isPermanentAtom())
return;
if (edge.kind == JSTRACE_SYMBOL && static_cast<JS::Symbol*>(edge.thing)->isWellKnownSymbol())
if (edge.kind == JS::TraceKind::Symbol && static_cast<JS::Symbol*>(edge.thing)->isWellKnownSymbol())
return;
char msgbuf[1024];
@@ -304,7 +309,7 @@ AssertMarkedOrAllocated(const EdgeValue& edge)
bool
gc::GCRuntime::endVerifyPreBarriers()
{
VerifyPreTracer* trc = (VerifyPreTracer*)verifyPreData;
VerifyPreTracer* trc = static_cast<VerifyPreTracer*>(verifyPreData);
if (!trc)
return false;
@@ -336,13 +341,13 @@ gc::GCRuntime::endVerifyPreBarriers()
incrementalState = NO_INCREMENTAL;
if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
trc->setTraceCallback(CheckEdge);
CheckEdgeTracer cetrc(rt);
/* Start after the roots. */
VerifyNode* node = NextNode(trc->root);
while ((char*)node < trc->edgeptr) {
trc->curnode = node;
JS_TraceChildren(trc, node->thing, node->kind);
cetrc.node = node;
JS_TraceChildren(&cetrc, node->thing, node->kind);
if (node->count <= MAX_VERIFIER_EDGES) {
for (uint32_t i = 0; i < node->count; i++)
@@ -387,7 +392,7 @@ gc::GCRuntime::maybeVerifyPreBarriers(bool always)
if (rt->mainThread.suppressGC)
return;
if (VerifyPreTracer* trc = (VerifyPreTracer*)verifyPreData) {
if (VerifyPreTracer* trc = static_cast<VerifyPreTracer*>(verifyPreData)) {
if (++trc->count < zealFrequency && !always)
return;
@@ -407,7 +412,7 @@ js::gc::MaybeVerifyBarriers(JSContext* cx, bool always)
void
js::gc::GCRuntime::finishVerifier()
{
if (VerifyPreTracer* trc = (VerifyPreTracer*)verifyPreData) {
if (VerifyPreTracer* trc = static_cast<VerifyPreTracer*>(verifyPreData)) {
js_delete(trc);
verifyPreData = nullptr;
}
+1 -1
View File
@@ -28,7 +28,7 @@ FRAGMENT(Root, handle) {
}
FRAGMENT(Root, HeapSlot) {
JS::Rooted<jsval> plinth(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "plinth")));
JS::Rooted<jsval> plinth(cx, JS::StringValue(JS_NewStringCopyZ(cx, "plinth")));
JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, JS::HandleValueArray(plinth)));
breakpoint();
+18 -1
View File
@@ -1,12 +1,29 @@
// |jit-test| error: InternalError
// This test case creates an array, with no third element. When we iterate over
// the third element of the array (GetElement) see that it is "undefined" and
// start looking for __noSuchMethod__. Iterating over the protoype chain end on
// the Proxy defined as the __proto__ of Array.
//
// When looking for the __noSuchMethod__ property (BaseProxyHandler::get) on the
// proxy, the function getPropertyDescriptor is called which cause an error.
//
// Unfortunately, IonMonkey GetElementIC do not have supports for
// __noSuchMethod__ (Bug 964574) at the moment, which cause a differential
// behaviour.
//
// As we hope to remote __noSuchMethod__ soon (Bug 683218), we disable the mode
// which force the selection of IonMonkey ICs.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
Array.prototype.__proto__ = Proxy.create({
getPropertyDescriptor: function(name) {
return (560566);
},
}, null);
function f() {}
function g() { }
function g() {}
var x = [f,f,f,undefined,g];
for (var i = 0; i < 5; ++i)
y = x[i]("x");
@@ -0,0 +1,3 @@
x = Array(4294967295);
x[1] = 0;
Array.prototype.shift.call(x);
+28
View File
@@ -0,0 +1,28 @@
function f() {
var arr = [];
for (var i=0; i<80; i++) {
var o3 = {foo: i};
var o2 = {owner: o3};
arr.push(o2);
}
for (var i=0; i<80; i++) {
var o2 = arr[i];
var o3 = o2.owner;
Object.defineProperty(o3, "bar", {value: arr, enumerable: false});
}
assertEq(JSON.stringify(arr).length, 1671);
}
f();
function g() {
var arr = [];
for (var i=0; i<100; i++) {
arr.push([1, i]);
}
for (var i=0; i<100; i++) {
for (var p in arr[i]) {
assertEq(p === "0" || p === "1", true);
}
}
}
g();
+3
View File
@@ -0,0 +1,3 @@
setJitCompilerOption("ion.warmup.trigger", 50);
for (var i = 0; i < 150; i++)
Infinity;
@@ -4,6 +4,12 @@
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 100)
setJitCompilerOption("ion.warmup.trigger", 100);
// This test checks that we are able to remove the getelem & setelem with scalar
// replacement, so we should not force inline caches, as this would skip the
// generation of getelem & setelem instructions.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
// This function is used to force a bailout when it is inlined, and to recover
// the frame which is inlining this function.
var resumeHere = function (i) { if (i >= 99) bailout(); };
@@ -1,3 +1,8 @@
// |jit-test| test-join=--no-unboxed-objects
//
// Unboxed object optimization might not trigger in all cases, thus we ensure
// that Sink optimization is working well independently of the
// object representation.
// Ion eager fails the test below because we have not yet created any
// template object in baseline before running the content of the top-level
@@ -5,6 +10,9 @@
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 20)
setJitCompilerOption("ion.warmup.trigger", 20);
// These arguments have to be computed by baseline, and thus captured in a
// resume point. The next function checks that we can remove the computation of
// these arguments.
function f(a, b, c, d) { }
function topLevel() {
@@ -0,0 +1,43 @@
// |jit-test| test-join=--no-unboxed-objects
//
// Unboxed object optimization might not trigger in all cases, thus we ensure
// that Scalar Replacement optimization is working well independently of the
// object representation.
// Ion eager fails the test below because we have not yet created any
// template object in baseline before running the content of the top-level
// function.
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 90)
setJitCompilerOption("ion.warmup.trigger", 90);
// This test checks that we are able to remove the getprop & setprop with scalar
// replacement, so we should not force inline caches, as this would skip the
// generation of getprop & setprop instructions.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
// Frequent GCs can interfere with the tests being performed here.
if (typeof gczeal != "undefined")
gczeal(0);
var arr = new Array();
var max = 2000;
for (var i=0; i < max; i++)
arr[i] = i;
function f() {
var res = 0;
var nextObj;
var itr = arr[Symbol.iterator]();
do {
nextObj = itr.next();
if (nextObj.done)
break;
res += nextObj.value;
assertRecoveredOnBailout(nextObj, true);
} while (true);
return res;
}
for (var j = 0; j < 10; j++)
assertEq(f(), max * (max - 1) / 2);
+38 -28
View File
@@ -1,15 +1,29 @@
// |jit-test| test-join=--no-unboxed-objects
//
// Unboxed object optimization might not trigger in all cases, thus we ensure
// that Scalar Replacement optimization is working well independently of the
// object representation.
// Ion eager fails the test below because we have not yet created any
// template object in baseline before running the content of the top-level
// function.
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 90)
setJitCompilerOption("ion.warmup.trigger", 90);
// This test checks that we are able to remove the getprop & setprop with scalar
// replacement, so we should not force inline caches, as this would skip the
// generation of getprop & setprop instructions.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
function resumeHere() {}
var uceFault = function (i) {
if (i > 98)
uceFault = function (i) { return true; };
return false;
};
// Without "use script" in the inner function, the arguments might be
// obersvable.
function inline_notSoEmpty1(a, b, c, d) {
@@ -19,11 +33,11 @@ function inline_notSoEmpty1(a, b, c, d) {
}
var uceFault_notSoEmpty1 = eval(uneval(uceFault).replace('uceFault', 'uceFault_notSoEmpty1'));
function notSoEmpty1() {
var a = { v: i, notunboxed: undefined };
var b = { v: 1 + a.v, notunboxed: undefined };
var c = { v: 2 + b.v, notunboxed: undefined };
var d = { v: 3 + c.v, notunboxed: undefined };
var unused = { v: 4 + d.v, notunboxed: undefined };
var a = { v: i };
var b = { v: 1 + a.v };
var c = { v: 2 + b.v };
var d = { v: 3 + c.v };
var unused = { v: 4 + d.v };
var res = inline_notSoEmpty1(a, b, c, d);
if (uceFault_notSoEmpty1(i) || uceFault_notSoEmpty1(i))
assertEq(i, res.v);
@@ -36,23 +50,23 @@ function notSoEmpty1() {
assertRecoveredOnBailout(c, true);
assertRecoveredOnBailout(d, true);
assertRecoveredOnBailout(unused, true);
// Scalar Replacement is coming after the branch removal made by GVN, and
// the ucefault branch is not taken yet.
assertRecoveredOnBailout(res, false);
// The ucefault branch is not taken yet, and GVN removes it. Scalar
// Replacement thus removes the creation of the object.
assertRecoveredOnBailout(res, true);
}
// Check that we can recover objects with their content.
function inline_notSoEmpty2(a, b, c, d) {
"use strict";
return { v: (a.v + b.v + c.v + d.v - 10) / 4, notunboxed: undefined };
return { v: (a.v + b.v + c.v + d.v - 10) / 4 };
}
var uceFault_notSoEmpty2 = eval(uneval(uceFault).replace('uceFault', 'uceFault_notSoEmpty2'));
function notSoEmpty2(i) {
var a = { v: i, notunboxed: undefined };
var b = { v: 1 + a.v, notunboxed: undefined };
var c = { v: 2 + b.v, notunboxed: undefined };
var d = { v: 3 + c.v, notunboxed: undefined };
var unused = { v: 4 + d.v, notunboxed: undefined };
var a = { v: i };
var b = { v: 1 + a.v };
var c = { v: 2 + b.v };
var d = { v: 3 + c.v };
var unused = { v: 4 + d.v };
var res = inline_notSoEmpty2(a, b, c, d);
if (uceFault_notSoEmpty2(i) || uceFault_notSoEmpty2(i))
assertEq(i, res.v);
@@ -61,22 +75,22 @@ function notSoEmpty2(i) {
assertRecoveredOnBailout(c, true);
assertRecoveredOnBailout(d, true);
assertRecoveredOnBailout(unused, true);
// Scalar Replacement is coming after the branch removal made by GVN, and
// the ucefault branch is not taken yet.
assertRecoveredOnBailout(res, false);
// The ucefault branch is not taken yet, and GVN removes it. Scalar
// Replacement thus removes the creation of the object.
assertRecoveredOnBailout(res, true);
}
// Check that we can recover objects with their content.
var argFault_observeArg = function (i) {
if (i > 98)
return inline_observeArg.arguments[0];
return { test : i, notunboxed: undefined };
return { test : i };
};
function inline_observeArg(obj, i) {
return argFault_observeArg(i);
}
function observeArg(i) {
var obj = { test: i, notunboxed: undefined };
var obj = { test: i };
var res = inline_observeArg(obj, i);
assertEq(res.test, i);
assertRecoveredOnBailout(obj, true);
@@ -84,7 +98,7 @@ function observeArg(i) {
// Check case where one successor can have multiple times the same predecessor.
function complexPhi(i) {
var obj = { test: i, notunboxed: undefined };
var obj = { test: i };
switch (i) { // TableSwitch
case 0: obj.test = 0; break;
case 1: obj.test = 1; break;
@@ -103,12 +117,12 @@ function complexPhi(i) {
function withinIf(i) {
var x = undefined;
if (i % 2 == 0) {
let obj = { foo: i, notunboxed: undefined };
let obj = { foo: i };
x = obj.foo;
assertRecoveredOnBailout(obj, true);
obj = undefined;
} else {
let obj = { bar: i, notunboxed: undefined };
let obj = { bar: i };
x = obj.bar;
assertRecoveredOnBailout(obj, true);
obj = undefined;
@@ -118,22 +132,20 @@ function withinIf(i) {
// Check case where one successor can have multiple times the same predecessor.
function unknownLoad(i) {
var obj = { foo: i, notunboxed: undefined };
var obj = { foo: i };
assertEq(obj.bar, undefined);
// Unknown properties are using GetPropertyCache.
assertRecoveredOnBailout(obj, false);
}
// Check with dynamic slots.
function resumeHere() {}
function dynamicSlots(i) {
var obj = {
p0: i + 0, p1: i + 1, p2: i + 2, p3: i + 3, p4: i + 4, p5: i + 5, p6: i + 6, p7: i + 7, p8: i + 8, p9: i + 9, p10: i + 10,
p11: i + 11, p12: i + 12, p13: i + 13, p14: i + 14, p15: i + 15, p16: i + 16, p17: i + 17, p18: i + 18, p19: i + 19, p20: i + 20,
p21: i + 21, p22: i + 22, p23: i + 23, p24: i + 24, p25: i + 25, p26: i + 26, p27: i + 27, p28: i + 28, p29: i + 29, p30: i + 30,
p31: i + 31, p32: i + 32, p33: i + 33, p34: i + 34, p35: i + 35, p36: i + 36, p37: i + 37, p38: i + 38, p39: i + 39, p40: i + 40,
p41: i + 41, p42: i + 42, p43: i + 43, p44: i + 44, p45: i + 45, p46: i + 46, p47: i + 47, p48: i + 48, p49: i + 49, p50: i + 50,
notunboxed: undefined
p41: i + 41, p42: i + 42, p43: i + 43, p44: i + 44, p45: i + 45, p46: i + 46, p47: i + 47, p48: i + 48, p49: i + 49, p50: i + 50
};
// Add a function call to capture a resumepoint at the end of the call or
// inside the inlined block, such as the bailout does not rewind to the
@@ -148,7 +160,6 @@ function Point(x, y)
{
this.x = x;
this.y = y;
this.notUnboxed = undefined;
}
function createThisWithTemplate(i)
@@ -159,7 +170,6 @@ function createThisWithTemplate(i)
assertRecoveredOnBailout(p, true);
}
for (var i = 0; i < 100; i++) {
notSoEmpty1(i);
notSoEmpty2(i);
+6
View File
@@ -1,3 +1,9 @@
// This test checks that we are able to optimize float32 inputs. As
// GetElementIC (float32 array accesses) output is not specialized with Float32
// output types, we should not force inline caches.
if (getJitCompilerOptions()["ion.forceinlineCaches"])
setJitCompilerOption("ion.forceinlineCaches", 0);
// Fuzz tests
(function(){
//
+15 -7
View File
@@ -5,6 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/BacktrackingAllocator.h"
#include "jsprf.h"
#include "jit/BitSet.h"
using namespace js;
@@ -322,14 +325,19 @@ VirtualRegister::setInitialDefinition(CodePosition from)
}
LiveRange*
VirtualRegister::rangeFor(CodePosition pos) const
VirtualRegister::rangeFor(CodePosition pos, bool preferRegister /* = false */) const
{
LiveRange* found = nullptr;
for (LiveRange::RegisterLinkIterator iter = rangesBegin(); iter; iter++) {
LiveRange* range = LiveRange::get(*iter);
if (range->covers(pos))
return range;
if (range->covers(pos)) {
if (!preferRegister || range->bundle()->allocation().isRegister())
return range;
if (!found)
found = range;
}
}
return nullptr;
return found;
}
void
@@ -1702,7 +1710,7 @@ BacktrackingAllocator::resolveControlFlow()
if (skip)
continue;
LiveRange* predecessorRange = reg.rangeFor(start.previous());
LiveRange* predecessorRange = reg.rangeFor(start.previous(), /* preferRegister = */ true);
if (start.subpos() == CodePosition::INPUT) {
if (!moveInput(ins->toInstruction(), predecessorRange, range, reg.type()))
return false;
@@ -1738,7 +1746,7 @@ BacktrackingAllocator::resolveControlFlow()
MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
LAllocation* input = phi->getOperand(k);
LiveRange* from = vreg(input).rangeFor(exitOf(predecessor));
LiveRange* from = vreg(input).rangeFor(exitOf(predecessor), /* preferRegister = */ true);
MOZ_ASSERT(from);
if (!moveAtExit(predecessor, from, to, def->type()))
@@ -1763,7 +1771,7 @@ BacktrackingAllocator::resolveControlFlow()
if (to->covers(exitOf(predecessor)))
continue;
LiveRange* from = reg.rangeFor(exitOf(predecessor));
LiveRange* from = reg.rangeFor(exitOf(predecessor), /* preferRegister = */ true);
if (mSuccessor->numPredecessors() > 1) {
MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
+1 -1
View File
@@ -524,7 +524,7 @@ class VirtualRegister
LiveRange* lastRange() const {
return LiveRange::get(ranges_.back());
}
LiveRange* rangeFor(CodePosition pos) const;
LiveRange* rangeFor(CodePosition pos, bool preferRegister = false) const;
void removeRange(LiveRange* range);
void addRange(LiveRange* range);
+1 -1
View File
@@ -1573,7 +1573,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter
BaselineBailoutInfo *info = builder.info();
uint8_t* newsp = info->incomingStack - (info->copyStackTop - info->copyStackBottom);
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
if (SimulatorType::Current()->overRecursed(uintptr_t(newsp)))
if (Simulator::Current()->overRecursed(uintptr_t(newsp)))
overRecursed = true;
#else
JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, newsp, overRecursed = true);
+4 -3
View File
@@ -3448,13 +3448,14 @@ BaselineCompiler::emit_JSOP_REST()
{
frame.syncStack(0);
ArrayObject* templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
JSObject* templateObject =
ObjectGroup::newArrayObject(cx, nullptr, 0, TenuredObject,
ObjectGroup::NewArrayKind::UnknownIndex);
if (!templateObject)
return false;
ObjectGroup::fixRestArgumentsGroup(cx, templateObject);
// Call IC.
ICRest_Fallback::Compiler compiler(cx, templateObject);
ICRest_Fallback::Compiler compiler(cx, &templateObject->as<ArrayObject>());
if (!emitOpIC(compiler.getStub(&stubSpace_)))
return false;
+111 -130
View File
@@ -261,8 +261,8 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// Call DoWarmUpCounterFallback to compile/check-for Ion-compiled function
{
// Push IonOsrTempData pointer storage
masm.subPtr(Imm32(sizeof(void*)), BaselineStackReg);
masm.push(BaselineStackReg);
masm.subFromStackPtr(Imm32(sizeof(void*)));
masm.push(masm.getStackPointer());
// Push stub pointer.
masm.push(ICStubReg);
@@ -298,7 +298,7 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// [...Baseline-Frame...]
// Restore the stack pointer to point to the saved frame pointer.
masm.movePtr(BaselineFrameReg, BaselineStackReg);
masm.moveToStackPtr(BaselineFrameReg);
// Discard saved frame pointer, so that the return address is on top of
// the stack.
@@ -319,9 +319,9 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// callee frame), turn on profiling, then return to this frame,
// and then OSR with profiling turned on. In this case, allow for
// lastProfilingFrame to be null.
masm.branchPtr(Assembler::Equal, scratchReg, Imm32(0), &checkOk);
masm.branchPtr(Assembler::Equal, scratchReg, ImmWord(0), &checkOk);
masm.branchPtr(Assembler::Equal, scratchReg, BaselineStackReg, &checkOk);
masm.branchStackPtr(Assembler::Equal, scratchReg, &checkOk);
masm.assumeUnreachable("Baseline OSR lastProfilingFrame mismatch.");
masm.bind(&checkOk);
}
@@ -2670,11 +2670,8 @@ CheckHasNoSuchProperty(JSContext* cx, HandleObject obj, HandlePropertyName name,
while (curObj) {
if (curObj->isNative()) {
// Don't handle proto chains with resolve hooks.
if (ClassMayResolveId(cx->names(), curObj->getClass(), NameToId(name), curObj) ||
curObj->getClass()->addProperty)
{
if (ClassMayResolveId(cx->names(), curObj->getClass(), NameToId(name), curObj))
return false;
}
if (curObj->as<NativeObject>().contains(cx, NameToId(name)))
return false;
} else if (curObj != obj) {
@@ -3690,7 +3687,7 @@ ICGetElemNativeCompiler::emitCallScripted(MacroAssembler& masm, Register objReg)
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(0), ArgumentsRectifierReg);
masm.movePtr(ImmWord(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -3867,12 +3864,12 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm)
} else {
masm.loadValue(valAddr, R0);
if (popR1)
masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
masm.addToStackPtr(ImmWord(sizeof(size_t)));
}
#else
masm.loadValue(valAddr, R0);
if (popR1)
masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
masm.addToStackPtr(ImmWord(sizeof(size_t)));
#endif
} else {
@@ -3886,7 +3883,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm)
// GetElem key (R1) is no longer needed.
if (popR1)
masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
masm.addToStackPtr(ImmWord(sizeof(size_t)));
emitCallNative(masm, objReg);
@@ -3902,7 +3899,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm)
// At this point, we are guaranteed to successfully complete.
if (popR1)
masm.addPtr(Imm32(sizeof(size_t)), BaselineStackReg);
masm.addToStackPtr(Imm32(sizeof(size_t)));
emitCallScripted(masm, objReg);
}
@@ -4762,8 +4759,8 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// so we push the index, then overwrite the rhs Value with R0
// and push the rhs value.
masm.pushValue(R1);
masm.loadValue(Address(BaselineStackReg, sizeof(Value)), R1);
masm.storeValue(R0, Address(BaselineStackReg, sizeof(Value)));
masm.loadValue(Address(masm.getStackPointer(), sizeof(Value)), R1);
masm.storeValue(R0, Address(masm.getStackPointer(), sizeof(Value)));
masm.pushValue(R1);
// Push arguments.
@@ -4771,13 +4768,13 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// Push index. On x86 and ARM two push instructions are emitted so use a
// separate register to store the old stack pointer.
masm.mov(BaselineStackReg, R1.scratchReg());
masm.moveStackPtrTo(R1.scratchReg());
masm.pushValue(Address(R1.scratchReg(), 2 * sizeof(Value)));
masm.pushValue(R0); // Object.
// Push pointer to stack values, so that the stub can overwrite the object
// (pushed for the decompiler) with the rhs.
masm.computeEffectiveAddress(Address(BaselineStackReg, 3 * sizeof(Value)), R0.scratchReg());
masm.computeEffectiveAddress(Address(masm.getStackPointer(), 3 * sizeof(Value)), R0.scratchReg());
masm.push(R0.scratchReg());
masm.push(ICStubReg);
@@ -4845,7 +4842,7 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
// Stack is now: { ..., rhs-value, object-value, key-value, maybe?-RET-ADDR }
// Load rhs-value into R0
masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R0);
masm.loadValue(Address(masm.getStackPointer(), 2 * sizeof(Value) + ICStackValueOffset), R0);
// Call the type-update stub.
if (!callTypeUpdateIC(masm, sizeof(Value)))
@@ -4860,7 +4857,7 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
// Trigger post barriers here on the value being written. Fields which
// objects can be written to also need update stubs.
masm.Push(R1);
masm.loadValue(Address(BaselineStackReg, sizeof(Value) + ICStackValueOffset), R1);
masm.loadValue(Address(masm.getStackPointer(), sizeof(Value) + ICStackValueOffset), R1);
LiveGeneralRegisterSet saveRegs;
saveRegs.add(R0);
@@ -4908,7 +4905,7 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
regs.takeUnchecked(obj);
regs.takeUnchecked(key);
Address valueAddr(BaselineStackReg, ICStackValueOffset);
Address valueAddr(masm.getStackPointer(), ICStackValueOffset);
// We need to convert int32 values being stored into doubles. In this case
// the heap typeset is guaranteed to contain both int32 and double, so it's
@@ -4943,7 +4940,7 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
EmitUnboxedPreBarrierForBaseline(masm, address, unboxedType_);
Address valueAddr(BaselineStackReg, ICStackValueOffset + sizeof(Value));
Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
masm.Push(R0);
masm.loadValue(valueAddr, R0);
masm.storeUnboxedProperty(address, unboxedType_,
@@ -5057,7 +5054,7 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm)
if (needsUpdateStubs()) {
// Stack is now: { ..., rhs-value, object-value, key-value, maybe?-RET-ADDR }
// Load rhs-value in to R0
masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R0);
masm.loadValue(Address(masm.getStackPointer(), 2 * sizeof(Value) + ICStackValueOffset), R0);
// Call the type-update stub.
if (!callTypeUpdateIC(masm, sizeof(Value)))
@@ -5074,7 +5071,7 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm)
// Trigger post barriers here on the value being written. Fields which
// objects can be written to also need update stubs.
masm.Push(R1);
masm.loadValue(Address(BaselineStackReg, sizeof(Value) + ICStackValueOffset), R1);
masm.loadValue(Address(masm.getStackPointer(), sizeof(Value) + ICStackValueOffset), R1);
LiveGeneralRegisterSet saveRegs;
saveRegs.add(R0);
@@ -5136,7 +5133,7 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm)
Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
&dontConvertDoubles);
Address valueAddr(BaselineStackReg, ICStackValueOffset);
Address valueAddr(masm.getStackPointer(), ICStackValueOffset);
// Note that double arrays are only created by IonMonkey, so if we have no
// floating-point support Ion is disabled and there should be no double arrays.
@@ -5169,7 +5166,7 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm)
// Write the value first, since this can fail. No need for pre-barrier
// since we're not overwriting an old value.
masm.Push(R0);
Address valueAddr(BaselineStackReg, ICStackValueOffset + sizeof(Value));
Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
masm.loadValue(valueAddr, R0);
BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_)));
masm.storeUnboxedProperty(address, unboxedType_,
@@ -5326,7 +5323,7 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
LoadTypedThingData(masm, layout_, obj, scratchReg);
BaseIndex dest(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
Address value(BaselineStackReg, ICStackValueOffset);
Address value(masm.getStackPointer(), ICStackValueOffset);
// We need a second scratch register. It's okay to clobber the type tag of
// R0 or R1, as long as it's restored before jumping to the next stub.
@@ -7366,7 +7363,7 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm)
masm.bind(&skipNoSuchMethod);
// Pop pushed objReg.
masm.addPtr(Imm32(sizeof(void*)), BaselineStackReg);
masm.addToStackPtr(Imm32(sizeof(void*)));
masm.bind(&afterNoSuchMethod);
} else {
masm.loadValue(result, R0);
@@ -7534,7 +7531,7 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm)
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(0), ArgumentsRectifierReg);
masm.movePtr(ImmWord(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -8698,7 +8695,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm)
// Load RHS into R0 for TypeUpdate check.
// Stack is currently: [..., ObjValue, RHSValue, MaybeReturnAddr? ]
masm.loadValue(Address(BaselineStackReg, ICStackValueOffset), R0);
masm.loadValue(Address(masm.getStackPointer(), ICStackValueOffset), R0);
// Call the type-update stub.
if (!callTypeUpdateIC(masm, sizeof(Value)))
@@ -8928,7 +8925,7 @@ ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm)
masm.addPtr(secondScratch, scratch);
Address dest(scratch, 0);
Address value(BaselineStackReg, 0);
Address value(masm.getStackPointer(), 0);
if (fieldDescr_->is<ScalarTypeDescr>()) {
Scalar::Type type = fieldDescr_->as<ScalarTypeDescr>().type();
@@ -9062,7 +9059,7 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm)
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(1), ArgumentsRectifierReg);
masm.movePtr(ImmWord(1), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -9148,7 +9145,7 @@ ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm)
// To Push R1, read it off of the stowed values on stack.
// Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
masm.movePtr(BaselineStackReg, scratch);
masm.moveStackPtrTo(scratch);
masm.pushValue(Address(scratch, STUB_FRAME_SIZE));
masm.push(objReg);
masm.push(callee);
@@ -9264,8 +9261,8 @@ TryAttachFunCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script,
}
static bool
GetTemplateObjectForNative(JSContext* cx, HandleScript script, jsbytecode* pc,
Native native, const CallArgs& args, MutableHandleObject res)
GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
MutableHandleObject res)
{
// Check for natives to which template objects can be attached. This is
// done to provide templates to Ion for inlining these natives later on.
@@ -9279,27 +9276,16 @@ GetTemplateObjectForNative(JSContext* cx, HandleScript script, jsbytecode* pc,
count = args.length();
else if (args.length() == 1 && args[0].isInt32() && args[0].toInt32() >= 0)
count = args[0].toInt32();
res.set(NewDenseUnallocatedArray(cx, count, nullptr, TenuredObject));
if (!res)
return false;
ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
if (!group)
return false;
res->setGroup(group);
return true;
}
if (native == intrinsic_NewDenseArray) {
res.set(NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
if (!res)
return false;
ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
if (!group)
return false;
res->setGroup(group);
return true;
if (count <= ArrayObject::EagerAllocationMaxLength) {
// With this and other array templates, set forceAnalyze so that we
// don't end up with a template whose structure might change later.
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject,
/* forceAnalyze = */ true));
if (!res)
return false;
return true;
}
}
if (native == js::array_concat || native == js::array_slice) {
@@ -9312,14 +9298,10 @@ GetTemplateObjectForNative(JSContext* cx, HandleScript script, jsbytecode* pc,
}
if (native == js::str_split && args.length() == 1 && args[0].isString()) {
res.set(NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject,
/* forceAnalyze = */ true));
if (!res)
return false;
ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
if (!group)
return false;
res->setGroup(group);
return true;
}
@@ -9613,7 +9595,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
RootedObject templateObject(cx);
if (MOZ_LIKELY(!isSpread)) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!GetTemplateObjectForNative(cx, script, pc, fun->native(), args, &templateObject))
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject))
return false;
}
@@ -9635,24 +9617,16 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
}
static bool
CopyArray(JSContext* cx, HandleArrayObject obj, MutableHandleValue result)
CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result)
{
MOZ_ASSERT(obj->is<ArrayObject>());
uint32_t length = obj->as<ArrayObject>().length();
MOZ_ASSERT(obj->getDenseInitializedLength() == length);
RootedObjectGroup group(cx, obj->getGroup(cx));
if (!group)
uint32_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, obj, length, TenuredObject,
/* forceAnalyze = */ true);
if (!nobj)
return false;
CopyAnyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length);
RootedArrayObject newObj(cx, NewDenseFullyAllocatedArray(cx, length, nullptr, TenuredObject));
if (!newObj)
return false;
newObj->setGroup(group);
newObj->setDenseInitializedLength(length);
newObj->initDenseElements(0, obj->getDenseElements(), length);
result.setObject(*newObj);
result.setObject(*nobj);
return true;
}
@@ -9680,7 +9654,7 @@ TryAttachStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript script,
RootedString thisString(cx, thisv.toString());
RootedString argString(cx, args[0].toString());
RootedArrayObject obj(cx, &res.toObject().as<ArrayObject>());
RootedObject obj(cx, &res.toObject());
RootedValue arr(cx);
// Copy the array before storing in stub.
@@ -9688,14 +9662,17 @@ TryAttachStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript script,
return false;
// Atomize all elements of the array.
RootedArrayObject arrObj(cx, &arr.toObject().as<ArrayObject>());
uint32_t initLength = arrObj->length();
RootedObject arrObj(cx, &arr.toObject());
uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(arrObj);
for (uint32_t i = 0; i < initLength; i++) {
JSAtom* str = js::AtomizeString(cx, arrObj->getDenseElement(i).toString());
JSAtom* str = js::AtomizeString(cx, GetAnyBoxedOrUnboxedDenseElement(arrObj, i).toString());
if (!str)
return false;
arrObj->setDenseElement(i, StringValue(str));
if (!SetAnyBoxedOrUnboxedDenseElement(cx, arrObj, i, StringValue(str))) {
// The value could not be stored to an unboxed dense element.
return true;
}
}
ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
@@ -9852,7 +9829,7 @@ ICCallStubCompiler::pushCallArguments(MacroAssembler& masm, AllocatableGeneralRe
// Account for new.target
Register count = regs.takeAny();
masm.mov(argcReg, count);
masm.move32(argcReg, count);
// If we are setting up for a jitcall, we have to align the stack taking
// into account the args and newTarget. We could also count callee and |this|,
@@ -9868,7 +9845,7 @@ ICCallStubCompiler::pushCallArguments(MacroAssembler& masm, AllocatableGeneralRe
// argPtr initially points to the last argument.
Register argPtr = regs.takeAny();
masm.mov(BaselineStackReg, argPtr);
masm.moveStackPtrTo(argPtr);
// Skip 4 pointers pushed on top of the arguments: the frame descriptor,
// return address, old frame pointer and stub reg.
@@ -9901,7 +9878,8 @@ void
ICCallStubCompiler::guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure,
bool isConstructing)
{
masm.unboxObject(Address(BaselineStackReg, isConstructing * sizeof(Value) + ICStackValueOffset), argcReg);
masm.unboxObject(Address(masm.getStackPointer(),
isConstructing * sizeof(Value) + ICStackValueOffset), argcReg);
masm.loadPtr(Address(argcReg, NativeObject::offsetOfElements()), argcReg);
masm.load32(Address(argcReg, ObjectElements::offsetOfLength()), argcReg);
@@ -9921,7 +9899,8 @@ ICCallStubCompiler::pushSpreadCallArguments(MacroAssembler& masm,
{
// Pull the array off the stack before aligning.
Register startReg = regs.takeAny();
masm.unboxObject(Address(BaselineStackReg, (isConstructing * sizeof(Value)) + STUB_FRAME_SIZE), startReg);
masm.unboxObject(Address(masm.getStackPointer(),
(isConstructing * sizeof(Value)) + STUB_FRAME_SIZE), startReg);
masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg);
// Align the stack such that the JitFrameLayout is aligned on the
@@ -9930,7 +9909,7 @@ ICCallStubCompiler::pushSpreadCallArguments(MacroAssembler& masm,
Register alignReg = argcReg;
if (isConstructing) {
alignReg = regs.takeAny();
masm.mov(argcReg, alignReg);
masm.movePtr(argcReg, alignReg);
masm.addPtr(Imm32(1), alignReg);
}
masm.alignJitStackBasedOnNArgs(alignReg);
@@ -9946,7 +9925,7 @@ ICCallStubCompiler::pushSpreadCallArguments(MacroAssembler& masm,
// Push arguments: set up endReg to point to &array[argc]
Register endReg = regs.takeAny();
masm.mov(argcReg, endReg);
masm.movePtr(argcReg, endReg);
static_assert(sizeof(Value) == 8, "Value must be 8 bytes");
masm.lshiftPtr(Imm32(3), endReg);
masm.addPtr(startReg, endReg);
@@ -9985,7 +9964,7 @@ ICCallStubCompiler::guardFunApply(MacroAssembler& masm, AllocatableGeneralRegist
// Stack looks like:
// [..., CalleeV, ThisV, Arg0V, Arg1V <MaybeReturnReg>]
Address secondArgSlot(BaselineStackReg, ICStackValueOffset);
Address secondArgSlot(masm.getStackPointer(), ICStackValueOffset);
if (applyThing == FunApply_MagicArgs) {
// Ensure that the second arg is magic arguments.
masm.branchTestMagic(Assembler::NotEqual, secondArgSlot, failure);
@@ -10058,7 +10037,7 @@ ICCallStubCompiler::guardFunApply(MacroAssembler& masm, AllocatableGeneralRegist
// Load the callee, ensure that it's fun_apply
ValueOperand val = regs.takeAnyValue();
Address calleeSlot(BaselineStackReg, ICStackValueOffset + (3 * sizeof(Value)));
Address calleeSlot(masm.getStackPointer(), ICStackValueOffset + (3 * sizeof(Value)));
masm.loadValue(calleeSlot, val);
masm.branchTestObject(Assembler::NotEqual, val, failure);
@@ -10072,7 +10051,7 @@ ICCallStubCompiler::guardFunApply(MacroAssembler& masm, AllocatableGeneralRegist
// Load the |thisv|, ensure that it's a scripted function with a valid baseline or ion
// script, or a native function.
Address thisSlot(BaselineStackReg, ICStackValueOffset + (2 * sizeof(Value)));
Address thisSlot(masm.getStackPointer(), ICStackValueOffset + (2 * sizeof(Value)));
masm.loadValue(thisSlot, val);
masm.branchTestObject(Assembler::NotEqual, val, failure);
@@ -10194,7 +10173,7 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// callee
masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
masm.push(BaselineStackReg);
masm.push(masm.getStackPointer());
masm.push(ICStubReg);
pushFramePtr(masm, R0.scratchReg());
@@ -10217,7 +10196,7 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
pushCallArguments(masm, regs, R0.scratchReg(), /* isJitCall = */ false, isConstructing_);
masm.push(BaselineStackReg);
masm.push(masm.getStackPointer());
masm.push(R0.scratchReg());
masm.push(ICStubReg);
@@ -10240,7 +10219,7 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// Load passed-in ThisV into R1 just in case it's needed. Need to do this before
// we leave the stub frame since that info will be lost.
// Current stack: [...., ThisV, ActualArgc, CalleeToken, Descriptor ]
masm.loadValue(Address(BaselineStackReg, 3 * sizeof(size_t)), R1);
masm.loadValue(Address(masm.getStackPointer(), 3 * sizeof(size_t)), R1);
leaveStubFrame(masm, true);
@@ -10309,11 +10288,11 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, [newTarget] +ICStackValueOffset+ ]
if (isSpread_) {
unsigned skipToCallee = (2 + isConstructing_) * sizeof(Value);
masm.loadValue(Address(BaselineStackReg, skipToCallee + ICStackValueOffset), R1);
masm.loadValue(Address(masm.getStackPointer(), skipToCallee + ICStackValueOffset), R1);
} else {
// Account for newTarget, if necessary
unsigned nonArgsSkip = (1 + isConstructing_) * sizeof(Value);
BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgsSkip);
BaseValueIndex calleeSlot(masm.getStackPointer(), argcReg, ICStackValueOffset + nonArgsSkip);
masm.loadValue(calleeSlot, R1);
}
regs.take(R1);
@@ -10375,10 +10354,10 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Stack now looks like:
// [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader, ArgC ]
if (isSpread_) {
masm.loadValue(Address(BaselineStackReg,
masm.loadValue(Address(masm.getStackPointer(),
3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1);
} else {
BaseValueIndex calleeSlot2(BaselineStackReg, argcReg,
BaseValueIndex calleeSlot2(masm.getStackPointer(), argcReg,
2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t));
masm.loadValue(calleeSlot2, R1);
}
@@ -10409,14 +10388,16 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Stack now looks like:
// [..., Callee, ThisV, Arg0V, ..., ArgNV, [NewTarget], StubFrameHeader ]
if (isSpread_) {
masm.storeValue(R0, Address(BaselineStackReg, (1 + isConstructing_) * sizeof(Value) + STUB_FRAME_SIZE));
masm.storeValue(R0, Address(masm.getStackPointer(),
(1 + isConstructing_) * sizeof(Value) + STUB_FRAME_SIZE));
} else {
BaseValueIndex thisSlot(BaselineStackReg, argcReg, STUB_FRAME_SIZE + isConstructing_ * sizeof(Value));
BaseValueIndex thisSlot(masm.getStackPointer(), argcReg,
STUB_FRAME_SIZE + isConstructing_ * sizeof(Value));
masm.storeValue(R0, thisSlot);
}
// Restore the stub register from the baseline stub frame.
masm.loadPtr(Address(BaselineStackReg, STUB_FRAME_SAVED_STUB_OFFSET), ICStubReg);
masm.loadPtr(Address(masm.getStackPointer(), STUB_FRAME_SAVED_STUB_OFFSET), ICStubReg);
// Reload callee script. Note that a GC triggered by CreateThis may
// have destroyed the callee BaselineScript and IonScript. CreateThis is
@@ -10426,11 +10407,11 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Just need to load the script now.
if (isSpread_) {
unsigned skipForCallee = (2 + isConstructing_) * sizeof(Value);
masm.loadValue(Address(BaselineStackReg, skipForCallee + STUB_FRAME_SIZE), R0);
masm.loadValue(Address(masm.getStackPointer(), skipForCallee + STUB_FRAME_SIZE), R0);
} else {
// Account for newTarget, if necessary
unsigned nonArgsSkip = (1 + isConstructing_) * sizeof(Value);
BaseValueIndex calleeSlot3(BaselineStackReg, argcReg, nonArgsSkip + STUB_FRAME_SIZE);
BaseValueIndex calleeSlot3(masm.getStackPointer(), argcReg, nonArgsSkip + STUB_FRAME_SIZE);
masm.loadValue(calleeSlot3, R0);
}
callee = masm.extractObject(R0, ExtractTemp0);
@@ -10487,7 +10468,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(argcReg, ArgumentsRectifierReg);
masm.movePtr(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -10511,11 +10492,11 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// + sizeof(Descriptor) + sizeof(Callee) + sizeof(ActualArgc)
// + stubFrameSize(Descriptor)
// - sizeof(ICStubReg) - sizeof(BaselineFrameReg)
Address descriptorAddr(BaselineStackReg, 0);
Address descriptorAddr(masm.getStackPointer(), 0);
masm.loadPtr(descriptorAddr, BaselineFrameReg);
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), BaselineFrameReg);
masm.addPtr(Imm32((3 - 2) * sizeof(size_t)), BaselineFrameReg);
masm.addPtr(BaselineStackReg, BaselineFrameReg);
masm.addStackPtrTo(BaselineFrameReg);
// Load the number of arguments present before the stub frame.
Register argcReg = JSReturnOperand.scratchReg();
@@ -10523,7 +10504,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Account for the Array object.
masm.move32(Imm32(1), argcReg);
} else {
Address argcAddr(BaselineStackReg, 2 * sizeof(size_t));
Address argcAddr(masm.getStackPointer(), 2 * sizeof(size_t));
masm.loadPtr(argcAddr, argcReg);
}
@@ -10552,14 +10533,14 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
inStubFrame_ = true;
leaveStubFrame(masm, false);
if (argcReg != R0.scratchReg())
masm.mov(argcReg, R0.scratchReg());
masm.movePtr(argcReg, R0.scratchReg());
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
typedef bool (*CopyArrayFn)(JSContext*, HandleArrayObject, MutableHandleValue);
typedef bool (*CopyArrayFn)(JSContext*, HandleObject, MutableHandleValue);
static const VMFunction CopyArrayInfo = FunctionInfo<CopyArrayFn>(CopyArray);
bool
@@ -10581,7 +10562,7 @@ ICCall_StringSplit::Compiler::generateStubCode(MacroAssembler& masm)
// Guard that callee is native function js::str_split.
{
Address calleeAddr(BaselineStackReg, ICStackValueOffset + (2 * sizeof(Value)));
Address calleeAddr(masm.getStackPointer(), ICStackValueOffset + (2 * sizeof(Value)));
ValueOperand calleeVal = regs.takeAnyValue();
// Ensure that callee is an object.
@@ -10603,7 +10584,7 @@ ICCall_StringSplit::Compiler::generateStubCode(MacroAssembler& masm)
// Guard argument.
{
// Ensure that arg is a string.
Address argAddr(BaselineStackReg, ICStackValueOffset);
Address argAddr(masm.getStackPointer(), ICStackValueOffset);
ValueOperand argVal = regs.takeAnyValue();
masm.loadValue(argAddr, argVal);
@@ -10618,7 +10599,7 @@ ICCall_StringSplit::Compiler::generateStubCode(MacroAssembler& masm)
// Guard this-value.
{
// Ensure that thisv is a string.
Address thisvAddr(BaselineStackReg, ICStackValueOffset + sizeof(Value));
Address thisvAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
ValueOperand thisvVal = regs.takeAnyValue();
masm.loadValue(thisvAddr, thisvVal);
@@ -10667,7 +10648,7 @@ ICCall_IsSuspendedStarGenerator::Compiler::generateStubCode(MacroAssembler& masm
AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
// Load the argument.
Address argAddr(BaselineStackReg, ICStackValueOffset);
Address argAddr(masm.getStackPointer(), ICStackValueOffset);
ValueOperand argVal = regs.takeAnyValue();
masm.loadValue(argAddr, argVal);
@@ -10716,10 +10697,10 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
// Load the callee in R1.
if (isSpread_) {
masm.loadValue(Address(BaselineStackReg, ICStackValueOffset + 2 * sizeof(Value)), R1);
masm.loadValue(Address(masm.getStackPointer(), ICStackValueOffset + 2 * sizeof(Value)), R1);
} else {
unsigned nonArgsSlots = (1 + isConstructing_) * sizeof(Value);
BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgsSlots);
BaseValueIndex calleeSlot(masm.getStackPointer(), argcReg, ICStackValueOffset + nonArgsSlots);
masm.loadValue(calleeSlot, R1);
}
regs.take(R1);
@@ -10749,10 +10730,9 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
if (isConstructing_) {
// Stack looks like: [ ..., Arg0Val, ThisVal, CalleeVal ]
// Replace ThisVal with MagicValue(JS_IS_CONSTRUCTING)
masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(BaselineStackReg, sizeof(Value)));
masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(masm.getStackPointer(), sizeof(Value)));
}
masm.checkStackAlignment();
// Native functions have the signature:
//
@@ -10781,7 +10761,7 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
masm.passABIArg(argcReg);
masm.passABIArg(vpReg);
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
// The simulator requires VM calls to be redirected to a special swi
// instruction to handle them, so we store the redirected pointer in the
// stub and use that instead of the original one.
@@ -10820,7 +10800,7 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
// Load the callee in R1.
unsigned nonArgSlots = (1 + isConstructing_) * sizeof(Value);
BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgSlots);
BaseValueIndex calleeSlot(masm.getStackPointer(), argcReg, ICStackValueOffset + nonArgSlots);
masm.loadValue(calleeSlot, R1);
regs.take(R1);
@@ -10848,7 +10828,7 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
if (isConstructing_) {
// Stack looks like: [ ..., Arg0Val, ThisVal, CalleeVal ]
// Replace ThisVal with MagicValue(JS_IS_CONSTRUCTING)
masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(BaselineStackReg, sizeof(Value)));
masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(masm.getStackPointer(), sizeof(Value)));
}
masm.checkStackAlignment();
@@ -10983,7 +10963,7 @@ ICCall_ScriptedApplyArray::Compiler::generateStubCode(MacroAssembler& masm)
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
masm.mov(argcReg, ArgumentsRectifierReg);
masm.movePtr(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
regs.add(argcReg);
@@ -11081,7 +11061,7 @@ ICCall_ScriptedApplyArguments::Compiler::generateStubCode(MacroAssembler& masm)
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
masm.mov(argcReg, ArgumentsRectifierReg);
masm.movePtr(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
regs.add(argcReg);
@@ -11116,7 +11096,7 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler& masm)
// Load the callee in R1.
// Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, +ICStackValueOffset+ ]
BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value));
BaseValueIndex calleeSlot(masm.getStackPointer(), argcReg, ICStackValueOffset + sizeof(Value));
masm.loadValue(calleeSlot, R1);
regs.take(R1);
@@ -11130,7 +11110,7 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler& masm)
masm.branchPtr(Assembler::NotEqual, callee, ImmPtr(fun_call), &failure);
// Ensure |this| is a scripted function with JIT code.
BaseIndex thisSlot(BaselineStackReg, argcReg, TimesEight, ICStackValueOffset);
BaseIndex thisSlot(masm.getStackPointer(), argcReg, TimesEight, ICStackValueOffset);
masm.loadValue(thisSlot, R1);
masm.branchTestObject(Assembler::NotEqual, R1, &failure);
@@ -11162,6 +11142,7 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler& masm)
// Values are on the stack left-to-right. Calling convention wants them
// right-to-left so duplicate them on the stack in reverse order.
pushCallArguments(masm, regs, argcReg, /* isJitCall = */ true);
// Pop scripted callee (the original |this|).
@@ -11209,7 +11190,7 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler& masm)
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(argcReg, ArgumentsRectifierReg);
masm.movePtr(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -11281,7 +11262,7 @@ ICTableSwitch::Compiler::generateStubCode(MacroAssembler& masm)
// If the function returns |true|, the value has been converted to
// int32.
masm.mov(ReturnReg, scratch);
masm.movePtr(ReturnReg, scratch);
masm.popValue(R0);
masm.branchIfFalseBool(scratch, &outOfRange);
masm.unboxInt32(R0, key);
@@ -12411,7 +12392,7 @@ ICCall_Native::ICCall_Native(JitCode* stubCode, ICStub* firstMonitorStub,
templateObject_(templateObject),
pcOffset_(pcOffset)
{
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
// The simulator requires VM calls to be redirected to a special swi
// instruction to handle them. To make this work, we store the redirected
// pointer in the stub.
@@ -12437,7 +12418,7 @@ ICCall_ClassHook::ICCall_ClassHook(JitCode* stubCode, ICStub* firstMonitorStub,
templateObject_(templateObject),
pcOffset_(pcOffset)
{
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
// The simulator requires VM calls to be redirected to a special swi
// instruction to handle them. To make this work, we store the redirected
// pointer in the stub.
@@ -12575,10 +12556,10 @@ static bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICRest_Fallback*
unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
Value* rest = frame->argv() + numFormals;
ArrayObject* obj = NewDenseCopiedArray(cx, numRest, rest, nullptr);
JSObject* obj = ObjectGroup::newArrayObject(cx, rest, numRest, GenericObject,
ObjectGroup::NewArrayKind::UnknownIndex);
if (!obj)
return false;
ObjectGroup::fixRestArgumentsGroup(cx, obj);
res.setObject(*obj);
return true;
}
+17 -10
View File
@@ -609,6 +609,11 @@ class ICNewArray_Fallback : public ICFallbackStub
HeapPtrObjectGroup& templateGroup() {
return templateGroup_;
}
void setTemplateGroup(ObjectGroup* group) {
templateObject_ = nullptr;
templateGroup_ = group;
}
};
class ICNewObject_Fallback : public ICFallbackStub
@@ -1940,7 +1945,7 @@ class ICGetElem_UnboxedArray : public ICMonitoredStub
: ICStubCompiler(cx, ICStub::GetElem_UnboxedArray, Engine::Baseline),
firstMonitorStub_(firstMonitorStub),
group_(cx, group),
elementType_(group->unboxedLayout().elementType())
elementType_(group->unboxedLayoutDontCheckGeneration().elementType())
{}
ICStub* getStub(ICStubSpace* space) {
@@ -2152,7 +2157,9 @@ class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub
: ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArray, Engine::Baseline),
shape_(cx, shape),
group_(cx, group),
unboxedType_(shape ? JSVAL_TYPE_MAGIC : group->unboxedLayout().elementType())
unboxedType_(shape
? JSVAL_TYPE_MAGIC
: group->unboxedLayoutDontCheckGeneration().elementType())
{}
ICUpdatedStub* getStub(ICStubSpace* space) {
@@ -4610,8 +4617,8 @@ class ICCall_Native : public ICMonitoredStub
HeapPtrObject templateObject_;
uint32_t pcOffset_;
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
void* native_;
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
void *native_;
#endif
ICCall_Native(JitCode* stubCode, ICStub* firstMonitorStub,
@@ -4636,7 +4643,7 @@ class ICCall_Native : public ICMonitoredStub
return offsetof(ICCall_Native, pcOffset_);
}
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
static size_t offsetOfNative() {
return offsetof(ICCall_Native, native_);
}
@@ -4912,10 +4919,10 @@ class ICCall_StringSplit : public ICMonitoredStub
uint32_t pcOffset_;
HeapPtrString expectedThis_;
HeapPtrString expectedArg_;
HeapPtrArrayObject templateObject_;
HeapPtrObject templateObject_;
ICCall_StringSplit(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset, JSString* thisString,
JSString* argString, ArrayObject* templateObject)
JSString* argString, JSObject* templateObject)
: ICMonitoredStub(ICStub::Call_StringSplit, stubCode, firstMonitorStub),
pcOffset_(pcOffset), expectedThis_(thisString), expectedArg_(argString),
templateObject_(templateObject)
@@ -4942,7 +4949,7 @@ class ICCall_StringSplit : public ICMonitoredStub
return expectedArg_;
}
HeapPtrArrayObject& templateObject() {
HeapPtrObject& templateObject() {
return templateObject_;
}
@@ -4952,7 +4959,7 @@ class ICCall_StringSplit : public ICMonitoredStub
uint32_t pcOffset_;
RootedString expectedThis_;
RootedString expectedArg_;
RootedArrayObject templateObject_;
RootedObject templateObject_;
bool generateStubCode(MacroAssembler& masm);
@@ -4969,7 +4976,7 @@ class ICCall_StringSplit : public ICMonitoredStub
pcOffset_(pcOffset),
expectedThis_(cx, thisString),
expectedArg_(cx, argString),
templateObject_(cx, &templateObject.toObject().as<ArrayObject>())
templateObject_(cx, &templateObject.toObject())
{ }
ICStub* getStub(ICStubSpace* space) {
+5 -1
View File
@@ -10,6 +10,8 @@
#include "jit/BaselineIC.h"
#include "vm/ObjectGroup-inl.h"
using namespace js;
using namespace js::jit;
@@ -519,7 +521,7 @@ BaselineInspector::getTemplateObjectForNative(jsbytecode* pc, Native native)
bool
BaselineInspector::isOptimizableCallStringSplit(jsbytecode* pc, JSString** stringOut, JSString** stringArg,
NativeObject** objOut)
JSObject** objOut)
{
if (!hasBaselineScript())
return false;
@@ -731,6 +733,7 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
return MIRType_Value;
case ICStub::GetProp_ArrayLength:
case ICStub::GetProp_UnboxedArrayLength:
case ICStub::GetProp_Native:
case ICStub::GetProp_NativeDoesNotExist:
case ICStub::GetProp_NativePrototype:
@@ -748,6 +751,7 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
case ICStub::GetElem_String:
case ICStub::GetElem_Dense:
case ICStub::GetElem_TypedArray:
case ICStub::GetElem_UnboxedArray:
stubType = MIRType_Object;
break;
+1 -1
View File
@@ -113,7 +113,7 @@ class BaselineInspector
bool hasSeenNonStringIterMore(jsbytecode* pc);
bool isOptimizableCallStringSplit(jsbytecode* pc, JSString** stringOut, JSString** stringArg,
NativeObject** objOut);
JSObject** objOut);
JSObject* getTemplateObject(jsbytecode* pc);
JSObject* getTemplateObjectForNative(jsbytecode* pc, Native native);
JSObject* getTemplateObjectForClassHook(jsbytecode* pc, const Class* clasp);
+123 -90
View File
@@ -189,7 +189,7 @@ CodeGenerator::visitValueToInt32(LValueToInt32* lir)
Register stringReg;
if (input->mightBeType(MIRType_String)) {
stringReg = ToRegister(lir->temp());
OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg),
OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(stringReg),
StoreFloatRegisterTo(temp));
stringEntry = oolString->entry();
stringRejoin = oolString->rejoin();
@@ -850,7 +850,7 @@ CodeGenerator::visitIntToString(LIntToString* lir)
Register input = ToRegister(lir->input());
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input),
OutOfLineCode* ool = oolCallVM(IntToStringInfo, lir, ArgList(input),
StoreRegisterTo(output));
emitIntToString(input, output, ool->entry());
@@ -868,7 +868,7 @@ CodeGenerator::visitDoubleToString(LDoubleToString* lir)
Register temp = ToRegister(lir->tempInt());
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(DoubleToStringInfo, lir, (ArgList(), input),
OutOfLineCode* ool = oolCallVM(DoubleToStringInfo, lir, ArgList(input),
StoreRegisterTo(output));
// Try double to integer conversion and run integer to string code.
@@ -887,7 +887,7 @@ CodeGenerator::visitValueToString(LValueToString* lir)
ValueOperand input = ToValue(lir, LValueToString::Input);
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(PrimitiveToStringInfo, lir, (ArgList(), input),
OutOfLineCode* ool = oolCallVM(PrimitiveToStringInfo, lir, ArgList(input),
StoreRegisterTo(output));
Label done;
@@ -982,7 +982,7 @@ CodeGenerator::visitValueToObjectOrNull(LValueToObjectOrNull* lir)
ValueOperand input = ToValue(lir, LValueToObjectOrNull::Input);
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(ToObjectInfo, lir, (ArgList(), input, Imm32(0)),
OutOfLineCode* ool = oolCallVM(ToObjectInfo, lir, ArgList(input, Imm32(0)),
StoreRegisterTo(output));
Label done;
@@ -1701,7 +1701,7 @@ CodeGenerator::visitLambda(LLambda* lir)
Register tempReg = ToRegister(lir->temp());
const LambdaFunctionInfo& info = lir->mir()->info();
OutOfLineCode* ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(info.fun), scopeChain),
OutOfLineCode* ool = oolCallVM(LambdaInfo, lir, ArgList(ImmGCPtr(info.fun), scopeChain),
StoreRegisterTo(output));
MOZ_ASSERT(!info.singletonType);
@@ -2208,8 +2208,14 @@ CodeGenerator::visitMoveGroup(LMoveGroup* group)
masm.propagateOOM(resolver.resolve());
MoveEmitter emitter(masm);
#ifdef JS_CODEGEN_X86
if (group->maybeScratchRegister().isGeneralReg())
emitter.setScratchRegister(group->maybeScratchRegister().toGeneralReg()->reg());
else
resolver.sortMemoryToMemoryMoves();
#endif
emitter.emit(resolver);
emitter.finish();
}
@@ -2509,7 +2515,7 @@ CodeGenerator::visitConvertElementsToDoubles(LConvertElementsToDoubles* lir)
Register elements = ToRegister(lir->elements());
OutOfLineCode* ool = oolCallVM(ConvertElementsToDoublesInfo, lir,
(ArgList(), elements), StoreNothing());
ArgList(elements), StoreNothing());
Address convertedAddress(elements, ObjectElements::offsetOfFlags());
Imm32 bit(ObjectElements::CONVERT_DOUBLE_ELEMENTS);
@@ -2555,7 +2561,7 @@ CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir)
Register temp = ToRegister(lir->temp());
OutOfLineCode* ool = oolCallVM(CopyElementsForWriteInfo, lir,
(ArgList(), object), StoreNothing());
ArgList(object), StoreNothing());
if (lir->mir()->checkNative()) {
masm.loadObjClass(object, temp);
@@ -4109,9 +4115,20 @@ typedef JSObject* (*NewArrayOperationFn)(JSContext*, HandleScript, jsbytecode*,
static const VMFunction NewArrayOperationInfo =
FunctionInfo<NewArrayOperationFn>(NewArrayOperation);
typedef ArrayObject* (*NewDenseArrayFn)(ExclusiveContext*, uint32_t, HandleObjectGroup,
AllocatingBehaviour, bool);
static const VMFunction NewDenseArrayInfo = FunctionInfo<NewDenseArrayFn>(NewDenseArray);
static JSObject*
NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group,
bool convertDoubleElements)
{
JSObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
if (!res)
return nullptr;
if (convertDoubleElements)
res->as<ArrayObject>().setShouldConvertDoubleElements();
return res;
}
typedef JSObject* (*NewArrayWithGroupFn)(JSContext*, uint32_t, HandleObjectGroup, bool);
static const VMFunction NewArrayWithGroupInfo = FunctionInfo<NewArrayWithGroupFn>(NewArrayWithGroup);
void
CodeGenerator::visitNewArrayCallVM(LNewArray* lir)
@@ -4123,13 +4140,12 @@ CodeGenerator::visitNewArrayCallVM(LNewArray* lir)
JSObject* templateObject = lir->mir()->templateObject();
if (templateObject && !templateObject->is<UnboxedArrayObject>()) {
if (templateObject) {
pushArg(Imm32(lir->mir()->convertDoubleElements()));
pushArg(Imm32(lir->mir()->allocatingBehaviour()));
pushArg(ImmGCPtr(templateObject->group()));
pushArg(Imm32(lir->mir()->count()));
callVM(NewDenseArrayInfo, lir);
callVM(NewArrayWithGroupInfo, lir);
} else {
pushArg(Imm32(GenericObject));
pushArg(Imm32(lir->mir()->count()));
@@ -4244,7 +4260,7 @@ CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir)
// If we have a template object, we can inline call object creation.
OutOfLineCode* ool = oolCallVM(NewArrayCopyOnWriteInfo, lir,
(ArgList(), ImmGCPtr(templateObject), Imm32(initialHeap)),
ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
StoreRegisterTo(objReg));
masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
@@ -4252,7 +4268,7 @@ CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir)
masm.bind(ool->rejoin());
}
typedef ArrayObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
typedef JSObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
static const VMFunction ArrayConstructorOneArgInfo =
FunctionInfo<ArrayConstructorOneArgFn>(ArrayConstructorOneArg);
@@ -4263,32 +4279,47 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
ArrayObject* templateObject = lir->mir()->templateObject();
JSObject* templateObject = lir->mir()->templateObject();
gc::InitialHeap initialHeap = lir->mir()->initialHeap();
OutOfLineCode* ool = oolCallVM(ArrayConstructorOneArgInfo, lir,
(ArgList(), ImmGCPtr(templateObject->group()), lengthReg),
ArgList(ImmGCPtr(templateObject->group()), lengthReg),
StoreRegisterTo(objReg));
size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
size_t inlineLength = numSlots >= ObjectElements::VALUES_PER_HEADER
? numSlots - ObjectElements::VALUES_PER_HEADER
: 0;
bool canInline = true;
size_t inlineLength = 0;
if (templateObject->is<ArrayObject>()) {
if (templateObject->as<ArrayObject>().hasFixedElements()) {
size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
} else {
canInline = false;
}
} else {
if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
size_t nbytes =
templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements();
inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize();
} else {
canInline = false;
}
}
// Try to do the allocation inline if the template object is big enough
// for the length in lengthReg. If the length is bigger we could still
// use the template object and not allocate the elements, but it's more
// efficient to do a single big allocation than (repeatedly) reallocating
// the array later on when filling it.
if (!templateObject->isSingleton() && templateObject->length() <= inlineLength)
masm.branch32(Assembler::Above, lengthReg, Imm32(templateObject->length()), ool->entry());
else
if (canInline) {
// Try to do the allocation inline if the template object is big enough
// for the length in lengthReg. If the length is bigger we could still
// use the template object and not allocate the elements, but it's more
// efficient to do a single big allocation than (repeatedly) reallocating
// the array later on when filling it.
masm.branch32(Assembler::Above, lengthReg, Imm32(inlineLength), ool->entry());
masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
size_t lengthOffset = NativeObject::offsetOfFixedElements() + ObjectElements::offsetOfLength();
masm.store32(lengthReg, Address(objReg, lengthOffset));
} else {
masm.jump(ool->entry());
masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
size_t lengthOffset = NativeObject::offsetOfFixedElements() + ObjectElements::offsetOfLength();
masm.store32(lengthReg, Address(objReg, lengthOffset));
}
masm.bind(ool->rejoin());
}
@@ -4489,7 +4520,7 @@ CodeGenerator::visitNewTypedObject(LNewTypedObject* lir)
gc::InitialHeap initialHeap = lir->mir()->initialHeap();
OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObject), Imm32(initialHeap)),
ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
StoreRegisterTo(object));
masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
@@ -4511,7 +4542,7 @@ CodeGenerator::visitSimdBox(LSimdBox* lir)
MOZ_ASSERT(lir->safepoint()->liveRegs().has(in),
"Save the input register across the oolCallVM");
OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObject), Imm32(initialHeap)),
ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
StoreRegisterTo(object));
masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
@@ -4635,8 +4666,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject* lir)
// If we have a template object, we can inline call object creation.
OutOfLineCode* ool = oolCallVM(NewDeclEnvObjectInfo, lir,
(ArgList(), ImmGCPtr(info.funMaybeLazy()),
Imm32(gc::DefaultHeap)),
ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(gc::DefaultHeap)),
StoreRegisterTo(objReg));
bool initContents = ShouldInitFixedSlots(lir, templateObj);
@@ -4661,9 +4691,9 @@ CodeGenerator::visitNewCallObject(LNewCallObject* lir)
JSScript* script = lir->mir()->block()->info().script();
uint32_t lexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin();
OutOfLineCode* ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->group()),
Imm32(lexicalBegin)),
ArgList(ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->group()),
Imm32(lexicalBegin)),
StoreRegisterTo(objReg));
// Inline call object creation, using the OOL path only for tricky cases.
@@ -4689,8 +4719,8 @@ CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject* lir)
uint32_t lexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin();
OutOfLineCode* ool;
ool = oolCallVM(NewSingletonCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->as<CallObject>().lastProperty()),
Imm32(lexicalBegin)),
ArgList(ImmGCPtr(templateObj->as<CallObject>().lastProperty()),
Imm32(lexicalBegin)),
StoreRegisterTo(objReg));
// Objects can only be given singleton types in VM calls. We make the call
@@ -4712,7 +4742,7 @@ CodeGenerator::visitNewStringObject(LNewStringObject* lir)
StringObject* templateObj = lir->mir()->templateObj();
OutOfLineCode* ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input),
OutOfLineCode* ool = oolCallVM(NewStringObjectInfo, lir, ArgList(input),
StoreRegisterTo(output));
masm.createGCObject(output, temp, templateObj, gc::DefaultHeap, ool->entry());
@@ -4864,7 +4894,7 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate* lir)
Register tempReg = ToRegister(lir->temp());
OutOfLineCode* ool = oolCallVM(NewInitObjectWithTemplateInfo, lir,
(ArgList(), ImmGCPtr(templateObject)),
ArgList(ImmGCPtr(templateObject)),
StoreRegisterTo(objReg));
// Allocate. If the FreeList is empty, call to VM, which may GC.
@@ -4967,7 +4997,7 @@ CodeGenerator::visitComputeThis(LComputeThis* lir)
ValueOperand value = ToValue(lir, LComputeThis::ValueIndex);
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, (ArgList(), value),
OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, ArgList(value),
StoreRegisterTo(output));
masm.branchTestObject(Assembler::NotEqual, value, ool->entry());
@@ -5193,21 +5223,6 @@ CodeGenerator::visitPowD(LPowD* ins)
MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
}
void
CodeGenerator::visitRandom(LRandom* ins)
{
Register temp = ToRegister(ins->temp());
Register temp2 = ToRegister(ins->temp2());
masm.loadJSContext(temp);
masm.setupUnalignedABICall(1, temp2);
masm.passABIArg(temp);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
}
void
CodeGenerator::visitMathFunctionD(LMathFunctionD* ins)
{
@@ -5410,10 +5425,10 @@ CodeGenerator::emitCompareS(LInstruction* lir, JSOp op, Register left, Register
OutOfLineCode* ool = nullptr;
if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
ool = oolCallVM(StringsEqualInfo, lir, (ArgList(), left, right), StoreRegisterTo(output));
ool = oolCallVM(StringsEqualInfo, lir, ArgList(left, right), StoreRegisterTo(output));
} else {
MOZ_ASSERT(op == JSOP_NE || op == JSOP_STRICTNE);
ool = oolCallVM(StringsNotEqualInfo, lir, (ArgList(), left, right), StoreRegisterTo(output));
ool = oolCallVM(StringsNotEqualInfo, lir, ArgList(left, right), StoreRegisterTo(output));
}
masm.compareStrings(op, left, right, output, ool->entry());
@@ -5764,7 +5779,7 @@ static const VMFunction ConcatStringsInfo = FunctionInfo<ConcatStringsFn>(Concat
void
CodeGenerator::emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output)
{
OutOfLineCode* ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
OutOfLineCode* ool = oolCallVM(ConcatStringsInfo, lir, ArgList(lhs, rhs),
StoreRegisterTo(output));
JitCode* stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier();
@@ -5954,8 +5969,8 @@ CodeGenerator::visitSubstr(LSubstr* lir)
// can be handled by allocate in ool code and returning to jit code to fill
// in all data.
OutOfLineCode* ool = oolCallVM(SubstringKernelInfo, lir,
(ArgList(), string, begin, length),
StoreRegisterTo(output));
ArgList(string, begin, length),
StoreRegisterTo(output));
Label* slowPath = ool->entry();
Label* done = ool->rejoin();
@@ -6283,7 +6298,7 @@ CodeGenerator::visitCharCodeAt(LCharCodeAt* lir)
Register index = ToRegister(lir->index());
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(CharCodeAtInfo, lir, (ArgList(), str, index), StoreRegisterTo(output));
OutOfLineCode* ool = oolCallVM(CharCodeAtInfo, lir, ArgList(str, index), StoreRegisterTo(output));
masm.branchIfRope(str, ool->entry());
masm.loadStringChar(str, index, output);
@@ -6300,7 +6315,7 @@ CodeGenerator::visitFromCharCode(LFromCharCode* lir)
Register code = ToRegister(lir->code());
Register output = ToRegister(lir->output());
OutOfLineCode* ool = oolCallVM(StringFromCharCodeInfo, lir, (ArgList(), code), StoreRegisterTo(output));
OutOfLineCode* ool = oolCallVM(StringFromCharCodeInfo, lir, ArgList(code), StoreRegisterTo(output));
// OOL path if code >= UNIT_STATIC_LIMIT.
masm.branch32(Assembler::AboveOrEqual, code, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
@@ -6368,6 +6383,25 @@ CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArra
masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
}
void
CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
Int32Key key = ToInt32Key(lir->length());
Register temp = ToRegister(lir->temp());
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLengthAddr, temp);
masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp);
if (key.isRegister())
masm.or32(key.reg(), temp);
else
masm.or32(Imm32(key.constant()), temp);
masm.store32(temp, initLengthAddr);
}
void
CodeGenerator::visitNotO(LNotO* lir)
{
@@ -6922,7 +6956,7 @@ CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative*
OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray()
? ConvertUnboxedArrayObjectToNativeInfo
: ConvertUnboxedPlainObjectToNativeInfo,
lir, (ArgList(), object), StoreNothing());
lir, ArgList(object), StoreNothing());
masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(lir->mir()->group()), ool->entry());
@@ -6940,10 +6974,10 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
OutOfLineCode* ool;
if (mir->mode() == MArrayPopShift::Pop) {
ool = oolCallVM(ArrayPopDenseInfo, lir, (ArgList(), obj), StoreValueTo(out));
ool = oolCallVM(ArrayPopDenseInfo, lir, ArgList(obj), StoreValueTo(out));
} else {
MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
ool = oolCallVM(ArrayShiftDenseInfo, lir, (ArgList(), obj), StoreValueTo(out));
ool = oolCallVM(ArrayShiftDenseInfo, lir, ArgList(obj), StoreValueTo(out));
}
// VM call if a write barrier is necessary.
@@ -7064,7 +7098,7 @@ void
CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register obj,
ConstantOrRegister value, Register elementsTemp, Register length)
{
OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, (ArgList(), obj, value), StoreRegisterTo(length));
OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
Int32Key key = Int32Key(length);
if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
@@ -7254,7 +7288,7 @@ CodeGenerator::visitIteratorStart(LIteratorStart* lir)
uint32_t flags = lir->mir()->flags();
OutOfLineCode* ool = oolCallVM(GetIteratorObjectInfo, lir,
(ArgList(), obj, Imm32(flags)), StoreRegisterTo(output));
ArgList(obj, Imm32(flags)), StoreRegisterTo(output));
const Register temp1 = ToRegister(lir->temp1());
const Register temp2 = ToRegister(lir->temp2());
@@ -7383,7 +7417,7 @@ CodeGenerator::visitIteratorMore(LIteratorMore* lir)
const ValueOperand output = ToOutValue(lir);
const Register temp = ToRegister(lir->temp());
OutOfLineCode* ool = oolCallVM(IteratorMoreInfo, lir, (ArgList(), obj), StoreValueTo(output));
OutOfLineCode* ool = oolCallVM(IteratorMoreInfo, lir, ArgList(obj), StoreValueTo(output));
Register outputScratch = output.scratchReg();
LoadNativeIterator(masm, obj, outputScratch, ool->entry());
@@ -7438,7 +7472,7 @@ CodeGenerator::visitIteratorEnd(LIteratorEnd* lir)
const Register temp2 = ToRegister(lir->temp2());
const Register temp3 = ToRegister(lir->temp3());
OutOfLineCode* ool = oolCallVM(CloseIteratorInfo, lir, (ArgList(), obj), StoreNothing());
OutOfLineCode* ool = oolCallVM(CloseIteratorInfo, lir, ArgList(obj), StoreNothing());
LoadNativeIterator(masm, obj, temp1, ool->entry());
@@ -8797,11 +8831,10 @@ CodeGenerator::visitToIdV(LToIdV* lir)
ValueOperand index = ToValue(lir, LToIdV::Index);
OutOfLineCode* ool = oolCallVM(ToIdInfo, lir,
(ArgList(),
ImmGCPtr(current->mir()->info().script()),
ImmPtr(lir->mir()->resumePoint()->pc()),
ToValue(lir, LToIdV::Object),
ToValue(lir, LToIdV::Index)),
ArgList(ImmGCPtr(current->mir()->info().script()),
ImmPtr(lir->mir()->resumePoint()->pc()),
ToValue(lir, LToIdV::Object),
ToValue(lir, LToIdV::Index)),
StoreValueTo(out));
Register tag = masm.splitTagForTest(index);
@@ -9274,7 +9307,7 @@ CodeGenerator::visitClampVToUint8(LClampVToUint8* lir)
Label* stringEntry;
Label* stringRejoin;
if (input->mightBeType(MIRType_String)) {
OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), output),
OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(output),
StoreFloatRegisterTo(tempFloat));
stringEntry = oolString->entry();
stringRejoin = oolString->rejoin();
@@ -9326,13 +9359,13 @@ CodeGenerator::visitInArray(LInArray* lir)
MOZ_ASSERT_IF(index < 0, mir->needsNegativeIntCheck());
if (mir->needsNegativeIntCheck()) {
ool = oolCallVM(OperatorInIInfo, lir,
(ArgList(), Imm32(index), ToRegister(lir->object())),
ArgList(Imm32(index), ToRegister(lir->object())),
StoreRegisterTo(output));
failedInitLength = ool->entry();
}
masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength);
if (mir->needsHoleCheck()) {
if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
NativeObject::elementsSizeMustNotOverflow();
Address address = Address(elements, index * sizeof(Value));
masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
@@ -9345,7 +9378,7 @@ CodeGenerator::visitInArray(LInArray* lir)
failedInitLength = &negativeIntCheck;
masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength);
if (mir->needsHoleCheck()) {
if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight);
masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
}
@@ -9354,7 +9387,7 @@ CodeGenerator::visitInArray(LInArray* lir)
if (mir->needsNegativeIntCheck()) {
masm.bind(&negativeIntCheck);
ool = oolCallVM(OperatorInIInfo, lir,
(ArgList(), index, ToRegister(lir->object())),
ArgList(index, ToRegister(lir->object())),
StoreRegisterTo(output));
masm.branch32(Assembler::LessThan, index, Imm32(0), ool->entry());
@@ -9456,7 +9489,7 @@ CodeGenerator::emitInstanceOf(LInstruction* ins, JSObject* prototypeObject)
// register is already correct.
OutOfLineCode* ool = oolCallVM(IsDelegateObjectInfo, ins,
(ArgList(), ImmGCPtr(prototypeObject), objReg),
ArgList(ImmGCPtr(prototypeObject), objReg),
StoreRegisterTo(output));
// Regenerate the original lhs object for the VM call.
@@ -9988,7 +10021,7 @@ CodeGenerator::visitAssertRangeV(LAssertRangeV* ins)
void
CodeGenerator::visitInterruptCheck(LInterruptCheck* lir)
{
OutOfLineCode* ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
OutOfLineCode* ool = oolCallVM(InterruptCheckInfo, lir, ArgList(), StoreNothing());
AbsoluteAddress interruptAddr(GetJitContext()->runtime->addressOfInterruptUint32());
masm.branch32(Assembler::NotEqual, interruptAddr, Imm32(0), ool->entry());
@@ -10024,9 +10057,9 @@ CodeGenerator::visitRecompileCheck(LRecompileCheck* ins)
Register tmp = ToRegister(ins->scratch());
OutOfLineCode* ool;
if (ins->mir()->forceRecompilation())
ool = oolCallVM(ForcedRecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
ool = oolCallVM(ForcedRecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
else
ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
ool = oolCallVM(RecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
// Check if warm-up counter is high enough.
AbsoluteAddress warmUpCount = AbsoluteAddress(ins->mir()->script()->addressOfWarmUpCounter());
+4 -4
View File
@@ -196,6 +196,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitUnboxedArrayLength(LUnboxedArrayLength* lir);
void visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir);
void visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir);
void visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir);
void visitNotO(LNotO* ins);
void visitNotV(LNotV* ins);
void visitBoundsCheck(LBoundsCheck* lir);
@@ -219,10 +220,9 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitHypot(LHypot* lir);
void visitPowI(LPowI* lir);
void visitPowD(LPowD* lir);
void visitRandom(LRandom* lir);
void visitMathFunctionD(LMathFunctionD *ins);
void visitMathFunctionF(LMathFunctionF *ins);
void visitModD(LModD *ins);
void visitMathFunctionD(LMathFunctionD* ins);
void visitMathFunctionF(LMathFunctionF* ins);
void visitModD(LModD* ins);
void visitMinMaxI(LMinMaxI* lir);
void visitBinaryV(LBinaryV* lir);
void emitCompareS(LInstruction* lir, JSOp op, Register left, Register right, Register output);
+27 -13
View File
@@ -1350,16 +1350,14 @@ OptimizeMIR(MIRGenerator* mir)
return false;
}
if (mir->optimizationInfo().scalarReplacementEnabled()) {
AutoTraceLog log(logger, TraceLogger_ScalarReplacement);
if (!ScalarReplacement(mir, graph))
return false;
gs.spewPass("Scalar Replacement");
AssertGraphCoherency(graph);
ValueNumberer gvn(mir, graph);
if (!gvn.init())
return false;
if (mir->shouldCancel("Scalar Replacement"))
return false;
}
size_t doRepeatOptimizations = 0;
repeatOptimizations:
doRepeatOptimizations++;
MOZ_ASSERT(doRepeatOptimizations <= 2);
if (!mir->compilingAsmJS()) {
AutoTraceLog log(logger, TraceLogger_ApplyTypes);
@@ -1395,10 +1393,6 @@ OptimizeMIR(MIRGenerator* mir)
return false;
}
ValueNumberer gvn(mir, graph);
if (!gvn.init())
return false;
// Alias analysis is required for LICM and GVN so that we don't move
// loads across stores.
if (mir->optimizationInfo().licmEnabled() ||
@@ -1454,6 +1448,26 @@ OptimizeMIR(MIRGenerator* mir)
}
}
if (mir->optimizationInfo().scalarReplacementEnabled() && doRepeatOptimizations <= 1) {
AutoTraceLog log(logger, TraceLogger_ScalarReplacement);
bool success = false;
if (!ScalarReplacement(mir, graph, &success))
return false;
gs.spewPass("Scalar Replacement");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Scalar Replacement"))
return false;
// We got some success at removing objects allocation and removing the
// loads and stores, unfortunately, this phase is terrible at keeping
// the type consistency, so we re-run the Apply Type phase. As this
// optimization folds loads and stores, it might also introduce new
// opportunities for GVN and LICM, so re-run them as well.
if (success)
goto repeatOptimizations;
}
if (mir->optimizationInfo().rangeAnalysisEnabled()) {
AutoTraceLog log(logger, TraceLogger_RangeAnalysis);
RangeAnalysis r(mir, graph);
+156 -126
View File
@@ -29,7 +29,9 @@
#include "jit/CompileInfo-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/ObjectGroup-inl.h"
#include "vm/ScopeObject-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;
using namespace js::jit;
@@ -6199,9 +6201,6 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
bool
IonBuilder::testShouldDOMCall(TypeSet* inTypes, JSFunction* func, JSJitInfo::OpType opType)
{
if (IsInsideNursery(func))
return false;
if (!func->isNative() || !func->jitInfo())
return false;
@@ -6521,8 +6520,7 @@ IonBuilder::jsop_newarray(uint32_t count)
}
current->add(templateConst);
MNewArray* ins = MNewArray::New(alloc(), constraints(), count, templateConst,
heap, NewArray_FullyAllocating, pc);
MNewArray* ins = MNewArray::New(alloc(), constraints(), count, templateConst, heap, pc);
current->add(ins);
current->push(ins);
@@ -6640,7 +6638,15 @@ IonBuilder::jsop_initelem_array()
return resumeAfter(store);
}
MConstant* id = MConstant::New(alloc(), Int32Value(GET_UINT24(pc)));
return initializeArrayElement(obj, GET_UINT24(pc), value, unboxedType, /* addResumePoint = */ true);
}
bool
IonBuilder::initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value,
JSValueType unboxedType,
bool addResumePointAndIncrementInitializedLength)
{
MConstant* id = MConstant::New(alloc(), Int32Value(index));
current->add(id);
// Get the elements vector.
@@ -6651,11 +6657,13 @@ IonBuilder::jsop_initelem_array()
// Note: storeUnboxedValue takes care of any post barriers on the value.
storeUnboxedValue(obj, elements, 0, id, unboxedType, value, /* preBarrier = */ false);
MInstruction* increment = MIncrementUnboxedArrayInitializedLength::New(alloc(), obj);
current->add(increment);
if (addResumePointAndIncrementInitializedLength) {
MInstruction* increment = MIncrementUnboxedArrayInitializedLength::New(alloc(), obj);
current->add(increment);
if (!resumeAfter(increment))
return false;
if (!resumeAfter(increment))
return false;
}
} else {
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
@@ -6671,14 +6679,16 @@ IonBuilder::jsop_initelem_array()
/* needsHoleCheck = */ false);
current->add(store);
// Update the initialized length. (The template object for this array has
// the array's ultimate length, so the length field is already correct: no
// updating needed.)
MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id);
current->add(initLength);
if (addResumePointAndIncrementInitializedLength) {
// Update the initialized length. (The template object for this
// array has the array's ultimate length, so the length field is
// already correct: no updating needed.)
MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id);
current->add(initLength);
if (!resumeAfter(initLength))
return false;
if (!resumeAfter(initLength))
return false;
}
}
return true;
@@ -7477,6 +7487,8 @@ bool
IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded,
MDefinition* lexicalCheck)
{
MOZ_ASSERT(*psucceeded == false);
jsid id = NameToId(name);
MOZ_ASSERT(staticObject->is<GlobalObject>() || staticObject->is<CallObject>());
@@ -7558,8 +7570,13 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc
if (barrier != BarrierKind::NoBarrier)
rvalType = MIRType_Value;
return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
rvalType, barrier, types);
if (!loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
rvalType, barrier, types)) {
*psucceeded = false;
return false;
}
return true;
}
// Whether a write of the given value may need a post-write barrier for GC purposes.
@@ -7623,19 +7640,21 @@ bool
IonBuilder::jsop_getgname(PropertyName* name)
{
JSObject* obj = &script()->global();
bool succeeded;
if (!getStaticName(obj, name, &succeeded))
return false;
if (succeeded)
return true;
bool emitted = false;
if (!getStaticName(obj, name, &emitted) || emitted)
return emitted;
TemporaryTypeSet* types = bytecodeTypes(pc);
MDefinition* globalObj = constant(ObjectValue(*obj));
if (!getPropTryCommonGetter(&succeeded, globalObj, name, types))
return false;
if (succeeded)
return true;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
{
TemporaryTypeSet* types = bytecodeTypes(pc);
MDefinition* globalObj = constant(ObjectValue(*obj));
if (!getPropTryCommonGetter(&emitted, globalObj, name, types) || emitted)
return emitted;
}
do_InlineCache:
return jsop_getname(name);
}
@@ -7759,6 +7778,8 @@ IonBuilder::jsop_getelem()
obj = maybeUnboxForPropertyAccess(obj);
bool emitted = false;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedObject);
if (!getElemTryTypedObject(&emitted, obj, index) || emitted)
@@ -7788,6 +7809,7 @@ IonBuilder::jsop_getelem()
if (!getElemTryArgumentsInlined(&emitted, obj, index) || emitted)
return emitted;
do_InlineCache:
if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_MagicOptimizedArguments))
return abort("Type is not definitely lazy arguments.");
@@ -8532,12 +8554,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
// Note: to help GVN, use the original MElements instruction and not
// MConvertElementsToDoubles as operand. This is fine because converting
// elements to double does not change the initialized length.
MInstruction* initLength;
if (unboxedType != JSVAL_TYPE_MAGIC)
initLength = MUnboxedArrayInitializedLength::New(alloc(), obj);
else
initLength = MInitializedLength::New(alloc(), elements);
current->add(initLength);
MInstruction* initLength = initializedLength(obj, elements, unboxedType);
// If we can load the element as a definite double, make sure to check that
// the array has been converted to homogenous doubles first.
@@ -8789,6 +8806,9 @@ IonBuilder::jsop_setelem()
return resumeAfter(ins);
}
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedObject);
if (!setElemTryTypedObject(&emitted, object, index, value) || emitted)
return emitted;
@@ -8801,14 +8821,19 @@ IonBuilder::jsop_setelem()
if (!setElemTryTypedArray(&emitted, object, index, value) || emitted)
return emitted;
trackOptimizationAttempt(TrackedStrategy::SetElem_Dense);
if (!setElemTryDense(&emitted, object, index, value) || emitted)
return emitted;
{
trackOptimizationAttempt(TrackedStrategy::SetElem_Dense);
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
bool writeHole = icInspect.sawOOBDenseWrite();
if (!setElemTryDense(&emitted, object, index, value, writeHole) || emitted)
return emitted;
}
trackOptimizationAttempt(TrackedStrategy::SetElem_Arguments);
if (!setElemTryArguments(&emitted, object, index, value) || emitted)
return emitted;
do_InlineCache:
if (script()->argumentsHasVarBinding() &&
object->mightBeType(MIRType_MagicOptimizedArguments) &&
info().analysisMode() != Analysis_ArgumentsUsage)
@@ -8995,7 +9020,7 @@ IonBuilder::setElemTryTypedArray(bool* emitted, MDefinition* object,
}
// Emit typed setelem variant.
if (!jsop_setelem_typed(arrayType, SetElem_Normal, object, index, value))
if (!jsop_setelem_typed(arrayType, object, index, value))
return false;
trackOptimizationSuccess();
@@ -9005,7 +9030,7 @@ IonBuilder::setElemTryTypedArray(bool* emitted, MDefinition* object,
bool
IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
MDefinition* index, MDefinition* value)
MDefinition* index, MDefinition* value, bool writeHole)
{
MOZ_ASSERT(*emitted == false);
@@ -9048,7 +9073,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
}
// Emit dense setelem variant.
if (!jsop_setelem_dense(conversion, SetElem_Normal, object, index, value, unboxedType))
if (!jsop_setelem_dense(conversion, object, index, value, unboxedType, writeHole))
return false;
trackOptimizationSuccess();
@@ -9134,9 +9159,8 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
bool
IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition* obj, MDefinition* id, MDefinition* value,
JSValueType unboxedType)
JSValueType unboxedType, bool writeHole)
{
MIRType elementType = MIRType_None;
if (unboxedType == JSVAL_TYPE_MAGIC)
@@ -9188,20 +9212,12 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
MOZ_CRASH("Unknown double conversion");
}
bool writeHole = false;
if (safety == SetElem_Normal) {
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
writeHole = icInspect.sawOOBDenseWrite();
}
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
// the initialized length and bounds check.
MInstruction* store;
MStoreElementCommon *common = nullptr;
if (writeHole && writeOutOfBounds) {
MOZ_ASSERT(safety == SetElem_Normal);
MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue, unboxedType);
store = ins;
common = ins;
@@ -9209,20 +9225,10 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
current->add(ins);
current->push(value);
} else {
MInstruction* initLength;
if (unboxedType != JSVAL_TYPE_MAGIC)
initLength = MUnboxedArrayInitializedLength::New(alloc(), obj);
else
initLength = MInitializedLength::New(alloc(), elements);
current->add(initLength);
MInstruction* initLength = initializedLength(obj, elements, unboxedType);
bool needsHoleCheck;
if (safety == SetElem_Normal) {
id = addBoundsCheck(id, initLength);
needsHoleCheck = !packed && !writeOutOfBounds;
} else {
needsHoleCheck = false;
}
id = addBoundsCheck(id, initLength);
bool needsHoleCheck = !packed && !writeOutOfBounds;
if (unboxedType != JSVAL_TYPE_MAGIC) {
store = storeUnboxedValue(obj, elements, 0, id, unboxedType, newValue);
@@ -9234,8 +9240,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
current->add(store);
}
if (safety == SetElem_Normal)
current->push(value);
current->push(value);
}
if (!resumeAfter(store))
@@ -9255,16 +9260,11 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
bool
IonBuilder::jsop_setelem_typed(Scalar::Type arrayType, SetElemSafety safety,
IonBuilder::jsop_setelem_typed(Scalar::Type arrayType,
MDefinition* obj, MDefinition* id, MDefinition* value)
{
bool expectOOB;
if (safety == SetElem_Normal) {
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
expectOOB = icInspect.sawOOBTypedArrayWrite();
} else {
expectOOB = false;
}
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
bool expectOOB = icInspect.sawOOBTypedArrayWrite();
if (expectOOB)
spew("Emitting OOB TypedArray SetElem");
@@ -9277,9 +9277,7 @@ IonBuilder::jsop_setelem_typed(Scalar::Type arrayType, SetElemSafety safety,
// Get length, bounds-check, then get elements, and add all instructions.
MInstruction* length;
MInstruction* elements;
BoundsChecking checking = (!expectOOB && safety == SetElem_Normal)
? DoBoundsCheck
: SkipBoundsCheck;
BoundsChecking checking = expectOOB ? SkipBoundsCheck : DoBoundsCheck;
addTypedArrayLengthAndData(obj, checking, &id, &length, &elements);
// Clamp value to [0, 255] for Uint8ClampedArray.
@@ -9300,31 +9298,11 @@ IonBuilder::jsop_setelem_typed(Scalar::Type arrayType, SetElemSafety safety,
}
current->add(ins);
if (safety == SetElem_Normal)
current->push(value);
current->push(value);
return resumeAfter(ins);
}
bool
IonBuilder::jsop_setelem_typed_object(Scalar::Type arrayType, SetElemSafety safety,
MDefinition* object, MDefinition* index, MDefinition* value)
{
MOZ_ASSERT(safety == SetElem_Unsafe); // Can be fixed, but there's been no reason to as of yet
MInstruction* intIndex = MToInt32::New(alloc(), index);
current->add(intIndex);
size_t elemSize = ScalarTypeDescr::alignment(arrayType);
LinearSum byteOffset(alloc());
if (!byteOffset.add(intIndex, elemSize))
setForceAbort();
return storeScalarTypedObjectValue(object, byteOffset, arrayType, value);
}
bool
IonBuilder::jsop_length()
{
@@ -9498,8 +9476,7 @@ IonBuilder::jsop_rest()
current->add(templateConst);
MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
templateObject->group()->initialHeap(constraints()),
NewArray_FullyAllocating, pc);
templateObject->group()->initialHeap(constraints()), pc);
current->add(array);
if (numRest == 0) {
@@ -10147,6 +10124,9 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!getPropTryInnerize(&emitted, obj, name, types) || emitted)
return emitted;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
// Try to hardcode known constants.
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
@@ -10182,6 +10162,7 @@ IonBuilder::jsop_getprop(PropertyName* name)
if (!getPropTryInlineAccess(&emitted, obj, name, barrier, types) || emitted)
return emitted;
do_InlineCache:
// Try to emit a polymorphic cache.
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineCache);
if (!getPropTryCache(&emitted, obj, name, barrier, types) || emitted)
@@ -10869,8 +10850,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
}
}
JSFunction* tenuredCommonGetter = IsInsideNursery(commonGetter) ? nullptr : commonGetter;
if (!makeCall(tenuredCommonGetter, callInfo))
if (!makeCall(commonGetter, callInfo))
return false;
// If the getter could have been inlined, don't track success. The call to
@@ -10934,11 +10914,6 @@ IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName
{
MOZ_ASSERT(*emitted == false);
if (obj->type() != MIRType_Object) {
trackOptimizationOutcome(TrackedOutcome::NotObject);
return true;
}
BaselineInspector::ReceiverVector receivers(alloc());
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups))
@@ -11176,6 +11151,9 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
if (inner == obj)
return true;
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache;
// Note: the Baseline ICs don't know about this optimization, so it's
// possible the global property's HeapTypeSet has not been initialized
// yet. In this case we'll fall back to getPropTryCache for now.
@@ -11197,6 +11175,7 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
if (!getPropTryCommonGetter(emitted, inner, name, types) || *emitted)
return *emitted;
do_InlineCache:
// Passing the inner object to GetProperty IC is safe, see the
// needsOuterizedThisObject check in IsCacheableGetPropCallNative.
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
@@ -11230,6 +11209,9 @@ IonBuilder::jsop_setprop(PropertyName* name)
return resumeAfter(ins);
}
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache_step1;
// Try to inline a common property setter, or make a call.
trackOptimizationAttempt(TrackedStrategy::SetProp_CommonSetter);
if (!setPropTryCommonSetter(&emitted, obj, name, value) || emitted)
@@ -11240,20 +11222,28 @@ IonBuilder::jsop_setprop(PropertyName* name)
if (!setPropTryTypedObject(&emitted, obj, name, value) || emitted)
return emitted;
do_InlineCache_step1:
TemporaryTypeSet* objTypes = obj->resultTypeSet();
bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value,
/* canModify = */ true);
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache_step2;
// Try to emit stores to unboxed objects.
trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
return emitted;
do_InlineCache_step2:
// Add post barrier if needed. The instructions above manage any post
// barriers they need directly.
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
goto do_InlineCache_step3;
// Try to emit store from definite slots.
trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
@@ -11264,7 +11254,9 @@ IonBuilder::jsop_setprop(PropertyName* name)
if (!setPropTryInlineAccess(&emitted, obj, name, value, barrier, objTypes) || emitted)
return emitted;
do_InlineCache_step3:
// Emit a polymorphic cache.
trackOptimizationAttempt(TrackedStrategy::SetProp_InlineCache);
return setPropTryCache(&emitted, obj, name, value, barrier, objTypes);
}
@@ -11360,8 +11352,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
}
}
JSFunction* tenuredCommonSetter = IsInsideNursery(commonSetter) ? nullptr : commonSetter;
MCall* call = makeCallHelper(tenuredCommonSetter, callInfo);
MCall* call = makeCallHelper(commonSetter, callInfo);
if (!call)
return false;
@@ -11783,6 +11774,7 @@ IonBuilder::setPropTryCache(bool* emitted, MDefinition* obj,
if (!resumeAfter(ins))
return false;
trackOptimizationSuccess();
*emitted = true;
return true;
}
@@ -12294,11 +12286,9 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
JSObject* call = nullptr;
if (hasStaticScopeObject(sc, &call) && call) {
PropertyName* name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc);
bool succeeded;
if (!getStaticName(call, name, &succeeded, takeLexicalCheck()))
return false;
if (succeeded)
return true;
bool emitted = false;
if (!getStaticName(call, name, &emitted, takeLexicalCheck()) || emitted)
return emitted;
}
// See jsop_checkaliasedlet.
@@ -12368,12 +12358,21 @@ IonBuilder::jsop_in()
MDefinition* obj = current->peek(-1);
MDefinition* id = current->peek(-2);
if (!shouldAbortOnPreliminaryGroups(obj) &&
ElementAccessIsDenseNative(constraints(), obj, id) &&
!ElementAccessHasExtraIndexedProperty(constraints(), obj))
{
return jsop_in_dense();
}
do {
if (shouldAbortOnPreliminaryGroups(obj))
break;
JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, id);
if (unboxedType == JSVAL_TYPE_MAGIC) {
if (!ElementAccessIsDenseNative(constraints(), obj, id))
break;
}
if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
break;
return jsop_in_dense(unboxedType);
} while (false);
current->pop();
current->pop();
@@ -12386,7 +12385,7 @@ IonBuilder::jsop_in()
}
bool
IonBuilder::jsop_in_dense()
IonBuilder::jsop_in_dense(JSValueType unboxedType)
{
MDefinition* obj = current->pop();
MDefinition* id = current->pop();
@@ -12399,11 +12398,10 @@ IonBuilder::jsop_in_dense()
id = idInt32;
// Get the elements vector.
MElements* elements = MElements::New(alloc(), obj);
MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC);
current->add(elements);
MInitializedLength* initLength = MInitializedLength::New(alloc(), elements);
current->add(initLength);
MInstruction* initLength = initializedLength(obj, elements, unboxedType);
// If there are no holes, speculate the InArray check will not fail.
if (!needsHoleCheck && !failedBoundsCheck_) {
@@ -12412,7 +12410,8 @@ IonBuilder::jsop_in_dense()
}
// Check if id < initLength and elem[id] not a hole.
MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck);
MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck,
unboxedType);
current->add(ins);
current->push(ins);
@@ -13048,6 +13047,37 @@ IonBuilder::constantInt(int32_t i)
return constant(Int32Value(i));
}
MInstruction*
IonBuilder::initializedLength(MDefinition* obj, MDefinition* elements, JSValueType unboxedType)
{
MInstruction* res;
if (unboxedType != JSVAL_TYPE_MAGIC)
res = MUnboxedArrayInitializedLength::New(alloc(), obj);
else
res = MInitializedLength::New(alloc(), elements);
current->add(res);
return res;
}
MInstruction*
IonBuilder::setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count)
{
MOZ_ASSERT(count);
MInstruction* res;
if (unboxedType != JSVAL_TYPE_MAGIC) {
res = MSetUnboxedArrayInitializedLength::New(alloc(), obj, constant(Int32Value(count)));
} else {
// MSetInitializedLength takes the index of the last element, rather
// than the count itself.
MInstruction* elements = MElements::New(alloc(), obj, /* unboxed = */ false);
current->add(elements);
res = MSetInitializedLength::New(alloc(), elements, constant(Int32Value(count - 1)));
}
current->add(res);
return res;
}
MDefinition*
IonBuilder::getCallee()
{
+11 -29
View File
@@ -46,16 +46,6 @@ class IonBuilder
ControlStatus_None // No control flow.
};
enum SetElemSafety {
// Normal write like a[b] = c.
SetElem_Normal,
// Write due to UnsafePutElements:
// - assumed to be in bounds,
// - not checked for data races
SetElem_Unsafe,
};
struct DeferredEdge : public TempObject
{
MBasicBlock* block;
@@ -352,6 +342,9 @@ class IonBuilder
MConstant* constant(const Value& v);
MConstant* constantInt(int32_t i);
MInstruction* initializedLength(MDefinition* obj, MDefinition* elements,
JSValueType unboxedType);
MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count);
// Improve the type information at tests
bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test);
@@ -548,7 +541,7 @@ class IonBuilder
bool setElemTryTypedStatic(bool* emitted, MDefinition* object,
MDefinition* index, MDefinition* value);
bool setElemTryDense(bool* emitted, MDefinition* object,
MDefinition* index, MDefinition* value);
MDefinition* index, MDefinition* value, bool writeHole);
bool setElemTryArguments(bool* emitted, MDefinition* object,
MDefinition* index, MDefinition* value);
bool setElemTryCache(bool* emitted, MDefinition* object,
@@ -566,6 +559,9 @@ class IonBuilder
MDefinition* value,
TypedObjectPrediction elemTypeReprs,
int32_t elemSize);
bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value,
JSValueType unboxedType,
bool addResumePointAndIncrementInitializedLength);
// jsop_getelem() helpers.
bool getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index);
@@ -661,15 +657,10 @@ class IonBuilder
bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType);
bool jsop_setelem();
bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition* object, MDefinition* index, MDefinition* value,
JSValueType unboxedType);
JSValueType unboxedType, bool writeHole);
bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
SetElemSafety safety,
MDefinition* object, MDefinition* index, MDefinition* value);
bool jsop_setelem_typed_object(ScalarTypeDescr::Type arrayType,
SetElemSafety safety,
MDefinition* object, MDefinition* index, MDefinition* value);
bool jsop_length();
bool jsop_length_fastPath();
bool jsop_arguments();
@@ -702,7 +693,7 @@ class IonBuilder
bool jsop_isnoiter();
bool jsop_iterend();
bool jsop_in();
bool jsop_in_dense();
bool jsop_in_dense(JSValueType unboxedType);
bool jsop_instanceof();
bool jsop_getaliasedvar(ScopeCoordinate sc);
bool jsop_setaliasedvar(ScopeCoordinate sc);
@@ -781,8 +772,9 @@ class IonBuilder
InliningStatus inlineRegExpExec(CallInfo& callInfo);
InliningStatus inlineRegExpTest(CallInfo& callInfo);
// Object natives.
// Object natives and intrinsics.
InliningStatus inlineObjectCreate(CallInfo& callInfo);
InliningStatus inlineDefineDataProperty(CallInfo& callInfo);
// Atomics natives.
InliningStatus inlineAtomicsCompareExchange(CallInfo& callInfo);
@@ -791,14 +783,6 @@ class IonBuilder
InliningStatus inlineAtomicsFence(CallInfo& callInfo);
InliningStatus inlineAtomicsBinop(CallInfo& callInfo, JSFunction* target);
// Array intrinsics.
InliningStatus inlineUnsafePutElements(CallInfo& callInfo);
bool inlineUnsafeSetDenseArrayElement(CallInfo& callInfo, uint32_t base);
bool inlineUnsafeSetTypedArrayElement(CallInfo& callInfo, uint32_t base,
ScalarTypeDescr::Type arrayType);
bool inlineUnsafeSetTypedObjectArrayElement(CallInfo& callInfo, uint32_t base,
ScalarTypeDescr::Type arrayType);
// Slot intrinsics.
InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo);
InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo,
@@ -815,8 +799,6 @@ class IonBuilder
// TypedObject intrinsics and natives.
InliningStatus inlineObjectIsTypeDescr(CallInfo& callInfo);
InliningStatus inlineSetTypedObjectOffset(CallInfo& callInfo);
bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
ScalarTypeDescr::Type* arrayType);
InliningStatus inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target);
// SIMD intrinsics and natives.
+4 -7
View File
@@ -3028,6 +3028,9 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, ConstantOrR
if (obj->isNative() && (!shape || (obj != holder && shape->hasDefaultSetter() && shape->hasSlot())))
return SetPropertyIC::MaybeCanAttachAddSlot;
if (IsImplicitNonNativeProperty(shape))
return SetPropertyIC::CanAttachNone;
if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
IsCacheableSetPropCallNative(obj, holder, shape) ||
IsCacheableSetPropCallScripted(obj, holder, shape))
@@ -3067,13 +3070,7 @@ GenerateSetUnboxed(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher&
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType));
}
// If the unboxed object's type has known properties, then instances have
// never been converted to native objects and the type set check performed
// above ensures the value being written can be stored in the unboxed
// object.
Label* storeFailure = obj->group()->unknownProperties() ? &failure : nullptr;
masm.storeUnboxedProperty(address, unboxedType, value, storeFailure);
masm.storeUnboxedProperty(address, unboxedType, value, &failure);
attacher.jumpRejoin(masm);
+6
View File
@@ -117,6 +117,9 @@ JitOptions::JitOptions()
// Whether functions are compiled immediately.
SET_DEFAULT(eagerCompilation, false);
// Whether IonBuilder should prefer IC generation above specialized MIR.
SET_DEFAULT(forceInlineCaches, false);
// Force how many invocation or loop iterations are needed before compiling
// a function with the highest ionmonkey optimization level.
// (i.e. OptimizationLevel_Normal)
@@ -165,6 +168,9 @@ JitOptions::JitOptions()
// The bytecode length limit for small function.
SET_DEFAULT(smallFunctionMaxBytecodeLength_, 100);
// Toggles whether unboxed plain objects can be created by the VM.
SET_DEFAULT(disableUnboxedObjects, false);
}
bool
+4
View File
@@ -56,6 +56,7 @@ struct JitOptions
bool disableEaa;
bool disableAma;
bool eagerCompilation;
bool forceInlineCaches;
mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
bool limitScriptSize;
@@ -67,6 +68,9 @@ struct JitOptions
uint32_t osrPcMismatchesBeforeRecompile;
uint32_t smallFunctionMaxBytecodeLength_;
// The options below affect the rest of the VM, and not just the JIT.
bool disableUnboxedObjects;
JitOptions();
bool isSmallFunction(JSScript* script) const;
void setEagerCompilation();
+8 -4
View File
@@ -505,7 +505,8 @@ jit::JitSpewStartVA(JitSpewChannel channel, const char* fmt, va_list ap)
return;
JitSpewHeader(channel);
vfprintf(stderr, fmt, ap);
Fprinter& out = JitSpewPrinter();
out.vprintf(fmt, ap);
}
void
@@ -514,7 +515,8 @@ jit::JitSpewContVA(JitSpewChannel channel, const char* fmt, va_list ap)
if (!JitSpewEnabled(channel))
return;
vfprintf(stderr, fmt, ap);
Fprinter& out = JitSpewPrinter();
out.vprintf(fmt, ap);
}
void
@@ -523,7 +525,8 @@ jit::JitSpewFin(JitSpewChannel channel)
if (!JitSpewEnabled(channel))
return;
fprintf(stderr, "\n");
Fprinter& out = JitSpewPrinter();
out.put("\n");
}
void
@@ -578,7 +581,8 @@ jit::JitSpewHeader(JitSpewChannel channel)
if (!JitSpewEnabled(channel))
return;
fprintf(stderr, "[%s] ", ChannelNames[channel]);
Fprinter& out = JitSpewPrinter();
out.printf("[%s] ", ChannelNames[channel]);
}
bool
+25 -22
View File
@@ -119,14 +119,10 @@ class LMoveGroup : public LInstructionHelper<0, 0, 0>
void setScratchRegister(Register reg) {
scratchRegister_ = LGeneralReg(reg);
}
#endif
LAllocation maybeScratchRegister() {
#ifdef JS_CODEGEN_X86
return scratchRegister_;
#else
return LAllocation();
#endif
}
#endif
bool uses(Register reg) {
for (size_t i = 0; i < numMoves(); i++) {
@@ -3052,23 +3048,6 @@ class LPowD : public LCallInstructionHelper<1, 2, 1>
}
};
// Math.random().
class LRandom : public LCallInstructionHelper<1, 0, 2>
{
public:
LIR_HEADER(Random)
LRandom(const LDefinition& temp, const LDefinition& temp2) {
setTemp(0, temp);
setTemp(1, temp2);
}
const LDefinition* temp() {
return getTemp(0);
}
const LDefinition* temp2() {
return getTemp(1);
}
};
class LMathFunctionD : public LCallInstructionHelper<1, 1, 1>
{
public:
@@ -4162,6 +4141,30 @@ class LIncrementUnboxedArrayInitializedLength : public LInstructionHelper<0, 1,
}
};
class LSetUnboxedArrayInitializedLength : public LInstructionHelper<0, 2, 1>
{
public:
LIR_HEADER(SetUnboxedArrayInitializedLength)
explicit LSetUnboxedArrayInitializedLength(const LAllocation& object,
const LAllocation& length,
const LDefinition& temp) {
setOperand(0, object);
setOperand(1, length);
setTemp(0, temp);
}
const LAllocation* object() {
return getOperand(0);
}
const LAllocation* length() {
return getOperand(1);
}
const LDefinition* temp() {
return getTemp(0);
}
};
// Load the length from an elements header.
class LArrayLength : public LInstructionHelper<1, 1, 0>
{
+1
View File
@@ -215,6 +215,7 @@
_(UnboxedArrayLength) \
_(UnboxedArrayInitializedLength) \
_(IncrementUnboxedArrayInitializedLength) \
_(SetUnboxedArrayInitializedLength) \
_(BoundsCheck) \
_(BoundsCheckRange) \
_(BoundsCheckLower) \
+8 -7
View File
@@ -1376,13 +1376,6 @@ LIRGenerator::visitPow(MPow* ins)
defineReturn(lir, ins);
}
void
LIRGenerator::visitRandom(MRandom* ins)
{
LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
defineReturn(lir, ins);
}
void
LIRGenerator::visitMathFunction(MMathFunction* ins)
{
@@ -2501,6 +2494,14 @@ LIRGenerator::visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArray
add(new(alloc()) LIncrementUnboxedArrayInitializedLength(useRegister(ins->object())), ins);
}
void
LIRGenerator::visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins)
{
add(new(alloc()) LSetUnboxedArrayInitializedLength(useRegister(ins->object()),
useRegisterOrConstant(ins->length()),
temp()), ins);
}
void
LIRGenerator::visitNot(MNot* ins)
{

Some files were not shown because too many files have changed in this diff Show More