mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:43:44 +00:00
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:
@@ -201,7 +201,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aValue = OBJECT_TO_JSVAL(array);
|
||||
aValue->setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
@@ -61,6 +61,9 @@ UNIFIED_SOURCES += [
|
||||
EXPORTS.mozilla += [
|
||||
'PeerIdentity.h',
|
||||
]
|
||||
EXPORTS.mozilla.dom += [
|
||||
'RTCCertificate.h',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2459,7 +2459,7 @@ XMLHttpRequest::GetResponse(JSContext* /* unused */,
|
||||
return;
|
||||
}
|
||||
|
||||
mStateData.mResponse = STRING_TO_JSVAL(str);
|
||||
mStateData.mResponse.setString(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace JS {
|
||||
_(SetProp_DefiniteSlot) \
|
||||
_(SetProp_Unboxed) \
|
||||
_(SetProp_InlineAccess) \
|
||||
_(SetProp_InlineCache) \
|
||||
\
|
||||
_(GetElem_TypedObject) \
|
||||
_(GetElem_Dense) \
|
||||
|
||||
+1
-1
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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(){
|
||||
//
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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>
|
||||
{
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
_(UnboxedArrayLength) \
|
||||
_(UnboxedArrayInitializedLength) \
|
||||
_(IncrementUnboxedArrayInitializedLength) \
|
||||
_(SetUnboxedArrayInitializedLength) \
|
||||
_(BoundsCheck) \
|
||||
_(BoundsCheckRange) \
|
||||
_(BoundsCheckLower) \
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user