Bug 977117 - Enable inlining of the ObjectIsTypeDescr primitive. r=nmatsakis

This commit is contained in:
Lars T Hansen 2014-02-28 09:54:44 -05:00
parent 5b6cc58518
commit 68cd7bf617
12 changed files with 306 additions and 10 deletions

View File

@ -880,6 +880,29 @@ IsTypedObjectClass(const Class *class_)
class_ == &OpaqueTypedObject::class_;
}
inline bool
IsSimpleTypeDescrClass(const Class* clasp)
{
return clasp == &ScalarTypeDescr::class_ ||
clasp == &ReferenceTypeDescr::class_;
}
inline bool
IsSizedTypeDescrClass(const Class* clasp)
{
return IsSimpleTypeDescrClass(clasp) ||
clasp == &StructTypeDescr::class_ ||
clasp == &SizedArrayTypeDescr::class_ ||
clasp == &X4TypeDescr::class_;
}
inline bool
IsTypeDescrClass(const Class* clasp)
{
return IsSizedTypeDescrClass(clasp) ||
clasp == &UnsizedArrayTypeDescr::class_;
}
} // namespace js
JSObject *
@ -889,26 +912,21 @@ template <>
inline bool
JSObject::is<js::SimpleTypeDescr>() const
{
return is<js::ScalarTypeDescr>() ||
is<js::ReferenceTypeDescr>();
return IsSimpleTypeDescrClass(getClass());
}
template <>
inline bool
JSObject::is<js::SizedTypeDescr>() const
{
return is<js::SimpleTypeDescr>() ||
is<js::StructTypeDescr>() ||
is<js::SizedArrayTypeDescr>() ||
is<js::X4TypeDescr>();
return IsSizedTypeDescrClass(getClass());
}
template <>
inline bool
JSObject::is<js::TypeDescr>() const
{
return is<js::SizedTypeDescr>() ||
is<js::UnsizedArrayTypeDescr>();
return IsTypeDescrClass(getClass());
}
template <>
@ -919,4 +937,3 @@ JSObject::is<js::TypedObject>() const
}
#endif /* builtin_TypedObject_h */

View File

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Used to verify that the JIT resolves the ObjectIsTypeDescr tests
* internal to Type.toSource().
*
* In this case the argument type is always a type descriptor object
* (though not a unique one), so ObjectIsTypeDescr resolves to true
* and there should be no exceptions.
*
* Load this into the js shell with IONFLAGS=logs, then exit and run
* iongraph. You're looking for a smallish function within the
* "self-hosted" domain. Look for a call to ObjectIsTypeDescr far
* down in the graph for pass00, with a call to DescrToSource in a
* subsequent block (all of this is at the mercy of the way the code
* is currently written).
*/
var T = TypedObject;
var ST1 = new T.StructType({x:T.int32});
var ST2 = new T.StructType({x:T.float64});
function check(v) {
return v.toSource();
}
function test() {
var a = [ ST1, ST2 ];
for ( var i=0 ; i < 1000 ; i++ )
check(a[i%2]);
return check(a[0]);
}
print(test());

View File

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Used to verify that the JIT resolves the ObjectIsTypeDescr tests
* internal to Type.toSource().
*
* In this case the argument type is never a type descriptor object,
* so ObjectIsTypeDescr resolves to false (and we have to catch
* exceptions).
*
* Load this into the js shell with IONFLAGS=logs, then exit and run
* iongraph. You're looking for a smallish function within the
* "self-hosted" domain. Look for a call to ObjectIsTypeDescr far
* down in the graph for pass00, with a call to DescrToSource in a
* subsequent block (all of this is at the mercy of the way the code
* is currently written).
*/
var T = TypedObject;
var ST = new T.StructType({x:T.int32});
function check(v) {
return v.toSource();
}
function test() {
var fake = { toSource: ST.toSource };
var a = [ ST, fake ];
for ( var i=0 ; i < 1000 ; i++ )
try { check(a[i%2]); } catch (e) {}
try { return check(a[0]); } catch (e) { return "Thrown" }
}
print(test());

View File

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Used to verify that the JIT resolves the ObjectIsTypeDescr tests
* internal to Type.toSource().
*
* In this case the argument type is never a type descriptor object
* (though not a unique non-type-descriptor), so ObjectIsTypeDescr
* resolves to false (and we have to catch exceptions).
*
* Load this into the js shell with IONFLAGS=logs, then exit and run
* iongraph. You're looking for a smallish function within the
* "self-hosted" domain. Look for a call to ObjectIsTypeDescr far
* down in the graph for pass00, with a call to DescrToSource in a
* subsequent block (all of this is at the mercy of the way the code
* is currently written).
*/
var T = TypedObject;
var ST = new T.StructType({x:T.int32});
function check(v) {
return v.toSource();
}
function test() {
var fake1 = { toSource: ST.toSource };
var fake2 = []; fake2.toSource = ST.toSource;
var a = [ fake1, fake2 ];
for ( var i=0 ; i < 1000 ; i++ )
try { check(a[i%2]); } catch (e) {}
try { return check(a[0]); } catch (e) { return "Thrown" }
}
print(test());

View File

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Used to verify that the JIT resolves the ObjectIsTypeDescr tests
* internal to Type.toSource().
*
* In this case the argument type is never a type descriptor object,
* so ObjectIsTypeDescr resolves to false (and we have to catch
* exceptions).
*
* Load this into the js shell with IONFLAGS=logs, then exit and run
* iongraph. You're looking for a smallish function within the
* "self-hosted" domain. Look for a call to ObjectIsTypeDescr far
* down in the graph for pass00, with a call to DescrToSource in a
* subsequent block (all of this is at the mercy of the way the code
* is currently written).
*/
var T = TypedObject;
var ST = new T.StructType({x:T.int32});
function check(v) {
return v.toSource();
}
function test() {
var fake = { toSource: ST.toSource };
for ( var i=0 ; i < 1000 ; i++ )
try { check(fake); } catch (e) {}
try { return check(fake); } catch (e) { return "Thrown" }
}
print(test());

