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 "v8.h" 31 #include "api.h" 32 #include "heap.h" 33 #include "objects.h" 34 35 #include "cctest.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 CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap())); 93 { 94 v8::HandleScope s1(context->GetIsolate()); 95 v8::Handle<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(256); 96 { 97 v8::HandleScope s2(context->GetIsolate()); 98 v8::Handle<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(128); 99 100 Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1); 101 Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2); 102 CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap())); 103 CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1)); 104 CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2)); 105 } 106 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 107 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap())); 108 { 109 HandleScope scope2(isolate); 110 Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1); 111 112 CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1)); 113 } 114 } 115 116 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 117 CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap())); 118 } 119 120 121 TEST(WeakArrayBuffersFromScript) { 122 v8::V8::Initialize(); 123 LocalContext context; 124 Isolate* isolate = GetIsolateFrom(&context); 125 126 for (int i = 1; i <= 3; i++) { 127 // Create 3 array buffers, make i-th of them garbage, 128 // validate correct state of array buffer weak list. 129 CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap())); 130 { 131 v8::HandleScope scope(context->GetIsolate()); 132 133 { 134 v8::HandleScope s1(context->GetIsolate()); 135 CompileRun("var ab1 = new ArrayBuffer(256);" 136 "var ab2 = new ArrayBuffer(256);" 137 "var ab3 = new ArrayBuffer(256);"); 138 v8::Handle<v8::ArrayBuffer> ab1 = 139 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab1")); 140 v8::Handle<v8::ArrayBuffer> ab2 = 141 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab2")); 142 v8::Handle<v8::ArrayBuffer> ab3 = 143 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab3")); 144 145 CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap())); 146 CHECK(HasArrayBufferInWeakList(isolate->heap(), 147 *v8::Utils::OpenHandle(*ab1))); 148 CHECK(HasArrayBufferInWeakList(isolate->heap(), 149 *v8::Utils::OpenHandle(*ab2))); 150 CHECK(HasArrayBufferInWeakList(isolate->heap(), 151 *v8::Utils::OpenHandle(*ab3))); 152 } 153 154 i::ScopedVector<char> source(1024); 155 i::OS::SNPrintF(source, "ab%d = null;", i); 156 CompileRun(source.start()); 157 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 158 159 CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap())); 160 161 { 162 v8::HandleScope s2(context->GetIsolate()); 163 for (int j = 1; j <= 3; j++) { 164 if (j == i) continue; 165 i::OS::SNPrintF(source, "ab%d", j); 166 v8::Handle<v8::ArrayBuffer> ab = 167 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun(source.start())); 168 CHECK(HasArrayBufferInWeakList(isolate->heap(), 169 *v8::Utils::OpenHandle(*ab))); 170 } 171 } 172 173 CompileRun("ab1 = null; ab2 = null; ab3 = null;"); 174 } 175 176 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 177 CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap())); 178 } 179 } 180 181 template <typename View> 182 void TestViewFromApi() { 183 v8::V8::Initialize(); 184 LocalContext context; 185 Isolate* isolate = GetIsolateFrom(&context); 186 187 v8::HandleScope s1(context->GetIsolate()); 188 v8::Handle<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(2048); 189 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 190 { 191 v8::HandleScope s2(context->GetIsolate()); 192 v8::Handle<View> ta1 = View::New(ab, 0, 256); 193 { 194 v8::HandleScope s3(context->GetIsolate()); 195 v8::Handle<View> ta2 = View::New(ab, 0, 128); 196 197 Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1); 198 Handle<JSArrayBufferView> ita2 = v8::Utils::OpenHandle(*ta2); 199 CHECK_EQ(2, CountViews(*iab)); 200 CHECK(HasViewInWeakList(*iab, *ita1)); 201 CHECK(HasViewInWeakList(*iab, *ita2)); 202 } 203 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 204 CHECK_EQ(1, CountViews(*iab)); 205 Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1); 206 CHECK(HasViewInWeakList(*iab, *ita1)); 207 } 208 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 209 210 CHECK_EQ(0, CountViews(*iab)); 211 } 212 213 214 TEST(Uint8ArrayFromApi) { 215 TestViewFromApi<v8::Uint8Array>(); 216 } 217 218 219 TEST(Int8ArrayFromApi) { 220 TestViewFromApi<v8::Int8Array>(); 221 } 222 223 224 TEST(Uint16ArrayFromApi) { 225 TestViewFromApi<v8::Uint16Array>(); 226 } 227 228 229 TEST(Int16ArrayFromApi) { 230 TestViewFromApi<v8::Int16Array>(); 231 } 232 233 234 TEST(Uint32ArrayFromApi) { 235 TestViewFromApi<v8::Uint32Array>(); 236 } 237 238 239 TEST(Int32ArrayFromApi) { 240 TestViewFromApi<v8::Int32Array>(); 241 } 242 243 244 TEST(Float32ArrayFromApi) { 245 TestViewFromApi<v8::Float32Array>(); 246 } 247 248 249 TEST(Float64ArrayFromApi) { 250 TestViewFromApi<v8::Float64Array>(); 251 } 252 253 254 TEST(Uint8ClampedArrayFromApi) { 255 TestViewFromApi<v8::Uint8ClampedArray>(); 256 } 257 258 259 TEST(DataViewFromApi) { 260 TestViewFromApi<v8::DataView>(); 261 } 262 263 template <typename TypedArray> 264 static void TestTypedArrayFromScript(const char* constructor) { 265 v8::V8::Initialize(); 266 LocalContext context; 267 Isolate* isolate = GetIsolateFrom(&context); 268 v8::HandleScope scope(context->GetIsolate()); 269 CompileRun("var ab = new ArrayBuffer(2048);"); 270 for (int i = 1; i <= 3; i++) { 271 // Create 3 typed arrays, make i-th of them garbage, 272 // validate correct state of typed array weak list. 273 v8::HandleScope s0(context->GetIsolate()); 274 i::ScopedVector<char> source(2048); 275 276 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap())); 277 278 { 279 v8::HandleScope s1(context->GetIsolate()); 280 i::OS::SNPrintF(source, 281 "var ta1 = new %s(ab);" 282 "var ta2 = new %s(ab);" 283 "var ta3 = new %s(ab)", 284 constructor, constructor, constructor); 285 286 CompileRun(source.start()); 287 v8::Handle<v8::ArrayBuffer> ab = 288 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); 289 v8::Handle<TypedArray> ta1 = 290 v8::Handle<TypedArray>::Cast(CompileRun("ta1")); 291 v8::Handle<TypedArray> ta2 = 292 v8::Handle<TypedArray>::Cast(CompileRun("ta2")); 293 v8::Handle<TypedArray> ta3 = 294 v8::Handle<TypedArray>::Cast(CompileRun("ta3")); 295 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap())); 296 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 297 CHECK_EQ(3, CountViews(*iab)); 298 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1))); 299 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta2))); 300 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta3))); 301 } 302 303 i::OS::SNPrintF(source, "ta%d = null;", i); 304 CompileRun(source.start()); 305 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 306 307 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap())); 308 309 { 310 v8::HandleScope s2(context->GetIsolate()); 311 v8::Handle<v8::ArrayBuffer> ab = 312 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); 313 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 314 CHECK_EQ(2, CountViews(*iab)); 315 for (int j = 1; j <= 3; j++) { 316 if (j == i) continue; 317 i::OS::SNPrintF(source, "ta%d", j); 318 v8::Handle<TypedArray> ta = 319 v8::Handle<TypedArray>::Cast(CompileRun(source.start())); 320 CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta))); 321 } 322 } 323 324 CompileRun("ta1 = null; ta2 = null; ta3 = null;"); 325 isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 326 327 CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap())); 328 329 { 330 v8::HandleScope s3(context->GetIsolate()); 331 v8::Handle<v8::ArrayBuffer> ab = 332 v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); 333 Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); 334 CHECK_EQ(0, CountViews(*iab)); 335 } 336 } 337 } 338 339 340 TEST(Uint8ArrayFromScript) { 341 TestTypedArrayFromScript<v8::Uint8Array>("Uint8Array"); 342 } 343 344 345 TEST(Int8ArrayFromScript) { 346 TestTypedArrayFromScript<v8::Int8Array>("Int8Array"); 347 } 348 349 350 TEST(Uint16ArrayFromScript) { 351 TestTypedArrayFromScript<v8::Uint16Array>("Uint16Array"); 352 } 353 354 355 TEST(Int16ArrayFromScript) { 356 TestTypedArrayFromScript<v8::Int16Array>("Int16Array"); 357 } 358 359 360 TEST(Uint32ArrayFromScript) { 361 TestTypedArrayFromScript<v8::Uint32Array>("Uint32Array"); 362 } 363 364 365 TEST(Int32ArrayFromScript) { 366 TestTypedArrayFromScript<v8::Int32Array>("Int32Array"); 367 } 368 369 370 TEST(Float32ArrayFromScript) { 371 TestTypedArrayFromScript<v8::Float32Array>("Float32Array"); 372 } 373 374 375 TEST(Float64ArrayFromScript) { 376 TestTypedArrayFromScript<v8::Float64Array>("Float64Array"); 377 } 378 379 380 TEST(Uint8ClampedArrayFromScript) { 381 TestTypedArrayFromScript<v8::Uint8ClampedArray>("Uint8ClampedArray"); 382 } 383 384 385 TEST(DataViewFromScript) { 386 TestTypedArrayFromScript<v8::DataView>("DataView"); 387 } 388