diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 54bbc06e3ab6..0f8412421d34 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -230,7 +230,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args) } Value sourceValue = args[0]; - if (ValueIsRegExp(sourceValue)) { + if (IsObjectWithClass(sourceValue, ESClass_RegExp, cx)) { /* * If we get passed in a |RegExpObject| source we return a new * object with the same source/flags. @@ -243,9 +243,15 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args) return false; } - RegExpObject *reobj = builder.build(&sourceObj.asRegExp()); + RegExpShared *shared = RegExpToShared(cx, sourceObj); + if (!shared) + return false; + + shared->incref(cx); + RegExpObject *reobj = builder.build(AlreadyIncRefed(shared)); if (!reobj) return false; + args.rval() = ObjectValue(*reobj); return true; } @@ -314,7 +320,7 @@ regexp_construct(JSContext *cx, uintN argc, Value *vp) * Otherwise, delegate to the standard constructor. * See ECMAv5 15.10.3.1. */ - if (args.length() >= 1 && ValueIsRegExp(args[0]) && + if (args.length() >= 1 && IsObjectWithClass(args[0], ESClass_RegExp, cx) && (args.length() == 1 || args[1].isUndefined())) { args.rval() = args[0]; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index bdd171ee1a9b..367fea8ca5e0 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -983,7 +983,7 @@ static bool EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce) { const size_t len = 1 + UINT32_INDEX_LEN; - JS_ASSERT(js_CodeSpec[op].length == len); + JS_ASSERT(size_t(js_CodeSpec[op].length) == len); ptrdiff_t offset = EmitCheck(cx, bce, len); if (offset < 0) return false; diff --git a/js/src/jit-test/tests/basic/testCrossCompartmentTransparency.js b/js/src/jit-test/tests/basic/testCrossCompartmentTransparency.js index c93b704eee1a..d9d15d24a215 100644 --- a/js/src/jit-test/tests/basic/testCrossCompartmentTransparency.js +++ b/js/src/jit-test/tests/basic/testCrossCompartmentTransparency.js @@ -27,7 +27,6 @@ function test(str, f) { f(g1.eval("new Object()")); } catch (e) { assertEq(Object.prototype.toString.call(e), "[object Error]"); - assertEq(e.name, "TypeError"); threw = true; } assertEq(threw, true); @@ -36,7 +35,6 @@ function test(str, f) { f(g2.eval("new Object()")); } catch (e) { assertEq(Object.prototype.toString.call(e), "[object Error]"); - assertEq(e.name, "TypeError"); threw = true; } assertEq(threw, true); @@ -45,7 +43,6 @@ function test(str, f) { f(proxy1); } catch (e) { assertEq(Object.prototype.toString.call(e), "[object Error]"); - assertEq(e.name, "TypeError"); threw = true; } assertEq(threw, true); @@ -54,7 +51,6 @@ function test(str, f) { f(proxy2); } catch (e) { assertEq(Object.prototype.toString.call(e), "[object Error]"); - assertEq(e.name, "TypeError"); threw = true; } assertEq(threw, true); @@ -78,6 +74,13 @@ test("new RegExp('1')", function(r) RegExp.prototype.toString.call(r)); test("new RegExp('1')", function(r) RegExp.prototype.exec.call(r, '1').toString()); test("new RegExp('1')", function(r) RegExp.prototype.test.call(r, '1')); test("new RegExp('1')", function(r) RegExp.prototype.compile.call(r, '1').toString()); +test("new RegExp('1')", function(r) assertEq("a1".search(r), 1)); +test("new RegExp('1')", function(r) assertEq("a1".match(r)[0], '1')); +test("new RegExp('1')", function(r) assertEq("a1".replace(r, 'A'), 'aA')); +test("new RegExp('1')", function(r) assertEq(String("a1b".split(r)), "a,b")); +test("new RegExp('1')", function(r) assertEq(r, RegExp(r))); +test("new RegExp('1')", function(r) assertEq(String(new RegExp(r)), String(r))); +test("new RegExp('1')", function(r) assertEq(String(/x/.compile(r)), String(r))); test("new WeakMap()", function(w) WeakMap.prototype.has.call(w, {})); test("new WeakMap()", function(w) WeakMap.prototype.get.call(w, {})); test("new WeakMap()", function(w) WeakMap.prototype.delete.call(w, {})); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index d925a3b0e118..b32edd5e031f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3567,9 +3567,7 @@ static JSBool array_isArray(JSContext *cx, uintN argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool isArray = args.length() > 0 && - args[0].isObject() && - ObjectClassIs(args[0].toObject(), ESClass_Array, cx); + bool isArray = args.length() > 0 && IsObjectWithClass(args[0], ESClass_Array, cx); args.rval().setBoolean(isArray); return true; } diff --git a/js/src/jsclass.h b/js/src/jsclass.h index 5a3a18e578fa..37f911471df7 100644 --- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -407,7 +407,9 @@ Valueify(const JSClass *c) * Enumeration describing possible values of the [[Class]] internal property * value of objects. */ -enum ESClassValue { ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean }; +enum ESClassValue { + ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean, ESClass_RegExp +}; /* * Return whether the given object has the given [[Class]] internal property @@ -418,6 +420,10 @@ enum ESClassValue { ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boole inline bool ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx); +/* Just a helper that checks v.isObject before calling ObjectClassIs. */ +inline bool +IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx); + } /* namespace js */ #endif /* __cplusplus */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index b80aada2aee4..9ba7180064a0 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1953,11 +1953,20 @@ ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx) case ESClass_Number: return obj.isNumber(); case ESClass_String: return obj.isString(); case ESClass_Boolean: return obj.isBoolean(); + case ESClass_RegExp: return obj.isRegExp(); } JS_NOT_REACHED("bad classValue"); return false; } +inline bool +IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx) +{ + if (!v.isObject()) + return false; + return ObjectClassIs(v.toObject(), classValue, cx); +} + static JS_ALWAYS_INLINE bool ValueIsSpecial(JSObject *obj, Value *propval, SpecialId *sidp, JSContext *cx) { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 5b5693655a8e..f5024caf63ec 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -301,6 +301,13 @@ ProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, uintN indent) return fun_toStringHelper(cx, &fval.toObject(), indent); } +RegExpShared * +ProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy) +{ + JS_NOT_REACHED("This should have been a wrapped regexp"); + return (RegExpShared *)NULL; +} + bool ProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp) { @@ -946,6 +953,14 @@ Proxy::fun_toString(JSContext *cx, JSObject *proxy, uintN indent) return GetProxyHandler(proxy)->fun_toString(cx, proxy, indent); } +RegExpShared * +Proxy::regexp_toShared(JSContext *cx, JSObject *proxy) +{ + JS_CHECK_RECURSION(cx, return NULL); + AutoPendingProxyOperation pending(cx, proxy); + return GetProxyHandler(proxy)->regexp_toShared(cx, proxy); +} + bool Proxy::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp) { diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 3377f98247ec..fb21c9e1ad9c 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -84,6 +84,7 @@ class JS_FRIEND_API(ProxyHandler) { virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx); virtual JSString *obj_toString(JSContext *cx, JSObject *proxy); virtual JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent); + virtual RegExpShared *regexp_toShared(JSContext *cx, JSObject *proxy); virtual bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp); virtual void finalize(JSContext *cx, JSObject *proxy); virtual void trace(JSTracer *trc, JSObject *proxy); @@ -137,6 +138,7 @@ class Proxy { static bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx); static JSString *obj_toString(JSContext *cx, JSObject *proxy); static JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent); + static RegExpShared *regexp_toShared(JSContext *cx, JSObject *proxy); static bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp); }; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index e99866afa9bf..56fcece72d73 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1400,11 +1400,11 @@ class RegExpGuard bool init(CallArgs args, bool convertVoid = false) { - if (args.length() != 0 && ValueIsRegExp(args[0])) { - RegExpObject &reobj = args[0].toObject().asRegExp(); - RegExpShared *shared = reobj.getShared(cx); + if (args.length() != 0 && IsObjectWithClass(args[0], ESClass_RegExp, cx)) { + RegExpShared *shared = RegExpToShared(cx, args[0].toObject()); if (!shared) return false; + matcher.init(NeedsIncRef(shared)); } else { if (convertVoid && (args.length() == 0 || args[0].isUndefined())) { @@ -2547,9 +2547,8 @@ js::str_split(JSContext *cx, uintN argc, Value *vp) JSLinearString *sepstr = NULL; bool sepUndefined = (args.length() == 0 || args[0].isUndefined()); if (!sepUndefined) { - if (ValueIsRegExp(args[0])) { - RegExpObject &reobj = args[0].toObject().asRegExp(); - RegExpShared *shared = reobj.getShared(cx); + if (IsObjectWithClass(args[0], ESClass_RegExp, cx)) { + RegExpShared *shared = RegExpToShared(cx, args[0].toObject()); if (!shared) return false; matcher.init(NeedsIncRef(shared)); diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 5d2c7156eb30..254a2ab214c7 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -54,10 +54,10 @@ #endif #include "jscompartment.h" -#include "vm/RegExpObject.h" - #include "jsobjinlines.h" +#include "vm/RegExpObject-inl.h" + using namespace js; using namespace js::gc; @@ -334,6 +334,12 @@ Wrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) return str; } +RegExpShared * +Wrapper::regexp_toShared(JSContext *cx, JSObject *wrapper) +{ + return wrappedObject(wrapper)->asRegExp().getShared(cx); +} + bool Wrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp) { @@ -881,5 +887,13 @@ SecurityWrapper::objectClassIs(JSObject *obj, ESClassValue classValue, JSC return Base::objectClassIs(obj, classValue, cx); } +template +RegExpShared * +SecurityWrapper::regexp_toShared(JSContext *cx, JSObject *obj) +{ + return Base::regexp_toShared(cx, obj); +} + + template class js::SecurityWrapper; template class js::SecurityWrapper; diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index e9ddd8fc7011..8edf4e4f3830 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -94,6 +94,7 @@ class JS_FRIEND_API(Wrapper) : public ProxyHandler virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE; virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE; virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) MOZ_OVERRIDE; + virtual RegExpShared *regexp_toShared(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp) MOZ_OVERRIDE; virtual void trace(JSTracer *trc, JSObject *wrapper) MOZ_OVERRIDE; @@ -178,6 +179,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE; virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE; + virtual RegExpShared *regexp_toShared(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE; }; typedef SecurityWrapper SameCompartmentSecurityWrapper; diff --git a/js/src/vm/RegExpObject-inl.h b/js/src/vm/RegExpObject-inl.h index 4d2a45e5e313..4f060d418d4c 100644 --- a/js/src/vm/RegExpObject-inl.h +++ b/js/src/vm/RegExpObject-inl.h @@ -59,12 +59,6 @@ JSObject::asRegExp() namespace js { -inline bool -ValueIsRegExp(const Value &v) -{ - return !v.isPrimitive() && v.toObject().isRegExp(); -} - inline bool IsRegExpMetaChar(jschar c) { @@ -506,6 +500,15 @@ RegExpShared::decref(JSContext *cx) #endif } +inline RegExpShared * +RegExpToShared(JSContext *cx, JSObject &obj) +{ + JS_ASSERT(ObjectClassIs(obj, ESClass_RegExp, cx)); + if (obj.isRegExp()) + return obj.asRegExp().getShared(cx); + return Proxy::regexp_toShared(cx, &obj); +} + } /* namespace js */ #endif diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 113fb800fc66..d72865062d90 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -137,18 +137,6 @@ RegExpObjectBuilder::build(JSLinearString *source, RegExpFlag flags) return reobj_->init(cx, source, flags) ? reobj_ : NULL; } -RegExpObject * -RegExpObjectBuilder::build(RegExpObject *other) -{ - RegExpShared *shared = other->getShared(cx); - if (!shared) - return NULL; - - /* Now, incref it for the RegExpObject being built. */ - shared->incref(cx); - return build(AlreadyIncRefed(shared)); -} - RegExpObject * RegExpObjectBuilder::clone(RegExpObject *other, RegExpObject *proto) { diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index f039f2bb42e1..12931131fe74 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -207,8 +207,6 @@ class RegExpObjectBuilder bool getOrCreate(); bool getOrCreateClone(RegExpObject *proto); - RegExpObject *build(AlreadyIncRefed shared); - friend class RegExpMatcher; public: @@ -219,7 +217,7 @@ class RegExpObjectBuilder RegExpObject *reobj() { return reobj_; } RegExpObject *build(JSLinearString *str, RegExpFlag flags); - RegExpObject *build(RegExpObject *other); + RegExpObject *build(AlreadyIncRefed shared); /* Perform a VM-internal clone. */ RegExpObject *clone(RegExpObject *other, RegExpObject *proto); @@ -469,9 +467,6 @@ class RegExpMatcher bool ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut); -inline bool -ValueIsRegExp(const Value &v); - inline bool IsRegExpMetaChar(jschar c); @@ -481,6 +476,9 @@ CheckRegExpSyntax(JSContext *cx, JSLinearString *str) return detail::RegExpCode::checkSyntax(cx, NULL, str); } +inline RegExpShared * +RegExpToShared(JSContext *cx, JSObject &obj); + } /* namespace js */ extern JS_FRIEND_API(JSObject *) JS_FASTCALL