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 "src/api.h" 32#include "src/heap.h" 33#include "src/objects.h" 34 35#include "test/cctest/cctest.h" 36 37using namespace v8::internal; 38 39static Isolate* GetIsolateFrom(LocalContext* context) { 40 return reinterpret_cast<Isolate*>((*context)->GetIsolate()); 41} 42 43 44static 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 55static 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 65static 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 76static 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 87TEST(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 123TEST(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 184template <typename View> 185void 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 218TEST(Uint8ArrayFromApi) { 219 TestViewFromApi<v8::Uint8Array>(); 220} 221 222 223TEST(Int8ArrayFromApi) { 224 TestViewFromApi<v8::Int8Array>(); 225} 226 227 228TEST(Uint16ArrayFromApi) { 229 TestViewFromApi<v8::Uint16Array>(); 230} 231 232 233TEST(Int16ArrayFromApi) { 234 TestViewFromApi<v8::Int16Array>(); 235} 236 237 238TEST(Uint32ArrayFromApi) { 239 TestViewFromApi<v8::Uint32Array>(); 240} 241 242 243TEST(Int32ArrayFromApi) { 244 TestViewFromApi<v8::Int32Array>(); 245} 246 247 248TEST(Float32ArrayFromApi) { 249 TestViewFromApi<v8::Float32Array>(); 250} 251 252 253TEST(Float64ArrayFromApi) { 254 TestViewFromApi<v8::Float64Array>(); 255} 256 257 258TEST(Uint8ClampedArrayFromApi) { 259 TestViewFromApi<v8::Uint8ClampedArray>(); 260} 261 262 263TEST(DataViewFromApi) { 264 TestViewFromApi<v8::DataView>(); 265} 266 267template <typename TypedArray> 268static 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 345TEST(Uint8ArrayFromScript) { 346 TestTypedArrayFromScript<v8::Uint8Array>("Uint8Array"); 347} 348 349 350TEST(Int8ArrayFromScript) { 351 TestTypedArrayFromScript<v8::Int8Array>("Int8Array"); 352} 353 354 355TEST(Uint16ArrayFromScript) { 356 TestTypedArrayFromScript<v8::Uint16Array>("Uint16Array"); 357} 358 359 360TEST(Int16ArrayFromScript) { 361 TestTypedArrayFromScript<v8::Int16Array>("Int16Array"); 362} 363 364 365TEST(Uint32ArrayFromScript) { 366 TestTypedArrayFromScript<v8::Uint32Array>("Uint32Array"); 367} 368 369 370TEST(Int32ArrayFromScript) { 371 TestTypedArrayFromScript<v8::Int32Array>("Int32Array"); 372} 373 374 375TEST(Float32ArrayFromScript) { 376 TestTypedArrayFromScript<v8::Float32Array>("Float32Array"); 377} 378 379 380TEST(Float64ArrayFromScript) { 381 TestTypedArrayFromScript<v8::Float64Array>("Float64Array"); 382} 383 384 385TEST(Uint8ClampedArrayFromScript) { 386 TestTypedArrayFromScript<v8::Uint8ClampedArray>("Uint8ClampedArray"); 387} 388 389 390TEST(DataViewFromScript) { 391 TestTypedArrayFromScript<v8::DataView>("DataView"); 392} 393