View File

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Used to verify that the JIT resolves the ObjectIsTypeDescr tests
* internal to Type.toSource().
*
* In this case the argument type is always a type descriptor object,
* so ObjectIsTypeDescr resolves to true and there should be no
* exceptions.
*
* Load this into the js shell with IONFLAGS=logs, then exit and run
* iongraph. You're looking for a smallish function within the
* "self-hosted" domain. Look for a call to ObjectIsTypeDescr far
* down in the graph for pass00, with a call to DescrToSource in a
* subsequent block (all of this is at the mercy of the way the code
* is currently written).
*/
var T = TypedObject;
var ST = new T.StructType({x:T.int32});
function check(v) {
return v.toSource();
}
function test() {
for ( var i=0 ; i < 1000 ; i++ )
check(ST);
return check(ST);
}
print(test());

View File

@ -677,6 +677,9 @@ class IonBuilder : public MIRGenerator
// ForkJoin intrinsics
InliningStatus inlineForkJoinGetSlice(CallInfo &callInfo);
// TypedObject intrinsics.
InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);
InliningStatus inlineHaveSameClass(CallInfo &callInfo);

View File

@ -162,6 +162,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
return inlineHasClass(callInfo, &TransparentTypedObject::class_);
if (native == intrinsic_ObjectIsOpaqueTypedObject)
return inlineHasClass(callInfo, &OpaqueTypedObject::class_);
if (native == intrinsic_ObjectIsTypeDescr)
return inlineObjectIsTypeDescr(callInfo);
// Testing Functions
if (native == testingFunc_inParallelSection)
@ -1508,6 +1510,43 @@ IonBuilder::inlineHasClass(CallInfo &callInfo, const Class *clasp)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
{
if (callInfo.constructing() || callInfo.argc() != 1)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
// The test is elaborate: in-line only if there is exact
// information.
types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
if (!types)
return InliningStatus_NotInlined;
bool result = false;
switch (types->forAllClasses(IsTypeDescrClass)) {
case types::TemporaryTypeSet::ForAllResult::ALL_FALSE:
case types::TemporaryTypeSet::ForAllResult::EMPTY:
result = false;
break;
case types::TemporaryTypeSet::ForAllResult::ALL_TRUE:
result = true;
break;
case types::TemporaryTypeSet::ForAllResult::MIXED:
return InliningStatus_NotInlined;
}
pushConstant(BooleanValue(result));
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
{

View File

@ -1036,6 +1036,7 @@ bool intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_ObjectIsTransparentTypedObject(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp);
class AutoLockForExclusiveAccess
{

View File

@ -1698,6 +1698,37 @@ TemporaryTypeSet::getKnownClass()
return clasp;
}
TemporaryTypeSet::ForAllResult
TemporaryTypeSet::forAllClasses(bool (*func)(const Class* clasp))
{
if (unknownObject())
return ForAllResult::MIXED;
unsigned count = getObjectCount();
if (count == 0)
return ForAllResult::EMPTY;
bool true_results = false;
bool false_results = false;
for (unsigned i = 0; i < count; i++) {
const Class *clasp = getObjectClass(i);
if (!clasp)
return ForAllResult::MIXED;
if (func(clasp)) {
true_results = true;
if (false_results) return ForAllResult::MIXED;
}
else {
false_results = true;
if (true_results) return ForAllResult::MIXED;
}
}
JS_ASSERT(true_results != false_results);
return true_results ? ForAllResult::ALL_TRUE : ForAllResult::ALL_FALSE;
}
int
TemporaryTypeSet::getTypedArrayType()
{

View File

@ -673,6 +673,21 @@ class TemporaryTypeSet : public TypeSet
/* Get the class shared by all objects in this set, or nullptr. */
const Class *getKnownClass();
/* Result returned from forAllClasses */
enum ForAllResult {
EMPTY=1, // Set empty
ALL_TRUE, // Set not empty and predicate returned true for all classes
ALL_FALSE, // Set not empty and predicate returned false for all classes
MIXED, // Set not empty and predicate returned false for some classes
// and true for others, or set contains an unknown or non-object
// type
};
/* Apply func to the members of the set and return an appropriate result.
* The iteration may end early if the result becomes known early.
*/
ForAllResult forAllClasses(bool (*func)(const Class *clasp));
/* Get the prototype shared by all objects in this set, or nullptr. */
JSObject *getCommonPrototype();

View File

@ -635,6 +635,12 @@ js::intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp)
return js::ObjectIsOpaqueTypedObject(cx, argc, vp);
}
bool
js::intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp)
{
return js::ObjectIsTypeDescr(cx, argc, vp);
}
/**
* Returns the default locale as a well-formed, but not necessarily canonicalized,
* BCP-47 language tag.
@ -712,7 +718,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JSNativeThreadSafeWrapper<js::SetTypedObjectOffset>,
&js::SetTypedObjectOffsetJitInfo, 2, 0),
JS_FNINFO("ObjectIsTypeDescr",
JSNativeThreadSafeWrapper<js::ObjectIsTypeDescr>,
intrinsic_ObjectIsTypeDescr,
&js::ObjectIsTypeDescrJitInfo, 5, 0),
JS_FNINFO("ObjectIsTransparentTypedObject",
intrinsic_ObjectIsTransparentTypedObject,