1// Copyright 2011 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 "v8.h"
29
30#include "api.h"
31#include "debug.h"
32#include "execution.h"
33#include "factory.h"
34#include "macro-assembler.h"
35#include "objects.h"
36#include "global-handles.h"
37#include "cctest.h"
38
39using namespace v8::internal;
40
41
42TEST(ObjectHashTable) {
43  LocalContext context;
44  Isolate* isolate = Isolate::Current();
45  Factory* factory = isolate->factory();
46  v8::HandleScope scope(context->GetIsolate());
47  Handle<ObjectHashTable> table = factory->NewObjectHashTable(23);
48  Handle<JSObject> a = factory->NewJSArray(7);
49  Handle<JSObject> b = factory->NewJSArray(11);
50  table = PutIntoObjectHashTable(table, a, b);
51  CHECK_EQ(table->NumberOfElements(), 1);
52  CHECK_EQ(table->Lookup(*a), *b);
53  CHECK_EQ(table->Lookup(*b), HEAP->the_hole_value());
54
55  // Keys still have to be valid after objects were moved.
56  HEAP->CollectGarbage(NEW_SPACE);
57  CHECK_EQ(table->NumberOfElements(), 1);
58  CHECK_EQ(table->Lookup(*a), *b);
59  CHECK_EQ(table->Lookup(*b), HEAP->the_hole_value());
60
61  // Keys that are overwritten should not change number of elements.
62  table = PutIntoObjectHashTable(table, a, factory->NewJSArray(13));
63  CHECK_EQ(table->NumberOfElements(), 1);
64  CHECK_NE(table->Lookup(*a), *b);
65
66  // Keys mapped to the hole should be removed permanently.
67  table = PutIntoObjectHashTable(table, a, factory->the_hole_value());
68  CHECK_EQ(table->NumberOfElements(), 0);
69  CHECK_EQ(table->NumberOfDeletedElements(), 1);
70  CHECK_EQ(table->Lookup(*a), HEAP->the_hole_value());
71
72  // Keys should map back to their respective values and also should get
73  // an identity hash code generated.
74  for (int i = 0; i < 100; i++) {
75    Handle<JSObject> key = factory->NewJSArray(7);
76    Handle<JSObject> value = factory->NewJSArray(11);
77    table = PutIntoObjectHashTable(table, key, value);
78    CHECK_EQ(table->NumberOfElements(), i + 1);
79    CHECK_NE(table->FindEntry(*key), ObjectHashTable::kNotFound);
80    CHECK_EQ(table->Lookup(*key), *value);
81    CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi());
82  }
83
84  // Keys never added to the map which already have an identity hash
85  // code should not be found.
86  for (int i = 0; i < 100; i++) {
87    Handle<JSObject> key = factory->NewJSArray(7);
88    CHECK(key->GetIdentityHash(ALLOW_CREATION)->ToObjectChecked()->IsSmi());
89    CHECK_EQ(table->FindEntry(*key), ObjectHashTable::kNotFound);
90    CHECK_EQ(table->Lookup(*key), HEAP->the_hole_value());
91    CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi());
92  }
93
94  // Keys that don't have an identity hash should not be found and also
95  // should not get an identity hash code generated.
96  for (int i = 0; i < 100; i++) {
97    Handle<JSObject> key = factory->NewJSArray(7);
98    CHECK_EQ(table->Lookup(*key), HEAP->the_hole_value());
99    CHECK_EQ(key->GetIdentityHash(OMIT_CREATION), HEAP->undefined_value());
100  }
101}
102
103
104#ifdef DEBUG
105TEST(ObjectHashSetCausesGC) {
106  i::FLAG_stress_compaction = false;
107  LocalContext context;
108  Isolate* isolate = Isolate::Current();
109  Factory* factory = isolate->factory();
110  v8::HandleScope scope(context->GetIsolate());
111  Handle<ObjectHashSet> table = factory->NewObjectHashSet(1);
112  Handle<JSObject> key = factory->NewJSArray(0);
113  v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key);
114
115  // Force allocation of hash table backing store for hidden properties.
116  key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1"));
117  key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2"));
118  key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3"));
119
120  // Simulate a full heap so that generating an identity hash code
121  // in subsequent calls will request GC.
122  SimulateFullSpace(HEAP->new_space());
123  SimulateFullSpace(HEAP->old_pointer_space());
124
125  // Calling Contains() should not cause GC ever.
126  CHECK(!table->Contains(*key));
127
128  // Calling Remove() should not cause GC ever.
129  CHECK(!table->Remove(*key)->IsFailure());
130
131  // Calling Add() should request GC by returning a failure.
132  CHECK(table->Add(*key)->IsRetryAfterGC());
133}
134#endif
135
136
137#ifdef DEBUG
138TEST(ObjectHashTableCausesGC) {
139  i::FLAG_stress_compaction = false;
140  LocalContext context;
141  Isolate* isolate = Isolate::Current();
142  Factory* factory = isolate->factory();
143  v8::HandleScope scope(context->GetIsolate());
144  Handle<ObjectHashTable> table = factory->NewObjectHashTable(1);
145  Handle<JSObject> key = factory->NewJSArray(0);
146  v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key);
147
148  // Force allocation of hash table backing store for hidden properties.
149  key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1"));
150  key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2"));
151  key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3"));
152
153  // Simulate a full heap so that generating an identity hash code
154  // in subsequent calls will request GC.
155  SimulateFullSpace(HEAP->new_space());
156  SimulateFullSpace(HEAP->old_pointer_space());
157
158  // Calling Lookup() should not cause GC ever.
159  CHECK(table->Lookup(*key)->IsTheHole());
160
161  // Calling Put() should request GC by returning a failure.
162  CHECK(table->Put(*key, *key)->IsRetryAfterGC());
163}
164#endif
165