1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <stdlib.h> 29 30 #include "src/v8.h" 31 #include "test/cctest/cctest.h" 32 33 #include "src/api.h" 34 #include "src/heap/heap.h" 35 #include "src/objects.h" 36 37 using namespace v8::internal; 38 39 static Isolate* GetIsolateFrom(LocalContext* context) { 40 return reinterpret_cast<Isolate*>((*context)->GetIsolate()); 41 } 42 43 44 static int CountArrayBuffersInWeakList(Heap* heap) { 45 int count = 0; 46 for (Object* o = heap->array_buffers_list(); 47 !o->IsUndefined(); 48 o = JSArrayBuffer::cast(o)->weak_next()) { 49 count++; 50 } 51 return count; 52 } 53 54 55 static bool HasArrayBufferInWeakList(Heap* heap, JSArrayBuffer* ab) { 56 for (Object* o = heap->array_buffers_list(); 57 !o->IsUndefined(); 58 o = JSArrayBuffer::cast(o)->weak_next()) { 59 if (ab == o) return true; 60 } 61 return false; 62 } 63 64 65 static int CountViews(JSArrayBuffer* array_buffer) { 66 int count = 0; 67 for (Object* o = array_buffer->weak_first_view(); 68 !o->IsUndefined(); 69 o = JSArrayBufferView::cast(o)->weak_next()) { 70 count++; 71 } 72 73 return count; 74 } 75 76 static bool HasViewInWeakList(JSArrayBuffer* array_buffer, 77 JSArrayBufferView* ta) { 78 for (Object* o = array_buffer->weak_first_view(); 79 !o->IsUndefined(); 80 o = JSArrayBufferView::cast(o)->weak_next()) { 81 if (ta == o) return true; 82 } 83 return false; 84 } 85 86 87 TEST(WeakArrayBuffersFromApi) { 88 v8::V8::Initialize(); 89 LocalContext context; 90 Isolate* isolate = GetIsolateFrom(&context); 91 92 int start = CountArrayBuffersInWeakList(isolate->heap()); 93 { 94 v8::HandleScope s1(context->GetIsolate()); 95 v8::Handle<v8::ArrayBuffer> ab1 = 96 v8::ArrayBuffer::New(context->GetIsolate(), 256); 97 { 98 v8::HandleScope s2(context->GetIsolate()); 99 v8::Handle<v8::ArrayBuffer> ab2 = 100 v8::ArrayBuffer::New(context->GetIsolate(), 128); 101 102 Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1); 103 Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2); 104 CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start); 105 CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1)); 106 CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2)); 107 } 108 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 109 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); 110 { 111 HandleScope scope2(isolate); 112 Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1); 113 114 CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1)); 115 } 116 } 117 118 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 119 CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap())); 120 } 121 122 123 TEST(WeakArrayBuffersFromScript) { 124 v8::V8::Initialize(); 125 LocalContext context; 126 Isolate* isolate = GetIsolateFrom(&context); 127 int start = CountArrayBuffersInWeakList(isolate->heap()); 128 129 for (int i = 1; i <= 3; i++) { 130 // Create 3 array buffers, make i-th of them garbage, 131 // validate correct state of array buffer weak list. 132 CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap())); 133 { 134 v8::HandleScope scope(context->GetIsolate()); 135 136 { 137 v8::HandleScope s1(context->GetIsolate()); 138 CompileRun("var ab1 = new ArrayBuffer(256);" 139 "var ab2 = new ArrayBuffer(256);" 140 "var ab3 = new ArrayBuffer(256);"); 141 v8::Handle<v8::ArrayBuffer> ab1 = 142 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab1")); 143 v8::Handle<v8::ArrayBuffer> ab2 = 144 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab2")); 145 v8::Handle<v8::ArrayBuffer> ab3 = 146 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab3")); 147 148 CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()) - start); 149 CHECK(HasArrayBufferInWeakList(isolate->heap(), 150 *v8::Utils::OpenHandle(*ab1))); 151 CHECK(HasArrayBufferInWeakList(isolate->heap(), 152 *v8::Utils::OpenHandle(*ab2))); 153 CHECK(HasArrayBufferInWeakList(isolate->heap(), 154 *v8::Utils::OpenHandle(*ab3))); 155 } 156 157 i::ScopedVector<char> source(1024); 158 i::SNPrintF(source, "ab%d = null;", i); 159 CompileRun(source.start()); 160 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 161 162 CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start); 163 164 { 165 v8::HandleScope s2(context->GetIsolate()); 166 for (int j = 1; j <= 3; j++) { 167 if (j == i) continue; 168 i::SNPrintF(source, "ab%d", j); 169 v8::Handle<v8::ArrayBuffer> ab = 170 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun(source.start())); 171 CHECK(HasArrayBufferInWeakList(isolate->heap(), 172 *v8::Utils::OpenHandle(*ab))); 173 } 174 } 175 176 CompileRun("ab1 = null; ab2 = null; ab3 = null;"); 177 } 178 179 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 180 CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap())); 181 } 182 } 183 184 template <typename View> 185 void TestViewFromApi() { 186 v8::V8::Initialize(); 187 LocalContext context; 188 Isolate* isolate = GetIsolateFrom(&context); 189 190 v8::HandleScope s1(context->GetIsolate()); 191 v8::Handle<v8::ArrayBuffer> ab = 192 v8::ArrayBuffer::New(context->GetIsolate(), 2048); 193 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 194 { 195 v8::HandleScope s2(context->GetIsolate()); 196 v8::Handle<View> ta1 = View::New(ab, 0, 256); 197 { 198 v8::HandleScope s3(context->GetIsolate()); 199 v8::Handle<View> ta2 = View::New(ab, 0, 128); 200 201 Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1); 202 Handle<JSArrayBufferView> ita2 = v8::Utils::OpenHandle(*ta2); 203 CHECK_EQ(2, CountViews(*iab)); 204 CHECK(HasViewInWeakList(*iab, *ita1)); 205 CHECK(HasViewInWeakList(*iab, *ita2)); 206 } 207 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 208 CHECK_EQ(1, CountViews(*iab)); 209 Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1); 210 CHECK(HasViewInWeakList(*iab, *ita1)); 211 } 212 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 213 214 CHECK_EQ(0, CountViews(*iab)); 215 } 216 217 218 TEST(Uint8ArrayFromApi) { 219 TestViewFromApi<v8::Uint8Array>(); 220 } 221 222 223 TEST(Int8ArrayFromApi) { 224 TestViewFromApi<v8::Int8Array>(); 225 } 226 227 228 TEST(Uint16ArrayFromApi) { 229 TestViewFromApi<v8::Uint16Array>(); 230 } 231 232 233 TEST(Int16ArrayFromApi) { 234 TestViewFromApi<v8::Int16Array>(); 235 } 236 237 238 TEST(Uint32ArrayFromApi) { 239 TestViewFromApi<v8::Uint32Array>(); 240 } 241 242 243 TEST(Int32ArrayFromApi) { 244 TestViewFromApi<v8::Int32Array>(); 245 } 246 247 248 TEST(Float32ArrayFromApi) { 249 TestViewFromApi<v8::Float32Array>(); 250 } 251 252 253 TEST(Float64ArrayFromApi) { 254 TestViewFromApi<v8::Float64Array>(); 255 } 256 257 258 TEST(Uint8ClampedArrayFromApi) { 259 TestViewFromApi<v8::Uint8ClampedArray>(); 260 } 261 262 263 TEST(DataViewFromApi) { 264 TestViewFromApi<v8::DataView>(); 265 } 266 267 template <typename TypedArray> 268 static void TestTypedArrayFromScript(const char* constructor) { 269 v8::V8::Initialize(); 270 LocalContext context; 271 Isolate* isolate = GetIsolateFrom(&context); 272 v8::HandleScope scope(context->GetIsolate()); 273 int start = CountArrayBuffersInWeakList(isolate->heap()); 274 CompileRun("var ab = new ArrayBuffer(2048);"); 275 for (int i = 1; i <= 3; i++) { 276 // Create 3 typed arrays, make i-th of them garbage, 277 // validate correct state of typed array weak list. 278 v8::HandleScope s0(context->GetIsolate()); 279 i::ScopedVector<char> source(2048); 280 281 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); 282 283 { 284 v8::HandleScope s1(context->GetIsolate()); 285 i::SNPrintF(source, 286 "var ta1 = new %s(ab);" 287 "var ta2 = new %s(ab);" 288 "var ta3 = new %s(ab)", 289 constructor, constructor, constructor); 290 291 CompileRun(source.start()); 292 v8::Handle<v8::ArrayBuffer> ab = 293 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); 294 v8::Handle<TypedArray> ta1 = 295 v8::Handle<TypedArray>::Cast(CompileRun("ta1")); 296 v8::Handle<TypedArray> ta2 = 297 v8::Handle<TypedArray>::Cast(CompileRun("ta2")); 298 v8::Handle<TypedArray> ta3 = 299 v8::Handle<TypedArray>::Cast(CompileRun("ta3")); 300 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); 301 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 302 CHECK_EQ(3, CountViews(*iab)); 303 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1))); 304 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta2))); 305 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta3))); 306 } 307 308 i::SNPrintF(source, "ta%d = null;", i); 309 CompileRun(source.start()); 310 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 311 312 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); 313 314 { 315 v8::HandleScope s2(context->GetIsolate()); 316 v8::Handle<v8::ArrayBuffer> ab = 317 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); 318 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 319 CHECK_EQ(2, CountViews(*iab)); 320 for (int j = 1; j <= 3; j++) { 321 if (j == i) continue; 322 i::SNPrintF(source, "ta%d", j); 323 v8::Handle<TypedArray> ta = 324 v8::Handle<TypedArray>::Cast(CompileRun(source.start())); 325 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta))); 326 } 327 } 328 329 CompileRun("ta1 = null; ta2 = null; ta3 = null;"); 330 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 331 332 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); 333 334 { 335 v8::HandleScope s3(context->GetIsolate()); 336 v8::Handle<v8::ArrayBuffer> ab = 337 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); 338 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 339 CHECK_EQ(0, CountViews(*iab)); 340 } 341 } 342 } 343 344 345 TEST(Uint8ArrayFromScript) { 346 TestTypedArrayFromScript<v8::Uint8Array>("Uint8Array"); 347 } 348 349 350 TEST(Int8ArrayFromScript) { 351 TestTypedArrayFromScript<v8::Int8Array>("Int8Array"); 352 } 353 354 355 TEST(Uint16ArrayFromScript) { 356 TestTypedArrayFromScript<v8::Uint16Array>("Uint16Array"); 357 } 358 359 360 TEST(Int16ArrayFromScript) { 361 TestTypedArrayFromScript<v8::Int16Array>("Int16Array"); 362 } 363 364 365 TEST(Uint32ArrayFromScript) { 366 TestTypedArrayFromScript<v8::Uint32Array>("Uint32Array"); 367 } 368 369 370 TEST(Int32ArrayFromScript) { 371 TestTypedArrayFromScript<v8::Int32Array>("Int32Array"); 372 } 373 374 375 TEST(Float32ArrayFromScript) { 376 TestTypedArrayFromScript<v8::Float32Array>("Float32Array"); 377 } 378 379 380 TEST(Float64ArrayFromScript) { 381 TestTypedArrayFromScript<v8::Float64Array>("Float64Array"); 382 } 383 384 385 TEST(Uint8ClampedArrayFromScript) { 386 TestTypedArrayFromScript<v8::Uint8ClampedArray>("Uint8ClampedArray"); 387 } 388 389 390 TEST(DataViewFromScript) { 391 TestTypedArrayFromScript<v8::DataView>("DataView"); 392 } 393