Bug 1316913 - Warn about ArrayBuffer.slice. r=till
authorTom Schuster <evilpies@gmail.com>
Sat, 12 Nov 2016 19:26:25 +0100
changeset 352387 884861c655c718bec160c5b2778220c14fa3906a
parent 352386 0e366a3e90d2f87c8466dd9edf19581029023659
child 352388 ac12dbbe7b632995c7b7f46e0394979de8d28e72
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1316913
milestone52.0a1
Bug 1316913 - Warn about ArrayBuffer.slice. r=till
js/src/builtin/TypedArray.js
js/src/jit-test/tests/basic/arraybuffer-slice-warn.js
js/src/js.msg
js/src/vm/ArrayBufferObject.cpp
js/src/vm/GlobalObject.h
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1651,22 +1651,16 @@ function ArrayBufferSlice(start, end) {
     // Step 22.
     return new_;
 }
 
 function IsDetachedBufferThis() {
   return IsDetachedBuffer(this);
 }
 
-function ArrayBufferStaticSlice(buf, start, end) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'ArrayBuffer.slice');
-    return callFunction(ArrayBufferSlice, buf, start, end);
-}
-
 // ES 2016 draft Mar 25, 2016 24.1.3.3.
 function ArrayBufferSpecies() {
     // Step 1.
     return this;
 }
 _SetCanonicalName(ArrayBufferSpecies, "get [Symbol.species]");
 
 // Shared memory and atomics proposal (30 Oct 2016)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/arraybuffer-slice-warn.js
@@ -0,0 +1,13 @@
+// ArrayBuffer.slice should be warned once and only once.
+
+enableLastWarning();
+
+ArrayBuffer.slice(new ArrayBuffer(10), 1);
+var warning = getLastWarning();
+assertEq(warning !== null, true, "warning should be generated");
+assertEq(warning.name, "Warning");
+
+clearLastWarning();
+ArrayBuffer.slice(new ArrayBuffer(10), 1);
+warning = getLastWarning();
+assertEq(warning, null, "warning should not generated for 2nd ocurrence");
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -67,16 +67,17 @@ MSG_DEF(JSMSG_REDECLARED_VAR,          2
 MSG_DEF(JSMSG_UNDECLARED_VAR,          1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
 MSG_DEF(JSMSG_GETTER_ONLY,             0, JSEXN_TYPEERR, "setting a property that has only a getter")
 MSG_DEF(JSMSG_OVERWRITING_ACCESSOR,    1, JSEXN_TYPEERR, "can't overwrite accessor property {0}")
 MSG_DEF(JSMSG_UNDEFINED_PROP,          1, JSEXN_REFERENCEERR, "reference to undefined property {0}")
 MSG_DEF(JSMSG_INVALID_MAP_ITERABLE,    1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects")
 MSG_DEF(JSMSG_NESTING_GENERATOR,       0, JSEXN_TYPEERR, "already executing generator")
 MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,     3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
 MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
+MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead")
 MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,      1, JSEXN_TYPEERR, "bad surrogate character {0}")
 MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,     1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
 MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,     1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
 MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW,     1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden")
 MSG_DEF(JSMSG_BAD_GENERATOR_YIELD,     1, JSEXN_TYPEERR, "yield from closing generator {0}")
 MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,      0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
 MSG_DEF(JSMSG_UNEXPECTED_TYPE,         2, JSEXN_TYPEERR, "{0} is {1}")
 MSG_DEF(JSMSG_MISSING_FUN_ARG,         2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -39,16 +39,17 @@
 
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "js/Conversions.h"
 #include "js/MemoryMetrics.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/WrapperObject.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmTypes.h"
 
 #include "jsatominlines.h"
 
 #include "vm/NativeObject-inl.h"
@@ -82,16 +83,35 @@ js::ToClampedIndex(JSContext* cx, Handle
             result = 0;
     } else if (uint32_t(result) > length) {
         result = length;
     }
     *out = uint32_t(result);
     return true;
 }
 
+static bool
+arraybuffer_static_slice(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (args.length() < 1) {
+        ReportMissingArg(cx, args.calleev(), 1);
+        return false;
+    }
+
+    if (!GlobalObject::warnOnceAboutArrayBufferSlice(cx, cx->global()))
+        return false;
+
+    FixedInvokeArgs<2> args2(cx);
+    args2[0].set(args.get(1));
+    args2[1].set(args.get(2));
+    return CallSelfHostedFunction(cx, "ArrayBufferSlice", args[0], args2, args.rval());
+}
+
 /*
  * ArrayBufferObject
  *
  * This class holds the underlying raw buffer that the TypedArrayObject classes
  * access.  It can be created explicitly and passed to a TypedArrayObject, or
  * can be created implicitly by constructing a TypedArrayObject with a size.
  */
 
@@ -135,17 +155,17 @@ static const ClassOps ArrayBufferObjectC
     nullptr,        /* call        */
     nullptr,        /* hasInstance */
     nullptr,        /* construct   */
     ArrayBufferObject::trace,
 };
 
 static const JSFunctionSpec static_functions[] = {
     JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
-    JS_SELF_HOSTED_FN("slice", "ArrayBufferStaticSlice", 3, 0),
+    JS_FN("slice", arraybuffer_static_slice, 3, 0),
     JS_FS_END
 };
 
 static const JSPropertySpec static_properties[] = {
     JS_SELF_HOSTED_SYM_GET(species, "ArrayBufferSpecies", 0),
     JS_PS_END
 };
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -125,16 +125,17 @@ class GlobalObject : public NativeObject
      * we won't expose GlobalObject, so just assert that the two values are
      * synchronized.
      */
     static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS,
                   "global object slot counts are inconsistent");
 
     enum WarnOnceFlag : int32_t {
         WARN_WATCH_DEPRECATED                   = 1 << 0,
+        WARN_ARRAYBUFFER_SLICE_DEPRECATED       = 1 << 1,
     };
 
     // Emit the specified warning if the given slot in |obj|'s global isn't
     // true, then set the slot to true.  Thus calling this method warns once
     // for each global object it's called on, and every other call does
     // nothing.
     static bool
     warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, unsigned errorNumber);
@@ -720,16 +721,22 @@ class GlobalObject : public NativeObject
     // in which |obj| was created, if no prior warning was given.
     static bool warnOnceAboutWatch(JSContext* cx, HandleObject obj) {
         // Temporarily disabled until we've provided a watch/unwatch workaround for
         // debuggers like Firebug (bug 934669).
         //return warnOnceAbout(cx, obj, WARN_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED);
         return true;
     }
 
+    // Warn about use of the deprecated (static) ArrayBuffer.slice method.
+    static bool warnOnceAboutArrayBufferSlice(JSContext* cx, HandleObject obj) {
+        return warnOnceAbout(cx, obj, WARN_ARRAYBUFFER_SLICE_DEPRECATED,
+                             JSMSG_ARRAYBUFFER_SLICE_DEPRECATED);
+    }
+
     static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
                                 MutableHandleObject eval);
 
     // Infallibly test whether the given value is the eval function for this global.
     bool valueIsEval(const Value& val);
 
     // Implemented in jsiter.cpp.
     static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);