<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[195360] trunk/Source/JavaScriptCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/195360">195360</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2016-01-20 11:32:30 -0800 (Wed, 20 Jan 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>[ES6] Fix various issues with TypedArrays.
https://bugs.webkit.org/show_bug.cgi?id=153245
Reviewed by Geoffrey Garen.
This patch fixes a couple of issues with TypedArrays:
1) We were not checking if a view had been neutered and throwing an error
if it had in the our TypedArray.prototype functions.
2) The TypedArray.prototype.set function had a couple of minor issues with
checking for the offset being negative.
3) The JSArrayBufferView class did not check if the backing store had
been neutered when computing the offset even though the view's vector
pointer had been set to NULL. This meant that under some conditions we
could, occasionally, return a garbage number as the offset. Now, we only
neuter views if the backing ArrayBuffer's view is actually transfered.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionNeuterTypedArray):
* runtime/JSArrayBufferView.h:
(JSC::JSArrayBufferView::isNeutered):
* runtime/JSArrayBufferViewInlines.h:
(JSC::JSArrayBufferView::byteOffset):
* runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
(JSC::genericTypedArrayViewProtoFuncSet):
(JSC::genericTypedArrayViewProtoFuncEntries):
(JSC::genericTypedArrayViewProtoFuncCopyWithin):
(JSC::genericTypedArrayViewProtoFuncFill):
(JSC::genericTypedArrayViewProtoFuncIndexOf):
(JSC::genericTypedArrayViewProtoFuncJoin):
(JSC::genericTypedArrayViewProtoFuncKeys):
(JSC::genericTypedArrayViewProtoFuncLastIndexOf):
(JSC::genericTypedArrayViewProtoFuncReverse):
(JSC::genericTypedArrayViewPrivateFuncSort):
(JSC::genericTypedArrayViewProtoFuncSlice):
(JSC::genericTypedArrayViewProtoFuncSubarray):
(JSC::typedArrayViewProtoFuncValues):
* runtime/JSTypedArrayViewPrototype.cpp:
(JSC::typedArrayViewPrivateFuncLength):
(JSC::typedArrayViewPrivateFuncSort): Deleted.
* tests/stress/typedarray-functions-with-neutered.js: Added.
(getGetter):
(unit):
(args.new.Int32Array):
(arrays.typedArrays.map):
(checkProtoFunc.throwsCorrectError):
(checkProtoFunc):
(test):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayBuffercpp">trunk/Source/JavaScriptCore/runtime/ArrayBuffer.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayBufferViewh">trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayBufferViewInlinesh">trunk/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGenericTypedArrayViewPrototypeFunctionsh">trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSTypedArrayViewPrototypecpp">trunk/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstresstypedarrayfunctionswithneuteredjs">trunk/Source/JavaScriptCore/tests/stress/typedarray-functions-with-neutered.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (195359 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-01-20 19:30:42 UTC (rev 195359)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -1,3 +1,57 @@
</span><ins>+2016-01-19 Keith Miller <keith_miller@apple.com>
+
+ [ES6] Fix various issues with TypedArrays.
+ https://bugs.webkit.org/show_bug.cgi?id=153245
+
+ Reviewed by Geoffrey Garen.
+
+ This patch fixes a couple of issues with TypedArrays:
+
+ 1) We were not checking if a view had been neutered and throwing an error
+ if it had in the our TypedArray.prototype functions.
+
+ 2) The TypedArray.prototype.set function had a couple of minor issues with
+ checking for the offset being negative.
+
+ 3) The JSArrayBufferView class did not check if the backing store had
+ been neutered when computing the offset even though the view's vector
+ pointer had been set to NULL. This meant that under some conditions we
+ could, occasionally, return a garbage number as the offset. Now, we only
+ neuter views if the backing ArrayBuffer's view is actually transfered.
+
+ * jsc.cpp:
+ (GlobalObject::finishCreation):
+ (functionNeuterTypedArray):
+ * runtime/JSArrayBufferView.h:
+ (JSC::JSArrayBufferView::isNeutered):
+ * runtime/JSArrayBufferViewInlines.h:
+ (JSC::JSArrayBufferView::byteOffset):
+ * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+ (JSC::genericTypedArrayViewProtoFuncSet):
+ (JSC::genericTypedArrayViewProtoFuncEntries):
+ (JSC::genericTypedArrayViewProtoFuncCopyWithin):
+ (JSC::genericTypedArrayViewProtoFuncFill):
+ (JSC::genericTypedArrayViewProtoFuncIndexOf):
+ (JSC::genericTypedArrayViewProtoFuncJoin):
+ (JSC::genericTypedArrayViewProtoFuncKeys):
+ (JSC::genericTypedArrayViewProtoFuncLastIndexOf):
+ (JSC::genericTypedArrayViewProtoFuncReverse):
+ (JSC::genericTypedArrayViewPrivateFuncSort):
+ (JSC::genericTypedArrayViewProtoFuncSlice):
+ (JSC::genericTypedArrayViewProtoFuncSubarray):
+ (JSC::typedArrayViewProtoFuncValues):
+ * runtime/JSTypedArrayViewPrototype.cpp:
+ (JSC::typedArrayViewPrivateFuncLength):
+ (JSC::typedArrayViewPrivateFuncSort): Deleted.
+ * tests/stress/typedarray-functions-with-neutered.js: Added.
+ (getGetter):
+ (unit):
+ (args.new.Int32Array):
+ (arrays.typedArrays.map):
+ (checkProtoFunc.throwsCorrectError):
+ (checkProtoFunc):
+ (test):
+
</ins><span class="cx"> 2016-01-19 Andy VanWagoner <thetalecrafter@gmail.com>
</span><span class="cx">
</span><span class="cx"> [INTL] Implement Date.prototype.toLocaleDateString in ECMA-402
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayBuffer.cpp (195359 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayBuffer.cpp        2016-01-20 19:30:42 UTC (rev 195359)
+++ trunk/Source/JavaScriptCore/runtime/ArrayBuffer.cpp        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -44,14 +44,14 @@
</span><span class="cx">
</span><span class="cx"> bool isNeuterable = !m_pinCount;
</span><span class="cx">
</span><del>- if (isNeuterable)
- m_contents.transfer(result);
- else {
</del><ins>+ if (!isNeuterable) {
</ins><span class="cx"> m_contents.copyTo(result);
</span><span class="cx"> if (!result.m_data)
</span><span class="cx"> return false;
</span><ins>+ return true;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ m_contents.transfer(result);
</ins><span class="cx"> for (size_t i = numberOfIncomingReferences(); i--;) {
</span><span class="cx"> JSCell* cell = incomingReferenceAt(i);
</span><span class="cx"> if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(cell))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayBufferViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.h (195359 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.h        2016-01-20 19:30:42 UTC (rev 195359)
+++ trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.h        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -159,6 +159,7 @@
</span><span class="cx">
</span><span class="cx"> ArrayBuffer* buffer();
</span><span class="cx"> PassRefPtr<ArrayBufferView> impl();
</span><ins>+ bool isNeutered() { return hasArrayBuffer() && !vector(); }
</ins><span class="cx"> void neuter();
</span><span class="cx">
</span><span class="cx"> void* vector()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayBufferViewInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h (195359 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h        2016-01-20 19:30:42 UTC (rev 195359)
+++ trunk/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -66,7 +66,9 @@
</span><span class="cx"> {
</span><span class="cx"> if (!hasArrayBuffer())
</span><span class="cx"> return 0;
</span><del>-
</del><ins>+
+ ASSERT(!vector() == !buffer()->data());
+
</ins><span class="cx"> ptrdiff_t delta =
</span><span class="cx"> bitwise_cast<uint8_t*>(vector()) - static_cast<uint8_t*>(buffer()->data());
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGenericTypedArrayViewPrototypeFunctionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (195359 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h        2016-01-20 19:30:42 UTC (rev 195359)
+++ trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -43,6 +43,8 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><ins>+static const char* typedArrayBufferHasBeenDetachedErrorMessage = "Underlying ArrayBuffer has been detached from the view";
+
</ins><span class="cx"> inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
</span><span class="cx"> {
</span><span class="cx"> JSValue value = exec->argument(argument);
</span><span class="lines">@@ -68,20 +70,30 @@
</span><span class="cx">
</span><span class="cx"> unsigned offset;
</span><span class="cx"> if (exec->argumentCount() >= 2) {
</span><del>- offset = exec->uncheckedArgument(1).toUInt32(exec);
</del><ins>+ double offsetNumber = exec->uncheckedArgument(1).toInteger(exec);
</ins><span class="cx"> if (exec->hadException())
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span><ins>+ if (offsetNumber < 0)
+ return throwVMRangeError(exec, "Offset should not be negative");
+ offset = offsetNumber;
</ins><span class="cx"> } else
</span><span class="cx"> offset = 0;
</span><span class="cx">
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
</ins><span class="cx"> JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0));
</span><span class="cx"> if (!sourceArray)
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "First argument should be an object"));
</span><span class="cx">
</span><span class="cx"> unsigned length;
</span><del>- if (isTypedView(sourceArray->classInfo()->typedArrayStorageType))
- length = jsDynamicCast<JSArrayBufferView*>(sourceArray)->length();
- else
</del><ins>+ if (isTypedView(sourceArray->classInfo()->typedArrayStorageType)) {
+ JSArrayBufferView* sourceView = jsCast<JSArrayBufferView*>(sourceArray);
+ if (sourceView->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ length = jsCast<JSArrayBufferView*>(sourceArray)->length();
+ } else
</ins><span class="cx"> length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
</span><span class="cx">
</span><span class="cx"> if (exec->hadException())
</span><span class="lines">@@ -96,6 +108,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.6
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKeyValue, thisObject));
</span><span class="cx"> }
</span><span class="lines">@@ -105,6 +119,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.5
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> if (exec->argumentCount() < 2)
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "Expected at least two arguments"));
</span><span class="lines">@@ -133,6 +149,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.8
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> JSValue valueToInsert = exec->argument(0);
</span><span class="cx"> if (exec->hadException())
</span><span class="lines">@@ -156,6 +174,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.13
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> if (!exec->argumentCount())
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
</span><span class="lines">@@ -181,6 +201,10 @@
</span><span class="cx"> template<typename ViewClass>
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncJoin(ExecState* exec)
</span><span class="cx"> {
</span><ins>+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
</ins><span class="cx"> // 22.2.3.14
</span><span class="cx"> auto joinWithSeparator = [&] (StringView separator) -> EncodedJSValue {
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><span class="lines">@@ -214,6 +238,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.15
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKey, thisObject));
</span><span class="cx"> }
</span><span class="lines">@@ -223,6 +249,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.16
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> if (!exec->argumentCount())
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
</span><span class="lines">@@ -289,6 +317,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.21
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> typename ViewClass::ElementType* array = thisObject->typedVector();
</span><span class="cx"> std::reverse(array, array + thisObject->length());
</span><span class="lines">@@ -301,6 +331,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.25
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->argument(0));
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> thisObject->sort();
</span><span class="cx">
</span><span class="lines">@@ -314,6 +346,8 @@
</span><span class="cx"> JSFunction* callee = jsCast<JSFunction*>(exec->callee());
</span><span class="cx">
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> if (!exec->argumentCount())
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
</span><span class="lines">@@ -349,6 +383,8 @@
</span><span class="cx"> JSFunction* callee = jsCast<JSFunction*>(exec->callee());
</span><span class="cx">
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> if (!exec->argumentCount())
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
</span><span class="lines">@@ -385,6 +421,8 @@
</span><span class="cx"> {
</span><span class="cx"> // 22.2.3.29
</span><span class="cx"> ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
</ins><span class="cx">
</span><span class="cx"> return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateValue, thisObject));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSTypedArrayViewPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp (195359 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp        2016-01-20 19:30:42 UTC (rev 195359)
+++ trunk/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -68,6 +68,8 @@
</span><span class="cx"> JSArrayBufferView* thisObject = jsDynamicCast<JSArrayBufferView*>(exec->argument(0));
</span><span class="cx"> if (!thisObject)
</span><span class="cx"> return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view"));
</span><ins>+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, "Underlying ArrayBuffer has been detached from the view");
</ins><span class="cx">
</span><span class="cx"> return JSValue::encode(jsNumber(thisObject->length()));
</span><span class="cx"> }
</span><span class="lines">@@ -75,8 +77,6 @@
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSort(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx"> JSValue thisValue = exec->argument(0);
</span><del>- if (!thisValue.isObject())
- return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
</del><span class="cx"> CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewPrivateFuncSort);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstypedarrayfunctionswithneuteredjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/typedarray-functions-with-neutered.js (0 => 195360)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/typedarray-functions-with-neutered.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/typedarray-functions-with-neutered.js        2016-01-20 19:32:30 UTC (rev 195360)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+typedArrays = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array];
+
+proto = Int8Array.prototype.__proto__;
+
+function getGetter(prop) {
+ return Object.getOwnPropertyDescriptor(proto, prop).get;
+}
+
+function unit() { }
+
+
+prototypeFunctions = [
+ { func:getGetter("length"), args:[], result:0 },
+ { func:getGetter("byteLength"), args:[], result:0 },
+ { func:getGetter("byteOffset"), args:[], result:0 },
+ { func:proto.copyWithin, args:[0, 1] },
+ { func:proto.entries, args:[] },
+ { func:proto.every, args:[unit] },
+ { func:proto.every, args:[1] },
+ { func:proto.filter, args:[unit] },
+ { func:proto.find, args:[] },
+ { func:proto.findIndex, args:[] },
+ { func:proto.forEach, args:[] },
+ { func:proto.indexOf, args:[] },
+ { func:proto.join, args:[] },
+ { func:proto.keys, args:[] },
+ { func:proto.lastIndexOf, args:[] },
+ { func:proto.map, args:[] },
+ { func:proto.reduce, args:[] },
+ { func:proto.reduceRight, args:[] },
+ { func:proto.reverse, args:[] },
+ { func:proto.set, args:[[]] },
+ { func:proto.set, args:[new Int32Array(1)] },
+ { func:proto.set, args:[new Int32Array(1)] },
+ { func:proto.set, args:[new Int32Array(1), -1], error:"RangeError: Offset should not be negative" },
+ { func:proto.slice, args:[] },
+ { func:proto.some, args:[] },
+ { func:proto.sort, args:[] },
+ { func:proto.subarray, args:[] },
+ { func:proto.toString, args:[] },
+ { func:proto.values, args:[] },
+];
+
+arrays = typedArrays.map(function(constructor) {
+ let view = new constructor(10);
+ transferArrayBuffer(view.buffer);
+ return view;
+});
+
+function checkProtoFunc(testArgs) {
+ function throwsCorrectError(elem) {
+ try {
+ result = testArgs.func.call(...[elem, ...testArgs.args]);
+ if (testArgs.result !== undefined) {
+ return result === testArgs.result;
+ }
+ } catch (e) {
+ if (testArgs.error)
+ return e == testArgs.error;
+ return e == "TypeError: Underlying ArrayBuffer has been detached from the view";
+ }
+ return false;
+ }
+
+ if (!arrays.every(throwsCorrectError))
+ throw "bad" + testArgs.func.name;
+}
+
+function test() {
+ prototypeFunctions.forEach(checkProtoFunc);
+}
+
+for (var i = 0; i < 1000; i++)
+ test();
+
</ins></span></pre>
</div>
</div>
</body>
</html>