blob: 6f426392bd7b6cebf91373bd8bae882b1045e4c4 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002
3// Check that we can traverse very deep stacks of ConsStrings using
4// StringInputBuffer. Check that Get(int) works on very deep stacks
5// of ConsStrings. These operations may not be very fast, but they
6// should be possible without getting errors due to too deep recursion.
7
8#include <stdlib.h>
9
10#include "v8.h"
11
ager@chromium.org5ec48922009-05-05 07:25:34 +000012#include "api.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013#include "factory.h"
14#include "cctest.h"
ager@chromium.org41826e72009-03-30 13:30:57 +000015#include "zone-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000016
17unsigned int seed = 123;
18
19static uint32_t gen() {
20 uint64_t z;
21 z = seed;
22 z *= 279470273;
23 z %= 4294967291U;
24 seed = static_cast<unsigned int>(z);
25 return static_cast<uint32_t>(seed >> 16);
26}
27
28
29using namespace v8::internal;
30
31static v8::Persistent<v8::Context> env;
32
33
34static void InitializeVM() {
35 if (env.IsEmpty()) {
36 v8::HandleScope scope;
37 const char* extensions[] = { "v8/print" };
38 v8::ExtensionConfiguration config(1, extensions);
39 env = v8::Context::New(&config);
40 }
41 v8::HandleScope scope;
42 env->Enter();
43}
44
45
46static const int NUMBER_OF_BUILDING_BLOCKS = 128;
47static const int DEEP_DEPTH = 8 * 1024;
48static const int SUPER_DEEP_DEPTH = 80 * 1024;
49
50
51static void InitializeBuildingBlocks(
52 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
ager@chromium.org41826e72009-03-30 13:30:57 +000053 // A list of pointers that we don't have any interest in cleaning up.
54 // If they are reachable from a root then leak detection won't complain.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000055 for (int i = 0; i < NUMBER_OF_BUILDING_BLOCKS; i++) {
56 int len = gen() % 16;
57 if (len > 14) {
58 len += 1234;
59 }
60 switch (gen() % 4) {
61 case 0: {
62 uc16 buf[2000];
63 for (int j = 0; j < len; j++) {
64 buf[j] = gen() % 65536;
65 }
66 building_blocks[i] =
67 Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
68 for (int j = 0; j < len; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000069 CHECK_EQ(buf[j], building_blocks[i]->Get(j));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000070 }
71 break;
72 }
73 case 1: {
74 char buf[2000];
75 for (int j = 0; j < len; j++) {
76 buf[j] = gen() % 128;
77 }
78 building_blocks[i] =
79 Factory::NewStringFromAscii(Vector<const char>(buf, len));
80 for (int j = 0; j < len; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000081 CHECK_EQ(buf[j], building_blocks[i]->Get(j));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000082 }
83 break;
84 }
85 case 2: {
86 class Resource: public v8::String::ExternalStringResource,
ager@chromium.org41826e72009-03-30 13:30:57 +000087 public ZoneObject {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000088 public:
89 explicit Resource(Vector<const uc16> string): data_(string.start()) {
90 length_ = string.length();
91 }
92 virtual const uint16_t* data() const { return data_; }
93 virtual size_t length() const { return length_; }
94
95 private:
96 const uc16* data_;
97 size_t length_;
98 };
ager@chromium.org41826e72009-03-30 13:30:57 +000099 uc16* buf = Zone::NewArray<uc16>(len);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100 for (int j = 0; j < len; j++) {
101 buf[j] = gen() % 65536;
102 }
103 Resource* resource = new Resource(Vector<const uc16>(buf, len));
104 building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
105 for (int j = 0; j < len; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 CHECK_EQ(buf[j], building_blocks[i]->Get(j));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000107 }
108 break;
109 }
110 case 3: {
111 char* buf = NewArray<char>(len);
112 for (int j = 0; j < len; j++) {
113 buf[j] = gen() % 128;
114 }
115 building_blocks[i] =
116 Factory::NewStringFromAscii(Vector<const char>(buf, len));
117 for (int j = 0; j < len; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 CHECK_EQ(buf[j], building_blocks[i]->Get(j));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000119 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 DeleteArray<char>(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000121 break;
122 }
123 }
124 }
125}
126
127
128static Handle<String> ConstructLeft(
129 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
130 int depth) {
131 Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
132 for (int i = 0; i < depth; i++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000133 answer = Factory::NewConsString(
134 answer,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000135 building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000136 }
137 return answer;
138}
139
140
141static Handle<String> ConstructRight(
142 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
143 int depth) {
144 Handle<String> answer = Factory::NewStringFromAscii(CStrVector(""));
145 for (int i = depth - 1; i >= 0; i--) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000146 answer = Factory::NewConsString(
147 building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 answer);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000149 }
150 return answer;
151}
152
153
154static Handle<String> ConstructBalancedHelper(
155 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
156 int from,
157 int to) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000158 CHECK(to > from);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000159 if (to - from == 1) {
160 return building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
161 }
162 if (to - from == 2) {
163 return Factory::NewConsString(
164 building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000166 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000167 Handle<String> part1 =
168 ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
169 Handle<String> part2 =
170 ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 return Factory::NewConsString(part1, part2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000172}
173
174
175static Handle<String> ConstructBalanced(
176 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
177 return ConstructBalancedHelper(building_blocks, 0, DEEP_DEPTH);
178}
179
180
181static StringInputBuffer buffer;
182
183
184static void Traverse(Handle<String> s1, Handle<String> s2) {
185 int i = 0;
186 buffer.Reset(*s1);
187 StringInputBuffer buffer2(*s2);
188 while (buffer.has_more()) {
189 CHECK(buffer2.has_more());
190 uint16_t c = buffer.GetNext();
191 CHECK_EQ(c, buffer2.GetNext());
192 i++;
193 }
194 CHECK_EQ(s1->length(), i);
195 CHECK_EQ(s2->length(), i);
196}
197
198
199static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
200 int i = 0;
201 buffer.Reset(*s1);
202 StringInputBuffer buffer2(*s2);
203 while (buffer.has_more() && i < chars) {
204 CHECK(buffer2.has_more());
205 uint16_t c = buffer.GetNext();
206 CHECK_EQ(c, buffer2.GetNext());
207 i++;
208 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000209 s1->Get(s1->length() - 1);
210 s2->Get(s2->length() - 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000211}
212
213
214TEST(Traverse) {
215 printf("TestTraverse\n");
216 InitializeVM();
217 v8::HandleScope scope;
218 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
ager@chromium.org41826e72009-03-30 13:30:57 +0000219 ZoneScope zone(DELETE_ON_EXIT);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220 InitializeBuildingBlocks(building_blocks);
221 Handle<String> flat = ConstructBalanced(building_blocks);
222 FlattenString(flat);
223 Handle<String> left_asymmetric = ConstructLeft(building_blocks, DEEP_DEPTH);
224 Handle<String> right_asymmetric = ConstructRight(building_blocks, DEEP_DEPTH);
225 Handle<String> symmetric = ConstructBalanced(building_blocks);
226 printf("1\n");
227 Traverse(flat, symmetric);
228 printf("2\n");
229 Traverse(flat, left_asymmetric);
230 printf("3\n");
231 Traverse(flat, right_asymmetric);
232 printf("4\n");
233 Handle<String> left_deep_asymmetric =
234 ConstructLeft(building_blocks, SUPER_DEEP_DEPTH);
235 Handle<String> right_deep_asymmetric =
236 ConstructRight(building_blocks, SUPER_DEEP_DEPTH);
237 printf("5\n");
238 TraverseFirst(left_asymmetric, left_deep_asymmetric, 1050);
239 printf("6\n");
240 TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536);
241 printf("7\n");
242 Handle<String> right_deep_slice =
243 Factory::NewStringSlice(left_deep_asymmetric,
244 left_deep_asymmetric->length() - 1050,
245 left_deep_asymmetric->length() - 50);
246 Handle<String> left_deep_slice =
247 Factory::NewStringSlice(right_deep_asymmetric,
248 right_deep_asymmetric->length() - 1050,
249 right_deep_asymmetric->length() - 50);
250 printf("8\n");
251 Traverse(right_deep_slice, left_deep_slice);
252 printf("9\n");
253 FlattenString(left_asymmetric);
254 printf("10\n");
255 Traverse(flat, left_asymmetric);
256 printf("11\n");
257 FlattenString(right_asymmetric);
258 printf("12\n");
259 Traverse(flat, right_asymmetric);
260 printf("14\n");
261 FlattenString(symmetric);
262 printf("15\n");
263 Traverse(flat, symmetric);
264 printf("16\n");
265 FlattenString(left_deep_asymmetric);
266 printf("18\n");
267}
268
269
270static Handle<String> SliceOf(Handle<String> underlying) {
271 int start = gen() % underlying->length();
272 int end = start + gen() % (underlying->length() - start);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000273 return Factory::NewStringSlice(underlying,
ager@chromium.org870a0b62008-11-04 11:43:05 +0000274 start,
275 end);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000276}
277
278
279static Handle<String> ConstructSliceTree(
280 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
281 int from,
282 int to) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000283 CHECK(to > from);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000284 if (to - from <= 1)
285 return SliceOf(building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]);
286 if (to - from == 2) {
287 Handle<String> lhs = building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
288 if (gen() % 2 == 0)
289 lhs = SliceOf(lhs);
290 Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
291 if (gen() % 2 == 0)
292 rhs = SliceOf(rhs);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293 return Factory::NewConsString(lhs, rhs);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000294 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000295 Handle<String> part1 =
296 ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
297 Handle<String> part2 =
298 ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299 Handle<String> branch = Factory::NewConsString(part1, part2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000300 if (gen() % 2 == 0)
301 return branch;
302 return(SliceOf(branch));
303}
304
305
306TEST(Slice) {
307 printf("TestSlice\n");
308 InitializeVM();
309 v8::HandleScope scope;
310 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
ager@chromium.org41826e72009-03-30 13:30:57 +0000311 ZoneScope zone(DELETE_ON_EXIT);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000312 InitializeBuildingBlocks(building_blocks);
313
314 seed = 42;
315 Handle<String> slice_tree =
316 ConstructSliceTree(building_blocks, 0, DEEP_DEPTH);
317 seed = 42;
318 Handle<String> flat_slice_tree =
319 ConstructSliceTree(building_blocks, 0, DEEP_DEPTH);
320 FlattenString(flat_slice_tree);
321 Traverse(flat_slice_tree, slice_tree);
322}
323
324static const int DEEP_ASCII_DEPTH = 100000;
325
326
327TEST(DeepAscii) {
328 printf("TestDeepAscii\n");
329 InitializeVM();
330 v8::HandleScope scope;
331
332 char* foo = NewArray<char>(DEEP_ASCII_DEPTH);
333 for (int i = 0; i < DEEP_ASCII_DEPTH; i++) {
334 foo[i] = "foo "[i % 4];
335 }
336 Handle<String> string =
337 Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
338 Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
339 for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000340 string = Factory::NewConsString(string, foo_string);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000341 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000342 Handle<String> flat_string = Factory::NewConsString(string, foo_string);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343 FlattenString(flat_string);
344
345 for (int i = 0; i < 500; i++) {
346 TraverseFirst(flat_string, string, DEEP_ASCII_DEPTH);
347 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000348 DeleteArray<char>(foo);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349}
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000350
351
352TEST(Utf8Conversion) {
353 // Smoke test for converting strings to utf-8.
354 InitializeVM();
355 v8::HandleScope handle_scope;
356 // A simple ascii string
357 const char* ascii_string = "abcdef12345";
358 int len = v8::String::New(ascii_string, strlen(ascii_string))->Utf8Length();
359 CHECK_EQ(strlen(ascii_string), len);
360 // A mixed ascii and non-ascii string
361 // U+02E4 -> CB A4
362 // U+0064 -> 64
363 // U+12E4 -> E1 8B A4
364 // U+0030 -> 30
365 // U+3045 -> E3 81 85
366 const uint16_t mixed_string[] = {0x02E4, 0x0064, 0x12E4, 0x0030, 0x3045};
367 // The characters we expect to be output
368 const unsigned char as_utf8[11] = {0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 0x30,
369 0xE3, 0x81, 0x85, 0x00};
370 // The number of bytes expected to be written for each length
371 const int lengths[12] = {0, 0, 2, 3, 3, 3, 6, 7, 7, 7, 10, 11};
372 v8::Handle<v8::String> mixed = v8::String::New(mixed_string, 5);
373 CHECK_EQ(10, mixed->Utf8Length());
374 // Try encoding the string with all capacities
375 char buffer[11];
376 const char kNoChar = static_cast<char>(-1);
377 for (int i = 0; i <= 11; i++) {
378 // Clear the buffer before reusing it
379 for (int j = 0; j < 11; j++)
380 buffer[j] = kNoChar;
381 int written = mixed->WriteUtf8(buffer, i);
382 CHECK_EQ(lengths[i], written);
383 // Check that the contents are correct
384 for (int j = 0; j < lengths[i]; j++)
385 CHECK_EQ(as_utf8[j], static_cast<unsigned char>(buffer[j]));
386 // Check that the rest of the buffer hasn't been touched
387 for (int j = lengths[i]; j < 11; j++)
388 CHECK_EQ(kNoChar, buffer[j]);
389 }
390}
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000391
392
393class TwoByteResource: public v8::String::ExternalStringResource {
394 public:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000395 TwoByteResource(const uint16_t* data, size_t length, bool* destructed)
396 : data_(data), length_(length), destructed_(destructed) {
397 if (destructed_ != NULL) {
398 *destructed_ = false;
399 }
400 }
401
402 virtual ~TwoByteResource() {
403 if (destructed_ != NULL) {
404 CHECK(!*destructed_);
405 *destructed_ = true;
406 }
407 }
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000408
409 const uint16_t* data() const { return data_; }
410 size_t length() const { return length_; }
411
412 private:
413 const uint16_t* data_;
414 size_t length_;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000415 bool* destructed_;
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000416};
417
418
419TEST(ExternalCrBug9746) {
420 InitializeVM();
421 v8::HandleScope handle_scope;
422
423 // This set of tests verifies that the workaround for Chromium bug 9746
424 // works correctly. In certain situations the external resource of a symbol
425 // is collected while the symbol is still part of the symbol table.
426 static uint16_t two_byte_data[] = {
427 't', 'w', 'o', '-', 'b', 'y', 't', 'e', ' ', 'd', 'a', 't', 'a'
428 };
429 static size_t two_byte_length =
430 sizeof(two_byte_data) / sizeof(two_byte_data[0]);
431 static const char* one_byte_data = "two-byte data";
432
433 // Allocate an external string resource and external string.
434 TwoByteResource* resource = new TwoByteResource(two_byte_data,
ager@chromium.org5ec48922009-05-05 07:25:34 +0000435 two_byte_length,
436 NULL);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000437 Handle<String> string = Factory::NewExternalStringFromTwoByte(resource);
438 Vector<const char> one_byte_vec = CStrVector(one_byte_data);
439 Handle<String> compare = Factory::NewStringFromAscii(one_byte_vec);
440
441 // Verify the correct behaviour before "collecting" the external resource.
442 CHECK(string->IsEqualTo(one_byte_vec));
443 CHECK(string->Equals(*compare));
444
445 // "Collect" the external resource manually by setting the external resource
446 // pointer to NULL. Then redo the comparisons, they should not match AND
447 // not crash.
448 Handle<ExternalTwoByteString> external(ExternalTwoByteString::cast(*string));
449 external->set_resource(NULL);
450 CHECK_EQ(false, string->IsEqualTo(one_byte_vec));
451#if !defined(DEBUG)
452 // These tests only work in non-debug as there are ASSERTs in the code that
453 // do prevent the ability to even get into the broken code when running the
454 // debug version of V8.
455 CHECK_EQ(false, string->Equals(*compare));
456 CHECK_EQ(false, compare->Equals(*string));
457 CHECK_EQ(false, string->Equals(Heap::empty_string()));
458#endif // !defined(DEBUG)
459}
ager@chromium.org5ec48922009-05-05 07:25:34 +0000460
461
462// Regression test case for http://crbug.com/9746. The problem was
463// that when we marked objects reachable only through weak pointers,
464// we ended up keeping a sliced symbol alive, even though we already
465// invoked the weak callback on the underlying external string thus
466// deleting its resource.
467TEST(Regress9746) {
468 InitializeVM();
469
470 // Setup lengths that guarantee we'll get slices instead of simple
471 // flat strings.
472 static const int kFullStringLength = String::kMinNonFlatLength * 2;
473 static const int kSliceStringLength = String::kMinNonFlatLength + 1;
474
475 uint16_t* source = new uint16_t[kFullStringLength];
476 for (int i = 0; i < kFullStringLength; i++) source[i] = '1';
477 char* key = new char[kSliceStringLength];
478 for (int i = 0; i < kSliceStringLength; i++) key[i] = '1';
479
480 // Allocate an external string resource that keeps track of when it
481 // is destructed.
482 bool resource_destructed = false;
483 TwoByteResource* resource =
484 new TwoByteResource(source, kFullStringLength, &resource_destructed);
485
486 {
487 v8::HandleScope scope;
488
489 // Allocate an external string resource and external string. We
490 // have to go through the API to get the weak handle and the
491 // automatic destruction going.
492 Handle<String> string =
493 v8::Utils::OpenHandle(*v8::String::NewExternal(resource));
494
495 // Create a slice of the external string.
496 Handle<String> slice =
497 Factory::NewStringSlice(string, 0, kSliceStringLength);
498 CHECK_EQ(kSliceStringLength, slice->length());
499 CHECK(StringShape(*slice).IsSliced());
500
501 // Make sure the slice ends up in old space so we can morph it
502 // into a symbol.
503 while (Heap::InNewSpace(*slice)) {
504 Heap::PerformScavenge();
505 }
506
507 // Force the slice into the symbol table.
508 slice = Factory::SymbolFromString(slice);
509 CHECK(slice->IsSymbol());
510 CHECK(StringShape(*slice).IsSliced());
511
512 Handle<String> buffer(Handle<SlicedString>::cast(slice)->buffer());
513 CHECK(StringShape(*buffer).IsExternal());
514 CHECK(buffer->IsTwoByteRepresentation());
515
516 // Finally, base a script on the slice of the external string and
517 // get its wrapper. This allocated yet another weak handle that
518 // indirectly refers to the external string.
519 Handle<Script> script = Factory::NewScript(slice);
520 Handle<JSObject> wrapper = GetScriptWrapper(script);
521 }
522
523 // When we collect all garbage, we cannot get rid of the sliced
524 // symbol entry in the symbol table because it is used by the script
525 // kept alive by the weak wrapper. Make sure we don't destruct the
526 // external string.
527 Heap::CollectAllGarbage();
528 CHECK(!resource_destructed);
529
530 // Make sure the sliced symbol is still in the table.
531 v8::HandleScope scope;
532 Vector<const char> vector(key, kSliceStringLength);
533 Handle<String> symbol = Factory::LookupSymbol(vector);
534 CHECK(StringShape(*symbol).IsSliced());
535
536 // Make sure the buffer is still a two-byte external string.
537 Handle<String> buffer(Handle<SlicedString>::cast(symbol)->buffer());
538 CHECK(StringShape(*buffer).IsExternal());
539 CHECK(buffer->IsTwoByteRepresentation());
540
541 delete[] source;
542 delete[] key;
543}